diff options
679 files changed, 71733 insertions, 8313 deletions
diff --git a/.clang-format b/.clang-format new file mode 100644 index 000000000..28d13da25 --- /dev/null +++ b/.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/.dockerignore b/.dockerignore new file mode 100644 index 000000000..9910e9954 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,13 @@ +.editorconfig
+.gitignore
+.gitmodules
+.github
+.git
+Dockerfile
+README.md
+manual
+CodingReadme
+CodeOfConduct
+.travis
+.travis.yml
+
diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..4d6f5ef7a --- /dev/null +++ b/.editorconfig @@ -0,0 +1,7 @@ +root = true + +[*] +indent_style = tab +indent_size = tab +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/.github/issue_template.md b/.github/issue_template.md index 24e91a4e7..5a0723c3e 100644 --- a/.github/issue_template.md +++ b/.github/issue_template.md @@ -1,9 +1,20 @@ ## Steps to reproduce the issue *Provide instructions for reproducing the issue. Make sure to include -all neccessary source files. (You can simply drag&drop a .zip file into +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.* @@ -11,6 +22,3 @@ the issue editor.)* ## Actual behavior *Please describe how the behavior you see differs from the expected behavior.* - -**Important Note:** Nobody will be able to help you and/or fix the issue if you -do not provide sufficient information for reproducing the problem. diff --git a/.gitignore b/.gitignore index cd624f233..76f53cd06 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,9 @@ *.d .*.swp *.gch +*.gcda +*.gcno +__pycache__ /.cproject /.project /.settings @@ -10,6 +13,8 @@ /qtcreator.config /qtcreator.creator /qtcreator.creator.user +/coverage.info +/coverage_html /Makefile.conf /abc /viz.js @@ -20,8 +25,12 @@ /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-* @@ -30,3 +39,4 @@ /libyosys.so /tests/unit/bintest/ /tests/unit/objtest/ +/tests/ystests diff --git a/.travis.yml b/.travis.yml index fbb4018af..09f380831 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,39 +28,18 @@ matrix: - tcl-dev - libffi-dev - git - - mercurial - graphviz - xdot - pkg-config - python + - python3 + - libboost-system-dev + - libboost-python-dev + - libboost-filesystem-dev + - zlib1g-dev env: - MATRIX_EVAL="CONFIG=gcc && CC=gcc-4.8 && CXX=g++-4.8" - # Latest gcc-6 on Travis Linux - - os: linux - addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - g++-6 - - gperf - - build-essential - - bison - - flex - - libreadline-dev - - gawk - - tcl-dev - - libffi-dev - - git - - mercurial - - graphviz - - xdot - - pkg-config - - python - env: - - MATRIX_EVAL="CONFIG=gcc && CC=gcc-6 && CXX=g++-6" - # Latest gcc supported on Travis Linux - os: linux addons: @@ -68,7 +47,7 @@ matrix: sources: - ubuntu-toolchain-r-test packages: - - g++-7 + - g++-9 - gperf - build-essential - bison @@ -78,13 +57,17 @@ matrix: - tcl-dev - libffi-dev - git - - mercurial - graphviz - xdot - pkg-config - python + - python3 + - libboost-system-dev + - libboost-python-dev + - libboost-filesystem-dev + - zlib1g-dev env: - - MATRIX_EVAL="CONFIG=gcc && CC=gcc-7 && CXX=g++-7" + - MATRIX_EVAL="CONFIG=gcc && CC=gcc-9 && CXX=g++-9" # Clang which ships on Trusty Linux - os: linux @@ -104,11 +87,15 @@ matrix: - tcl-dev - libffi-dev - git - - mercurial - graphviz - xdot - pkg-config - python + - python3 + - libboost-system-dev + - libboost-python-dev + - libboost-filesystem-dev + - zlib1g-dev env: - MATRIX_EVAL="CONFIG=clang && CC=clang-3.8 && CXX=clang++-3.8" @@ -117,9 +104,9 @@ matrix: addons: apt: sources: - - llvm-toolchain-trusty-5.0 + - llvm-toolchain-xenial-8 packages: - - clang-5.0 + - clang-8 - gperf - build-essential - bison @@ -129,19 +116,23 @@ matrix: - tcl-dev - libffi-dev - git - - mercurial - graphviz - xdot - pkg-config - python + - python3 + - libboost-system-dev + - libboost-python-dev + - libboost-filesystem-dev + - zlib1g-dev env: - - MATRIX_EVAL="CONFIG=clang && CC=clang-5.0 && CXX=clang++-5.0" + - MATRIX_EVAL="CONFIG=clang && CC=clang-8 && CXX=clang++-8" - # Latest clang on Mac OS X - - os: osx - osx_image: xcode8 - env: - - MATRIX_EVAL="CONFIG=gcc && CC=gcc-7 && CXX=g++-7" +# # Latest clang on Mac OS X +# - os: osx +# osx_image: xcode9.4 +# env: +# - MATRIX_EVAL="CONFIG=clang && CC=clang && CXX=clang++" before_install: - ./.travis/setup.sh diff --git a/.travis/build-and-test.sh b/.travis/build-and-test.sh index 096dde64f..801407d1e 100755 --- a/.travis/build-and-test.sh +++ b/.travis/build-and-test.sh @@ -28,7 +28,7 @@ echo echo 'Building...' && echo -en 'travis_fold:start:script.build\\r' echo -make +make CC=$CC CXX=$CC LD=$CC echo echo -en 'travis_fold:end:script.build\\r' @@ -36,6 +36,8 @@ echo ########################################################################## +./yosys tests/simple/fiedler-cooley.v + echo echo 'Testing...' && echo -en 'travis_fold:start:script.test\\r' echo diff --git a/.travis/setup.sh b/.travis/setup.sh index 81ff37742..02879b974 100755 --- a/.travis/setup.sh +++ b/.travis/setup.sh @@ -6,48 +6,15 @@ source .travis/common.sh ########################################################################## -# Fixing Travis's git clone -echo -echo 'Fixing git setup...' && echo -en 'travis_fold:start:before_install.git\\r' -echo -git fetch --unshallow && git fetch --tags - -# For pull requests, we get more info about the git source. -if [ z"$TRAVIS_PULL_REQUEST_SLUG" != z ]; then - echo "- Fetching from pull request source" - git remote add source https://github.com/$TRAVIS_PULL_REQUEST_SLUG.git - git fetch source && git fetch --tags - - echo "- Fetching the actual pull request" - git fetch origin pull/$TRAVIS_PULL_REQUEST/head:pull-$TRAVIS_PULL_REQUEST-head - git fetch origin pull/$TRAVIS_PULL_REQUEST/merge:pull-$TRAVIS_PULL_REQUEST-merge - - git log -n 5 --graph pull-$TRAVIS_PULL_REQUEST-merge -fi - -# For building branches we need to fix the "detached head" state. -if [ z"$TRAVIS_BRANCH" != z ]; then - TRAVIS_COMMIT_ACTUAL=$(git log --pretty=format:'%H' -n 1) - echo "- Fixing detached head (current $TRAVIS_COMMIT_ACTUAL -> $TRAVIS_COMMIT)" - git remote -v - git branch -v - if [ x"$(git show-ref -s HEAD)" = x"$TRAVIS_COMMIT" ]; then - echo "Checked out at $TRAVIS_COMMIT" - else - if [ z"$TRAVIS_PULL_REQUEST_SLUG" != z ]; then - git fetch source $TRAVIS_COMMIT || echo "Unable to fetch $TRAVIS_COMMIT from source" - fi - git fetch origin $TRAVIS_COMMIT || echo "Unable to fetch $TRAVIS_COMMIT from origin" - fi - git branch -D $TRAVIS_BRANCH || true - git checkout $TRAVIS_COMMIT -b $TRAVIS_BRANCH - git branch -v -fi - # Output status information. -git status -git describe --tags -git log -n 5 --graph +( + 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 @@ -64,7 +31,6 @@ if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew tap Homebrew/bundle brew bundle brew install ccache - brew install gcc echo echo -en 'travis_fold:end:before_install.brew\\r' echo @@ -85,7 +51,7 @@ fi git clone git://github.com/steveicarus/iverilog.git cd iverilog autoconf - ./configure --prefix=$HOME/.local-bin + CC=gcc CXX=g++ ./configure --prefix=$HOME/.local-bin make make install echo @@ -3,7 +3,8 @@ brew "flex" brew "gawk" brew "libffi" brew "git" -brew "mercurial" brew "graphviz" brew "pkg-config" brew "python3" +brew "tcl-tk" +brew "xdot" @@ -3,9 +3,276 @@ List of major changes and improvements between releases ======================================================= -Yosys 0.7 .. Yosys ??? +Yosys 0.9 .. Yosys 0.9-dev +-------------------------- + + * Various + - Added "write_xaiger" backend + - Added "abc9" pass for timing-aware techmapping (experimental, FPGA only, no FFs) + - Added "synth_xilinx -abc9" (experimental) + - Added "synth_ice40 -abc9" (experimental) + - Added "synth -abc9" (experimental) + - Added "script -scriptwire" + - Added "synth_xilinx -nocarry" + - Added "synth_xilinx -nowidelut" + - Added "synth_ecp5 -nowidelut" + - "synth_xilinx" to now infer wide multiplexers (-widemux <min> to enable) + - Renamed labels/options in synth_ice40 (e.g. dram -> map_lutram; -nodram -> -nolutram) + - Renamed labels/options in synth_ecp5 (e.g. dram -> map_lutram; -nodram -> -nolutram) + - Renamed labels in synth_intel (e.g. bram -> map_bram) + - Renamed labels/options in synth_xilinx (e.g. dram -> map_lutram; -nodram -> -nolutram) + - Added automatic gzip decompression for frontends + - Added $_NMUX_ cell type + - Added automatic gzip compression (based on filename extension) for backends + - Improve attribute and parameter encoding in JSON to avoid ambiguities between + bit vectors and strings containing [01xz]* + - Added "clkbufmap" pass + - Added "extractinv" pass and "invertible_pin" attribute + - Added "synth_xilinx -family xc6s" for Spartan 6 support (experimental) + - Added "synth_xilinx -ise" (experimental) + - Added "synth_xilinx -iopad" + - "synth_xilinx" now automatically inserts clock buffers (add -noclkbuf to disable) + - Improvements in pmgen: subpattern and recursive matches + - Added "opt_share" pass, run as part of "opt -full" + - Added "ice40_wrapcarry" to encapsulate SB_LUT+SB_CARRY pairs for techmapping + - Removed "ice40_unlut" + - Improvements in pmgen: slices, choices, define, generate + - Added "xilinx_srl" for Xilinx shift register extraction + - Removed "shregmap -tech xilinx" (superseded by "xilinx_srl") + - Added "_TECHMAP_WIREINIT_*_" attribute and "_TECHMAP_REMOVEINIT_*_" wire for "techmap" pass + - Added "-match-init" option to "dff2dffs" pass + - Added "techmap_autopurge" support to techmap + - Added "add -mod <modname[s]>" + +Yosys 0.8 .. Yosys 0.9 +---------------------- + + * Various + - Many bugfixes and small improvements + - Added support for SystemVerilog interfaces and modports + - Added "write_edif -attrprop" + - Added "opt_lut" pass + - Added "gate2lut.v" techmap rule + - Added "rename -src" + - Added "equiv_opt" pass + - 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}=<cost>" + - Added "muxcover -dmux=<cost>" + - 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 ---------------------- + * Various + - Many bugfixes and small improvements + - Strip debug symbols from installed binary + - Replace -ignore_redef with -[no]overwrite in front-ends + - Added write_verilog hex dump support, add -nohex option + - Added "write_verilog -decimal" + - Added "scc -set_attr" + - Added "verilog_defines" command + - Remember defines from one read_verilog to next + - Added support for hierarchical defparam + - Added FIRRTL back-end + - Improved ABC default scripts + - Added "design -reset-vlog" + - Added "yosys -W regex", "yosys -w regex", and "yosys -e regex" + - Added Verilog $rtoi and $itor support + - Added "check -initdrv" + - Added "read_blif -wideports" + - 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 + - Added simple C beck-end (bitwise combinatorical only atm) + - Added $_ANDNOT_ and $_ORNOT_ cell types + - Added cell library aliases to "abc -g" + - Added "setundef -anyseq" + - Added "chtype" command + - Added "design -import" + - Added "write_table" command + - Added "read_json" command + - Added "sim" command + - Added "extract_fa" and "extract_reduce" commands + - Added "extract_counter" command + - Added "opt_demorgan" command + - Added support for $size and $bits SystemVerilog functions + - Added "blackbox" command + - Added "ltp" command + - Added support for editline as replacement for readline + - Added warnings for driver-driver conflicts between FFs (and other cells) and constants + - Added "yosys -E" for creating Makefile dependencies files + - Added "synth -noshare" + - Added "memory_nordff" + - Added "setundef -undef -expose -anyconst" + - Added "expose -input" + - Added specify/specparam parser support (simply ignore them) + - Added "write_blif -inames -iattr" + - Added "hierarchy -simcheck" + - Added an option to statically link abc into yosys + - Added protobuf back-end + - Added BLIF parsing support for .conn and .cname + - Added read_verilog error checking for reg/wire/logic misuse + - Added "make coverage" and ENABLE_GCOV build option + + * Changes in Yosys APIs + - Added ConstEval defaultval feature + - Added {get,set}_src_attribute() methods on RTLIL::AttrObject + - Added SigSpec::is_fully_ones() and Const::is_fully_ones() + - Added log_file_warning() and log_file_error() functions + + * Formal Verification + - Added "write_aiger" + - Added "yosys-smtbmc --aig" + - Added "always <positive_int>" to .smtc format + - Added $cover cell type and support for cover properties + - Added $fair/$live cell type and support for liveness properties + - Added smtbmc support for memory vcd dumping + - Added "chformal" command + - Added "write_smt2 -stbv" and "write_smt2 -stdt" + - Fix equiv_simple, old behavior now available with "equiv_simple -short" + - Change to Yices2 as default SMT solver (it is GPL now) + - Added "yosys-smtbmc --presat" (now default in SymbiYosys) + - Added "yosys-smtbmc --smtc-init --smtc-top --noinit" + - Added a brand new "write_btor" command for BTOR2 + - Added clk2fflogic memory support and other improvements + - Added "async memory write" support to write_smt2 + - Simulate clock toggling in yosys-smtbmc VCD output + - Added $allseq/$allconst cells for EA-solving + - Make -nordff the default in "prep" + - Added (* gclk *) attribute + - Added "async2sync" pass for single-clock designs with async resets + + * Verific support + - Many improvements in Verific front-end + - Added proper handling of concurent SVA properties + - Map "const" and "rand const" to $anyseq/$anyconst + - Added "verific -import -flatten" and "verific -import -extnets" + - Added "verific -vlog-incdir -vlog-define -vlog-libdir" + - Remove PSL support (because PSL has been removed in upstream Verific) + - Improve integration with "hierarchy" command design elaboration + - Added YOSYS_NOVERIFIC for running non-verific test cases with verific bin + - Added simpilied "read" command that automatically uses verific if available + - Added "verific -set-<severity> <msg_id>.." + - Added "verific -work <libname>" + + * New back-ends + - Added initial Coolrunner-II support + - Added initial eASIC support + - Added initial ECP5 support + + * GreenPAK Support + - Added support for GP_DLATCH, GP_SPI, GP_DCMx, GP_COUNTx, etc. + + * iCE40 Support + - Add "synth_ice40 -vpr" + - Add "synth_ice40 -nodffe" + - Add "synth_ice40 -json" + - Add Support for UltraPlus cells + * MAX10 and Cyclone IV Support - Added initial version of metacommand "synth_intel". - Improved write_verilog command to produce VQM netlist for Quartus Prime. @@ -14,6 +281,7 @@ Yosys 0.7 .. Yosys ??? - Added example of implementation for DE2i-150 board. - Added example of implementation for MAX10 development kit. - Added LFSR example from Asic World. + - Added "dffinit -highlow" for mapping to Intel primitives Yosys 0.6 .. Yosys 0.7 @@ -1,4 +1,4 @@ -Copyright (C) 2012 - 2017 Clifford Wolf <clifford@clifford.at> +Copyright (C) 2012 - 2019 Clifford Wolf <clifford@clifford.at> 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/CodingReadme b/CodingReadme index 5800e30c3..8212436e5 100644 --- a/CodingReadme +++ b/CodingReadme @@ -21,7 +21,7 @@ Here is a the C++ code for a "hello_world" Yosys command (hello.cc): struct HelloWorldPass : public Pass { HelloWorldPass() : Pass("hello_world") { } - virtual void execute(vector<string>, Design*) { + void execute(vector<string>, Design*) override { log("Hello World!\n"); } } HelloWorldPass; @@ -373,6 +373,7 @@ Finally run all tests with "make config-{clang,gcc,gcc-4.8}": cd ~yosys make clean make test + make ystests make vloghtb make install @@ -389,6 +390,7 @@ Finally run all tests with "make config-{clang,gcc,gcc-4.8}": Release: - set YOSYS_VER to x.y.z in Makefile + - remove "bumpversion" target from Makefile - update version string in CHANGELOG git commit -am "Yosys x.y.z" diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..549c73c97 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,57 @@ +ARG IMAGE="python:3-slim-buster" + +#--- + +FROM $IMAGE AS base + +RUN apt-get update -qq \ + && DEBIAN_FRONTEND=noninteractive apt-get -y install --no-install-recommends \ + ca-certificates \ + clang \ + curl \ + libffi-dev \ + libreadline-dev \ + tcl-dev \ + graphviz \ + xdot \ + && apt-get autoclean && apt-get clean && apt-get -y autoremove \ + && update-ca-certificates \ + && rm -rf /var/lib/apt/lists + +#--- + +FROM base AS build + +RUN apt-get update -qq \ + && DEBIAN_FRONTEND=noninteractive apt-get -y install --no-install-recommends \ + bison \ + flex \ + gawk \ + gcc \ + git \ + iverilog \ + pkg-config \ + && apt-get autoclean && apt-get clean && apt-get -y autoremove \ + && rm -rf /var/lib/apt/lists + +COPY . /yosys + +ENV PREFIX /opt/yosys + +RUN cd /yosys \ + && make \ + && make install \ + && make test + +#--- + +FROM base + +COPY --from=build /opt/yosys /opt/yosys + +ENV PATH /opt/yosys/bin:$PATH + +RUN useradd -m yosys +USER yosys + +CMD ["yosys"] @@ -2,13 +2,16 @@ CONFIG := clang # CONFIG := gcc # CONFIG := gcc-4.8 +# CONFIG := afl-gcc # CONFIG := emcc # CONFIG := mxe # CONFIG := msys2 +# CONFIG := msys2-64 # features (the more the better) ENABLE_TCL := 1 ENABLE_ABC := 1 +ENABLE_GLOB := 1 ENABLE_PLUGINS := 1 ENABLE_READLINE := 1 ENABLE_EDITLINE := 0 @@ -16,8 +19,13 @@ ENABLE_VERIFIC := 0 ENABLE_COVER := 1 ENABLE_LIBYOSYS := 0 ENABLE_PROTOBUF := 0 +ENABLE_ZLIB := 1 + +# python wrappers +ENABLE_PYOSYS := 0 # other configuration flags +ENABLE_GCOV := 0 ENABLE_GPROF := 0 ENABLE_DEBUG := 0 ENABLE_NDEBUG := 0 @@ -39,6 +47,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 @@ -70,13 +82,19 @@ PKG_CONFIG ?= pkg-config SED ?= sed BISON ?= bison STRIP ?= strip +AWK ?= awk ifeq ($(OS), Darwin) PLUGIN_LDFLAGS += -undefined dynamic_lookup # homebrew search paths -ifneq ($(shell which brew),) +ifneq ($(shell :; command -v brew),) BREW_PREFIX := $(shell brew --prefix)/opt +$(info $$BREW_PREFIX is [${BREW_PREFIX}]) +ifeq ($(ENABLE_PYOSYS),1) +CXXFLAGS += -I$(BREW_PREFIX)/boost/include/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) @@ -84,8 +102,8 @@ PKG_CONFIG_PATH := $(BREW_PREFIX)/tcl-tk/lib/pkgconfig:$(PKG_CONFIG_PATH) export PATH := $(BREW_PREFIX)/bison/bin:$(BREW_PREFIX)/gettext/bin:$(BREW_PREFIX)/flex/bin:$(PATH) # macports search paths -else ifneq ($(shell which port),) -PORT_PREFIX := $(patsubst %/bin/port,%,$(shell which port)) +else ifneq ($(shell :; command -v port),) +PORT_PREFIX := $(patsubst %/bin/port,%,$(shell :; command -v port)) CXXFLAGS += -I$(PORT_PREFIX)/include LDFLAGS += -L$(PORT_PREFIX)/lib PKG_CONFIG_PATH := $(PORT_PREFIX)/lib/pkgconfig:$(PKG_CONFIG_PATH) @@ -97,17 +115,20 @@ LDFLAGS += -rdynamic LDLIBS += -lrt endif -YOSYS_VER := 0.7+$(shell cd $(YOSYS_SRC) && test -e .git && { git log --author=clifford@clifford.at --oneline 61f6811.. | wc -l; }) +YOSYS_VER := 0.9+431 GIT_REV := $(shell cd $(YOSYS_SRC) && git rev-parse --short HEAD 2> /dev/null || echo UNKNOWN) OBJS = kernel/version_$(GIT_REV).o +bumpversion: + sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 8a4c6e6.. | wc -l`/;" Makefile + # set 'ABCREV = default' to use abc/ as it is # # Note: If you do ABC development, make sure that 'abc' in this directory # is just a symlink to your actual ABC working directory, as 'make mrproper' # will remove the 'abc' directory and you do not want to accidentally # delete your work on ABC.. -ABCREV = 6df1396 +ABCREV = 5776ad0 ABCPULL = 1 ABCURL ?= https://github.com/berkeley-abc/abc ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 @@ -126,6 +147,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++ @@ -155,12 +191,36 @@ LD = gcc CXXFLAGS += -std=c++11 -Os ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H" +else ifeq ($(CONFIG),gcc-static) +LD = $(CXX) +LDFLAGS := $(filter-out -rdynamic,$(LDFLAGS)) -static +LDLIBS := $(filter-out -lrt,$(LDLIBS)) +CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS)) +CXXFLAGS += -std=c++11 -Os +ABCMKARGS = CC="$(CC)" CXX="$(CXX)" LD="$(LD)" ABC_USE_LIBSTDCXX=1 LIBS="-lm -lpthread -static" OPTFLAGS="-O" \ + ARCHFLAGS="-DABC_USE_STDINT_H -DABC_NO_DYNAMIC_LINKING=1 -Wno-unused-but-set-variable $(ARCHFLAGS)" ABC_USE_NO_READLINE=1 +ifeq ($(DISABLE_ABC_THREADS),1) +ABCMKARGS += "ABC_USE_NO_PTHREADS=1" +endif + else ifeq ($(CONFIG),gcc-4.8) CXX = gcc-4.8 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 +CXXFLAGS += -std=gnu++11 -Os +ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H" + else ifeq ($(CONFIG),emcc) CXX = emcc LD = emcc @@ -199,14 +259,15 @@ yosys.html: misc/yosys.html else ifeq ($(CONFIG),mxe) PKG_CONFIG = /usr/local/src/mxe/usr/bin/i686-w64-mingw32.static-pkg-config -CXX = /usr/local/src/mxe/usr/bin/i686-w64-mingw32.static-gcc -LD = /usr/local/src/mxe/usr/bin/i686-w64-mingw32.static-gcc +CXX = /usr/local/src/mxe/usr/bin/i686-w64-mingw32.static-g++ +LD = /usr/local/src/mxe/usr/bin/i686-w64-mingw32.static-g++ CXXFLAGS += -std=c++11 -Os -D_POSIX_SOURCE -DYOSYS_MXE_HACKS -Wno-attributes CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS)) LDFLAGS := $(filter-out -rdynamic,$(LDFLAGS)) -s LDLIBS := $(filter-out -lrt,$(LDLIBS)) -ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H -DWIN32_NO_DLL -DHAVE_STRUCT_TIMESPEC -fpermissive -w" -ABCMKARGS += LIBS="lib/x86/pthreadVC2.lib -s" ABC_USE_NO_READLINE=1 +ABCMKARGS += ARCHFLAGS="-DWIN32_NO_DLL -DHAVE_STRUCT_TIMESPEC -fpermissive -w" +# 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) @@ -217,17 +278,77 @@ CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS)) LDFLAGS := $(filter-out -rdynamic,$(LDFLAGS)) -s LDLIBS := $(filter-out -lrt,$(LDLIBS)) ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H -DWIN32_NO_DLL -DHAVE_STRUCT_TIMESPEC -fpermissive -w" -ABCMKARGS += LIBS="lib/x86/pthreadVC2.lib -s" ABC_USE_NO_READLINE=0 +ABCMKARGS += LIBS="-lpthread -s" ABC_USE_NO_READLINE=0 CC="i686-w64-mingw32-gcc" CXX="$(CXX)" +EXE = .exe + +else ifeq ($(CONFIG),msys2-64) +CXX = x86_64-w64-mingw32-g++ +LD = x86_64-w64-mingw32-g++ +CXXFLAGS += -std=c++11 -Os -D_POSIX_SOURCE -DYOSYS_WIN32_UNIX_DIR +CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS)) +LDFLAGS := $(filter-out -rdynamic,$(LDFLAGS)) -s +LDLIBS := $(filter-out -lrt,$(LDLIBS)) +ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H -DWIN32_NO_DLL -DHAVE_STRUCT_TIMESPEC -fpermissive -w" +ABCMKARGS += LIBS="-lpthread -s" ABC_USE_NO_READLINE=0 CC="x86_64-w64-mingw32-gcc" CXX="$(CXX)" EXE = .exe else ifneq ($(CONFIG),none) -$(error Invalid CONFIG setting '$(CONFIG)'. Valid values: clang, gcc, gcc-4.8, emcc, mxe, msys2) +$(error Invalid CONFIG setting '$(CONFIG)'. Valid values: clang, gcc, gcc-4.8, emcc, mxe, msys2, msys2-64) endif ifeq ($(ENABLE_LIBYOSYS),1) TARGETS += libyosys.so endif +ifeq ($(ENABLE_PYOSYS),1) + +#Detect name of boost_python library. Some distros usbe boost_python-py<version>, other boost_python<version>, 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 += $(shell $(PYTHON_EXECUTABLE)-config --ldflags) $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem +CXXFLAGS += $(shell $(PYTHON_EXECUTABLE)-config --includes) -DWITH_PYTHON +else +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 ifeq ($(OS), FreeBSD) @@ -266,6 +387,16 @@ LDLIBS += -ldl endif endif +ifeq ($(ENABLE_GLOB),1) +CXXFLAGS += -DYOSYS_ENABLE_GLOB +endif + +ifeq ($(ENABLE_ZLIB),1) +CXXFLAGS += -DYOSYS_ENABLE_ZLIB +LDLIBS += -lz +endif + + ifeq ($(ENABLE_TCL),1) TCL_VERSION ?= tcl$(shell bash -c "tclsh <(echo 'puts [info tclversion]')") ifeq ($(OS), FreeBSD) @@ -276,7 +407,7 @@ endif ifeq ($(CONFIG),mxe) CXXFLAGS += -DYOSYS_ENABLE_TCL -LDLIBS += -ltcl86 -lwsock32 -lws2_32 -lnetapi32 +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) @@ -288,6 +419,11 @@ endif endif endif +ifeq ($(ENABLE_GCOV),1) +CXXFLAGS += --coverage +LDFLAGS += --coverage +endif + ifeq ($(ENABLE_GPROF),1) CXXFLAGS += -pg LDFLAGS += -pg @@ -320,11 +456,15 @@ endif endif ifeq ($(ENABLE_VERIFIC),1) -VERIFIC_DIR ?= /usr/local/src/verific_lib_eval -VERIFIC_COMPONENTS ?= verilog vhdl database util containers sdf hier_tree +VERIFIC_DIR ?= /usr/local/src/verific_lib +VERIFIC_COMPONENTS ?= verilog vhdl database util containers hier_tree CXXFLAGS += $(patsubst %,-I$(VERIFIC_DIR)/%,$(VERIFIC_COMPONENTS)) -DYOSYS_ENABLE_VERIFIC +ifeq ($(OS), Darwin) +LDLIBS += $(patsubst %,$(VERIFIC_DIR)/%/*-mac.a,$(VERIFIC_COMPONENTS)) -lz +else LDLIBS += $(patsubst %,$(VERIFIC_DIR)/%/*-linux.a,$(VERIFIC_COMPONENTS)) -lz endif +endif ifeq ($(ENABLE_PROTOBUF),1) LDLIBS += $(shell pkg-config --cflags --libs protobuf) @@ -352,11 +492,16 @@ define add_include_file $(eval $(call add_share_file,$(dir share/include/$(1)),$(1))) endef +define add_extra_objs +EXTRA_OBJS += $(1) +.SECONDARY: $(1) +endef + ifeq ($(PRETTY), 1) P_STATUS = 0 P_OFFSET = 0 -P_UPDATE = $(eval P_STATUS=$(shell echo $(OBJS) yosys$(EXE) | gawk 'BEGIN { RS = " "; I = $(P_STATUS)+0; } $$1 == "$@" && NR > I { I = NR; } END { print I; }')) -P_SHOW = [$(shell gawk "BEGIN { N=$(words $(OBJS) yosys$(EXE)); printf \"%3d\", $(P_OFFSET)+90*$(P_STATUS)/N; exit; }")%] +P_UPDATE = $(eval P_STATUS=$(shell echo $(OBJS) yosys$(EXE) | $(AWK) 'BEGIN { RS = " "; I = $(P_STATUS)+0; } $$1 == "$@" && NR > I { I = NR; } END { print I; }')) +P_SHOW = [$(shell $(AWK) "BEGIN { N=$(words $(OBJS) yosys$(EXE)); printf \"%3d\", $(P_OFFSET)+90*$(P_STATUS)/N; exit; }")%] P = @echo "$(if $(findstring $@,$(TARGETS) $(EXTRA_TARGETS)),$(eval P_OFFSET = 10))$(call P_UPDATE)$(call P_SHOW) Building $@"; Q = @ S = -s @@ -458,12 +603,26 @@ 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 $@) $(P) $(CXX) -o $@ -c $(CPPFLAGS) $(CXXFLAGS) $< +%.pyh: %.h + $(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 $@) $(P) $(CXX) -o $@ -c $(CPPFLAGS) $(CXXFLAGS) $< @@ -525,18 +684,32 @@ 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/simple_abc9 && bash run-test.sh $(SEEDOPT) +cd tests/hana && bash run-test.sh $(SEEDOPT) +cd tests/asicworld && bash run-test.sh $(SEEDOPT) - +cd tests/realmath && bash run-test.sh $(SEEDOPT) + # +cd tests/realmath && bash run-test.sh $(SEEDOPT) +cd tests/share && bash run-test.sh $(SEEDOPT) + +cd tests/opt_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/proc && bash run-test.sh + +cd tests/opt && bash run-test.sh + +cd tests/aiger && bash run-test.sh $(ABCOPT) + +cd tests/arch && bash run-test.sh + +cd tests/ice40 && bash run-test.sh $(SEEDOPT) @echo "" @echo " Passed \"make test\"." @echo "" @@ -555,6 +728,14 @@ vloghtb: $(TARGETS) $(EXTRA_TARGETS) @echo " Passed \"make vloghtb\"." @echo "" +ystests: $(TARGETS) $(EXTRA_TARGETS) + rm -rf tests/ystests + git clone https://github.com/YosysHQ/yosys-tests.git tests/ystests + +$(MAKE) PATH="$$PWD:$$PATH" -C tests/ystests + @echo "" + @echo " Finished \"make ystests\"." + @echo "" + # Unit test unit-test: libyosys.so @$(MAKE) -C $(UNITESTPATH) CXX="$(CXX)" CPPFLAGS="$(CPPFLAGS)" \ @@ -578,9 +759,14 @@ endif $(INSTALL_SUDO) mkdir -p $(DESTDIR)$(DATDIR) $(INSTALL_SUDO) cp -r share/. $(DESTDIR)$(DATDIR)/. ifeq ($(ENABLE_LIBYOSYS),1) - $(INSTALL_SUDO) cp libyosys.so $(DESTDIR)$(LIBDIR) + $(INSTALL_SUDO) mkdir -p $(DESTDIR)$(LIBDIR) + $(INSTALL_SUDO) cp libyosys.so $(DESTDIR)$(LIBDIR)/ $(INSTALL_SUDO) $(STRIP) -S $(DESTDIR)$(LIBDIR)/libyosys.so - $(INSTALL_SUDO) ldconfig +ifeq ($(ENABLE_PYOSYS),1) + $(INSTALL_SUDO) mkdir -p $(PYTHON_DESTDIR)/pyosys + $(INSTALL_SUDO) cp libyosys.so $(PYTHON_DESTDIR)/pyosys/ + $(INSTALL_SUDO) cp misc/__init__.py $(PYTHON_DESTDIR)/pyosys/ +endif endif uninstall: @@ -588,6 +774,11 @@ uninstall: $(INSTALL_SUDO) rm -rvf $(DESTDIR)$(DATDIR) ifeq ($(ENABLE_LIBYOSYS),1) $(INSTALL_SUDO) rm -vf $(DESTDIR)$(LIBDIR)/libyosys.so +ifeq ($(ENABLE_PYOSYS),1) + $(INSTALL_SUDO) rm -vf $(PYTHON_DESTDIR)/pyosys/libyosys.so + $(INSTALL_SUDO) rm -vf $(PYTHON_DESTDIR)/pyosys/__init__.py + $(INSTALL_SUDO) rmdir $(PYTHON_DESTDIR)/pyosys +endif endif update-manual: $(TARGETS) $(EXTRA_TARGETS) @@ -600,9 +791,10 @@ manual: $(TARGETS) $(EXTRA_TARGETS) clean: rm -rf share + rm -rf kernel/*.pyh if test -d manual; then cd manual && sh clean.sh; fi - rm -f $(OBJS) $(GENFILES) $(TARGETS) $(EXTRA_TARGETS) $(EXTRA_OBJS) - rm -f kernel/version_*.o kernel/version_*.cc abc/abc-[0-9a-f]* abc/libabc-[0-9a-f]*.a + rm -f $(OBJS) $(GENFILES) $(TARGETS) $(EXTRA_TARGETS) $(EXTRA_OBJS) $(PY_WRAP_INCLUDES) $(PY_WRAPPER_FILE).cc + rm -f kernel/version_*.o kernel/version_*.cc rm -f libs/*/*.d frontends/*/*.d passes/*/*.d backends/*/*.d kernel/*.d techlibs/*/*.d rm -rf tests/asicworld/*.out tests/asicworld/*.log rm -rf tests/hana/*.out tests/hana/*.log @@ -611,6 +803,7 @@ clean: rm -rf tests/sat/*.log tests/techmap/*.log tests/various/*.log rm -rf tests/bram/temp tests/fsm/temp tests/realmath/temp tests/share/temp tests/smv/temp rm -rf vloghtb/Makefile vloghtb/refdat vloghtb/rtl vloghtb/scripts vloghtb/spec vloghtb/check_yosys vloghtb/vloghammer_tb.tar.bz2 vloghtb/temp vloghtb/log_test_* + rm -f tests/svinterfaces/*.log_stdout tests/svinterfaces/*.log_stderr tests/svinterfaces/dut_result.txt tests/svinterfaces/reference_result.txt tests/svinterfaces/a.out tests/svinterfaces/*_syn.v tests/svinterfaces/*.diff rm -f tests/tools/cmp_tbdata clean-abc: @@ -620,6 +813,12 @@ clean-abc: mrproper: clean git clean -xdf +coverage: + ./yosys -qp 'help; help -all' + rm -rf coverage.info coverage_html + lcov --capture -d . --no-external -o coverage.info + genhtml coverage.info --output-directory coverage_html + qtcreator: { for file in $(basename $(OBJS)); do \ for prefix in cc y l; do if [ -f $${file}.$${prefix} ]; then echo $$file.$${prefix}; fi; done \ @@ -659,9 +858,18 @@ config-clang: clean config-gcc: clean echo 'CONFIG := gcc' > Makefile.conf +config-gcc-static: clean + echo 'CONFIG := gcc-static' > Makefile.conf + echo 'ENABLE_PLUGINS := 0' >> Makefile.conf + echo 'ENABLE_READLINE := 0' >> Makefile.conf + echo 'ENABLE_TCL := 0' >> Makefile.conf + 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 @@ -675,6 +883,19 @@ 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 + +config-gcov: clean + echo 'CONFIG := gcc' > Makefile.conf + echo 'ENABLE_GCOV := 1' >> Makefile.conf + echo 'ENABLE_DEBUG := 1' >> Makefile.conf config-gprof: clean echo 'CONFIG := gcc' > Makefile.conf @@ -696,6 +917,6 @@ echo-git-rev: -include kernel/*.d -include techlibs/*/*.d -.PHONY: all top-all abc test install install-abc manual clean mrproper qtcreator -.PHONY: config-clean config-clang config-gcc config-gcc-4.8 config-gprof config-sudo +.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-afl-gcc config-gprof config-sudo @@ -1,7 +1,7 @@ ``` yosys -- Yosys Open SYnthesis Suite -Copyright (C) 2012 - 2017 Clifford Wolf <clifford@clifford.at> +Copyright (C) 2012 - 2019 Clifford Wolf <clifford@clifford.at> Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -34,11 +34,24 @@ compatible license that is similar in terms to the MIT license or the 2-clause BSD license). -Web Site -======== +Web Site and Other Resources +============================ More information and documentation can be found on the Yosys web site: -http://www.clifford.at/yosys/ +- http://www.clifford.at/yosys/ + +The "Documentation" page on the web site contains links to more resources, +including a manual that even describes some of the Yosys internals: +- http://www.clifford.at/yosys/documentation.html + +The file `CodingReadme` in this directory contains additional information +for people interested in using the Yosys C++ APIs. + +Users interested in formal verification might want to use the formal verification +front-end for Yosys, SymbiYosys: +- https://symbiyosys.readthedocs.io/en/latest/ +- https://github.com/YosysHQ/SymbiYosys + Setup ====== @@ -53,22 +66,30 @@ prerequisites for building yosys: $ sudo apt-get install build-essential clang bison flex \ libreadline-dev gawk tcl-dev libffi-dev git \ - graphviz xdot pkg-config python3 + graphviz xdot pkg-config python3 libboost-system-dev \ + libboost-python-dev libboost-filesystem-dev zlib1g-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 + git graphviz pkgconfig python36 boost zlib tcl On FreeBSD use the following command to install all prerequisites: # pkg install bison flex readline gawk libffi\ - git graphviz pkgconfig python3 python36 tcl-wrapper + git graphviz pkgconf python3 python36 tcl-wrapper boost-libs On FreeBSD system use gmake instead of make. To run tests use: % MAKE=gmake CC=cc gmake test +For Cygwin use the following command to install all prerequisites, or select these additional packages: + + setup-x86_64.exe -q --packages=bison,flex,gcc-core,gcc-g++,git,libffi-devel,libreadline-devel,make,pkg-config,python3,tcl-devel,boost-build,zlib-devel + 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 @@ -88,12 +109,15 @@ Makefile. 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). +Tests are located in the tests subdirectory and can be executed using the test target. Note that you need gawk as well as a recent version of iverilog (i.e. build from git). Then, execute tests via: + + $ make test + Getting Started =============== @@ -109,18 +133,15 @@ commands and ``help <command>`` to print details on the specified command: yosys> help help -reading the design using the Verilog frontend: +reading and elaborating the design using the Verilog frontend: - yosys> read_verilog tests/simple/fiedler-cooley.v + yosys> read -sv tests/simple/fiedler-cooley.v + yosys> hierarchy -top up3down5 -writing the design to the console in yosys's internal format: +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: @@ -142,51 +163,26 @@ 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 + read -sv tests/simple/fiedler-cooley.v + hierarchy -top up3down5 + 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: + # read design + read -sv tests/simple/fiedler-cooley.v + hierarchy -top up3down5 + # the high-level stuff - hierarchy; proc; fsm; opt; memory; opt + proc; fsm; opt; memory; opt # mapping to internal cell library techmap; opt @@ -201,7 +197,8 @@ synthesize for the given cell library: 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. +you can use the file ``examples/cmos/cmos_cells.lib`` from the yosys sources +as simple example. Liberty file downloads for and information about free and open ASIC standard cell libraries can be found here: @@ -210,39 +207,33 @@ cell libraries can be found here: - 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: +``help synth``): - # the high-level stuff - hierarchy - synth -run coarse + read -sv tests/simple/fiedler-cooley.v + synth -top up3down5 - # mapping to internal cells - techmap; opt -fast + # mapping to target cells dfflibmap -liberty mycells.lib abc -liberty mycells.lib clean -Yosys is under construction. A more detailed documentation will follow. +The command ``prep`` provides a good default word-level synthesis script, as +used in SMT-based formal verification. Unsupported Verilog-2005 Features ================================= The following Verilog-2005 features are not supported by -yosys and there are currently no plans to add support +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 +- The ``tri``, ``triand`` and ``trior`` net types -- Latched logic (is synthesized as logic with feedback loops) +- The ``config`` and ``disable`` keywords and library map files Verilog Attributes and non-standard features @@ -281,16 +272,34 @@ Verilog Attributes and non-standard features 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. + by Yosys to synthesize Verilog functions and access arrays. -- The ``onehot`` attribute on wires mark them as onehot state register. This +- The ``onehot`` attribute on wires mark them as one-hot 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. + also does not output blackbox modules on default. ``read_verilog``, unless + called with ``-noblackbox`` will automatically set the blackbox attribute + on any empty module it reads. + +- The ``noblackbox`` attribute set on an empty module prevents ``read_verilog`` + from automatically setting the blackbox attribute on the module. + +- The ``whitebox`` attribute on modules triggers the same behavior as + ``blackbox``, but is for whitebox modules, i.e. library modules that + contain a behavioral model of the cell type. + +- The ``lib_whitebox`` attribute overwrites ``whitebox`` when ``read_verilog`` + is run in `-lib` mode. Otherwise it's automatically removed. + +- The ``dynports`` attribute is used by the Verilog front-end to mark modules + that have ports with a width that depends on a parameter. + +- The ``hdlname`` attribute is used by some passes to document the original + (HDL) name of a module when renaming a module. - 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 @@ -315,13 +324,60 @@ 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. -- In addition to the ``(* ... *)`` attribute syntax, yosys supports +- 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). + +- Wires marked with the ``hierconn`` attribute are connected to wires with the + same name (format ``cell_name.identifier``) when they are imported from + sub-modules by ``flatten``. + +- The ``clkbuf_driver`` attribute can be set on an output port of a blackbox + module to mark it as a clock buffer output, and thus prevent ``clkbufmap`` + from inserting another clock buffer on a net driven by such output. + +- The ``clkbuf_sink`` attribute can be set on an input port of a module to + request clock buffer insertion by the ``clkbufmap`` pass. + +- The ``clkbuf_inhibit`` is the default attribute to set on a wire to prevent + automatic clock buffer insertion by ``clkbufmap``. This behaviour can be + overridden by providing a custom selection to ``clkbufmap``. + +- The ``invertible_pin`` attribute can be set on a port to mark it as + invertible via a cell parameter. The name of the inversion parameter + is specified as the value of this attribute. The value of the inversion + parameter must be of the same width as the port, with 1 indicating + an inverted bit and 0 indicating a non-inverted bit. + +- The ``iopad_external_pin`` attribute on a blackbox module's port marks + it as the external-facing pin of an I/O pad, and prevents ``iopadmap`` + from inserting another pad cell on it. + +- The module attribute ``abc_box_id`` specifies a positive integer linking a + blackbox or whitebox definition to a corresponding entry in a `abc9` + box-file. + +- The port attribute ``abc_carry`` marks the carry-in (if an input port) and + carry-out (if output port) ports of a box. This information is necessary for + `abc9` to preserve the integrity of carry-chains. Specifying this attribute + onto a bus port will affect only its most significant bit. + +- The port attribute ``abc_arrival`` specifies an integer (for output ports + only) to be used as the arrival time of this sequential port. It can be used, + for example, to specify the clk-to-Q delay of a flip-flop for consideration + during techmapping. + +- 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 + 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 @@ -331,7 +387,7 @@ Verilog Attributes and non-standard features - 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: + triple double quotes are removed from the macro body. For example: `define MY_MACRO(a, b) """ assign a = 23; @@ -378,18 +434,24 @@ Verilog Attributes and non-standard features $ yosys -p 'plugin -a foo -i /lib/libm.so; read_verilog dpitest.v' - Sized constants (the syntax ``<size>'s?[bodh]<value>``) support constant - expressions as <size>. If the expression is not a simple identifier, it + expressions as ``<size>``. 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. +- The system tasks ``$finish``, ``$stop`` and ``$display`` are supported in + initial blocks in an unconditional context (only if/case statements on + expressions over parameters and constant values are allowed). The intended + use for this is synthesis-time DRC. + +- There is limited support for converting specify .. endspecify statements to + special ``$specify2``, ``$specify3``, and ``$specrule`` cells, for use in + blackboxes and whiteboxes. Use ``read_verilog -specify`` to enable this + functionality. (By default specify .. endspecify blocks are ignored.) Non-standard or SystemVerilog features for formal verification ============================================================== -- Support for ``assert``, ``assume``, ``restrict``, and ``cover'' is enabled +- Support for ``assert``, ``assume``, ``restrict``, and ``cover`` is enabled when ``read_verilog`` is called with ``-formal``. - The system task ``$initstate`` evaluates to 1 in the initial state and @@ -406,11 +468,11 @@ Non-standard or SystemVerilog features for formal verification - The system functions ``$allconst`` and ``$allseq`` can be used to construct formal exist-forall problems. Assumptions only hold if the trace satisfies - the assumtion for all ``$allconst/$allseq`` values. For assertions and cover + the assumption for all ``$allconst/$allseq`` values. For assertions and cover statements it is sufficient if just one ``$allconst/$allseq`` value triggers the property (similar to ``$anyconst/$anyseq``). -- Wires/registers decalred using the ``anyconst/anyseq/allconst/allseq`` attribute +- Wires/registers declared using the ``anyconst/anyseq/allconst/allseq`` attribute (for example ``(* anyconst *) reg [7:0] foobar;``) will behave as if driven by a ``$anyconst/$anyseq/$allconst/$allseq`` function. @@ -418,7 +480,7 @@ Non-standard or SystemVerilog features for formal verification supported in any clocked block. - The syntax ``@($global_clock)`` can be used to create FFs that have no - explicit clock input ($ff cells). The same can be achieved by using + explicit clock input (``$ff`` cells). The same can be achieved by using ``@(posedge <netname>)`` or ``@(negedge <netname>)`` when ``<netname>`` is marked with the ``(* gclk *)`` Verilog attribute. @@ -431,7 +493,7 @@ from SystemVerilog: - The ``assert`` statement from SystemVerilog is supported in its most basic form. In module context: ``assert property (<expression>);`` and within an - always block: ``assert(<expression>);``. It is transformed to a $assert cell. + always block: ``assert(<expression>);``. It is transformed to an ``$assert`` cell. - The ``assume``, ``restrict``, and ``cover`` statements from SystemVerilog are also supported. The same limitations as with the ``assert`` statement apply. @@ -448,6 +510,9 @@ from SystemVerilog: into a design with ``read_verilog``, all its packages are available to SystemVerilog files being read into the same design afterwards. +- SystemVerilog interfaces (SVIs) are supported. Modports for specifying whether + ports are inputs or outputs are supported. + Building the documentation ========================== @@ -478,6 +543,6 @@ Then execute, from the root of the repository: Notes: -- To run `make manual` you need to have installed yosys with `make install`, +- 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/backends/aiger/Makefile.inc b/backends/aiger/Makefile.inc index 0fc37e95c..4a4cf30bd 100644 --- a/backends/aiger/Makefile.inc +++ b/backends/aiger/Makefile.inc @@ -1,3 +1,4 @@ OBJS += backends/aiger/aiger.o +OBJS += backends/aiger/xaiger.o diff --git a/backends/aiger/aiger.cc b/backends/aiger/aiger.cc index 526e50a49..0798fb35d 100644 --- a/backends/aiger/aiger.cc +++ b/backends/aiger/aiger.cc @@ -70,37 +70,38 @@ struct AigerWriter int bit2aig(SigBit bit) { - if (aig_map.count(bit) == 0) - { - aig_map[bit] = -1; - - if (initstate_bits.count(bit)) { - log_assert(initstate_ff > 0); - aig_map[bit] = initstate_ff; - } else - if (not_map.count(bit)) { - int a = bit2aig(not_map.at(bit)) ^ 1; - aig_map[bit] = a; - } else - if (and_map.count(bit)) { - auto args = and_map.at(bit); - int a0 = bit2aig(args.first); - int a1 = bit2aig(args.second); - aig_map[bit] = mkgate(a0, a1); - } else - if (alias_map.count(bit)) { - aig_map[bit] = bit2aig(alias_map.at(bit)); - } + auto it = aig_map.find(bit); + if (it != aig_map.end()) { + log_assert(it->second >= 0); + return it->second; + } - if (bit == State::Sx || bit == State::Sz) - log_error("Design contains 'x' or 'z' bits. Use 'setundef' to replace those constants.\n"); + // NB: Cannot use iterator returned from aig_map.insert() + // since this function is called recursively + + int a = -1; + if (not_map.count(bit)) { + a = bit2aig(not_map.at(bit)) ^ 1; + } else + if (and_map.count(bit)) { + auto args = and_map.at(bit); + int a0 = bit2aig(args.first); + int a1 = bit2aig(args.second); + a = mkgate(a0, a1); + } else + if (alias_map.count(bit)) { + a = bit2aig(alias_map.at(bit)); } - log_assert(aig_map.at(bit) >= 0); - return aig_map.at(bit); + if (bit == State::Sx || bit == State::Sz) + log_error("Design contains 'x' or 'z' bits. Use 'setundef' to replace those constants.\n"); + + log_assert(a >= 0); + aig_map[bit] = a; + return a; } - AigerWriter(Module *module, bool zinit_mode) : module(module), zinit_mode(zinit_mode), sigmap(module) + AigerWriter(Module *module, bool zinit_mode, bool imode, bool omode, bool bmode, bool lmode) : module(module), zinit_mode(zinit_mode), sigmap(module) { pool<SigBit> undriven_bits; pool<SigBit> unused_bits; @@ -293,6 +294,10 @@ struct AigerWriter aig_map[bit] = 2*aig_m; } + if (imode && input_bits.empty()) { + aig_m++, aig_i++; + } + if (zinit_mode) { for (auto it : ff_map) { @@ -362,6 +367,12 @@ struct AigerWriter aig_latchin.push_back(a); } + if (lmode && aig_l == 0) { + aig_m++, aig_l++; + aig_latchinit.push_back(0); + aig_latchin.push_back(0); + } + if (!initstate_bits.empty() || !init_inputs.empty()) aig_latchin.push_back(1); @@ -371,6 +382,11 @@ struct AigerWriter aig_outputs.push_back(bit2aig(bit)); } + if (omode && output_bits.empty()) { + aig_o++; + aig_outputs.push_back(0); + } + for (auto it : asserts) { aig_b++; int bit_a = bit2aig(it.first); @@ -378,6 +394,11 @@ struct AigerWriter aig_outputs.push_back(mkgate(bit_a^1, bit_en)); } + if (bmode && asserts.empty()) { + aig_b++; + aig_outputs.push_back(0); + } + for (auto it : assumes) { aig_c++; int bit_a = bit2aig(it.first); @@ -657,7 +678,7 @@ struct AigerWriter struct AigerBackend : public Backend { AigerBackend() : Backend("aiger", "write design to AIGER file") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -671,7 +692,7 @@ struct AigerBackend : public Backend { log("invariant constraints.\n"); log("\n"); log(" -ascii\n"); - log(" write ASCII version of AGIER format\n"); + log(" write ASCII version of AIGER format\n"); log("\n"); log(" -zinit\n"); log(" convert FFs to zero-initialized FFs, adding additional inputs for\n"); @@ -689,14 +710,23 @@ struct AigerBackend : public Backend { log(" -vmap <filename>\n"); log(" like -map, but more verbose\n"); log("\n"); + log(" -I, -O, -B, -L\n"); + log(" If the design contains no input/output/assert/flip-flop then create one\n"); + log(" dummy input/output/bad_state-pin or latch to make the tools reading the\n"); + log(" AIGER file happy.\n"); + log("\n"); } - virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) + void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { bool ascii_mode = false; bool zinit_mode = false; bool miter_mode = false; bool symbols_mode = false; bool verbose_map = false; + bool imode = false; + bool omode = false; + bool bmode = false; + bool lmode = false; std::string map_filename; log_header(design, "Executing AIGER backend.\n"); @@ -729,6 +759,22 @@ struct AigerBackend : public Backend { verbose_map = true; continue; } + if (args[argidx] == "-I") { + imode = true; + continue; + } + if (args[argidx] == "-O") { + omode = true; + continue; + } + if (args[argidx] == "-B") { + bmode = true; + continue; + } + if (args[argidx] == "-L") { + lmode = true; + continue; + } break; } extra_args(f, filename, args, argidx); @@ -738,10 +784,11 @@ struct AigerBackend : public Backend { if (top_module == nullptr) log_error("Can't find top module in current design!\n"); - AigerWriter writer(top_module, zinit_mode); + AigerWriter writer(top_module, zinit_mode, imode, omode, bmode, lmode); 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/backends/aiger/xaiger.cc b/backends/aiger/xaiger.cc new file mode 100644 index 000000000..fa6ba0aca --- /dev/null +++ b/backends/aiger/xaiger.cc @@ -0,0 +1,879 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * 2019 Eddie Hung <eddie@fpgeh.com> + * + * 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. + * + */ + +// https://stackoverflow.com/a/46137633 +#ifdef _MSC_VER +#include <stdlib.h> +#define bswap32 _byteswap_ulong +#elif defined(__APPLE__) +#include <libkern/OSByteOrder.h> +#define bswap32 OSSwapInt32 +#elif defined(__GNUC__) +#define bswap32 __builtin_bswap32 +#else +#include <cstdint> +inline static uint32_t bswap32(uint32_t x) +{ + // https://stackoverflow.com/a/27796212 + register uint32_t value = number_to_be_reversed; + uint8_t lolo = (value >> 0) & 0xFF; + uint8_t lohi = (value >> 8) & 0xFF; + uint8_t hilo = (value >> 16) & 0xFF; + uint8_t hihi = (value >> 24) & 0xFF; + return (hihi << 24) + | (hilo << 16) + | (lohi << 8) + | (lolo << 0); +} +#endif + +#include "kernel/yosys.h" +#include "kernel/sigtools.h" +#include "kernel/utils.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +inline int32_t to_big_endian(int32_t i32) { +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + return bswap32(i32); +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + return i32; +#else +#error "Unknown endianness" +#endif +} + +void aiger_encode(std::ostream &f, int x) +{ + log_assert(x >= 0); + + while (x & ~0x7f) { + f.put((x & 0x7f) | 0x80); + x = x >> 7; + } + + f.put(x); +} + +struct XAigerWriter +{ + Module *module; + SigMap sigmap; + + pool<SigBit> input_bits, output_bits; + dict<SigBit, SigBit> not_map, alias_map; + dict<SigBit, pair<SigBit, SigBit>> and_map; + vector<std::tuple<SigBit,RTLIL::Cell*,RTLIL::IdString,int>> ci_bits; + vector<std::tuple<SigBit,RTLIL::Cell*,RTLIL::IdString,int,int>> co_bits; + dict<SigBit, float> arrival_times; + + vector<pair<int, int>> aig_gates; + vector<int> aig_outputs; + int aig_m = 0, aig_i = 0, aig_l = 0, aig_o = 0, aig_a = 0; + + dict<SigBit, int> aig_map; + dict<SigBit, int> ordered_outputs; + + vector<Cell*> box_list; + bool omode = false; + + int mkgate(int a0, int a1) + { + aig_m++, aig_a++; + aig_gates.push_back(a0 > a1 ? make_pair(a0, a1) : make_pair(a1, a0)); + return 2*aig_m; + } + + int bit2aig(SigBit bit) + { + auto it = aig_map.find(bit); + if (it != aig_map.end()) { + log_assert(it->second >= 0); + return it->second; + } + + // NB: Cannot use iterator returned from aig_map.insert() + // since this function is called recursively + + int a = -1; + if (not_map.count(bit)) { + a = bit2aig(not_map.at(bit)) ^ 1; + } else + if (and_map.count(bit)) { + auto args = and_map.at(bit); + int a0 = bit2aig(args.first); + int a1 = bit2aig(args.second); + a = mkgate(a0, a1); + } else + if (alias_map.count(bit)) { + a = bit2aig(alias_map.at(bit)); + } + + if (bit == State::Sx || bit == State::Sz) { + log_debug("Design contains 'x' or 'z' bits. Treating as 1'b0.\n"); + a = aig_map.at(State::S0); + } + + log_assert(a >= 0); + aig_map[bit] = a; + return a; + } + + XAigerWriter(Module *module, bool holes_mode=false) : module(module), sigmap(module) + { + pool<SigBit> undriven_bits; + pool<SigBit> unused_bits; + pool<SigBit> keep_bits; + + // promote public wires + for (auto wire : module->wires()) + if (wire->name[0] == '\\') + sigmap.add(wire); + + // promote input wires + for (auto wire : module->wires()) + if (wire->port_input) + sigmap.add(wire); + + // promote output wires + for (auto wire : module->wires()) + if (wire->port_output) + sigmap.add(wire); + + for (auto wire : module->wires()) + { + bool keep = wire->attributes.count("\\keep"); + + for (int i = 0; i < GetSize(wire); i++) + { + SigBit wirebit(wire, i); + SigBit bit = sigmap(wirebit); + + if (bit.wire) { + undriven_bits.insert(bit); + unused_bits.insert(bit); + } + + if (keep) + keep_bits.insert(bit); + + if (wire->port_input || keep) { + if (bit != wirebit) + alias_map[bit] = wirebit; + input_bits.insert(wirebit); + } + + if (wire->port_output || keep) { + if (bit != RTLIL::Sx) { + if (bit != wirebit) + alias_map[wirebit] = bit; + output_bits.insert(wirebit); + } + else + log_debug("Skipping PO '%s' driven by 1'bx\n", log_signal(wirebit)); + } + } + } + + for (auto bit : input_bits) + undriven_bits.erase(sigmap(bit)); + for (auto bit : output_bits) + if (!bit.wire->port_input) + unused_bits.erase(bit); + + // TODO: Speed up toposort -- ultimately we care about + // box ordering, but not individual AIG cells + dict<SigBit, pool<IdString>> bit_drivers, bit_users; + TopoSort<IdString, RTLIL::sort_by_id_str> toposort; + bool abc_box_seen = false; + + for (auto cell : module->selected_cells()) { + if (cell->type == "$_NOT_") + { + SigBit A = sigmap(cell->getPort("\\A").as_bit()); + SigBit Y = sigmap(cell->getPort("\\Y").as_bit()); + unused_bits.erase(A); + undriven_bits.erase(Y); + not_map[Y] = A; + if (!holes_mode) { + toposort.node(cell->name); + bit_users[A].insert(cell->name); + bit_drivers[Y].insert(cell->name); + } + continue; + } + + if (cell->type == "$_AND_") + { + SigBit A = sigmap(cell->getPort("\\A").as_bit()); + SigBit B = sigmap(cell->getPort("\\B").as_bit()); + SigBit Y = sigmap(cell->getPort("\\Y").as_bit()); + unused_bits.erase(A); + unused_bits.erase(B); + undriven_bits.erase(Y); + and_map[Y] = make_pair(A, B); + if (!holes_mode) { + toposort.node(cell->name); + bit_users[A].insert(cell->name); + bit_users[B].insert(cell->name); + bit_drivers[Y].insert(cell->name); + } + continue; + } + + log_assert(!holes_mode); + + RTLIL::Module* inst_module = module->design->module(cell->type); + if (inst_module && inst_module->attributes.count("\\abc_box_id")) { + abc_box_seen = true; + + if (!holes_mode) { + toposort.node(cell->name); + for (const auto &conn : cell->connections()) { + auto port_wire = inst_module->wire(conn.first); + if (port_wire->port_input) { + // Ignore inout for the sake of topographical ordering + if (port_wire->port_output) continue; + for (auto bit : sigmap(conn.second)) + bit_users[bit].insert(cell->name); + } + + if (port_wire->port_output) + for (auto bit : sigmap(conn.second)) + bit_drivers[bit].insert(cell->name); + } + } + } + else { + bool cell_known = inst_module || cell->known(); + for (const auto &c : cell->connections()) { + if (c.second.is_fully_const()) continue; + auto port_wire = inst_module ? inst_module->wire(c.first) : nullptr; + auto is_input = (port_wire && port_wire->port_input) || !cell_known || cell->input(c.first); + auto is_output = (port_wire && port_wire->port_output) || !cell_known || cell->output(c.first); + if (!is_input && !is_output) + log_error("Connection '%s' on cell '%s' (type '%s') not recognised!\n", log_id(c.first), log_id(cell), log_id(cell->type)); + + if (is_input) { + for (auto b : c.second) { + Wire *w = b.wire; + if (!w) continue; + if (!w->port_output || !cell_known) { + SigBit I = sigmap(b); + if (I != b) + alias_map[b] = I; + output_bits.insert(b); + unused_bits.erase(b); + + if (!cell_known) + keep_bits.insert(b); + } + } + } + if (is_output) { + int arrival = 0; + if (port_wire) { + auto it = port_wire->attributes.find("\\abc_arrival"); + if (it != port_wire->attributes.end()) { + if (it->second.flags != 0) + log_error("Attribute 'abc_arrival' on port '%s' of module '%s' is not an integer.\n", log_id(port_wire), log_id(cell->type)); + arrival = it->second.as_int(); + } + } + + for (auto b : c.second) { + Wire *w = b.wire; + if (!w) continue; + input_bits.insert(b); + SigBit O = sigmap(b); + if (O != b) + alias_map[O] = b; + undriven_bits.erase(O); + + if (arrival) + arrival_times[b] = arrival; + } + } + } + } + + //log_warning("Unsupported cell type: %s (%s)\n", log_id(cell->type), log_id(cell)); + } + + if (abc_box_seen) { + for (auto &it : bit_users) + if (bit_drivers.count(it.first)) + for (auto driver_cell : bit_drivers.at(it.first)) + for (auto user_cell : it.second) + toposort.edge(driver_cell, user_cell); + +#if 0 + toposort.analyze_loops = true; +#endif + bool no_loops YS_ATTRIBUTE(unused) = toposort.sort(); +#if 0 + unsigned i = 0; + for (auto &it : toposort.loops) { + log(" loop %d\n", i++); + for (auto cell_name : it) { + auto cell = module->cell(cell_name); + log_assert(cell); + log("\t%s (%s @ %s)\n", log_id(cell), log_id(cell->type), cell->get_src_attribute().c_str()); + } + } +#endif + log_assert(no_loops); + + for (auto cell_name : toposort.sorted) { + RTLIL::Cell *cell = module->cell(cell_name); + log_assert(cell); + + RTLIL::Module* box_module = module->design->module(cell->type); + if (!box_module || !box_module->attributes.count("\\abc_box_id")) + continue; + + // Fully pad all unused input connections of this box cell with S0 + // Fully pad all undriven output connections of this box cell with anonymous wires + // NB: Assume box_module->ports are sorted alphabetically + // (as RTLIL::Module::fixup_ports() would do) + for (const auto &port_name : box_module->ports) { + RTLIL::Wire* w = box_module->wire(port_name); + log_assert(w); + auto it = cell->connections_.find(port_name); + if (w->port_input) { + RTLIL::SigSpec rhs; + if (it != cell->connections_.end()) { + if (GetSize(it->second) < GetSize(w)) + it->second.append(RTLIL::SigSpec(State::S0, GetSize(w)-GetSize(it->second))); + rhs = it->second; + } + else { + rhs = RTLIL::SigSpec(State::S0, GetSize(w)); + cell->setPort(port_name, rhs); + } + + int offset = 0; + for (auto b : rhs.bits()) { + SigBit I = sigmap(b); + if (b == RTLIL::Sx) + b = State::S0; + else if (I != b) { + if (I == RTLIL::Sx) + alias_map[b] = State::S0; + else + alias_map[b] = I; + } + co_bits.emplace_back(b, cell, port_name, offset++, 0); + unused_bits.erase(b); + } + } + if (w->port_output) { + RTLIL::SigSpec rhs; + auto it = cell->connections_.find(w->name); + if (it != cell->connections_.end()) { + if (GetSize(it->second) < GetSize(w)) + it->second.append(module->addWire(NEW_ID, GetSize(w)-GetSize(it->second))); + rhs = it->second; + } + else { + rhs = module->addWire(NEW_ID, GetSize(w)); + cell->setPort(port_name, rhs); + } + + int offset = 0; + for (const auto &b : rhs.bits()) { + ci_bits.emplace_back(b, cell, port_name, offset++); + SigBit O = sigmap(b); + if (O != b) + alias_map[O] = b; + undriven_bits.erase(O); + + auto jt = input_bits.find(b); + if (jt != input_bits.end()) { + log_assert(keep_bits.count(O)); + input_bits.erase(b); + } + } + } + } + box_list.emplace_back(cell); + } + + // TODO: Free memory from toposort, bit_drivers, bit_users + } + + for (auto bit : input_bits) { + if (!output_bits.count(bit)) + continue; + RTLIL::Wire *wire = bit.wire; + // If encountering an inout port, or a keep-ed wire, then create a new wire + // with $inout.out suffix, make it a PO driven by the existing inout, and + // inherit existing inout's drivers + if ((wire->port_input && wire->port_output && !undriven_bits.count(bit)) + || keep_bits.count(bit)) { + RTLIL::IdString wire_name = wire->name.str() + "$inout.out"; + RTLIL::Wire *new_wire = module->wire(wire_name); + if (!new_wire) + new_wire = module->addWire(wire_name, GetSize(wire)); + SigBit new_bit(new_wire, bit.offset); + module->connect(new_bit, bit); + if (not_map.count(bit)) { + auto a = not_map.at(bit); + not_map[new_bit] = a; + } + else if (and_map.count(bit)) { + auto a = and_map.at(bit); + and_map[new_bit] = a; + } + else if (alias_map.count(bit)) { + auto a = alias_map.at(bit); + alias_map[new_bit] = a; + } + else + alias_map[new_bit] = bit; + output_bits.erase(bit); + output_bits.insert(new_bit); + } + } + + for (auto bit : unused_bits) + undriven_bits.erase(bit); + + if (!undriven_bits.empty() && !holes_mode) { + undriven_bits.sort(); + for (auto bit : undriven_bits) { + log_warning("Treating undriven bit %s.%s like $anyseq.\n", log_id(module), log_signal(bit)); + input_bits.insert(bit); + } + log_warning("Treating a total of %d undriven bits in %s like $anyseq.\n", GetSize(undriven_bits), log_id(module)); + } + + if (holes_mode) { + struct sort_by_port_id { + bool operator()(const RTLIL::SigBit& a, const RTLIL::SigBit& b) const { + return a.wire->port_id < b.wire->port_id; + } + }; + input_bits.sort(sort_by_port_id()); + output_bits.sort(sort_by_port_id()); + } + else { + input_bits.sort(); + output_bits.sort(); + } + + not_map.sort(); + and_map.sort(); + + aig_map[State::S0] = 0; + aig_map[State::S1] = 1; + + for (auto bit : input_bits) { + aig_m++, aig_i++; + log_assert(!aig_map.count(bit)); + aig_map[bit] = 2*aig_m; + } + + for (auto &c : ci_bits) { + RTLIL::SigBit bit = std::get<0>(c); + aig_m++, aig_i++; + aig_map[bit] = 2*aig_m; + } + + for (auto &c : co_bits) { + RTLIL::SigBit bit = std::get<0>(c); + std::get<4>(c) = ordered_outputs[bit] = aig_o++; + aig_outputs.push_back(bit2aig(bit)); + } + + if (output_bits.empty()) { + output_bits.insert(State::S0); + omode = true; + } + + for (auto bit : output_bits) { + ordered_outputs[bit] = aig_o++; + aig_outputs.push_back(bit2aig(bit)); + } + + } + + void write_aiger(std::ostream &f, bool ascii_mode) + { + int aig_obc = aig_o; + int aig_obcj = aig_obc; + int aig_obcjf = aig_obcj; + + log_assert(aig_m == aig_i + aig_l + aig_a); + log_assert(aig_obcjf == GetSize(aig_outputs)); + + f << stringf("%s %d %d %d %d %d", ascii_mode ? "aag" : "aig", aig_m, aig_i, aig_l, aig_o, aig_a); + f << stringf("\n"); + + if (ascii_mode) + { + for (int i = 0; i < aig_i; i++) + f << stringf("%d\n", 2*i+2); + + for (int i = 0; i < aig_obc; i++) + f << stringf("%d\n", aig_outputs.at(i)); + + for (int i = aig_obc; i < aig_obcj; i++) + f << stringf("1\n"); + + for (int i = aig_obc; i < aig_obcj; i++) + f << stringf("%d\n", aig_outputs.at(i)); + + for (int i = aig_obcj; i < aig_obcjf; i++) + f << stringf("%d\n", aig_outputs.at(i)); + + for (int i = 0; i < aig_a; i++) + f << stringf("%d %d %d\n", 2*(aig_i+aig_l+i)+2, aig_gates.at(i).first, aig_gates.at(i).second); + } + else + { + for (int i = 0; i < aig_obc; i++) + f << stringf("%d\n", aig_outputs.at(i)); + + for (int i = aig_obc; i < aig_obcj; i++) + f << stringf("1\n"); + + for (int i = aig_obc; i < aig_obcj; i++) + f << stringf("%d\n", aig_outputs.at(i)); + + for (int i = aig_obcj; i < aig_obcjf; i++) + f << stringf("%d\n", aig_outputs.at(i)); + + for (int i = 0; i < aig_a; i++) { + int lhs = 2*(aig_i+aig_l+i)+2; + int rhs0 = aig_gates.at(i).first; + int rhs1 = aig_gates.at(i).second; + int delta0 = lhs - rhs0; + int delta1 = rhs0 - rhs1; + aiger_encode(f, delta0); + aiger_encode(f, delta1); + } + } + + f << "c"; + + log_assert(!output_bits.empty()); + auto write_buffer = [](std::stringstream &buffer, int i32) { + int32_t i32_be = to_big_endian(i32); + buffer.write(reinterpret_cast<const char*>(&i32_be), sizeof(i32_be)); + }; + std::stringstream h_buffer; + auto write_h_buffer = std::bind(write_buffer, std::ref(h_buffer), std::placeholders::_1); + write_h_buffer(1); + log_debug("ciNum = %d\n", GetSize(input_bits) + GetSize(ci_bits)); + write_h_buffer(input_bits.size() + ci_bits.size()); + log_debug("coNum = %d\n", GetSize(output_bits) + GetSize(co_bits)); + write_h_buffer(output_bits.size() + GetSize(co_bits)); + log_debug("piNum = %d\n", GetSize(input_bits)); + write_h_buffer(input_bits.size()); + log_debug("poNum = %d\n", GetSize(output_bits)); + write_h_buffer(output_bits.size()); + log_debug("boxNum = %d\n", GetSize(box_list)); + write_h_buffer(box_list.size()); + + auto write_buffer_float = [](std::stringstream &buffer, float f32) { + buffer.write(reinterpret_cast<const char*>(&f32), sizeof(f32)); + }; + std::stringstream i_buffer; + auto write_i_buffer = std::bind(write_buffer_float, std::ref(i_buffer), std::placeholders::_1); + for (auto bit : input_bits) + write_i_buffer(arrival_times.at(bit, 0)); + //std::stringstream o_buffer; + //auto write_o_buffer = std::bind(write_buffer_float, std::ref(o_buffer), std::placeholders::_1); + //for (auto bit : output_bits) + // write_o_buffer(0); + + if (!box_list.empty()) { + RTLIL::Module *holes_module = module->design->addModule("$__holes__"); + log_assert(holes_module); + + int port_id = 1; + int box_count = 0; + for (auto cell : box_list) { + RTLIL::Module* box_module = module->design->module(cell->type); + int box_inputs = 0, box_outputs = 0; + Cell *holes_cell = nullptr; + if (box_module->get_bool_attribute("\\whitebox")) { + holes_cell = holes_module->addCell(cell->name, cell->type); + holes_cell->parameters = cell->parameters; + } + + // NB: Assume box_module->ports are sorted alphabetically + // (as RTLIL::Module::fixup_ports() would do) + for (const auto &port_name : box_module->ports) { + RTLIL::Wire *w = box_module->wire(port_name); + log_assert(w); + RTLIL::Wire *holes_wire; + RTLIL::SigSpec port_wire; + if (w->port_input) { + for (int i = 0; i < GetSize(w); i++) { + box_inputs++; + holes_wire = holes_module->wire(stringf("\\i%d", box_inputs)); + if (!holes_wire) { + holes_wire = holes_module->addWire(stringf("\\i%d", box_inputs)); + holes_wire->port_input = true; + holes_wire->port_id = port_id++; + holes_module->ports.push_back(holes_wire->name); + } + if (holes_cell) + port_wire.append(holes_wire); + } + if (!port_wire.empty()) + holes_cell->setPort(w->name, port_wire); + } + if (w->port_output) { + box_outputs += GetSize(w); + for (int i = 0; i < GetSize(w); i++) { + if (GetSize(w) == 1) + holes_wire = holes_module->addWire(stringf("%s.%s", cell->name.c_str(), w->name.c_str())); + else + holes_wire = holes_module->addWire(stringf("%s.%s[%d]", cell->name.c_str(), w->name.c_str(), i)); + holes_wire->port_output = true; + holes_wire->port_id = port_id++; + holes_module->ports.push_back(holes_wire->name); + if (holes_cell) + port_wire.append(holes_wire); + else + holes_module->connect(holes_wire, State::S0); + } + if (!port_wire.empty()) + holes_cell->setPort(w->name, port_wire); + } + } + + write_h_buffer(box_inputs); + write_h_buffer(box_outputs); + write_h_buffer(box_module->attributes.at("\\abc_box_id").as_int()); + write_h_buffer(box_count++); + } + + std::stringstream r_buffer; + auto write_r_buffer = std::bind(write_buffer, std::ref(r_buffer), std::placeholders::_1); + write_r_buffer(0); + f << "r"; + std::string buffer_str = r_buffer.str(); + int32_t buffer_size_be = to_big_endian(buffer_str.size()); + f.write(reinterpret_cast<const char*>(&buffer_size_be), sizeof(buffer_size_be)); + f.write(buffer_str.data(), buffer_str.size()); + + if (holes_module) { + log_push(); + + // NB: fixup_ports() will sort ports by name + //holes_module->fixup_ports(); + holes_module->check(); + + holes_module->design->selection_stack.emplace_back(false); + RTLIL::Selection& sel = holes_module->design->selection_stack.back(); + sel.select(holes_module); + + // TODO: Should not need to opt_merge if we only instantiate + // each box type once... + Pass::call(holes_module->design, "opt_merge -share_all"); + + Pass::call(holes_module->design, "flatten -wb"); + + // TODO: Should techmap/aigmap/check all lib_whitebox-es just once, + // instead of per write_xaiger call + Pass::call(holes_module->design, "techmap"); + Pass::call(holes_module->design, "aigmap"); + for (auto cell : holes_module->cells()) + if (!cell->type.in("$_NOT_", "$_AND_")) + log_error("Whitebox contents cannot be represented as AIG. Please verify whiteboxes are synthesisable.\n"); + + holes_module->design->selection_stack.pop_back(); + + // Move into a new (temporary) design so that "clean" will only + // operate (and run checks on) this one module + RTLIL::Design *holes_design = new RTLIL::Design; + holes_module->design->modules_.erase(holes_module->name); + holes_design->add(holes_module); + Pass::call(holes_design, "clean -purge"); + + std::stringstream a_buffer; + XAigerWriter writer(holes_module, true /* holes_mode */); + writer.write_aiger(a_buffer, false /*ascii_mode*/); + + delete holes_design; + + f << "a"; + std::string buffer_str = a_buffer.str(); + int32_t buffer_size_be = to_big_endian(buffer_str.size()); + f.write(reinterpret_cast<const char*>(&buffer_size_be), sizeof(buffer_size_be)); + f.write(buffer_str.data(), buffer_str.size()); + + log_pop(); + } + } + + f << "h"; + std::string buffer_str = h_buffer.str(); + int32_t buffer_size_be = to_big_endian(buffer_str.size()); + f.write(reinterpret_cast<const char*>(&buffer_size_be), sizeof(buffer_size_be)); + f.write(buffer_str.data(), buffer_str.size()); + + f << "i"; + buffer_str = i_buffer.str(); + buffer_size_be = to_big_endian(buffer_str.size()); + f.write(reinterpret_cast<const char*>(&buffer_size_be), sizeof(buffer_size_be)); + f.write(buffer_str.data(), buffer_str.size()); + //f << "o"; + //buffer_str = o_buffer.str(); + //buffer_size_be = to_big_endian(buffer_str.size()); + //f.write(reinterpret_cast<const char*>(&buffer_size_be), sizeof(buffer_size_be)); + //f.write(buffer_str.data(), buffer_str.size()); + + f << stringf("Generated by %s\n", yosys_version_str); + } + + void write_map(std::ostream &f, bool verbose_map) + { + dict<int, string> input_lines; + dict<int, string> output_lines; + dict<int, string> wire_lines; + + for (auto wire : module->wires()) + { + //if (!verbose_map && wire->name[0] == '$') + // continue; + + SigSpec sig = sigmap(wire); + + for (int i = 0; i < GetSize(wire); i++) + { + RTLIL::SigBit b(wire, i); + if (input_bits.count(b)) { + int a = aig_map.at(b); + log_assert((a & 1) == 0); + input_lines[a] += stringf("input %d %d %s\n", (a >> 1)-1, i, log_id(wire)); + } + + if (output_bits.count(b)) { + int o = ordered_outputs.at(b); + output_lines[o] += stringf("output %d %d %s\n", o - GetSize(co_bits), i, log_id(wire)); + continue; + } + + if (verbose_map) { + if (aig_map.count(sig[i]) == 0) + continue; + + int a = aig_map.at(sig[i]); + wire_lines[a] += stringf("wire %d %d %s\n", a, i, log_id(wire)); + } + } + } + + input_lines.sort(); + for (auto &it : input_lines) + f << it.second; + log_assert(input_lines.size() == input_bits.size()); + + int box_count = 0; + for (auto cell : box_list) + f << stringf("box %d %d %s\n", box_count++, 0, log_id(cell->name)); + + output_lines.sort(); + if (omode) + output_lines[State::S0] = "output 0 0 $__dummy__\n"; + for (auto &it : output_lines) + f << it.second; + log_assert(output_lines.size() == output_bits.size()); + + wire_lines.sort(); + for (auto &it : wire_lines) + f << it.second; + } +}; + +struct XAigerBackend : public Backend { + XAigerBackend() : Backend("xaiger", "write design to XAIGER file") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" write_xaiger [options] [filename]\n"); + log("\n"); + log("Write the current design to an XAIGER file. The design must be flattened and\n"); + log("all unsupported cells will be converted into psuedo-inputs and pseudo-outputs.\n"); + log("\n"); + log(" -ascii\n"); + log(" write ASCII version of AIGER format\n"); + log("\n"); + log(" -map <filename>\n"); + log(" write an extra file with port and latch symbols\n"); + log("\n"); + log(" -vmap <filename>\n"); + log(" like -map, but more verbose\n"); + log("\n"); + } + void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + bool ascii_mode = false; + bool verbose_map = false; + std::string map_filename; + + log_header(design, "Executing XAIGER backend.\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + if (args[argidx] == "-ascii") { + ascii_mode = true; + continue; + } + if (map_filename.empty() && args[argidx] == "-map" && argidx+1 < args.size()) { + map_filename = args[++argidx]; + continue; + } + if (map_filename.empty() && args[argidx] == "-vmap" && argidx+1 < args.size()) { + map_filename = args[++argidx]; + verbose_map = true; + continue; + } + break; + } + extra_args(f, filename, args, argidx); + + Module *top_module = design->top_module(); + + if (top_module == nullptr) + log_error("Can't find top module in current design!\n"); + + XAigerWriter writer(top_module); + writer.write_aiger(*f, ascii_mode); + + if (!map_filename.empty()) { + std::ofstream mapf; + mapf.open(map_filename.c_str(), std::ofstream::trunc); + if (mapf.fail()) + log_error("Can't open file `%s' for writing: %s\n", map_filename.c_str(), strerror(errno)); + writer.write_map(mapf, verbose_map); + } + } +} XAigerBackend; + +PRIVATE_NAMESPACE_END diff --git a/backends/blif/blif.cc b/backends/blif/blif.cc index e4509e0d0..b6e38c16c 100644 --- a/backends/blif/blif.cc +++ b/backends/blif/blif.cc @@ -140,7 +140,7 @@ struct BlifDumper return "subckt"; if (!design->modules_.count(RTLIL::escape_id(cell_type))) return "gate"; - if (design->modules_.at(RTLIL::escape_id(cell_type))->get_bool_attribute("\\blackbox")) + if (design->modules_.at(RTLIL::escape_id(cell_type))->get_blackbox_attribute()) return "gate"; return "subckt"; } @@ -196,7 +196,7 @@ struct BlifDumper } f << stringf("\n"); - if (module->get_bool_attribute("\\blackbox")) { + if (module->get_blackbox_attribute()) { f << stringf(".blackbox\n"); f << stringf(".end\n"); return; @@ -327,6 +327,13 @@ struct BlifDumper goto internal_cell; } + if (!config->icells_mode && cell->type == "$_NMUX_") { + f << stringf(".names %s %s %s %s\n0-0 1\n-01 1\n", + cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), + cstr(cell->getPort("\\S")), cstr(cell->getPort("\\Y"))); + goto internal_cell; + } + if (!config->icells_mode && cell->type == "$_FF_") { f << stringf(".latch %s %s%s\n", cstr(cell->getPort("\\D")), cstr(cell->getPort("\\Q")), cstr_init(cell->getPort("\\Q"))); @@ -370,7 +377,7 @@ struct BlifDumper f << stringf("\n"); RTLIL::SigSpec mask = cell->parameters.at("\\LUT"); for (int i = 0; i < (1 << width); i++) - if (mask[i] == RTLIL::S1) { + if (mask[i] == State::S1) { for (int j = width-1; j >= 0; j--) { f << ((i>>j)&1 ? '1' : '0'); } @@ -409,12 +416,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"); @@ -464,7 +485,7 @@ struct BlifDumper struct BlifBackend : public Backend { BlifBackend() : Backend("blif", "write design to BLIF file") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -534,7 +555,7 @@ struct BlifBackend : public Backend { log(" do not write definitions for the $true, $false and $undef wires.\n"); log("\n"); } - virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) + void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { std::string top_module_name; std::string buf_type, buf_in, buf_out; @@ -640,7 +661,7 @@ struct BlifBackend : public Backend { for (auto module_it : design->modules_) { RTLIL::Module *module = module_it.second; - if (module->get_bool_attribute("\\blackbox") && !config.blackbox_mode) + if (module->get_blackbox_attribute() && !config.blackbox_mode) continue; if (module->processes.size() != 0) diff --git a/backends/btor/btor.cc b/backends/btor/btor.cc index 61a2f8ba3..4472993d4 100644 --- a/backends/btor/btor.cc +++ b/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,16 +134,23 @@ 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)); - if (cell->type.in("$add", "$sub", "$and", "$or", "$xor", "$xnor", "$shl", "$sshl", "$shr", "$sshr", "$shift", "$shiftx", - "$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_")) + if (cell->type.in("$add", "$sub", "$mul", "$and", "$or", "$xor", "$xnor", "$shl", "$sshl", "$shr", "$sshr", "$shift", "$shiftx", + "$concat", "$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_")) { string btor_op; if (cell->type == "$add") btor_op = "add"; if (cell->type == "$sub") btor_op = "sub"; + if (cell->type == "$mul") btor_op = "mul"; if (cell->type.in("$shl", "$sshl")) btor_op = "sll"; if (cell->type == "$shr") btor_op = "srl"; if (cell->type == "$sshr") btor_op = "sra"; @@ -146,6 +158,7 @@ struct BtorWorker if (cell->type.in("$and", "$_AND_")) btor_op = "and"; if (cell->type.in("$or", "$_OR_")) btor_op = "or"; if (cell->type.in("$xor", "$_XOR_")) btor_op = "xor"; + if (cell->type == "$concat") btor_op = "concat"; if (cell->type == "$_NAND_") btor_op = "nand"; if (cell->type == "$_NOR_") btor_op = "nor"; if (cell->type.in("$xnor", "$_XNOR_")) btor_op = "xnor"; @@ -214,6 +227,40 @@ struct BtorWorker goto okay; } + if (cell->type.in("$div", "$mod")) + { + string btor_op; + if (cell->type == "$div") btor_op = "div"; + if (cell->type == "$mod") btor_op = "rem"; + log_assert(!btor_op.empty()); + + int width = GetSize(cell->getPort("\\Y")); + width = std::max(width, GetSize(cell->getPort("\\A"))); + width = std::max(width, GetSize(cell->getPort("\\B"))); + + bool a_signed = cell->hasParam("\\A_SIGNED") ? cell->getParam("\\A_SIGNED").as_bool() : false; + bool b_signed = cell->hasParam("\\B_SIGNED") ? cell->getParam("\\B_SIGNED").as_bool() : false; + + int nid_a = get_sig_nid(cell->getPort("\\A"), width, a_signed); + int nid_b = get_sig_nid(cell->getPort("\\B"), width, b_signed); + + int sid = get_bv_sid(width); + int nid = next_nid++; + btorf("%d %c%s %d %d %d\n", nid, a_signed || b_signed ? 's' : 'u', btor_op.c_str(), sid, nid_a, nid_b); + + SigSpec sig = sigmap(cell->getPort("\\Y")); + + if (GetSize(sig) < width) { + int sid = get_bv_sid(GetSize(sig)); + int nid2 = next_nid++; + btorf("%d slice %d %d %d 0\n", nid2, sid, nid, GetSize(sig)-1); + nid = nid2; + } + + add_nid_sig(nid, sig); + goto okay; + } + if (cell->type.in("$_ANDNOT_", "$_ORNOT_")) { int sid = get_bv_sid(1); @@ -304,7 +351,7 @@ struct BtorWorker if (cell->type == "$lt") btor_op = "lt"; if (cell->type == "$le") btor_op = "lte"; if (cell->type.in("$eq", "$eqx")) btor_op = "eq"; - if (cell->type.in("$ne", "$nex")) btor_op = "ne"; + if (cell->type.in("$ne", "$nex")) btor_op = "neq"; if (cell->type == "$ge") btor_op = "gte"; if (cell->type == "$gt") btor_op = "gt"; log_assert(!btor_op.empty()); @@ -449,7 +496,7 @@ struct BtorWorker goto okay; } - if (cell->type.in("$mux", "$_MUX_")) + if (cell->type.in("$mux", "$_MUX_", "$_NMUX_")) { SigSpec sig_a = sigmap(cell->getPort("\\A")); SigSpec sig_b = sigmap(cell->getPort("\\B")); @@ -464,6 +511,12 @@ struct BtorWorker int nid = next_nid++; btorf("%d ite %d %d %d %d\n", nid, sid, nid_s, nid_b, nid_a); + if (cell->type == "$_NMUX_") { + int tmp = nid; + nid = next_nid++; + btorf("%d not %d %d\n", nid, sid, tmp); + } + add_nid_sig(nid, sig_y); goto okay; } @@ -506,6 +559,18 @@ struct BtorWorker } } + Const initval; + for (int i = 0; i < GetSize(sig_q); i++) + if (initbits.count(sig_q[i])) + initval.bits.push_back(initbits.at(sig_q[i]) ? State::S1 : State::S0); + else + initval.bits.push_back(State::Sx); + + int nid_init_val = -1; + + if (!initval.is_fully_undef()) + nid_init_val = get_sig_nid(initval); + int sid = get_bv_sid(GetSize(sig_q)); int nid = next_nid++; @@ -514,15 +579,7 @@ struct BtorWorker else btorf("%d state %d %s\n", nid, sid, log_id(symbol)); - Const initval; - for (int i = 0; i < GetSize(sig_q); i++) - if (initbits.count(sig_q[i])) - initval.bits.push_back(initbits.at(sig_q[i]) ? State::S1 : State::S0); - else - initval.bits.push_back(State::Sx); - - if (!initval.is_fully_undef()) { - int nid_init_val = get_sig_nid(initval); + if (nid_init_val >= 0) { int nid_init = next_nid++; if (verbose) btorf("; initval = %s\n", log_signal(initval)); @@ -559,8 +616,8 @@ struct BtorWorker if (initstate_nid < 0) { int sid = get_bv_sid(1); - int one_nid = get_sig_nid(Const(1, 1)); - int zero_nid = get_sig_nid(Const(0, 1)); + int one_nid = get_sig_nid(State::S1); + int zero_nid = get_sig_nid(State::S0); initstate_nid = next_nid++; btorf("%d state %d\n", initstate_nid, sid); btorf("%d init %d %d %d\n", next_nid++, sid, initstate_nid, one_nid); @@ -575,6 +632,7 @@ struct BtorWorker { int abits = cell->getParam("\\ABITS").as_int(); int width = cell->getParam("\\WIDTH").as_int(); + int nwords = cell->getParam("\\SIZE").as_int(); int rdports = cell->getParam("\\RD_PORTS").as_int(); int wrports = cell->getParam("\\WR_PORTS").as_int(); @@ -601,6 +659,52 @@ struct BtorWorker int data_sid = get_bv_sid(width); int bool_sid = get_bv_sid(1); int sid = get_mem_sid(abits, width); + + Const initdata = cell->getParam("\\INIT"); + initdata.exts(nwords*width); + int nid_init_val = -1; + + if (!initdata.is_fully_undef()) + { + bool constword = true; + Const firstword = initdata.extract(0, width); + + for (int i = 1; i < nwords; i++) { + Const thisword = initdata.extract(i*width, width); + if (thisword != firstword) { + constword = false; + break; + } + } + + if (constword) + { + if (verbose) + btorf("; initval = %s\n", log_signal(firstword)); + nid_init_val = get_sig_nid(firstword); + } + else + { + nid_init_val = next_nid++; + btorf("%d state %d\n", nid_init_val, sid); + + for (int i = 0; i < nwords; i++) { + Const thisword = initdata.extract(i*width, width); + if (thisword.is_fully_undef()) + continue; + Const thisaddr(i, abits); + int nid_thisword = get_sig_nid(thisword); + int nid_thisaddr = get_sig_nid(thisaddr); + int last_nid_init_val = nid_init_val; + nid_init_val = next_nid++; + if (verbose) + btorf("; initval[%d] = %s\n", i, log_signal(thisword)); + btorf("%d write %d %d %d %d\n", nid_init_val, sid, last_nid_init_val, nid_thisaddr, nid_thisword); + } + } + } + + int nid = next_nid++; int nid_head = nid; @@ -609,6 +713,12 @@ struct BtorWorker else btorf("%d state %d %s\n", nid, sid, log_id(cell)); + if (nid_init_val >= 0) + { + int nid_init = next_nid++; + btorf("%d init %d %d %d\n", nid_init, sid, nid, nid_init_val); + } + if (asyncwr) { for (int port = 0; port < wrports; port++) @@ -776,9 +886,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)); + } } } @@ -892,9 +1021,8 @@ struct BtorWorker btorf_push(stringf("output %s", log_id(wire))); - int sid = get_bv_sid(GetSize(wire)); int nid = get_sig_nid(wire); - btorf("%d output %d %d %s\n", next_nid++, sid, nid, log_id(wire)); + btorf("%d output %d %s\n", next_nid++, nid, log_id(wire)); btorf_pop(stringf("output %s", log_id(wire))); } @@ -1076,7 +1204,7 @@ struct BtorWorker struct BtorBackend : public Backend { BtorBackend() : Backend("btor", "write design to BTOR file") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -1091,7 +1219,7 @@ struct BtorBackend : public Backend { log(" Output only a single bad property for all asserts\n"); log("\n"); } - virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) + void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { bool verbose = false, single_bad = false; diff --git a/backends/edif/edif.cc b/backends/edif/edif.cc index a6534b911..6d9469538 100644 --- a/backends/edif/edif.cc +++ b/backends/edif/edif.cc @@ -90,7 +90,7 @@ struct EdifNames struct EdifBackend : public Backend { EdifBackend() : Backend("edif", "write design to EDIF netlist file") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -106,6 +106,13 @@ struct EdifBackend : public Backend { log(" if the design contains constant nets. use \"hilomap\" to map to custom\n"); log(" constant drivers first)\n"); log("\n"); + log(" -gndvccy\n"); + log(" create \"GND\" and \"VCC\" cells with \"Y\" outputs. (the default is \"G\"\n"); + log(" for \"GND\" and \"P\" for \"VCC\".)\n"); + log("\n"); + log(" -attrprop\n"); + log(" create EDIF properties for cell attributes\n"); + log("\n"); log(" -pvector {par|bra|ang}\n"); log(" sets the delimiting character for module port rename clauses to\n"); log(" parentheses, square brackets, or angle brackets.\n"); @@ -116,13 +123,14 @@ struct EdifBackend : public Backend { log("is targeted.\n"); log("\n"); } - virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) + void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing EDIF backend.\n"); std::string top_module_name; bool port_rename = false; + bool attr_properties = false; std::map<RTLIL::IdString, std::map<RTLIL::IdString, int>> lib_cell_ports; - bool nogndvcc = false; + bool nogndvcc = false, gndvccy = false; CellTypes ct(design); EdifNames edif_names; @@ -137,6 +145,14 @@ struct EdifBackend : public Backend { nogndvcc = true; continue; } + if (args[argidx] == "-gndvccy") { + gndvccy = true; + continue; + } + if (args[argidx] == "-attrprop") { + attr_properties = true; + continue; + } if (args[argidx] == "-pvector" && argidx+1 < args.size()) { std::string parray; port_rename = true; @@ -162,7 +178,7 @@ struct EdifBackend : public Backend { for (auto module_it : design->modules_) { RTLIL::Module *module = module_it.second; - if (module->get_bool_attribute("\\blackbox")) + if (module->get_blackbox_attribute()) continue; if (top_module_name.empty()) @@ -176,7 +192,7 @@ struct EdifBackend : public Backend { for (auto cell_it : module->cells_) { RTLIL::Cell *cell = cell_it.second; - if (!design->modules_.count(cell->type) || design->modules_.at(cell->type)->get_bool_attribute("\\blackbox")) { + if (!design->modules_.count(cell->type) || design->modules_.at(cell->type)->get_blackbox_attribute()) { lib_cell_ports[cell->type]; for (auto p : cell->connections()) lib_cell_ports[cell->type][p.first] = GetSize(p.second); @@ -203,7 +219,7 @@ struct EdifBackend : public Backend { *f << stringf(" (cellType GENERIC)\n"); *f << stringf(" (view VIEW_NETLIST\n"); *f << stringf(" (viewType NETLIST)\n"); - *f << stringf(" (interface (port G (direction OUTPUT)))\n"); + *f << stringf(" (interface (port %c (direction OUTPUT)))\n", gndvccy ? 'Y' : 'G'); *f << stringf(" )\n"); *f << stringf(" )\n"); @@ -211,7 +227,7 @@ struct EdifBackend : public Backend { *f << stringf(" (cellType GENERIC)\n"); *f << stringf(" (view VIEW_NETLIST\n"); *f << stringf(" (viewType NETLIST)\n"); - *f << stringf(" (interface (port P (direction OUTPUT)))\n"); + *f << stringf(" (interface (port %c (direction OUTPUT)))\n", gndvccy ? 'Y' : 'P'); *f << stringf(" )\n"); *f << stringf(" )\n"); } @@ -286,7 +302,7 @@ struct EdifBackend : public Backend { *f << stringf(" (technology (numberDefinition))\n"); for (auto module : sorted_modules) { - if (module->get_bool_attribute("\\blackbox")) + if (module->get_blackbox_attribute()) continue; SigMap sigmap(module); @@ -332,24 +348,33 @@ struct EdifBackend : public Backend { *f << stringf(" (instance %s\n", EDIF_DEF(cell->name)); *f << stringf(" (viewRef VIEW_NETLIST (cellRef %s%s))", EDIF_REF(cell->type), lib_cell_ports.count(cell->type) > 0 ? " (libraryRef LIB)" : ""); - for (auto &p : cell->parameters) - if ((p.second.flags & RTLIL::CONST_FLAG_STRING) != 0) - *f << stringf("\n (property %s (string \"%s\"))", EDIF_DEF(p.first), p.second.decode_string().c_str()); - else if (p.second.bits.size() <= 32 && RTLIL::SigSpec(p.second).is_fully_def()) - *f << stringf("\n (property %s (integer %u))", EDIF_DEF(p.first), p.second.as_int()); + + auto add_prop = [&](IdString name, Const val) { + if ((val.flags & RTLIL::CONST_FLAG_STRING) != 0) + *f << stringf("\n (property %s (string \"%s\"))", EDIF_DEF(name), val.decode_string().c_str()); + else if (val.bits.size() <= 32 && RTLIL::SigSpec(val).is_fully_def()) + *f << stringf("\n (property %s (integer %u))", EDIF_DEF(name), val.as_int()); else { std::string hex_string = ""; - for (size_t i = 0; i < p.second.bits.size(); i += 4) { + for (size_t i = 0; i < val.bits.size(); i += 4) { int digit_value = 0; - if (i+0 < p.second.bits.size() && p.second.bits.at(i+0) == RTLIL::State::S1) digit_value |= 1; - if (i+1 < p.second.bits.size() && p.second.bits.at(i+1) == RTLIL::State::S1) digit_value |= 2; - if (i+2 < p.second.bits.size() && p.second.bits.at(i+2) == RTLIL::State::S1) digit_value |= 4; - if (i+3 < p.second.bits.size() && p.second.bits.at(i+3) == RTLIL::State::S1) digit_value |= 8; + if (i+0 < val.bits.size() && val.bits.at(i+0) == RTLIL::State::S1) digit_value |= 1; + if (i+1 < val.bits.size() && val.bits.at(i+1) == RTLIL::State::S1) digit_value |= 2; + if (i+2 < val.bits.size() && val.bits.at(i+2) == RTLIL::State::S1) digit_value |= 4; + if (i+3 < val.bits.size() && val.bits.at(i+3) == RTLIL::State::S1) digit_value |= 8; char digit_str[2] = { "0123456789abcdef"[digit_value], 0 }; hex_string = std::string(digit_str) + hex_string; } - *f << stringf("\n (property %s (string \"%d'h%s\"))", EDIF_DEF(p.first), GetSize(p.second.bits), hex_string.c_str()); + *f << stringf("\n (property %s (string \"%d'h%s\"))", EDIF_DEF(name), GetSize(val.bits), hex_string.c_str()); } + }; + + for (auto &p : cell->parameters) + add_prop(p.first, p.second); + if (attr_properties) + for (auto &p : cell->attributes) + add_prop(p.first, p.second); + *f << stringf(")\n"); for (auto &p : cell->connections()) { RTLIL::SigSpec sig = sigmap(p.second); @@ -403,9 +428,9 @@ struct EdifBackend : public Backend { if (nogndvcc) log_error("Design contains constant nodes (map with \"hilomap\" first).\n"); if (sig == RTLIL::State::S0) - *f << stringf(" (portRef G (instanceRef GND))\n"); + *f << stringf(" (portRef %c (instanceRef GND))\n", gndvccy ? 'Y' : 'G'); if (sig == RTLIL::State::S1) - *f << stringf(" (portRef P (instanceRef VCC))\n"); + *f << stringf(" (portRef %c (instanceRef VCC))\n", gndvccy ? 'Y' : 'P'); } *f << stringf(" ))\n"); } diff --git a/backends/firrtl/firrtl.cc b/backends/firrtl/firrtl.cc index 06cbc9b2b..87db0edf7 100644 --- a/backends/firrtl/firrtl.cc +++ b/backends/firrtl/firrtl.cc @@ -23,7 +23,11 @@ #include "kernel/celltypes.h" #include "kernel/cellaigs.h" #include "kernel/log.h" +#include <algorithm> #include <string> +#include <regex> +#include <vector> +#include <cmath> USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -32,6 +36,28 @@ pool<string> used_names; dict<IdString, string> namecache; int autoid_counter; +typedef unsigned FDirection; +static const FDirection FD_NODIRECTION = 0x0; +static const FDirection FD_IN = 0x1; +static const FDirection FD_OUT = 0x2; +static const FDirection FD_INOUT = 0x3; +static const int FIRRTL_MAX_DSH_WIDTH_ERROR = 20; // For historic reasons, this is actually one greater than the maximum allowed shift width + +// Get a port direction with respect to a specific module. +FDirection getPortFDirection(IdString id, Module *module) +{ + Wire *wire = module->wires_.at(id); + FDirection direction = FD_NODIRECTION; + if (wire && wire->port_id) + { + if (wire->port_input) + direction |= FD_IN; + if (wire->port_output) + direction |= FD_OUT; + } + return direction; +} + string next_id() { string new_id; @@ -77,6 +103,127 @@ struct FirrtlWorker dict<SigBit, pair<string, int>> reverse_wire_map; string unconn_id; + RTLIL::Design *design; + std::string indent; + + // Define read/write ports and memories. + // We'll collect their definitions and emit the corresponding FIRRTL definitions at the appropriate point in module construction. + // For the moment, we don't handle $readmemh or $readmemb. + // These will be part of a subsequent PR. + struct read_port { + string name; + bool clk_enable; + bool clk_parity; + bool transparent; + RTLIL::SigSpec clk; + RTLIL::SigSpec ena; + RTLIL::SigSpec addr; + read_port(string name, bool clk_enable, bool clk_parity, bool transparent, RTLIL::SigSpec clk, RTLIL::SigSpec ena, RTLIL::SigSpec addr) : name(name), clk_enable(clk_enable), clk_parity(clk_parity), transparent(transparent), clk(clk), ena(ena), addr(addr) { + // Current (3/13/2019) conventions: + // generate a constant 0 for clock and a constant 1 for enable if they are undefined. + if (!clk.is_fully_def()) + this->clk = SigSpec(State::S0); + if (!ena.is_fully_def()) + this->ena = SigSpec(State::S1); + } + string gen_read(const char * indent) { + string addr_expr = make_expr(addr); + string ena_expr = make_expr(ena); + string clk_expr = make_expr(clk); + string addr_str = stringf("%s%s.addr <= %s\n", indent, name.c_str(), addr_expr.c_str()); + string ena_str = stringf("%s%s.en <= %s\n", indent, name.c_str(), ena_expr.c_str()); + string clk_str = stringf("%s%s.clk <= asClock(%s)\n", indent, name.c_str(), clk_expr.c_str()); + return addr_str + ena_str + clk_str; + } + }; + struct write_port : read_port { + RTLIL::SigSpec mask; + write_port(string name, bool clk_enable, bool clk_parity, bool transparent, RTLIL::SigSpec clk, RTLIL::SigSpec ena, RTLIL::SigSpec addr, RTLIL::SigSpec mask) : read_port(name, clk_enable, clk_parity, transparent, clk, ena, addr), mask(mask) { + if (!clk.is_fully_def()) + this->clk = SigSpec(RTLIL::Const(0)); + if (!ena.is_fully_def()) + this->ena = SigSpec(RTLIL::Const(0)); + if (!mask.is_fully_def()) + this->ena = SigSpec(RTLIL::Const(1)); + } + string gen_read(const char * /* indent */) { + log_error("gen_read called on write_port: %s\n", name.c_str()); + return stringf("gen_read called on write_port: %s\n", name.c_str()); + } + string gen_write(const char * indent) { + string addr_expr = make_expr(addr); + string ena_expr = make_expr(ena); + string clk_expr = make_expr(clk); + string mask_expr = make_expr(mask); + string mask_str = stringf("%s%s.mask <= %s\n", indent, name.c_str(), mask_expr.c_str()); + string addr_str = stringf("%s%s.addr <= %s\n", indent, name.c_str(), addr_expr.c_str()); + string ena_str = stringf("%s%s.en <= %s\n", indent, name.c_str(), ena_expr.c_str()); + string clk_str = stringf("%s%s.clk <= asClock(%s)\n", indent, name.c_str(), clk_expr.c_str()); + return addr_str + ena_str + clk_str + mask_str; + } + }; + /* Memories defined within this module. */ + struct memory { + Cell *pCell; // for error reporting + string name; // memory name + int abits; // number of address bits + int size; // size (in units) of the memory + int width; // size (in bits) of each element + int read_latency; + int write_latency; + vector<read_port> read_ports; + vector<write_port> write_ports; + std::string init_file; + std::string init_file_srcFileSpec; + string srcLine; + memory(Cell *pCell, string name, int abits, int size, int width) : pCell(pCell), name(name), abits(abits), size(size), width(width), read_latency(0), write_latency(1), init_file(""), init_file_srcFileSpec("") { + // Provide defaults for abits or size if one (but not the other) is specified. + if (this->abits == 0 && this->size != 0) { + this->abits = ceil_log2(this->size); + } else if (this->abits != 0 && this->size == 0) { + this->size = 1 << this->abits; + } + // Sanity-check this construction. + if (this->name == "") { + log_error("Nameless memory%s\n", this->atLine()); + } + if (this->abits == 0 && this->size == 0) { + log_error("Memory %s has zero address bits and size%s\n", this->name.c_str(), this->atLine()); + } + if (this->width == 0) { + log_error("Memory %s has zero width%s\n", this->name.c_str(), this->atLine()); + } + } + // We need a default constructor for the dict insert. + memory() : pCell(0), read_latency(0), write_latency(1), init_file(""), init_file_srcFileSpec(""){} + + const char *atLine() { + if (srcLine == "") { + if (pCell) { + auto p = pCell->attributes.find("\\src"); + srcLine = " at " + p->second.decode_string(); + } + } + return srcLine.c_str(); + } + void add_memory_read_port(read_port &rp) { + read_ports.push_back(rp); + } + void add_memory_write_port(write_port &wp) { + write_ports.push_back(wp); + } + void add_memory_file(std::string init_file, std::string init_file_srcFileSpec) { + this->init_file = init_file; + this->init_file_srcFileSpec = init_file_srcFileSpec; + } + + }; + dict<string, memory> memories; + + void register_memory(memory &m) + { + memories[m.name] = m; + } void register_reverse_wire_map(string id, SigSpec sig) { @@ -84,11 +231,11 @@ struct FirrtlWorker reverse_wire_map[sig[i]] = make_pair(id, i); } - FirrtlWorker(Module *module, std::ostream &f) : module(module), f(f) + FirrtlWorker(Module *module, std::ostream &f, RTLIL::Design *theDesign) : module(module), f(f), design(theDesign), indent(" ") { } - string make_expr(SigSpec sig) + static string make_expr(const SigSpec &sig) { string expr; @@ -135,6 +282,117 @@ struct FirrtlWorker return expr; } + std::string fid(RTLIL::IdString internal_id) + { + return make_id(internal_id); + } + + std::string cellname(RTLIL::Cell *cell) + { + return fid(cell->name).c_str(); + } + + void process_instance(RTLIL::Cell *cell, vector<string> &wire_exprs) + { + std::string cell_type = fid(cell->type); + std::string instanceOf; + // If this is a parameterized module, its parent module is encoded in the cell type + if (cell->type.begins_with("$paramod")) + { + std::string::iterator it; + for (it = cell_type.begin(); it < cell_type.end(); it++) + { + switch (*it) { + case '\\': /* FALL_THROUGH */ + case '=': /* FALL_THROUGH */ + case '\'': /* FALL_THROUGH */ + case '$': instanceOf.append("_"); break; + default: instanceOf.append(1, *it); break; + } + } + } + else + { + instanceOf = cell_type; + } + + std::string cell_name = cellname(cell); + std::string cell_name_comment; + if (cell_name != fid(cell->name)) + cell_name_comment = " /* " + fid(cell->name) + " */ "; + else + cell_name_comment = ""; + // Find the module corresponding to this instance. + auto instModule = design->module(cell->type); + // If there is no instance for this, just return. + if (instModule == NULL) + { + log_warning("No instance for %s.%s\n", cell_type.c_str(), cell_name.c_str()); + return; + } + wire_exprs.push_back(stringf("%s" "inst %s%s of %s", indent.c_str(), cell_name.c_str(), cell_name_comment.c_str(), instanceOf.c_str())); + + for (auto it = cell->connections().begin(); it != cell->connections().end(); ++it) { + if (it->second.size() > 0) { + const SigSpec &secondSig = it->second; + const std::string firstName = cell_name + "." + make_id(it->first); + const std::string secondExpr = make_expr(secondSig); + // Find the direction for this port. + FDirection dir = getPortFDirection(it->first, instModule); + std::string sourceExpr, sinkExpr; + const SigSpec *sinkSig = nullptr; + switch (dir) { + case FD_INOUT: + log_warning("Instance port connection %s.%s is INOUT; treating as OUT\n", cell_type.c_str(), log_signal(it->second)); + /* FALLTHRU */ + case FD_OUT: + sourceExpr = firstName; + sinkExpr = secondExpr; + sinkSig = &secondSig; + break; + case FD_NODIRECTION: + log_warning("Instance port connection %s.%s is NODIRECTION; treating as IN\n", cell_type.c_str(), log_signal(it->second)); + /* FALLTHRU */ + case FD_IN: + sourceExpr = secondExpr; + sinkExpr = firstName; + break; + default: + log_error("Instance port %s.%s unrecognized connection direction 0x%x !\n", cell_type.c_str(), log_signal(it->second), dir); + break; + } + // Check for subfield assignment. + std::string bitsString = "bits("; + if (sinkExpr.compare(0, bitsString.length(), bitsString) == 0) { + if (sinkSig == nullptr) + log_error("Unknown subfield %s.%s\n", cell_type.c_str(), sinkExpr.c_str()); + // Don't generate the assignment here. + // Add the source and sink to the "reverse_wire_map" and we'll output the assignment + // as part of the coalesced subfield assignments for this wire. + register_reverse_wire_map(sourceExpr, *sinkSig); + } else { + wire_exprs.push_back(stringf("\n%s%s <= %s", indent.c_str(), sinkExpr.c_str(), sourceExpr.c_str())); + } + } + } + wire_exprs.push_back(stringf("\n")); + + } + + // Given an expression for a shift amount, and a maximum width, + // generate the FIRRTL expression for equivalent dynamic shift taking into account FIRRTL shift semantics. + std::string gen_dshl(const string b_expr, const int b_width) + { + string result = b_expr; + if (b_width >= FIRRTL_MAX_DSH_WIDTH_ERROR) { + int max_shift_width_bits = FIRRTL_MAX_DSH_WIDTH_ERROR - 1; + string max_shift_string = stringf("UInt<%d>(%d)", max_shift_width_bits, (1<<max_shift_width_bits) - 1); + // Deal with the difference in semantics between FIRRTL and verilog + result = stringf("mux(gt(%s, %s), %s, bits(%s, %d, 0))", b_expr.c_str(), max_shift_string.c_str(), max_shift_string.c_str(), b_expr.c_str(), max_shift_width_bits - 1); + } + return result; + } + void run() { f << stringf(" module %s:\n", make_id(module->name)); @@ -142,58 +400,90 @@ struct FirrtlWorker for (auto wire : module->wires()) { + const auto wireName = make_id(wire->name); + // If a wire has initial data, issue a warning since FIRRTL doesn't currently support it. + if (wire->attributes.count("\\init")) { + log_warning("Initial value (%s) for (%s.%s) not supported\n", + wire->attributes.at("\\init").as_string().c_str(), + log_id(module), log_id(wire)); + } if (wire->port_id) { if (wire->port_input && wire->port_output) log_error("Module port %s.%s is inout!\n", log_id(module), log_id(wire)); port_decls.push_back(stringf(" %s %s: UInt<%d>\n", wire->port_input ? "input" : "output", - make_id(wire->name), wire->width)); + wireName, wire->width)); } else { - wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", make_id(wire->name), wire->width)); + wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", wireName, wire->width)); } } for (auto cell : module->cells()) { + static Const ndef(0, 0); + + // Is this cell is a module instance? + if (cell->type[0] != '$') + { + process_instance(cell, wire_exprs); + continue; + } + // Not a module instance. Set up cell properties + bool extract_y_bits = false; // Assume no extraction of final bits will be required. + int a_width = cell->parameters.at("\\A_WIDTH", ndef).as_int(); // The width of "A" + int b_width = cell->parameters.at("\\B_WIDTH", ndef).as_int(); // The width of "A" + const int y_width = cell->parameters.at("\\Y_WIDTH", ndef).as_int(); // The width of the result + const bool a_signed = cell->parameters.at("\\A_SIGNED", ndef).as_bool(); + const bool b_signed = cell->parameters.at("\\B_SIGNED", ndef).as_bool(); + bool firrtl_is_signed = a_signed; // The result is signed (subsequent code may change this). + int firrtl_width = 0; + string primop; + bool always_uint = false; + string y_id = make_id(cell->name); + if (cell->type.in("$not", "$logic_not", "$neg", "$reduce_and", "$reduce_or", "$reduce_xor", "$reduce_bool", "$reduce_xnor")) { - string y_id = make_id(cell->name); - bool is_signed = cell->parameters.at("\\A_SIGNED").as_bool(); - int y_width = cell->parameters.at("\\Y_WIDTH").as_int(); string a_expr = make_expr(cell->getPort("\\A")); wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width)); - if (cell->parameters.at("\\A_SIGNED").as_bool()) { + if (a_signed) { a_expr = "asSInt(" + a_expr + ")"; } - a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width); + // Don't use the results of logical operations (a single bit) to control padding + if (!(cell->type.in("$eq", "$eqx", "$gt", "$ge", "$lt", "$le", "$ne", "$nex", "$reduce_bool", "$logic_not") && y_width == 1) ) { + a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width); + } - string primop; - bool always_uint = false; + // Assume the FIRRTL width is a single bit. + firrtl_width = 1; if (cell->type == "$not") primop = "not"; - if (cell->type == "$neg") primop = "neg"; - if (cell->type == "$logic_not") { + else if (cell->type == "$neg") { + primop = "neg"; + firrtl_is_signed = true; // Result of "neg" is signed (an SInt). + firrtl_width = a_width; + } else if (cell->type == "$logic_not") { primop = "eq"; a_expr = stringf("%s, UInt(0)", a_expr.c_str()); } - if (cell->type == "$reduce_and") primop = "andr"; - if (cell->type == "$reduce_or") primop = "orr"; - if (cell->type == "$reduce_xor") primop = "xorr"; - if (cell->type == "$reduce_xnor") { + else if (cell->type == "$reduce_and") primop = "andr"; + else if (cell->type == "$reduce_or") primop = "orr"; + else if (cell->type == "$reduce_xor") primop = "xorr"; + else if (cell->type == "$reduce_xnor") { primop = "not"; a_expr = stringf("xorr(%s)", a_expr.c_str()); } - if (cell->type == "$reduce_bool") { - primop = "neq"; - a_expr = stringf("%s, UInt(0)", a_expr.c_str()); - } + else if (cell->type == "$reduce_bool") { + primop = "neq"; + // Use the sign of the a_expr and its width as the type (UInt/SInt) and width of the comparand. + a_expr = stringf("%s, %cInt<%d>(0)", a_expr.c_str(), a_signed ? 'S' : 'U', a_width); + } string expr = stringf("%s(%s)", primop.c_str(), a_expr.c_str()); - if ((is_signed && !always_uint)) + if ((firrtl_is_signed && !always_uint)) expr = stringf("asUInt(%s)", expr.c_str()); cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), expr.c_str())); @@ -201,99 +491,226 @@ struct FirrtlWorker continue; } - if (cell->type.in("$add", "$sub", "$mul", "$div", "$mod", "$xor", "$and", "$or", "$eq", "$eqx", - "$gt", "$ge", "$lt", "$le", "$ne", "$nex", "$shr", "$sshr", "$sshl", "$shl", - "$logic_and", "$logic_or")) + if (cell->type.in("$add", "$sub", "$mul", "$div", "$mod", "$xor", "$xnor", "$and", "$or", "$eq", "$eqx", + "$gt", "$ge", "$lt", "$le", "$ne", "$nex", "$shr", "$sshr", "$sshl", "$shl", + "$logic_and", "$logic_or", "$pow")) { - string y_id = make_id(cell->name); - bool is_signed = cell->parameters.at("\\A_SIGNED").as_bool(); - int y_width = cell->parameters.at("\\Y_WIDTH").as_int(); string a_expr = make_expr(cell->getPort("\\A")); string b_expr = make_expr(cell->getPort("\\B")); wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width)); - if (cell->parameters.at("\\A_SIGNED").as_bool()) { + if (a_signed) { a_expr = "asSInt(" + a_expr + ")"; + // Expand the "A" operand to the result width + if (a_width < y_width) { + a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width); + a_width = y_width; + } } - if (cell->parameters.at("\\A_SIGNED").as_bool() & (cell->type != "$shr")) { + // Shift amount is always unsigned, and needn't be padded to result width, + // otherwise, we need to cast the b_expr appropriately + if (b_signed && !cell->type.in("$shr", "$sshr", "$shl", "$sshl", "$pow")) { b_expr = "asSInt(" + b_expr + ")"; + // Expand the "B" operand to the result width + if (b_width < y_width) { + b_expr = stringf("pad(%s, %d)", b_expr.c_str(), y_width); + b_width = y_width; + } } - a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width); - - if ((cell->type != "$shl") && (cell->type != "$sshl")) { - b_expr = stringf("pad(%s, %d)", b_expr.c_str(), y_width); - } - - if (cell->parameters.at("\\A_SIGNED").as_bool() & (cell->type == "$shr")) { - a_expr = "asUInt(" + a_expr + ")"; + // For the arithmetic ops, expand operand widths to result widths befor performing the operation. + // This corresponds (according to iverilog) to what verilog compilers implement. + if (cell->type.in("$add", "$sub", "$mul", "$div", "$mod", "$xor", "$xnor", "$and", "$or")) + { + if (a_width < y_width) { + a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width); + a_width = y_width; + } + if (b_width < y_width) { + b_expr = stringf("pad(%s, %d)", b_expr.c_str(), y_width); + b_width = y_width; + } + } + // Assume the FIRRTL width is the width of "A" + firrtl_width = a_width; + auto a_sig = cell->getPort("\\A"); + + if (cell->type == "$add") { + primop = "add"; + firrtl_is_signed = a_signed | b_signed; + firrtl_width = max(a_width, b_width); + } else if (cell->type == "$sub") { + primop = "sub"; + firrtl_is_signed = true; + int a_widthInc = (!a_signed && b_signed) ? 2 : (a_signed && !b_signed) ? 1 : 0; + int b_widthInc = (a_signed && !b_signed) ? 2 : (!a_signed && b_signed) ? 1 : 0; + firrtl_width = max(a_width + a_widthInc, b_width + b_widthInc); + } else if (cell->type == "$mul") { + primop = "mul"; + firrtl_is_signed = a_signed | b_signed; + firrtl_width = a_width + b_width; + } else if (cell->type == "$div") { + primop = "div"; + firrtl_is_signed = a_signed | b_signed; + firrtl_width = a_width; + } else if (cell->type == "$mod") { + primop = "rem"; + firrtl_width = min(a_width, b_width); + } else if (cell->type == "$and") { + primop = "and"; + always_uint = true; + firrtl_width = max(a_width, b_width); + } + else if (cell->type == "$or" ) { + primop = "or"; + always_uint = true; + firrtl_width = max(a_width, b_width); + } + else if (cell->type == "$xor") { + primop = "xor"; + always_uint = true; + firrtl_width = max(a_width, b_width); + } + else if (cell->type == "$xnor") { + primop = "xnor"; + always_uint = true; + firrtl_width = max(a_width, b_width); + } + else if ((cell->type == "$eq") | (cell->type == "$eqx")) { + primop = "eq"; + always_uint = true; + firrtl_width = 1; + } + else if ((cell->type == "$ne") | (cell->type == "$nex")) { + primop = "neq"; + always_uint = true; + firrtl_width = 1; + } + else if (cell->type == "$gt") { + primop = "gt"; + always_uint = true; + firrtl_width = 1; + } + else if (cell->type == "$ge") { + primop = "geq"; + always_uint = true; + firrtl_width = 1; + } + else if (cell->type == "$lt") { + primop = "lt"; + always_uint = true; + firrtl_width = 1; + } + else if (cell->type == "$le") { + primop = "leq"; + always_uint = true; + firrtl_width = 1; + } + else if ((cell->type == "$shl") | (cell->type == "$sshl")) { + // FIRRTL will widen the result (y) by the amount of the shift. + // We'll need to offset this by extracting the un-widened portion as Verilog would do. + extract_y_bits = true; + // Is the shift amount constant? + auto b_sig = cell->getPort("\\B"); + if (b_sig.is_fully_const()) { + primop = "shl"; + int shift_amount = b_sig.as_int(); + b_expr = std::to_string(shift_amount); + firrtl_width = a_width + shift_amount; + } else { + primop = "dshl"; + // Convert from FIRRTL left shift semantics. + b_expr = gen_dshl(b_expr, b_width); + firrtl_width = a_width + (1 << b_width) - 1; + } + } + else if ((cell->type == "$shr") | (cell->type == "$sshr")) { + // We don't need to extract a specific range of bits. + extract_y_bits = false; + // Is the shift amount constant? + auto b_sig = cell->getPort("\\B"); + if (b_sig.is_fully_const()) { + primop = "shr"; + int shift_amount = b_sig.as_int(); + b_expr = std::to_string(shift_amount); + firrtl_width = max(1, a_width - shift_amount); + } else { + primop = "dshr"; + firrtl_width = a_width; + } + // We'll need to do some special fixups if the source (and thus result) is signed. + if (firrtl_is_signed) { + // If this is a "logical" shift right, pretend the source is unsigned. + if (cell->type == "$shr") { + a_expr = "asUInt(" + a_expr + ")"; + } + } + } + else if ((cell->type == "$logic_and")) { + primop = "and"; + a_expr = "neq(" + a_expr + ", UInt(0))"; + b_expr = "neq(" + b_expr + ", UInt(0))"; + always_uint = true; + firrtl_width = 1; + } + else if ((cell->type == "$logic_or")) { + primop = "or"; + a_expr = "neq(" + a_expr + ", UInt(0))"; + b_expr = "neq(" + b_expr + ", UInt(0))"; + always_uint = true; + firrtl_width = 1; + } + else if ((cell->type == "$pow")) { + if (a_sig.is_fully_const() && a_sig.as_int() == 2) { + // We'll convert this to a shift. To simplify things, change the a_expr to "1" + // so we can use b_expr directly as a shift amount. + // Only support 2 ** N (i.e., shift left) + // FIRRTL will widen the result (y) by the amount of the shift. + // We'll need to offset this by extracting the un-widened portion as Verilog would do. + a_expr = firrtl_is_signed ? "SInt(1)" : "UInt(1)"; + extract_y_bits = true; + // Is the shift amount constant? + auto b_sig = cell->getPort("\\B"); + if (b_sig.is_fully_const()) { + primop = "shl"; + int shiftAmount = b_sig.as_int(); + if (shiftAmount < 0) { + log_error("Negative power exponent - %d: %s.%s\n", shiftAmount, log_id(module), log_id(cell)); + } + b_expr = std::to_string(shiftAmount); + firrtl_width = a_width + shiftAmount; + } else { + primop = "dshl"; + // Convert from FIRRTL left shift semantics. + b_expr = gen_dshl(b_expr, b_width); + firrtl_width = a_width + (1 << b_width) - 1; + } + } else { + log_error("Non power 2: %s.%s\n", log_id(module), log_id(cell)); + } } - - string primop; - bool always_uint = false; - if (cell->type == "$add") primop = "add"; - if (cell->type == "$sub") primop = "sub"; - if (cell->type == "$mul") primop = "mul"; - if (cell->type == "$div") primop = "div"; - if (cell->type == "$mod") primop = "rem"; - if (cell->type == "$and") { - primop = "and"; - always_uint = true; - } - if (cell->type == "$or" ) { - primop = "or"; - always_uint = true; - } - if (cell->type == "$xor") { - primop = "xor"; - always_uint = true; - } - if ((cell->type == "$eq") | (cell->type == "$eqx")) { - primop = "eq"; - always_uint = true; - } - if ((cell->type == "$ne") | (cell->type == "$nex")) { - primop = "neq"; - always_uint = true; - } - if (cell->type == "$gt") { - primop = "gt"; - always_uint = true; - } - if (cell->type == "$ge") { - primop = "geq"; - always_uint = true; - } - if (cell->type == "$lt") { - primop = "lt"; - always_uint = true; - } - if (cell->type == "$le") { - primop = "leq"; - always_uint = true; - } - if ((cell->type == "$shl") | (cell->type == "$sshl")) primop = "dshl"; - if ((cell->type == "$shr") | (cell->type == "$sshr")) primop = "dshr"; - if ((cell->type == "$logic_and")) { - primop = "and"; - a_expr = "neq(" + a_expr + ", UInt(0))"; - b_expr = "neq(" + b_expr + ", UInt(0))"; - always_uint = true; - } - if ((cell->type == "$logic_or")) { - primop = "or"; - a_expr = "neq(" + a_expr + ", UInt(0))"; - b_expr = "neq(" + b_expr + ", UInt(0))"; - always_uint = true; - } if (!cell->parameters.at("\\B_SIGNED").as_bool()) { b_expr = "asUInt(" + b_expr + ")"; } - string expr = stringf("%s(%s, %s)", primop.c_str(), a_expr.c_str(), b_expr.c_str()); + string expr; + // Deal with $xnor == ~^ (not xor) + if (primop == "xnor") { + expr = stringf("not(xor(%s, %s))", a_expr.c_str(), b_expr.c_str()); + } else { + expr = stringf("%s(%s, %s)", primop.c_str(), a_expr.c_str(), b_expr.c_str()); + } + + // Deal with FIRRTL's "shift widens" semantics, or the need to widen the FIRRTL result. + // If the operation is signed, the FIRRTL width will be 1 one bit larger. + if (extract_y_bits) { + expr = stringf("bits(%s, %d, 0)", expr.c_str(), y_width - 1); + } else if (firrtl_is_signed && (firrtl_width + 1) < y_width) { + expr = stringf("pad(%s, %d)", expr.c_str(), y_width); + } - if ((is_signed && !always_uint) || cell->type.in("$sub")) + if ((firrtl_is_signed && !always_uint)) expr = stringf("asUInt(%s)", expr.c_str()); cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), expr.c_str())); @@ -304,7 +721,6 @@ struct FirrtlWorker if (cell->type.in("$mux")) { - string y_id = make_id(cell->name); int width = cell->parameters.at("\\WIDTH").as_int(); string a_expr = make_expr(cell->getPort("\\A")); string b_expr = make_expr(cell->getPort("\\B")); @@ -325,6 +741,7 @@ struct FirrtlWorker int abits = cell->parameters.at("\\ABITS").as_int(); int width = cell->parameters.at("\\WIDTH").as_int(); int size = cell->parameters.at("\\SIZE").as_int(); + memory m(cell, mem_id, abits, size, width); int rd_ports = cell->parameters.at("\\RD_PORTS").as_int(); int wr_ports = cell->parameters.at("\\WR_PORTS").as_int(); @@ -341,33 +758,24 @@ struct FirrtlWorker if (offset != 0) log_error("Memory with nonzero offset: %s.%s\n", log_id(module), log_id(cell)); - cell_exprs.push_back(stringf(" mem %s:\n", mem_id.c_str())); - cell_exprs.push_back(stringf(" data-type => UInt<%d>\n", width)); - cell_exprs.push_back(stringf(" depth => %d\n", size)); - - for (int i = 0; i < rd_ports; i++) - cell_exprs.push_back(stringf(" reader => r%d\n", i)); - - for (int i = 0; i < wr_ports; i++) - cell_exprs.push_back(stringf(" writer => w%d\n", i)); - - cell_exprs.push_back(stringf(" read-latency => 0\n")); - cell_exprs.push_back(stringf(" write-latency => 1\n")); - cell_exprs.push_back(stringf(" read-under-write => undefined\n")); - for (int i = 0; i < rd_ports; i++) { if (rd_clk_enable[i] != State::S0) log_error("Clocked read port %d on memory %s.%s.\n", i, log_id(module), log_id(cell)); + SigSpec addr_sig = cell->getPort("\\RD_ADDR").extract(i*abits, abits); SigSpec data_sig = cell->getPort("\\RD_DATA").extract(i*width, width); - string addr_expr = make_expr(cell->getPort("\\RD_ADDR").extract(i*abits, abits)); - - cell_exprs.push_back(stringf(" %s.r%d.addr <= %s\n", mem_id.c_str(), i, addr_expr.c_str())); - cell_exprs.push_back(stringf(" %s.r%d.en <= UInt<1>(1)\n", mem_id.c_str(), i)); - cell_exprs.push_back(stringf(" %s.r%d.clk <= asClock(UInt<1>(0))\n", mem_id.c_str(), i)); - - register_reverse_wire_map(stringf("%s.r%d.data", mem_id.c_str(), i), data_sig); + string addr_expr = make_expr(addr_sig); + string name(stringf("%s.r%d", m.name.c_str(), i)); + bool clk_enable = false; + bool clk_parity = true; + bool transparency = false; + SigSpec ena_sig = RTLIL::SigSpec(RTLIL::State::S1, 1); + SigSpec clk_sig = RTLIL::SigSpec(RTLIL::State::S0, 1); + read_port rp(name, clk_enable, clk_parity, transparency, clk_sig, ena_sig, addr_sig); + m.add_memory_read_port(rp); + cell_exprs.push_back(rp.gen_read(indent.c_str())); + register_reverse_wire_map(stringf("%s.data", name.c_str()), data_sig); } for (int i = 0; i < wr_ports; i++) @@ -378,9 +786,16 @@ struct FirrtlWorker if (wr_clk_polarity[i] != State::S1) log_error("Negedge write port %d on memory %s.%s.\n", i, log_id(module), log_id(cell)); - string addr_expr = make_expr(cell->getPort("\\WR_ADDR").extract(i*abits, abits)); - string data_expr = make_expr(cell->getPort("\\WR_DATA").extract(i*width, width)); - string clk_expr = make_expr(cell->getPort("\\WR_CLK").extract(i)); + string name(stringf("%s.w%d", m.name.c_str(), i)); + bool clk_enable = true; + bool clk_parity = true; + bool transparency = false; + SigSpec addr_sig =cell->getPort("\\WR_ADDR").extract(i*abits, abits); + string addr_expr = make_expr(addr_sig); + SigSpec data_sig =cell->getPort("\\WR_DATA").extract(i*width, width); + string data_expr = make_expr(data_sig); + SigSpec clk_sig = cell->getPort("\\WR_CLK").extract(i); + string clk_expr = make_expr(clk_sig); SigSpec wen_sig = cell->getPort("\\WR_EN").extract(i*width, width); string wen_expr = make_expr(wen_sig[0]); @@ -389,13 +804,57 @@ struct FirrtlWorker if (wen_sig[0] != wen_sig[i]) log_error("Complex write enable on port %d on memory %s.%s.\n", i, log_id(module), log_id(cell)); - cell_exprs.push_back(stringf(" %s.w%d.addr <= %s\n", mem_id.c_str(), i, addr_expr.c_str())); - cell_exprs.push_back(stringf(" %s.w%d.data <= %s\n", mem_id.c_str(), i, data_expr.c_str())); - cell_exprs.push_back(stringf(" %s.w%d.en <= %s\n", mem_id.c_str(), i, wen_expr.c_str())); - cell_exprs.push_back(stringf(" %s.w%d.mask <= UInt<1>(1)\n", mem_id.c_str(), i)); - cell_exprs.push_back(stringf(" %s.w%d.clk <= asClock(%s)\n", mem_id.c_str(), i, clk_expr.c_str())); + SigSpec mask_sig = RTLIL::SigSpec(RTLIL::State::S1, 1); + write_port wp(name, clk_enable, clk_parity, transparency, clk_sig, wen_sig[0], addr_sig, mask_sig); + m.add_memory_write_port(wp); + cell_exprs.push_back(stringf("%s%s.data <= %s\n", indent.c_str(), name.c_str(), data_expr.c_str())); + cell_exprs.push_back(wp.gen_write(indent.c_str())); } + register_memory(m); + continue; + } + if (cell->type.in("$memwr", "$memrd", "$meminit")) + { + std::string cell_type = fid(cell->type); + std::string mem_id = make_id(cell->parameters["\\MEMID"].decode_string()); + int abits = cell->parameters.at("\\ABITS").as_int(); + int width = cell->parameters.at("\\WIDTH").as_int(); + memory *mp = nullptr; + if (cell->type == "$meminit" ) { + log_error("$meminit (%s.%s.%s) currently unsupported\n", log_id(module), log_id(cell), mem_id.c_str()); + } else { + // It's a $memwr or $memrd. Remember the read/write port parameters for the eventual FIRRTL memory definition. + auto addrSig = cell->getPort("\\ADDR"); + auto dataSig = cell->getPort("\\DATA"); + auto enableSig = cell->getPort("\\EN"); + auto clockSig = cell->getPort("\\CLK"); + Const clk_enable = cell->parameters.at("\\CLK_ENABLE"); + Const clk_polarity = cell->parameters.at("\\CLK_POLARITY"); + + // Do we already have an entry for this memory? + if (memories.count(mem_id) == 0) { + memory m(cell, mem_id, abits, 0, width); + register_memory(m); + } + mp = &memories.at(mem_id); + int portNum = 0; + bool transparency = false; + string data_expr = make_expr(dataSig); + if (cell->type.in("$memwr")) { + portNum = (int) mp->write_ports.size(); + write_port wp(stringf("%s.w%d", mem_id.c_str(), portNum), clk_enable.as_bool(), clk_polarity.as_bool(), transparency, clockSig, enableSig, addrSig, dataSig); + mp->add_memory_write_port(wp); + cell_exprs.push_back(stringf("%s%s.data <= %s\n", indent.c_str(), wp.name.c_str(), data_expr.c_str())); + cell_exprs.push_back(wp.gen_write(indent.c_str())); + } else if (cell->type.in("$memrd")) { + portNum = (int) mp->read_ports.size(); + read_port rp(stringf("%s.r%d", mem_id.c_str(), portNum), clk_enable.as_bool(), clk_polarity.as_bool(), transparency, clockSig, enableSig, addrSig); + mp->add_memory_read_port(rp); + cell_exprs.push_back(rp.gen_read(indent.c_str())); + register_reverse_wire_map(stringf("%s.data", rp.name.c_str()), dataSig); + } + } continue; } @@ -405,19 +864,85 @@ struct FirrtlWorker if (clkpol == false) log_error("Negative edge clock on FF %s.%s.\n", log_id(module), log_id(cell)); - string q_id = make_id(cell->name); int width = cell->parameters.at("\\WIDTH").as_int(); string expr = make_expr(cell->getPort("\\D")); string clk_expr = "asClock(" + make_expr(cell->getPort("\\CLK")) + ")"; - wire_decls.push_back(stringf(" reg %s: UInt<%d>, %s\n", q_id.c_str(), width, clk_expr.c_str())); + wire_decls.push_back(stringf(" reg %s: UInt<%d>, %s\n", y_id.c_str(), width, clk_expr.c_str())); - cell_exprs.push_back(stringf(" %s <= %s\n", q_id.c_str(), expr.c_str())); - register_reverse_wire_map(q_id, cell->getPort("\\Q")); + cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), expr.c_str())); + register_reverse_wire_map(y_id, cell->getPort("\\Q")); continue; } + // This may be a parameterized module - paramod. + if (cell->type.begins_with("$paramod")) + { + process_instance(cell, wire_exprs); + continue; + } + if (cell->type == "$shiftx") { + // assign y = a[b +: y_width]; + // We'll extract the correct bits as part of the primop. + + string a_expr = make_expr(cell->getPort("\\A")); + // Get the initial bit selector + string b_expr = make_expr(cell->getPort("\\B")); + wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width)); + + if (cell->getParam("\\B_SIGNED").as_bool()) { + // Use validif to constrain the selection (test the sign bit) + auto b_string = b_expr.c_str(); + int b_sign = cell->parameters.at("\\B_WIDTH").as_int() - 1; + b_expr = stringf("validif(not(bits(%s, %d, %d)), %s)", b_string, b_sign, b_sign, b_string); + } + string expr = stringf("dshr(%s, %s)", a_expr.c_str(), b_expr.c_str()); + + cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), expr.c_str())); + register_reverse_wire_map(y_id, cell->getPort("\\Y")); + continue; + } + if (cell->type == "$shift") { + // assign y = a >> b; + // where b may be negative + + string a_expr = make_expr(cell->getPort("\\A")); + string b_expr = make_expr(cell->getPort("\\B")); + auto b_string = b_expr.c_str(); + string expr; + wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width)); + + if (cell->getParam("\\B_SIGNED").as_bool()) { + // We generate a left or right shift based on the sign of b. + std::string dshl = stringf("bits(dshl(%s, %s), 0, %d)", a_expr.c_str(), gen_dshl(b_expr, b_width).c_str(), y_width); + std::string dshr = stringf("dshr(%s, %s)", a_expr.c_str(), b_string); + expr = stringf("mux(%s < 0, %s, %s)", + b_string, + dshl.c_str(), + dshr.c_str() + ); + } else { + expr = stringf("dshr(%s, %s)", a_expr.c_str(), b_string); + } + cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), expr.c_str())); + register_reverse_wire_map(y_id, cell->getPort("\\Y")); + continue; + } + if (cell->type == "$pos") { + // assign y = a; +// printCell(cell); + string a_expr = make_expr(cell->getPort("\\A")); + // Verilog appears to treat the result as signed, so if the result is wider than "A", + // we need to pad. + if (a_width < y_width) { + a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width); + } + wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width)); + cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), a_expr.c_str())); + register_reverse_wire_map(y_id, cell->getPort("\\Y")); + continue; + } log_error("Cell type not supported: %s (%s.%s)\n", log_id(cell->type), log_id(module), log_id(cell)); } @@ -494,14 +1019,14 @@ struct FirrtlWorker if (is_valid) { if (make_unconn_id) { wire_decls.push_back(stringf(" wire %s: UInt<1>\n", unconn_id.c_str())); - cell_exprs.push_back(stringf(" %s is invalid\n", unconn_id.c_str())); + wire_decls.push_back(stringf(" %s is invalid\n", unconn_id.c_str())); } wire_exprs.push_back(stringf(" %s <= %s\n", make_id(wire->name), expr.c_str())); } else { if (make_unconn_id) { unconn_id.clear(); } - wire_exprs.push_back(stringf(" %s is invalid\n", make_id(wire->name))); + wire_decls.push_back(stringf(" %s is invalid\n", make_id(wire->name))); } } @@ -515,6 +1040,24 @@ struct FirrtlWorker f << stringf("\n"); + // If we have any memory definitions, output them. + for (auto kv : memories) { + memory &m = kv.second; + f << stringf(" mem %s:\n", m.name.c_str()); + f << stringf(" data-type => UInt<%d>\n", m.width); + f << stringf(" depth => %d\n", m.size); + for (int i = 0; i < (int) m.read_ports.size(); i += 1) { + f << stringf(" reader => r%d\n", i); + } + for (int i = 0; i < (int) m.write_ports.size(); i += 1) { + f << stringf(" writer => w%d\n", i); + } + f << stringf(" read-latency => %d\n", m.read_latency); + f << stringf(" write-latency => %d\n", m.write_latency); + f << stringf(" read-under-write => undefined\n"); + } + f << stringf("\n"); + for (auto str : cell_exprs) f << str; @@ -527,50 +1070,65 @@ struct FirrtlWorker struct FirrtlBackend : public Backend { FirrtlBackend() : Backend("firrtl", "write design to a FIRRTL file") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); log(" write_firrtl [options] [filename]\n"); log("\n"); log("Write a FIRRTL netlist of the current design.\n"); + log("The following commands are executed by this command:\n"); + log(" pmuxtree\n"); log("\n"); } - virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) + void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { - size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) - { - // if (args[argidx] == "-aig") { - // aig_mode = true; - // continue; - // } - break; + size_t argidx = args.size(); // We aren't expecting any arguments. + + // If we weren't explicitly passed a filename, use the last argument (if it isn't a flag). + if (filename == "") { + if (argidx > 0 && args[argidx - 1][0] != '-') { + // extra_args and friends need to see this argument. + argidx -= 1; + filename = args[argidx]; + } } extra_args(f, filename, args, argidx); - log_header(design, "Executing FIRRTL backend.\n"); + if (!design->full_selection()) + log_cmd_error("This command only operates on fully selected designs!\n"); - Module *top = design->top_module(); + log_header(design, "Executing FIRRTL backend.\n"); + log_push(); - if (top == nullptr) - log_error("No top module found!\n"); + Pass::call(design, stringf("pmuxtree")); namecache.clear(); autoid_counter = 0; + // Get the top module, or a reasonable facsimile - we need something for the circuit name. + Module *top = design->top_module(); + Module *last = nullptr; + // Generate module and wire names. for (auto module : design->modules()) { make_id(module->name); + last = module; + if (top == nullptr && module->get_bool_attribute("\\top")) { + top = module; + } for (auto wire : module->wires()) if (wire->port_id) make_id(wire->name); } + if (top == nullptr) + top = last; + *f << stringf("circuit %s:\n", make_id(top->name)); for (auto module : design->modules()) { - FirrtlWorker worker(module, *f); + FirrtlWorker worker(module, *f, design); worker.run(); } diff --git a/backends/ilang/ilang_backend.cc b/backends/ilang/ilang_backend.cc index 1f7f12361..e06786220 100644 --- a/backends/ilang/ilang_backend.cc +++ b/backends/ilang/ilang_backend.cc @@ -40,8 +40,8 @@ void ILANG_BACKEND::dump_const(std::ostream &f, const RTLIL::Const &data, int wi for (int i = 0; i < width; i++) { log_assert(offset+i < (int)data.bits.size()); switch (data.bits[offset+i]) { - case RTLIL::S0: break; - case RTLIL::S1: val |= 1 << i; break; + case State::S0: break; + case State::S1: val |= 1 << i; break; default: val = -1; break; } } @@ -54,8 +54,8 @@ void ILANG_BACKEND::dump_const(std::ostream &f, const RTLIL::Const &data, int wi for (int i = offset+width-1; i >= offset; i--) { log_assert(i < (int)data.bits.size()); switch (data.bits[i]) { - case RTLIL::S0: f << stringf("0"); break; - case RTLIL::S1: f << stringf("1"); break; + case State::S0: f << stringf("0"); break; + case State::S1: f << stringf("1"); break; case RTLIL::Sx: f << stringf("x"); break; case RTLIL::Sz: f << stringf("z"); break; case RTLIL::Sa: f << stringf("-"); break; @@ -160,7 +160,10 @@ void ILANG_BACKEND::dump_cell(std::ostream &f, std::string indent, const RTLIL:: } f << stringf("%s" "cell %s %s\n", indent.c_str(), cell->type.c_str(), cell->name.c_str()); for (auto &it : cell->parameters) { - f << stringf("%s parameter%s %s ", indent.c_str(), (it.second.flags & RTLIL::CONST_FLAG_SIGNED) != 0 ? " signed" : "", it.first.c_str()); + f << stringf("%s parameter%s%s %s ", indent.c_str(), + (it.second.flags & RTLIL::CONST_FLAG_SIGNED) != 0 ? " signed" : "", + (it.second.flags & RTLIL::CONST_FLAG_REAL) != 0 ? " real" : "", + it.first.c_str()); dump_const(f, it.second); f << stringf("\n"); } @@ -201,10 +204,15 @@ 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) - f << stringf(", "); + f << stringf(" , "); dump_sigspec(f, (*it)->compare[i]); } f << stringf("\n"); @@ -382,7 +390,7 @@ PRIVATE_NAMESPACE_BEGIN struct IlangBackend : public Backend { IlangBackend() : Backend("ilang", "write design to ilang file") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -395,7 +403,7 @@ struct IlangBackend : public Backend { log(" only write selected parts of the design.\n"); log("\n"); } - virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) + void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { bool selected = false; @@ -422,7 +430,7 @@ struct IlangBackend : public Backend { struct DumpPass : public Pass { DumpPass() : Pass("dump", "print parts of the design in ilang format") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -445,7 +453,7 @@ struct DumpPass : public Pass { log(" like -outfile but append instead of overwrite\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { std::string filename; bool flag_m = false, flag_n = false, append = false; @@ -480,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/backends/intersynth/intersynth.cc b/backends/intersynth/intersynth.cc index 34cb52fb4..809a0fa09 100644 --- a/backends/intersynth/intersynth.cc +++ b/backends/intersynth/intersynth.cc @@ -46,7 +46,7 @@ static std::string netname(std::set<std::string> &conntypes_code, std::set<std:: struct IntersynthBackend : public Backend { IntersynthBackend() : Backend("intersynth", "write design to InterSynth netlist file") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -71,7 +71,7 @@ struct IntersynthBackend : public Backend { log("http://www.clifford.at/intersynth/\n"); log("\n"); } - virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) + void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing INTERSYNTH backend.\n"); log_push(); @@ -108,7 +108,7 @@ struct IntersynthBackend : public Backend { if (f.fail()) log_error("Can't open lib file `%s'.\n", filename.c_str()); RTLIL::Design *lib = new RTLIL::Design; - Frontend::frontend_call(lib, &f, filename, (filename.size() > 3 && filename.substr(filename.size()-3) == ".il") ? "ilang" : "verilog"); + Frontend::frontend_call(lib, &f, filename, (filename.size() > 3 && filename.compare(filename.size()-3, std::string::npos, ".il") == 0 ? "ilang" : "verilog")); libs.push_back(lib); } @@ -127,7 +127,7 @@ struct IntersynthBackend : public Backend { RTLIL::Module *module = module_it.second; SigMap sigmap(module); - if (module->get_bool_attribute("\\blackbox")) + if (module->get_blackbox_attribute()) continue; if (module->memories.size() == 0 && module->processes.size() == 0 && module->cells_.size() == 0) continue; @@ -183,7 +183,7 @@ struct IntersynthBackend : public Backend { if (param.second.bits.size() != 32) { node_code += stringf(" %s '", RTLIL::id2cstr(param.first)); for (int i = param.second.bits.size()-1; i >= 0; i--) - node_code += param.second.bits[i] == RTLIL::S1 ? "1" : "0"; + node_code += param.second.bits[i] == State::S1 ? "1" : "0"; } else node_code += stringf(" %s 0x%x", RTLIL::id2cstr(param.first), param.second.as_int()); } diff --git a/backends/json/json.cc b/backends/json/json.cc index d3b7077a2..107009ee4 100644 --- a/backends/json/json.cc +++ b/backends/json/json.cc @@ -83,18 +83,43 @@ struct JsonWriter return str + " ]"; } + void write_parameter_value(const Const &value) + { + if ((value.flags & RTLIL::ConstFlags::CONST_FLAG_STRING) != 0) { + string str = value.decode_string(); + int state = 0; + for (char c : str) { + if (state == 0) { + if (c == '0' || c == '1' || c == 'x' || c == 'z') + state = 0; + else if (c == ' ') + state = 1; + else + state = 2; + } else if (state == 1 && c != ' ') + state = 2; + } + if (state < 2) + str += " "; + f << get_string(str); + } else + if (GetSize(value) == 32 && value.is_fully_def()) { + if ((value.flags & RTLIL::ConstFlags::CONST_FLAG_SIGNED) != 0) + f << stringf("%d", value.as_int()); + else + f << stringf("%u", value.as_int()); + } else { + f << get_string(value.as_string()); + } + } + void write_parameters(const dict<IdString, Const> ¶meters, bool for_module=false) { bool first = true; for (auto ¶m : parameters) { f << stringf("%s\n", first ? "" : ","); f << stringf(" %s%s: ", for_module ? "" : " ", get_name(param.first).c_str()); - if ((param.second.flags & RTLIL::ConstFlags::CONST_FLAG_STRING) != 0) - f << get_string(param.second.decode_string()); - else if (GetSize(param.second.bits) > 32) - f << get_string(param.second.as_string()); - else - f << stringf("%d", param.second.as_int()); + write_parameter_value(param.second); first = false; } } @@ -124,6 +149,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; @@ -187,6 +216,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"); @@ -250,7 +283,7 @@ struct JsonWriter struct JsonBackend : public Backend { JsonBackend() : Backend("json", "write design to a JSON file") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -332,12 +365,13 @@ struct JsonBackend : public Backend { log("Module and cell ports and nets can be single bit wide or vectors of multiple\n"); log("bits. Each individual signal bit is assigned a unique integer. The <bit_vector>\n"); log("values referenced above are vectors of this integers. Signal bits that are\n"); - log("connected to a constant driver are denoted as string \"0\" or \"1\" instead of\n"); - log("a number.\n"); + log("connected to a constant driver are denoted as string \"0\", \"1\", \"x\", or\n"); + log("\"z\" instead of a number.\n"); log("\n"); - log("Numeric parameter and attribute values up to 32 bits are written as decimal\n"); - log("values. Numbers larger than that are written as string holding the binary\n"); - log("representation of the value.\n"); + log("Numeric 32-bit parameter and attribute values are written as decimal values.\n"); + log("Bit verctors of different sizes, or ones containing 'x' or 'z' bits, are written\n"); + log("as string holding the binary representation of the value. Strings are written\n"); + log("as strings, with an appended blank in cases of strings of the form /[01xz]* */.\n"); log("\n"); log("For example the following Verilog code:\n"); log("\n"); @@ -458,7 +492,7 @@ struct JsonBackend : public Backend { log("format. A program processing this format must ignore all unknown fields.\n"); log("\n"); } - virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) + void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { bool aig_mode = false; @@ -482,7 +516,7 @@ struct JsonBackend : public Backend { struct JsonPass : public Pass { JsonPass() : Pass("json", "write design in JSON format") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -499,7 +533,7 @@ struct JsonPass : public Pass { log("See 'help write_json' for a description of the JSON format used.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { std::string filename; bool aig_mode = false; @@ -523,6 +557,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/backends/protobuf/protobuf.cc b/backends/protobuf/protobuf.cc index 9a6fedee7..fff110bb0 100644 --- a/backends/protobuf/protobuf.cc +++ b/backends/protobuf/protobuf.cc @@ -48,7 +48,7 @@ struct ProtobufDesignSerializer ProtobufDesignSerializer(bool use_selection, bool aig_mode) : aig_mode_(aig_mode), use_selection_(use_selection) { } - + string get_name(IdString name) { return RTLIL::unescape_id(name); @@ -60,7 +60,7 @@ struct ProtobufDesignSerializer { for (auto ¶m : parameters) { std::string key = get_name(param.first); - + yosys::pb::Parameter pb_param; @@ -207,7 +207,7 @@ struct ProtobufDesignSerializer (*models)[aig.name] = pb_model; } } - + void serialize_design(yosys::pb::Design *pb, Design *design) { GOOGLE_PROTOBUF_VERIFY_VERSION; @@ -231,7 +231,7 @@ struct ProtobufDesignSerializer struct ProtobufBackend : public Backend { ProtobufBackend(): Backend("protobuf", "write design to a Protocol Buffer file") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -249,7 +249,7 @@ struct ProtobufBackend : public Backend { log("Yosys source code distribution.\n"); log("\n"); } - virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) + void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { bool aig_mode = false; bool text_mode = false; @@ -286,7 +286,7 @@ struct ProtobufBackend : public Backend { struct ProtobufPass : public Pass { ProtobufPass() : Pass("protobuf", "write design in Protobuf format") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -307,7 +307,7 @@ struct ProtobufPass : public Pass { log("Yosys source code distribution.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { std::string filename; bool aig_mode = false; @@ -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/backends/simplec/simplec.cc b/backends/simplec/simplec.cc index c9656caff..54dbb84af 100644 --- a/backends/simplec/simplec.cc +++ b/backends/simplec/simplec.cc @@ -472,7 +472,7 @@ struct SimplecWorker return; } - if (cell->type == "$_MUX_") + if (cell->type.in("$_MUX_", "$_NMUX_")) { SigBit a = sigmaps.at(work->module)(cell->getPort("\\A")); SigBit b = sigmaps.at(work->module)(cell->getPort("\\B")); @@ -484,7 +484,9 @@ struct SimplecWorker string s_expr = s.wire ? util_get_bit(work->prefix + cid(s.wire->name), s.wire->width, s.offset) : s.data ? "1" : "0"; // casts to bool are a workaround for CBMC bug (https://github.com/diffblue/cbmc/issues/933) - string expr = stringf("%s ? (bool)%s : (bool)%s", s_expr.c_str(), b_expr.c_str(), a_expr.c_str()); + string expr = stringf("%s ? %s(bool)%s : %s(bool)%s", s_expr.c_str(), + cell->type == "$_NMUX_" ? "!" : "", b_expr.c_str(), + cell->type == "$_NMUX_" ? "!" : "", a_expr.c_str()); log_assert(y.wire); funct_declarations.push_back(util_set_bit(work->prefix + cid(y.wire->name), y.wire->width, y.offset, expr) + @@ -742,13 +744,13 @@ struct SimplecWorker struct SimplecBackend : public Backend { SimplecBackend() : Backend("simplec", "convert design to simple C code") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); log(" write_simplec [options] [filename]\n"); log("\n"); - log("Write simple C code for simulating the design. The C code writen can be used to\n"); + log("Write simple C code for simulating the design. The C code written can be used to\n"); log("simulate the design in a C environment, but the purpose of this command is to\n"); log("generate code that works well with C-based formal verification.\n"); log("\n"); @@ -761,7 +763,7 @@ struct SimplecBackend : public Backend { log("THIS COMMAND IS UNDER CONSTRUCTION\n"); log("\n"); } - virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) + void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { reserved_cids.clear(); id2cid.clear(); diff --git a/backends/simplec/test00_uut.v b/backends/simplec/test00_uut.v index 744dbe9e3..92329a6f9 100644 --- a/backends/simplec/test00_uut.v +++ b/backends/simplec/test00_uut.v @@ -3,12 +3,12 @@ module test(input [31:0] a, b, c, output [31:0] x, y, z, w); unit_y unit_y_inst (.a(a), .b(b), .c(c), .y(y)); assign z = a ^ b ^ c, w = z; endmodule - + module unit_x(input [31:0] a, b, c, output [31:0] x); assign x = (a & b) | c; endmodule - + module unit_y(input [31:0] a, b, c, output [31:0] y); assign y = a & (b | c); endmodule - + diff --git a/backends/smt2/Makefile.inc b/backends/smt2/Makefile.inc index eacda2734..68394a909 100644 --- a/backends/smt2/Makefile.inc +++ b/backends/smt2/Makefile.inc @@ -3,14 +3,30 @@ OBJS += backends/smt2/smt2.o ifneq ($(CONFIG),mxe) ifneq ($(CONFIG),emcc) + +# MSYS targets support yosys-smtbmc, but require a launcher script +ifeq ($(CONFIG),$(filter $(CONFIG),msys2 msys2-64)) +TARGETS += yosys-smtbmc.exe yosys-smtbmc-script.py +# Needed to find the Python interpreter for yosys-smtbmc scripts. +# Override if necessary, it is only used for msys2 targets. +PYTHON := $(shell cygpath -w -m $(PREFIX)/bin/python3) + +yosys-smtbmc-script.py: backends/smt2/smtbmc.py + $(P) sed -e 's|##yosys-sys-path##|sys.path += [os.path.dirname(os.path.realpath(__file__)) + p for p in ["/share/python3", "/../share/yosys/python3"]]|;' \ + -e "s|#!/usr/bin/env python3|#!$(PYTHON)|" < $< > $@ + +yosys-smtbmc.exe: misc/launcher.c yosys-smtbmc-script.py + $(P) $(CXX) -DGUI=0 -O -s -o $@ $< +# Other targets +else TARGETS += yosys-smtbmc yosys-smtbmc: backends/smt2/smtbmc.py - $(P) sed 's|##yosys-sys-path##|sys.path += [os.path.dirname(__file__) + p for p in ["/share/python3", "/../share/yosys/python3"]]|;' < $< > $@.new + $(P) sed 's|##yosys-sys-path##|sys.path += [os.path.dirname(os.path.realpath(__file__)) + p for p in ["/share/python3", "/../share/yosys/python3"]]|;' < $< > $@.new $(Q) chmod +x $@.new $(Q) mv $@.new $@ +endif $(eval $(call add_share_file,share/python3,backends/smt2/smtio.py)) endif endif - diff --git a/backends/smt2/smt2.cc b/backends/smt2/smt2.cc index ca1ceacc7..081dcda99 100644 --- a/backends/smt2/smt2.cc +++ b/backends/smt2/smt2.cc @@ -416,6 +416,7 @@ struct Smt2Worker for (char ch : expr) { if (ch == 'A') processed_expr += get_bv(sig_a); else if (ch == 'B') processed_expr += get_bv(sig_b); + else if (ch == 'P') processed_expr += get_bv(cell->getPort("\\B")); else if (ch == 'L') processed_expr += is_signed ? "a" : "l"; else if (ch == 'U') processed_expr += is_signed ? "s" : "u"; else processed_expr += ch; @@ -509,6 +510,7 @@ struct Smt2Worker if (cell->type == "$_ANDNOT_") return export_gate(cell, "(and A (not B))"); if (cell->type == "$_ORNOT_") return export_gate(cell, "(or A (not B))"); if (cell->type == "$_MUX_") return export_gate(cell, "(ite S B A)"); + if (cell->type == "$_NMUX_") return export_gate(cell, "(not (ite S B A))"); if (cell->type == "$_AOI3_") return export_gate(cell, "(not (or (and A B) C))"); if (cell->type == "$_OAI3_") return export_gate(cell, "(not (and (or A B) C))"); if (cell->type == "$_AOI4_") return export_gate(cell, "(not (or (and A B) (and C D)))"); @@ -554,7 +556,9 @@ struct Smt2Worker if (cell->type.in("$shift", "$shiftx")) { if (cell->getParam("\\B_SIGNED").as_bool()) { - /* FIXME */ + return export_bvop(cell, stringf("(ite (bvsge P #b%0*d) " + "(bvlshr A B) (bvlshr A (bvneg B)))", + GetSize(cell->getPort("\\B")), 0), 's'); } else { return export_bvop(cell, "(bvlshr A B)", 's'); } @@ -597,7 +601,7 @@ struct Smt2Worker if (cell->type == "$logic_and") return export_reduce(cell, "(and (or A) (or B))", false); if (cell->type == "$logic_or") return export_reduce(cell, "(or A B)", false); - if (cell->type == "$mux" || cell->type == "$pmux") + if (cell->type.in("$mux", "$pmux")) { int width = GetSize(cell->getPort("\\Y")); std::string processed_expr = get_bv(cell->getPort("\\A")); @@ -885,8 +889,8 @@ struct Smt2Worker string name_a = get_bool(cell->getPort("\\A")); string name_en = get_bool(cell->getPort("\\EN")); - decls.push_back(stringf("; yosys-smt2-%s %d %s\n", cell->type.c_str() + 1, id, - cell->attributes.count("\\src") ? cell->attributes.at("\\src").decode_string().c_str() : get_id(cell))); + string infostr = (cell->name[0] == '$' && cell->attributes.count("\\src")) ? cell->attributes.at("\\src").decode_string() : get_id(cell); + decls.push_back(stringf("; yosys-smt2-%s %d %s\n", cell->type.c_str() + 1, id, infostr.c_str())); if (cell->type == "$cover") decls.push_back(stringf("(define-fun |%s_%c %d| ((state |%s_s|)) Bool (and %s %s)) ; %s\n", @@ -1101,20 +1105,27 @@ struct Smt2Worker break; Const initword = init_data.extract(i*width, width, State::Sx); + Const initmask = initword; bool gen_init_constr = false; - for (auto bit : initword.bits) - if (bit == State::S0 || bit == State::S1) + for (int k = 0; k < GetSize(initword); k++) { + if (initword[k] == State::S0 || initword[k] == State::S1) { gen_init_constr = true; + initmask[k] = State::S1; + } else { + initmask[k] = State::S0; + initword[k] = State::S0; + } + } if (gen_init_constr) { if (statebv) /* FIXME */; else - init_list.push_back(stringf("(= (select (|%s#%d#0| state) #b%s) #b%s) ; %s[%d]", + init_list.push_back(stringf("(= (bvand (select (|%s#%d#0| state) #b%s) #b%s) #b%s) ; %s[%d]", get_id(module), arrayid, Const(i, abits).as_string().c_str(), - initword.as_string().c_str(), get_id(cell), i)); + initmask.as_string().c_str(), initword.as_string().c_str(), get_id(cell), i)); } } } @@ -1251,7 +1262,7 @@ struct Smt2Worker struct Smt2Backend : public Backend { Smt2Backend() : Backend("smt2", "write design to SMT-LIBv2 file") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -1407,7 +1418,7 @@ struct Smt2Backend : public Backend { log("from non-zero to zero in the test design.\n"); log("\n"); } - virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) + void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { std::ifstream template_f; bool bvmode = true, memmode = true, wiresmode = false, verbose = false, statebv = false, statedt = false; @@ -1465,7 +1476,7 @@ struct Smt2Backend : public Backend { int indent = 0; while (indent < GetSize(line) && (line[indent] == ' ' || line[indent] == '\t')) indent++; - if (line.substr(indent, 2) == "%%") + if (line.compare(indent, 2, "%%") == 0) break; *f << line << std::endl; } @@ -1533,7 +1544,7 @@ struct Smt2Backend : public Backend { for (auto module : sorted_modules) { - if (module->get_bool_attribute("\\blackbox") || module->has_memories_warn() || module->has_processes_warn()) + if (module->get_blackbox_attribute() || module->has_memories_warn() || module->has_processes_warn()) continue; log("Creating SMT-LIBv2 representation of module %s.\n", log_id(module)); diff --git a/backends/smt2/smtbmc.py b/backends/smt2/smtbmc.py index 6af2a5ac1..445a42e0d 100644 --- a/backends/smt2/smtbmc.py +++ b/backends/smt2/smtbmc.py @@ -32,6 +32,7 @@ cexfile = None aimfile = None aiwfile = None aigheader = True +btorwitfile = None vlogtbfile = None vlogtbtop = None inconstr = list() @@ -86,12 +87,15 @@ yosys-smtbmc [options] <yosys_smt2_output> --aig <aim_filename>:<aiw_filename> like above, but for map files and witness files that do not - share a filename prefix (or use differen file extensions). + share a filename prefix (or use different file extensions). --aig-noheader the AIGER witness file does not include the status and properties lines. + --btorwit <btor_witness_filename> + read a BTOR witness. + --noinfo only run the core proof, do not collect and print any additional information (e.g. which assert failed) @@ -99,8 +103,8 @@ yosys-smtbmc [options] <yosys_smt2_output> --presat check if the design with assumptions but without assertions is SAT before checking if assertions are UNSAT. This will - detect if there are contradicting assumtions. In some cases - this will also help to "warmup" the solver, potentially + detect if there are contradicting assumptions. In some cases + this will also help to "warm up" the solver, potentially yielding a speedup. --final-only @@ -145,14 +149,14 @@ yosys-smtbmc [options] <yosys_smt2_output> --append <num_steps> add <num_steps> time steps at the end of the trace when creating a counter example (this additional time - steps will still be constrained by assumtions) + steps will still be constrained by assumptions) """ + so.helpmsg()) sys.exit(1) try: opts, args = getopt.getopt(sys.argv[1:], so.shortopts + "t:igcm:", so.longopts + - ["final-only", "assume-skipped=", "smtc=", "cex=", "aig=", "aig-noheader", "presat", + ["final-only", "assume-skipped=", "smtc=", "cex=", "aig=", "aig-noheader", "btorwit=", "presat", "dump-vcd=", "dump-vlogtb=", "vlogtb-top=", "dump-smtc=", "dump-all", "noinfo", "append=", "smtc-init", "smtc-top=", "noinit"]) except: @@ -189,6 +193,8 @@ for o, a in opts: aiwfile = a + ".aiw" elif o == "--aig-noheader": aigheader = False + elif o == "--btorwit": + btorwitfile = a elif o == "--dump-vcd": vcdfile = a elif o == "--dump-vlogtb": @@ -575,6 +581,103 @@ if aimfile is not None: num_steps = max(num_steps, step+1) step += 1 +if btorwitfile is not None: + with open(btorwitfile, "r") as f: + step = None + suffix = None + altsuffix = None + header_okay = False + + for line in f: + line = line.strip() + + if line == "sat": + header_okay = True + continue + + if not header_okay: + continue + + if line == "" or line[0] == "b" or line[0] == "j": + continue + + if line == ".": + break + + if line[0] == '#' or line[0] == '@': + step = int(line[1:]) + suffix = line + altsuffix = suffix + if suffix[0] == "@": + altsuffix = "#" + suffix[1:] + else: + altsuffix = "@" + suffix[1:] + continue + + line = line.split() + + if len(line) == 0: + continue + + if line[-1].endswith(suffix): + line[-1] = line[-1][0:len(line[-1]) - len(suffix)] + + if line[-1].endswith(altsuffix): + line[-1] = line[-1][0:len(line[-1]) - len(altsuffix)] + + if line[-1][0] == "$": + continue + + # BV assignments + if len(line) == 3 and line[1][0] != "[": + value = line[1] + name = line[2] + + path = smt.get_path(topmod, name) + + if not smt.net_exists(topmod, path): + continue + + width = smt.net_width(topmod, path) + + if width == 1: + assert value in ["0", "1"] + value = "true" if value == "1" else "false" + else: + value = "#b" + value + + smtexpr = "(= [%s] %s)" % (name, value) + constr_assumes[step].append((btorwitfile, smtexpr)) + + # Array assignments + if len(line) == 4 and line[1][0] == "[": + index = line[1] + value = line[2] + name = line[3] + + path = smt.get_path(topmod, name) + + if not smt.mem_exists(topmod, path): + continue + + meminfo = smt.mem_info(topmod, path) + + if meminfo[1] == 1: + assert value in ["0", "1"] + value = "true" if value == "1" else "false" + else: + value = "#b" + value + + assert index[0] == "[" + assert index[-1] == "]" + index = "#b" + index[1:-1] + + smtexpr = "(= (select [%s] %s) %s)" % (name, index, value) + constr_assumes[step].append((btorwitfile, smtexpr)) + + skip_steps = step + num_steps = step+1 + def write_vcd_trace(steps_start, steps_stop, index): filename = vcdfile.replace("%", index) print_msg("Writing trace to VCD file: %s" % (filename)) @@ -1259,7 +1362,11 @@ elif covermode: smt_assert_antecedent("(|%s_t| s%d s%d)" % (topmod, i-1, i)) smt_assert_consequent(get_constr_expr(constr_assumes, i)) print_msg("Re-solving with appended steps..") - assert smt_check_sat() == "sat" + if smt_check_sat() == "unsat": + print("%s Cannot appended steps without violating assumptions!" % smt.timestamp()) + found_failed_assert = True + retstatus = False + break reached_covers = smt.bv2bin(smt.get("(covers_%d s%d)" % (coveridx, step))) assert len(reached_covers) == len(cover_desc) @@ -1377,7 +1484,11 @@ else: # not tempind, covermode smt_assert_antecedent("(|%s_h| s%d)" % (topmod, i)) smt_assert_antecedent("(|%s_t| s%d s%d)" % (topmod, i-1, i)) smt_assert_consequent(get_constr_expr(constr_assumes, i)) - assert smt_check_sat() == "sat" + print_msg("Re-solving with appended steps..") + if smt_check_sat() == "unsat": + print("%s Cannot appended steps without violating assumptions!" % smt.timestamp()) + retstatus = False + break print_anyconsts(step) for i in range(step, last_check_step+1): print_failed_asserts(i) diff --git a/backends/smt2/smtio.py b/backends/smt2/smtio.py index 1a8d2484c..bac68ac70 100644 --- a/backends/smt2/smtio.py +++ b/backends/smt2/smtio.py @@ -17,7 +17,9 @@ # import sys, re, os, signal -import resource, subprocess +import subprocess +if os.name == "posix": + import resource from copy import deepcopy from select import select from time import time @@ -27,12 +29,25 @@ from threading import Thread # This is needed so that the recursive SMT2 S-expression parser # does not run out of stack frames when parsing large expressions -smtio_reclimit = 64 * 1024 -smtio_stacksize = 128 * 1024 * 1024 -if sys.getrecursionlimit() < smtio_reclimit: - sys.setrecursionlimit(smtio_reclimit) -if resource.getrlimit(resource.RLIMIT_STACK)[0] < smtio_stacksize: - resource.setrlimit(resource.RLIMIT_STACK, (smtio_stacksize, -1)) +if os.name == "posix": + smtio_reclimit = 64 * 1024 + if sys.getrecursionlimit() < smtio_reclimit: + sys.setrecursionlimit(smtio_reclimit) + + current_rlimit_stack = resource.getrlimit(resource.RLIMIT_STACK) + if current_rlimit_stack[0] != resource.RLIM_INFINITY: + smtio_stacksize = 128 * 1024 * 1024 + if os.uname().sysname == "Darwin": + # MacOS has rather conservative stack limits + smtio_stacksize = 16 * 1024 * 1024 + if current_rlimit_stack[1] != resource.RLIM_INFINITY: + smtio_stacksize = min(smtio_stacksize, current_rlimit_stack[1]) + if current_rlimit_stack[0] < smtio_stacksize: + try: + resource.setrlimit(resource.RLIMIT_STACK, (smtio_stacksize, current_rlimit_stack[1])) + except ValueError: + # couldn't get more stack, just run with what we have + pass # currently running solvers (so we can kill them) @@ -51,8 +66,9 @@ def force_shutdown(signum, frame): os.kill(p.pid, signal.SIGTERM) sys.exit(1) +if os.name == "posix": + signal.signal(signal.SIGHUP, force_shutdown) signal.signal(signal.SIGINT, force_shutdown) -signal.signal(signal.SIGHUP, force_shutdown) signal.signal(signal.SIGTERM, force_shutdown) def except_hook(exctype, value, traceback): @@ -154,19 +170,28 @@ class SmtIo: self.unroll = False if self.solver == "yices": - self.popen_vargs = ['yices-smt2', '--incremental'] + self.solver_opts + if self.noincr: + self.popen_vargs = ['yices-smt2'] + self.solver_opts + else: + self.popen_vargs = ['yices-smt2', '--incremental'] + self.solver_opts if self.solver == "z3": self.popen_vargs = ['z3', '-smt2', '-in'] + self.solver_opts if self.solver == "cvc4": - self.popen_vargs = ['cvc4', '--incremental', '--lang', 'smt2.6' if self.logic_dt else 'smt2'] + self.solver_opts + if self.noincr: + self.popen_vargs = ['cvc4', '--lang', 'smt2.6' if self.logic_dt else 'smt2'] + self.solver_opts + else: + self.popen_vargs = ['cvc4', '--incremental', '--lang', 'smt2.6' if self.logic_dt else 'smt2'] + self.solver_opts if self.solver == "mathsat": self.popen_vargs = ['mathsat'] + self.solver_opts if self.solver == "boolector": - self.popen_vargs = ['boolector', '--smt2', '-i'] + self.solver_opts + if self.noincr: + self.popen_vargs = ['boolector', '--smt2'] + self.solver_opts + else: + self.popen_vargs = ['boolector', '--smt2', '-i'] + self.solver_opts self.unroll = True if self.solver == "abc": @@ -763,7 +788,7 @@ class SmtIo: def get_path(self, mod, path): assert mod in self.modinfo - path = path.split(".") + path = path.replace("\\", "/").split(".") for i in range(len(path)-1): first = ".".join(path[0:i+1]) @@ -1002,6 +1027,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) @@ -1020,7 +1047,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": @@ -1053,4 +1083,3 @@ class MkVcd: print("b0 %s" % self.nets[path][0], file=self.f) else: print("b1 %s" % self.nets[path][0], file=self.f) - diff --git a/backends/smv/smv.cc b/backends/smv/smv.cc index 768969e6b..f755307bf 100644 --- a/backends/smv/smv.cc +++ b/backends/smv/smv.cc @@ -42,7 +42,7 @@ struct SmvWorker pool<Wire*> partial_assignment_wires; dict<SigBit, std::pair<const char*, int>> partial_assignment_bits; - vector<string> assignments, invarspecs; + vector<string> inputvars, vars, definitions, assignments, invarspecs; const char *cid() { @@ -61,7 +61,7 @@ struct SmvWorker { string name = stringf("_%s", id.c_str()); - if (name.substr(0, 2) == "_\\") + if (name.compare(0, 2, "_\\") == 0) name = "_" + name.substr(2); for (auto &c : name) { @@ -195,7 +195,7 @@ struct SmvWorker return rvalue(sig); const char *temp_id = cid(); - f << stringf(" %s : unsigned word[%d]; -- %s\n", temp_id, GetSize(sig), log_signal(sig)); +// f << stringf(" %s : unsigned word[%d]; -- %s\n", temp_id, GetSize(sig), log_signal(sig)); int offset = 0; for (auto bit : sig) { @@ -210,14 +210,14 @@ struct SmvWorker void run() { f << stringf("MODULE %s\n", cid(module->name)); - f << stringf(" VAR\n"); for (auto wire : module->wires()) { if (SigSpec(wire) != sigmap(wire)) partial_assignment_wires.insert(wire); - f << stringf(" %s : unsigned word[%d]; -- %s\n", cid(wire->name), wire->width, log_id(wire)); + if (wire->port_input) + inputvars.push_back(stringf("%s : unsigned word[%d]; -- %s", cid(wire->name), wire->width, log_id(wire))); if (wire->attributes.count("\\init")) assignments.push_back(stringf("init(%s) := %s;", lvalue(wire), rvalue(wire->attributes.at("\\init")))); @@ -275,8 +275,8 @@ struct SmvWorker const char *b_shr = rvalue_u(sig_b); const char *b_shl = cid(); - f << stringf(" %s : unsigned word[%d]; -- neg(%s)\n", b_shl, GetSize(sig_b), log_signal(sig_b)); - assignments.push_back(stringf("%s := unsigned(-%s);", b_shl, rvalue_s(sig_b))); +// f << stringf(" %s : unsigned word[%d]; -- neg(%s)\n", b_shl, GetSize(sig_b), log_signal(sig_b)); + definitions.push_back(stringf("%s := unsigned(-%s);", b_shl, rvalue_s(sig_b))); string expr_shl = stringf("resize(%s << %s[%d:0], %d)", expr_a.c_str(), b_shl, shift_b_width-1, width_y); string expr_shr = stringf("resize(%s >> %s[%d:0], %d)", expr_a.c_str(), b_shr, shift_b_width-1, width_y); @@ -303,7 +303,7 @@ struct SmvWorker GetSize(sig_b)-shift_b_width, width_y, expr.c_str()); } - assignments.push_back(stringf("%s := %s;", lvalue(cell->getPort("\\Y")), expr.c_str())); + definitions.push_back(stringf("%s := %s;", lvalue(cell->getPort("\\Y")), expr.c_str())); continue; } @@ -319,12 +319,12 @@ struct SmvWorker if (cell->getParam("\\A_SIGNED").as_bool()) { - assignments.push_back(stringf("%s := unsigned(%s%s);", lvalue(cell->getPort("\\Y")), + definitions.push_back(stringf("%s := unsigned(%s%s);", lvalue(cell->getPort("\\Y")), op.c_str(), rvalue_s(cell->getPort("\\A"), width))); } else { - assignments.push_back(stringf("%s := %s%s;", lvalue(cell->getPort("\\Y")), + definitions.push_back(stringf("%s := %s%s;", lvalue(cell->getPort("\\Y")), op.c_str(), rvalue_u(cell->getPort("\\A"), width))); } @@ -346,12 +346,12 @@ struct SmvWorker if (cell->getParam("\\A_SIGNED").as_bool()) { - assignments.push_back(stringf("%s := unsigned(%s %s %s);", lvalue(cell->getPort("\\Y")), + definitions.push_back(stringf("%s := unsigned(%s %s %s);", lvalue(cell->getPort("\\Y")), rvalue_s(cell->getPort("\\A"), width), op.c_str(), rvalue_s(cell->getPort("\\B"), width))); } else { - assignments.push_back(stringf("%s := %s %s %s;", lvalue(cell->getPort("\\Y")), + definitions.push_back(stringf("%s := %s %s %s;", lvalue(cell->getPort("\\Y")), rvalue_u(cell->getPort("\\A"), width), op.c_str(), rvalue_u(cell->getPort("\\B"), width))); } @@ -370,12 +370,12 @@ struct SmvWorker if (cell->getParam("\\A_SIGNED").as_bool()) { - assignments.push_back(stringf("%s := resize(unsigned(%s %s %s), %d);", lvalue(cell->getPort("\\Y")), + definitions.push_back(stringf("%s := resize(unsigned(%s %s %s), %d);", lvalue(cell->getPort("\\Y")), rvalue_s(cell->getPort("\\A"), width), op.c_str(), rvalue_s(cell->getPort("\\B"), width), width_y)); } else { - assignments.push_back(stringf("%s := resize(%s %s %s, %d);", lvalue(cell->getPort("\\Y")), + definitions.push_back(stringf("%s := resize(%s %s %s, %d);", lvalue(cell->getPort("\\Y")), rvalue_u(cell->getPort("\\A"), width), op.c_str(), rvalue_u(cell->getPort("\\B"), width), width_y)); } @@ -407,7 +407,7 @@ struct SmvWorker expr_b = stringf("resize(%s, %d)", rvalue(cell->getPort("\\B")), width); } - assignments.push_back(stringf("%s := resize(word1(%s %s %s), %d);", lvalue(cell->getPort("\\Y")), + definitions.push_back(stringf("%s := resize(word1(%s %s %s), %d);", lvalue(cell->getPort("\\Y")), expr_a.c_str(), op.c_str(), expr_b.c_str(), GetSize(cell->getPort("\\Y")))); continue; @@ -425,7 +425,7 @@ struct SmvWorker if (cell->type == "$reduce_or") expr = stringf("%s != 0ub%d_0", expr_a, width_a); if (cell->type == "$reduce_bool") expr = stringf("%s != 0ub%d_0", expr_a, width_a); - assignments.push_back(stringf("%s := resize(word1(%s), %d);", expr_y, expr.c_str(), width_y)); + definitions.push_back(stringf("%s := resize(word1(%s), %d);", expr_y, expr.c_str(), width_y)); continue; } @@ -444,7 +444,7 @@ struct SmvWorker if (cell->type == "$reduce_xnor") expr = "!(" + expr + ")"; - assignments.push_back(stringf("%s := resize(%s, %d);", expr_y, expr.c_str(), width_y)); + definitions.push_back(stringf("%s := resize(%s, %d);", expr_y, expr.c_str(), width_y)); continue; } @@ -462,7 +462,7 @@ struct SmvWorker if (cell->type == "$logic_and") expr = expr_a + " & " + expr_b; if (cell->type == "$logic_or") expr = expr_a + " | " + expr_b; - assignments.push_back(stringf("%s := resize(word1(%s), %d);", expr_y, expr.c_str(), width_y)); + definitions.push_back(stringf("%s := resize(word1(%s), %d);", expr_y, expr.c_str(), width_y)); continue; } @@ -474,7 +474,7 @@ struct SmvWorker string expr_a = stringf("(%s = 0ub%d_0)", rvalue(cell->getPort("\\A")), width_a); const char *expr_y = lvalue(cell->getPort("\\Y")); - assignments.push_back(stringf("%s := resize(word1(%s), %d);", expr_y, expr_a.c_str(), width_y)); + definitions.push_back(stringf("%s := resize(word1(%s), %d);", expr_y, expr_a.c_str(), width_y)); continue; } @@ -490,12 +490,13 @@ struct SmvWorker expr += stringf("bool(%s) ? %s : ", rvalue(sig_s[i]), rvalue(sig_b.extract(i*width, width))); expr += rvalue(sig_a); - assignments.push_back(stringf("%s := %s;", lvalue(cell->getPort("\\Y")), expr.c_str())); + definitions.push_back(stringf("%s := %s;", lvalue(cell->getPort("\\Y")), expr.c_str())); continue; } if (cell->type == "$dff") { + vars.push_back(stringf("%s : unsigned word[%d]; -- %s", lvalue(cell->getPort("\\Q")), GetSize(cell->getPort("\\Q")), log_signal(cell->getPort("\\Q")))); assignments.push_back(stringf("next(%s) := %s;", lvalue(cell->getPort("\\Q")), rvalue(cell->getPort("\\D")))); continue; } @@ -503,7 +504,7 @@ struct SmvWorker if (cell->type.in("$_BUF_", "$_NOT_")) { string op = cell->type == "$_NOT_" ? "!" : ""; - assignments.push_back(stringf("%s := %s%s;", lvalue(cell->getPort("\\Y")), op.c_str(), rvalue(cell->getPort("\\A")))); + definitions.push_back(stringf("%s := %s%s;", lvalue(cell->getPort("\\Y")), op.c_str(), rvalue(cell->getPort("\\A")))); continue; } @@ -517,49 +518,56 @@ struct SmvWorker if (cell->type.in("$_XNOR_")) op = "xnor"; if (cell->type.in("$_ANDNOT_", "$_ORNOT_")) - assignments.push_back(stringf("%s := %s %s (!%s);", lvalue(cell->getPort("\\Y")), + definitions.push_back(stringf("%s := %s %s (!%s);", lvalue(cell->getPort("\\Y")), rvalue(cell->getPort("\\A")), op.c_str(), rvalue(cell->getPort("\\B")))); else if (cell->type.in("$_NAND_", "$_NOR_")) - assignments.push_back(stringf("%s := !(%s %s %s);", lvalue(cell->getPort("\\Y")), + definitions.push_back(stringf("%s := !(%s %s %s);", lvalue(cell->getPort("\\Y")), rvalue(cell->getPort("\\A")), op.c_str(), rvalue(cell->getPort("\\B")))); else - assignments.push_back(stringf("%s := %s %s %s;", lvalue(cell->getPort("\\Y")), + definitions.push_back(stringf("%s := %s %s %s;", lvalue(cell->getPort("\\Y")), rvalue(cell->getPort("\\A")), op.c_str(), rvalue(cell->getPort("\\B")))); continue; } if (cell->type == "$_MUX_") { - assignments.push_back(stringf("%s := bool(%s) ? %s : %s;", lvalue(cell->getPort("\\Y")), + definitions.push_back(stringf("%s := bool(%s) ? %s : %s;", lvalue(cell->getPort("\\Y")), + rvalue(cell->getPort("\\S")), rvalue(cell->getPort("\\B")), rvalue(cell->getPort("\\A")))); + continue; + } + + if (cell->type == "$_NMUX_") + { + definitions.push_back(stringf("%s := !(bool(%s) ? %s : %s);", lvalue(cell->getPort("\\Y")), rvalue(cell->getPort("\\S")), rvalue(cell->getPort("\\B")), rvalue(cell->getPort("\\A")))); continue; } if (cell->type == "$_AOI3_") { - assignments.push_back(stringf("%s := !((%s & %s) | %s);", lvalue(cell->getPort("\\Y")), + definitions.push_back(stringf("%s := !((%s & %s) | %s);", lvalue(cell->getPort("\\Y")), rvalue(cell->getPort("\\A")), rvalue(cell->getPort("\\B")), rvalue(cell->getPort("\\C")))); continue; } if (cell->type == "$_OAI3_") { - assignments.push_back(stringf("%s := !((%s | %s) & %s);", lvalue(cell->getPort("\\Y")), + definitions.push_back(stringf("%s := !((%s | %s) & %s);", lvalue(cell->getPort("\\Y")), rvalue(cell->getPort("\\A")), rvalue(cell->getPort("\\B")), rvalue(cell->getPort("\\C")))); continue; } if (cell->type == "$_AOI4_") { - assignments.push_back(stringf("%s := !((%s & %s) | (%s & %s));", lvalue(cell->getPort("\\Y")), + definitions.push_back(stringf("%s := !((%s & %s) | (%s & %s));", lvalue(cell->getPort("\\Y")), rvalue(cell->getPort("\\A")), rvalue(cell->getPort("\\B")), rvalue(cell->getPort("\\C")), rvalue(cell->getPort("\\D")))); continue; } if (cell->type == "$_OAI4_") { - assignments.push_back(stringf("%s := !((%s | %s) & (%s | %s));", lvalue(cell->getPort("\\Y")), + definitions.push_back(stringf("%s := !((%s | %s) & (%s | %s));", lvalue(cell->getPort("\\Y")), rvalue(cell->getPort("\\A")), rvalue(cell->getPort("\\B")), rvalue(cell->getPort("\\C")), rvalue(cell->getPort("\\D")))); continue; } @@ -567,13 +575,13 @@ struct SmvWorker if (cell->type[0] == '$') log_error("Found currently unsupported cell type %s (%s.%s).\n", log_id(cell->type), log_id(module), log_id(cell)); - f << stringf(" %s : %s;\n", cid(cell->name), cid(cell->type)); +// f << stringf(" %s : %s;\n", cid(cell->name), cid(cell->type)); for (auto &conn : cell->connections()) if (cell->output(conn.first)) - assignments.push_back(stringf("%s := %s.%s;", lvalue(conn.second), cid(cell->name), cid(conn.first))); + definitions.push_back(stringf("%s := %s.%s;", lvalue(conn.second), cid(cell->name), cid(conn.first))); else - assignments.push_back(stringf("%s.%s := %s;", cid(cell->name), cid(conn.first), rvalue(conn.second))); + definitions.push_back(stringf("%s.%s := %s;", cid(cell->name), cid(conn.first), rvalue(conn.second))); } for (Wire *wire : partial_assignment_wires) @@ -657,7 +665,25 @@ struct SmvWorker } } - assignments.push_back(stringf("%s := %s;", cid(wire->name), expr.c_str())); + definitions.push_back(stringf("%s := %s;", cid(wire->name), expr.c_str())); + } + + if (!inputvars.empty()) { + f << stringf(" IVAR\n"); + for (const string &line : inputvars) + f << stringf(" %s\n", line.c_str()); + } + + if (!vars.empty()) { + f << stringf(" VAR\n"); + for (const string &line : vars) + f << stringf(" %s\n", line.c_str()); + } + + if (!definitions.empty()) { + f << stringf(" DEFINE\n"); + for (const string &line : definitions) + f << stringf(" %s\n", line.c_str()); } if (!assignments.empty()) { @@ -675,7 +701,7 @@ struct SmvWorker struct SmvBackend : public Backend { SmvBackend() : Backend("smv", "write design to SMV file") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -693,7 +719,7 @@ struct SmvBackend : public Backend { log("THIS COMMAND IS UNDER CONSTRUCTION\n"); log("\n"); } - virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) + void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { std::ifstream template_f; bool verbose = false; @@ -720,7 +746,7 @@ struct SmvBackend : public Backend { pool<Module*> modules; for (auto module : design->modules()) - if (!module->get_bool_attribute("\\blackbox") && !module->has_memories_warn() && !module->has_processes_warn()) + if (!module->get_blackbox_attribute() && !module->has_memories_warn() && !module->has_processes_warn()) modules.insert(module); if (template_f.is_open()) diff --git a/backends/spice/spice.cc b/backends/spice/spice.cc index 4101cbf98..6738a4bbd 100644 --- a/backends/spice/spice.cc +++ b/backends/spice/spice.cc @@ -132,7 +132,7 @@ static void print_spice_module(std::ostream &f, RTLIL::Module *module, RTLIL::De struct SpiceBackend : public Backend { SpiceBackend() : Backend("spice", "write design to SPICE netlist file") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -161,7 +161,7 @@ struct SpiceBackend : public Backend { log(" set the specified module as design top module\n"); log("\n"); } - virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) + void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { std::string top_module_name; RTLIL::Module *top_module = NULL; @@ -212,7 +212,7 @@ struct SpiceBackend : public Backend { for (auto module_it : design->modules_) { RTLIL::Module *module = module_it.second; - if (module->get_bool_attribute("\\blackbox")) + if (module->get_blackbox_attribute()) continue; if (module->processes.size() != 0) diff --git a/backends/table/table.cc b/backends/table/table.cc index 27b7edfff..796f18059 100644 --- a/backends/table/table.cc +++ b/backends/table/table.cc @@ -29,7 +29,7 @@ PRIVATE_NAMESPACE_BEGIN struct TableBackend : public Backend { TableBackend() : Backend("table", "write design as connectivity table") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -48,7 +48,7 @@ struct TableBackend : public Backend { log("module inputs and outputs are output using cell type and port '-' and with\n"); log("'pi' (primary input) or 'po' (primary output) or 'pio' as direction.\n"); } - virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) + void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing TABLE backend.\n"); @@ -67,7 +67,7 @@ struct TableBackend : public Backend { for (auto module : design->modules()) { - if (module->get_bool_attribute("\\blackbox")) + if (module->get_blackbox_attribute()) continue; SigMap sigmap(module); @@ -109,7 +109,7 @@ struct TableBackend : public Backend { else if (cell->output(conn.first)) *f << "out" << "\t"; else - *f << "unkown" << "\t"; + *f << "unknown" << "\t"; *f << log_signal(sigmap(conn.second)) << "\n"; } diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index b50dc12af..7b1db4776 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -33,7 +33,7 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN -bool verbose, norename, noattr, attr2comment, noexpr, nodec, nohex, nostr, defparam, decimal; +bool verbose, norename, noattr, attr2comment, noexpr, nodec, nohex, nostr, defparam, decimal, siminit; int auto_name_counter, auto_name_offset, auto_name_digits; std::map<RTLIL::IdString, int> auto_name_map; std::set<RTLIL::IdString> reg_wires, reg_ct; @@ -126,6 +126,33 @@ std::string id(RTLIL::IdString internal_id, bool may_rename = true) break; } + const pool<string> keywords = { + // IEEE 1800-2017 Annex B + "accept_on", "alias", "always", "always_comb", "always_ff", "always_latch", "and", "assert", "assign", "assume", "automatic", "before", + "begin", "bind", "bins", "binsof", "bit", "break", "buf", "bufif0", "bufif1", "byte", "case", "casex", "casez", "cell", "chandle", + "checker", "class", "clocking", "cmos", "config", "const", "constraint", "context", "continue", "cover", "covergroup", "coverpoint", + "cross", "deassign", "default", "defparam", "design", "disable", "dist", "do", "edge", "else", "end", "endcase", "endchecker", + "endclass", "endclocking", "endconfig", "endfunction", "endgenerate", "endgroup", "endinterface", "endmodule", "endpackage", + "endprimitive", "endprogram", "endproperty", "endsequence", "endspecify", "endtable", "endtask", "enum", "event", "eventually", + "expect", "export", "extends", "extern", "final", "first_match", "for", "force", "foreach", "forever", "fork", "forkjoin", "function", + "generate", "genvar", "global", "highz0", "highz1", "if", "iff", "ifnone", "ignore_bins", "illegal_bins", "implements", "implies", + "import", "incdir", "include", "initial", "inout", "input", "inside", "instance", "int", "integer", "interconnect", "interface", + "intersect", "join", "join_any", "join_none", "large", "let", "liblist", "library", "local", "localparam", "logic", "longint", + "macromodule", "matches", "medium", "modport", "module", "nand", "negedge", "nettype", "new", "nexttime", "nmos", "nor", + "noshowcancelled", "not", "notif0", "notif1", "null", "or", "output", "package", "packed", "parameter", "pmos", "posedge", "primitive", + "priority", "program", "property", "protected", "pull0", "pull1", "pulldown", "pullup", "pulsestyle_ondetect", "pulsestyle_onevent", + "pure", "rand", "randc", "randcase", "randsequence", "rcmos", "real", "realtime", "ref", "reg", "reject_on", "release", "repeat", + "restrict", "return", "rnmos", "rpmos", "rtran", "rtranif0", "rtranif1", "s_always", "s_eventually", "s_nexttime", "s_until", + "s_until_with", "scalared", "sequence", "shortint", "shortreal", "showcancelled", "signed", "small", "soft", "solve", "specify", + "specparam", "static", "string", "strong", "strong0", "strong1", "struct", "super", "supply0", "supply1", "sync_accept_on", + "sync_reject_on", "table", "tagged", "task", "this", "throughout", "time", "timeprecision", "timeunit", "tran", "tranif0", "tranif1", + "tri", "tri0", "tri1", "triand", "trior", "trireg", "type", "typedef", "union", "unique", "unique0", "unsigned", "until", "until_with", + "untyped", "use", "uwire", "var", "vectored", "virtual", "void", "wait", "wait_order", "wand", "weak", "weak0", "weak1", "while", + "wildcard", "wire", "with", "within", "wor", "xnor", "xor", + }; + if (keywords.count(str)) + do_escape = true; + if (do_escape) return "\\" + std::string(str) + " "; return std::string(str); @@ -156,10 +183,16 @@ bool is_reg_wire(RTLIL::SigSpec sig, std::string ®_name) return true; } -void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int offset = 0, bool no_decimal = false, bool set_signed = false, bool escape_comment = false) +void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int offset = 0, bool no_decimal = false, bool escape_comment = false) { + bool set_signed = (data.flags & RTLIL::CONST_FLAG_SIGNED) != 0; if (width < 0) width = data.bits.size() - offset; + if (width == 0) { + // See IEEE 1364-2005 Clause 5.1.14. + f << "{0{1'b0}}"; + return; + } if (nostr) goto dump_hex; if ((data.flags & RTLIL::CONST_FLAG_STRING) == 0 || width != (int)data.bits.size()) { @@ -167,9 +200,9 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o int32_t val = 0; for (int i = offset+width-1; i >= offset; i--) { log_assert(i < (int)data.bits.size()); - if (data.bits[i] != RTLIL::S0 && data.bits[i] != RTLIL::S1) + if (data.bits[i] != State::S0 && data.bits[i] != State::S1) goto dump_hex; - if (data.bits[i] == RTLIL::S1) + if (data.bits[i] == State::S1) val |= 1 << (i - offset); } if (decimal) @@ -186,11 +219,11 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o for (int i = offset; i < offset+width; i++) { log_assert(i < (int)data.bits.size()); switch (data.bits[i]) { - case RTLIL::S0: bin_digits.push_back('0'); break; - case RTLIL::S1: bin_digits.push_back('1'); break; + case State::S0: bin_digits.push_back('0'); break; + case State::S1: bin_digits.push_back('1'); break; case RTLIL::Sx: bin_digits.push_back('x'); break; case RTLIL::Sz: bin_digits.push_back('z'); break; - case RTLIL::Sa: bin_digits.push_back('z'); break; + case RTLIL::Sa: bin_digits.push_back('?'); break; case RTLIL::Sm: log_error("Found marker state in final netlist."); } } @@ -219,6 +252,12 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o hex_digits.push_back('z'); continue; } + if (bit_3 == '?' || bit_2 == '?' || bit_1 == '?' || bit_0 == '?') { + if (bit_3 != '?' || bit_2 != '?' || bit_1 != '?' || bit_0 != '?') + goto dump_bin; + hex_digits.push_back('?'); + continue; + } int val = 8*(bit_3 - '0') + 4*(bit_2 - '0') + 2*(bit_1 - '0') + (bit_0 - '0'); hex_digits.push_back(val < 10 ? '0' + val : 'a' + val - 10); } @@ -234,17 +273,18 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o for (int i = offset+width-1; i >= offset; i--) { log_assert(i < (int)data.bits.size()); switch (data.bits[i]) { - case RTLIL::S0: f << stringf("0"); break; - case RTLIL::S1: f << stringf("1"); break; + case State::S0: f << stringf("0"); break; + case State::S1: f << stringf("1"); break; case RTLIL::Sx: f << stringf("x"); break; case RTLIL::Sz: f << stringf("z"); break; - case RTLIL::Sa: f << stringf("z"); break; + case RTLIL::Sa: f << stringf("?"); break; case RTLIL::Sm: log_error("Found marker state in final netlist."); } } } } else { - f << stringf("\""); + if ((data.flags & RTLIL::CONST_FLAG_REAL) == 0) + f << stringf("\""); std::string str = data.decode_string(); for (size_t i = 0; i < str.size(); i++) { if (str[i] == '\n') @@ -262,7 +302,8 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o else f << str[i]; } - f << stringf("\""); + if ((data.flags & RTLIL::CONST_FLAG_REAL) == 0) + f << stringf("\""); } } @@ -313,6 +354,10 @@ void dump_sigchunk(std::ostream &f, const RTLIL::SigChunk &chunk, bool no_decima void dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig) { + if (GetSize(sig) == 0) { + f << "\"\""; + return; + } if (sig.is_chunk()) { dump_sigchunk(f, sig.as_chunk()); } else { @@ -326,20 +371,22 @@ void dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig) } } -void dump_attributes(std::ostream &f, std::string indent, dict<RTLIL::IdString, RTLIL::Const> &attributes, char term = '\n', bool modattr = false) +void dump_attributes(std::ostream &f, std::string indent, dict<RTLIL::IdString, RTLIL::Const> &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))) + if (modattr && (it->second == State::S0 || it->second == Const(0))) f << stringf(" 0 "); - else if (modattr && (it->second == Const(1, 1) || it->second == Const(1))) + else if (modattr && (it->second == State::S1 || it->second == Const(1))) f << stringf(" 1 "); else - dump_const(f, it->second, -1, 0, false, 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); } } @@ -388,7 +435,7 @@ void dump_wire(std::ostream &f, std::string indent, RTLIL::Wire *wire) void dump_memory(std::ostream &f, std::string indent, RTLIL::Memory *memory) { dump_attributes(f, indent, memory->attributes); - f << stringf("%s" "reg [%d:0] %s [%d:0];\n", indent.c_str(), memory->width-1, id(memory->name).c_str(), memory->size-1); + f << stringf("%s" "reg [%d:0] %s [%d:%d];\n", indent.c_str(), memory->width-1, id(memory->name).c_str(), memory->size+memory->start_offset-1, memory->start_offset); } void dump_cell_expr_port(std::ostream &f, RTLIL::Cell *cell, std::string port, bool gen_signed = true) @@ -511,6 +558,20 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) return true; } + if (cell->type == "$_NMUX_") { + f << stringf("%s" "assign ", indent.c_str()); + dump_sigspec(f, cell->getPort("\\Y")); + f << stringf(" = !("); + dump_cell_expr_port(f, cell, "S", false); + f << stringf(" ? "); + dump_attributes(f, "", cell->attributes, ' '); + dump_cell_expr_port(f, cell, "B", false); + f << stringf(" : "); + dump_cell_expr_port(f, cell, "A", false); + f << stringf(");\n"); + return true; + } + if (cell->type.in("$_AOI3_", "$_OAI3_")) { f << stringf("%s" "assign ", indent.c_str()); dump_sigspec(f, cell->getPort("\\Y")); @@ -543,7 +604,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) return true; } - if (cell->type.substr(0, 6) == "$_DFF_") + if (cell->type.begins_with("$_DFF_")) { std::string reg_name = cellname(cell); bool out_is_reg_wire = is_reg_wire(cell->getPort("\\Q"), reg_name); @@ -584,7 +645,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) return true; } - if (cell->type.substr(0, 8) == "$_DFFSR_") + if (cell->type.begins_with("$_DFFSR_")) { char pol_c = cell->type[8], pol_s = cell->type[9], pol_r = cell->type[10]; @@ -678,13 +739,45 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) #undef HANDLE_UNIOP #undef HANDLE_BINOP - if (cell->type == "$shiftx") + if (cell->type == "$shift") { f << stringf("%s" "assign ", indent.c_str()); dump_sigspec(f, cell->getPort("\\Y")); f << stringf(" = "); + if (cell->getParam("\\B_SIGNED").as_bool()) + { + f << stringf("$signed("); + dump_sigspec(f, cell->getPort("\\B")); + f << stringf(")"); + f << stringf(" < 0 ? "); + dump_sigspec(f, cell->getPort("\\A")); + f << stringf(" << - "); + dump_sigspec(f, cell->getPort("\\B")); + f << stringf(" : "); + dump_sigspec(f, cell->getPort("\\A")); + f << stringf(" >> "); + dump_sigspec(f, cell->getPort("\\B")); + } + else + { + dump_sigspec(f, cell->getPort("\\A")); + f << stringf(" >> "); + dump_sigspec(f, cell->getPort("\\B")); + } + f << stringf(";\n"); + return true; + } + + if (cell->type == "$shiftx") + { + std::string temp_id = next_auto_id(); + f << stringf("%s" "wire [%d:0] %s = ", indent.c_str(), GetSize(cell->getPort("\\A"))-1, temp_id.c_str()); dump_sigspec(f, cell->getPort("\\A")); - f << stringf("["); + f << stringf(";\n"); + + f << stringf("%s" "assign ", indent.c_str()); + dump_sigspec(f, cell->getPort("\\Y")); + f << stringf(" = %s[", temp_id.c_str()); if (cell->getParam("\\B_SIGNED").as_bool()) f << stringf("$signed("); dump_sigspec(f, cell->getPort("\\B")); @@ -710,7 +803,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) return true; } - if (cell->type == "$pmux" || cell->type == "$pmux_safe") + if (cell->type == "$pmux") { int width = cell->parameters["\\WIDTH"].as_int(); int s_width = cell->getPort("\\S").size(); @@ -722,18 +815,17 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) f << stringf("%s" " input [%d:0] s;\n", indent.c_str(), s_width-1); dump_attributes(f, indent + " ", cell->attributes); - if (cell->type != "$pmux_safe" && !noattr) + if (!noattr) f << stringf("%s" " (* parallel_case *)\n", indent.c_str()); f << stringf("%s" " casez (s)", indent.c_str()); - if (cell->type != "$pmux_safe") - f << stringf(noattr ? " // synopsys parallel_case\n" : "\n"); + f << stringf(noattr ? " // synopsys parallel_case\n" : "\n"); for (int i = 0; i < s_width; i++) { f << stringf("%s" " %d'b", indent.c_str(), s_width); for (int j = s_width-1; j >= 0; j--) - f << stringf("%c", j == i ? '1' : cell->type == "$pmux_safe" ? '0' : '?'); + f << stringf("%c", j == i ? '1' : '?'); f << stringf(":\n"); f << stringf("%s" " %s = b[%d:%d];\n", indent.c_str(), func_name.c_str(), (i+1)*width-1, i*width); @@ -757,6 +849,18 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) return true; } + if (cell->type == "$tribuf") + { + f << stringf("%s" "assign ", indent.c_str()); + dump_sigspec(f, cell->getPort("\\Y")); + f << stringf(" = "); + dump_sigspec(f, cell->getPort("\\EN")); + f << stringf(" ? "); + dump_sigspec(f, cell->getPort("\\A")); + f << stringf(" : %d'bz;\n", cell->parameters.at("\\WIDTH").as_int()); + return true; + } + if (cell->type == "$slice") { f << stringf("%s" "assign ", indent.c_str()); @@ -779,6 +883,19 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) return true; } + if (cell->type == "$lut") + { + f << stringf("%s" "assign ", indent.c_str()); + dump_sigspec(f, cell->getPort("\\Y")); + f << stringf(" = "); + dump_const(f, cell->parameters.at("\\LUT")); + f << stringf(" >> "); + dump_attributes(f, "", cell->attributes, ' '); + dump_sigspec(f, cell->getPort("\\A")); + f << stringf(";\n"); + return true; + } + if (cell->type == "$dffsr") { SigSpec sig_clk = cell->getPort("\\CLK"); @@ -832,7 +949,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) return true; } - if (cell->type == "$dff" || cell->type == "$adff" || cell->type == "$dffe") + if (cell->type.in("$dff", "$adff", "$dffe")) { RTLIL::SigSpec sig_clk, sig_arst, sig_en, val_arst; bool pol_clk, pol_arst = false, pol_en = false; @@ -939,6 +1056,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) std::string mem_id = id(cell->parameters["\\MEMID"].decode_string()); int abits = cell->parameters["\\ABITS"].as_int(); int size = cell->parameters["\\SIZE"].as_int(); + int offset = cell->parameters["\\OFFSET"].as_int(); int width = cell->parameters["\\WIDTH"].as_int(); bool use_init = !(RTLIL::SigSpec(cell->parameters["\\INIT"]).is_fully_undef()); @@ -947,7 +1065,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) // initial begin // memid[0] = ... // end - f << stringf("%s" "reg [%d:%d] %s [%d:%d];\n", indent.c_str(), width-1, 0, mem_id.c_str(), size-1, 0); + f << stringf("%s" "reg [%d:%d] %s [%d:%d];\n", indent.c_str(), width-1, 0, mem_id.c_str(), size+offset-1, offset); if (use_init) { f << stringf("%s" "initial begin\n", indent.c_str()); @@ -980,43 +1098,46 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) use_rd_clk = cell->parameters["\\RD_CLK_ENABLE"].extract(i).as_bool(); rd_clk_posedge = cell->parameters["\\RD_CLK_POLARITY"].extract(i).as_bool(); rd_transparent = cell->parameters["\\RD_TRANSPARENT"].extract(i).as_bool(); + if (use_rd_clk) { - std::ostringstream os; - dump_sigspec(os, sig_rd_clk); - clk_domain_str = stringf("%sedge %s", rd_clk_posedge ? "pos" : "neg", os.str().c_str()); - if( clk_to_lof_body.count(clk_domain_str) == 0 ) - clk_to_lof_body[clk_domain_str] = std::vector<std::string>(); - } - if (use_rd_clk && !rd_transparent) - { - // for clocked read ports make something like: - // reg [..] temp_id; - // always @(posedge clk) - // if (rd_en) temp_id <= array_reg[r_addr]; - // assign r_data = temp_id; - std::string temp_id = next_auto_id(); - lof_reg_declarations.push_back( stringf("reg [%d:0] %s;\n", sig_rd_data.size() - 1, temp_id.c_str()) ); { std::ostringstream os; - if (sig_rd_en != RTLIL::SigBit(true)) + dump_sigspec(os, sig_rd_clk); + clk_domain_str = stringf("%sedge %s", rd_clk_posedge ? "pos" : "neg", os.str().c_str()); + if( clk_to_lof_body.count(clk_domain_str) == 0 ) + clk_to_lof_body[clk_domain_str] = std::vector<std::string>(); + } + if (!rd_transparent) + { + // for clocked read ports make something like: + // reg [..] temp_id; + // always @(posedge clk) + // if (rd_en) temp_id <= array_reg[r_addr]; + // assign r_data = temp_id; + std::string temp_id = next_auto_id(); + lof_reg_declarations.push_back( stringf("reg [%d:0] %s;\n", sig_rd_data.size() - 1, temp_id.c_str()) ); { - os << stringf("if ("); - dump_sigspec(os, sig_rd_en); - os << stringf(") "); + std::ostringstream os; + if (sig_rd_en != RTLIL::SigBit(true)) + { + os << stringf("if ("); + dump_sigspec(os, sig_rd_en); + os << stringf(") "); + } + os << stringf("%s <= %s[", temp_id.c_str(), mem_id.c_str()); + dump_sigspec(os, sig_rd_addr); + os << stringf("];\n"); + clk_to_lof_body[clk_domain_str].push_back(os.str()); + } + { + std::ostringstream os; + dump_sigspec(os, sig_rd_data); + std::string line = stringf("assign %s = %s;\n", os.str().c_str(), temp_id.c_str()); + clk_to_lof_body[""].push_back(line); } - os << stringf("%s <= %s[", temp_id.c_str(), mem_id.c_str()); - dump_sigspec(os, sig_rd_addr); - os << stringf("];\n"); - clk_to_lof_body[clk_domain_str].push_back(os.str()); } + else { - std::ostringstream os; - dump_sigspec(os, sig_rd_data); - std::string line = stringf("assign %s = %s;\n", os.str().c_str(), temp_id.c_str()); - clk_to_lof_body[""].push_back(line); - } - } else { - if (rd_transparent) { // for rd-transparent read-ports make something like: // reg [..] temp_id; // always @(posedge clk) @@ -1036,15 +1157,15 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) std::string line = stringf("assign %s = %s[%s];\n", os.str().c_str(), mem_id.c_str(), temp_id.c_str()); clk_to_lof_body[""].push_back(line); } - } else { - // for non-clocked read-ports make something like: - // assign r_data = array_reg[r_addr]; - std::ostringstream os, os2; - dump_sigspec(os, sig_rd_data); - dump_sigspec(os2, sig_rd_addr); - std::string line = stringf("assign %s = %s[%s];\n", os.str().c_str(), mem_id.c_str(), os2.str().c_str()); - clk_to_lof_body[""].push_back(line); } + } else { + // for non-clocked read-ports make something like: + // assign r_data = array_reg[r_addr]; + std::ostringstream os, os2; + dump_sigspec(os, sig_rd_data); + dump_sigspec(os2, sig_rd_addr); + std::string line = stringf("assign %s = %s[%s];\n", os.str().c_str(), mem_id.c_str(), os2.str().c_str()); + clk_to_lof_body[""].push_back(line); } } @@ -1146,6 +1267,118 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) return true; } + if (cell->type.in("$assert", "$assume", "$cover")) + { + f << stringf("%s" "always @* if (", indent.c_str()); + dump_sigspec(f, cell->getPort("\\EN")); + f << stringf(") %s(", cell->type.c_str()+1); + dump_sigspec(f, cell->getPort("\\A")); + f << stringf(");\n"); + return true; + } + + if (cell->type.in("$specify2", "$specify3")) + { + f << stringf("%s" "specify\n%s ", indent.c_str(), indent.c_str()); + + SigSpec en = cell->getPort("\\EN"); + if (en != State::S1) { + f << stringf("if ("); + dump_sigspec(f, cell->getPort("\\EN")); + f << stringf(") "); + } + + f << "("; + if (cell->type == "$specify3" && cell->getParam("\\EDGE_EN").as_bool()) + f << (cell->getParam("\\EDGE_POL").as_bool() ? "posedge ": "negedge "); + + dump_sigspec(f, cell->getPort("\\SRC")); + + f << " "; + if (cell->getParam("\\SRC_DST_PEN").as_bool()) + f << (cell->getParam("\\SRC_DST_POL").as_bool() ? "+": "-"); + f << (cell->getParam("\\FULL").as_bool() ? "*> ": "=> "); + + if (cell->type == "$specify3") { + f << "("; + dump_sigspec(f, cell->getPort("\\DST")); + f << " "; + if (cell->getParam("\\DAT_DST_PEN").as_bool()) + f << (cell->getParam("\\DAT_DST_POL").as_bool() ? "+": "-"); + f << ": "; + dump_sigspec(f, cell->getPort("\\DAT")); + f << ")"; + } else { + dump_sigspec(f, cell->getPort("\\DST")); + } + + bool bak_decimal = decimal; + decimal = 1; + + f << ") = ("; + dump_const(f, cell->getParam("\\T_RISE_MIN")); + f << ":"; + dump_const(f, cell->getParam("\\T_RISE_TYP")); + f << ":"; + dump_const(f, cell->getParam("\\T_RISE_MAX")); + f << ", "; + dump_const(f, cell->getParam("\\T_FALL_MIN")); + f << ":"; + dump_const(f, cell->getParam("\\T_FALL_TYP")); + f << ":"; + dump_const(f, cell->getParam("\\T_FALL_MAX")); + f << ");\n"; + + decimal = bak_decimal; + + f << stringf("%s" "endspecify\n", indent.c_str()); + return true; + } + + if (cell->type == "$specrule") + { + f << stringf("%s" "specify\n%s ", indent.c_str(), indent.c_str()); + + string spec_type = cell->getParam("\\TYPE").decode_string(); + f << stringf("%s(", spec_type.c_str()); + + if (cell->getParam("\\SRC_PEN").as_bool()) + f << (cell->getParam("\\SRC_POL").as_bool() ? "posedge ": "negedge "); + dump_sigspec(f, cell->getPort("\\SRC")); + + if (cell->getPort("\\SRC_EN") != State::S1) { + f << " &&& "; + dump_sigspec(f, cell->getPort("\\SRC_EN")); + } + + f << ", "; + if (cell->getParam("\\DST_PEN").as_bool()) + f << (cell->getParam("\\DST_POL").as_bool() ? "posedge ": "negedge "); + dump_sigspec(f, cell->getPort("\\DST")); + + if (cell->getPort("\\DST_EN") != State::S1) { + f << " &&& "; + dump_sigspec(f, cell->getPort("\\DST_EN")); + } + + bool bak_decimal = decimal; + decimal = 1; + + f << ", "; + dump_const(f, cell->getParam("\\T_LIMIT")); + + if (spec_type == "$setuphold" || spec_type == "$recrem" || spec_type == "$fullskew") { + f << ", "; + dump_const(f, cell->getParam("\\T_LIMIT2")); + } + + f << ");\n"; + decimal = bak_decimal; + + f << stringf("%s" "endspecify\n", indent.c_str()); + return true; + } + // FIXME: $_SR_[PN][PN]_, $_DLATCH_[PN]_, $_DLATCHSR_[PN][PN][PN]_ // FIXME: $sr, $dlatch, $memrd, $memwr, $fsm @@ -1168,8 +1401,7 @@ void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell) if (it != cell->parameters.begin()) f << stringf(","); f << stringf("\n%s .%s(", indent.c_str(), id(it->first).c_str()); - bool is_signed = (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0; - dump_const(f, it->second, -1, 0, false, is_signed); + dump_const(f, it->second); f << stringf(")"); } f << stringf("\n%s" ")", indent.c_str()); @@ -1216,12 +1448,20 @@ void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell) if (defparam && cell->parameters.size() > 0) { for (auto it = cell->parameters.begin(); it != cell->parameters.end(); ++it) { f << stringf("%sdefparam %s.%s = ", indent.c_str(), cell_name.c_str(), id(it->first).c_str()); - bool is_signed = (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0; - dump_const(f, it->second, -1, 0, false, is_signed); + dump_const(f, it->second); f << stringf(";\n"); } } + if (siminit && reg_ct.count(cell->type) && cell->hasPort("\\Q")) { + std::stringstream ss; + dump_reg_init(ss, cell->getPort("\\Q")); + if (!ss.str().empty()) { + f << stringf("%sinitial %s.Q", indent.c_str(), cell_name.c_str()); + f << ss.str(); + f << ";\n"; + } + } } void dump_conn(std::ostream &f, std::string indent, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right) @@ -1274,12 +1514,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; @@ -1338,6 +1580,8 @@ void dump_process(std::ostream &f, std::string indent, RTLIL::Process *proc, boo if (sync->type == RTLIL::STa) { f << stringf("%s" "always @* begin\n", indent.c_str()); + } else if (sync->type == RTLIL::STi) { + f << stringf("%s" "initial begin\n", indent.c_str()); } else { f << stringf("%s" "always @(", indent.c_str()); if (sync->type == RTLIL::STp || sync->type == RTLIL::ST1) @@ -1398,14 +1642,15 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module) SigSpec sig = active_sigmap(wire); Const val = wire->attributes.at("\\init"); for (int i = 0; i < GetSize(sig) && i < GetSize(val); i++) - active_initdata[sig[i]] = val.bits.at(i); + if (val[i] == State::S0 || val[i] == State::S1) + active_initdata[sig[i]] = val[i]; } if (!module->processes.empty()) - log_warning("Module %s contains unmapped RTLIL proccesses. RTLIL processes\n" + log_warning("Module %s contains unmapped RTLIL processes. RTLIL processes\n" "can't always be mapped directly to Verilog always blocks. Unintended\n" "changes in simulation behavior are possible! Use \"proc\" to convert\n" - "processes to logic networks and registers.", log_id(module)); + "processes to logic networks and registers.\n", log_id(module)); f << stringf("\n"); for (auto it = module->processes.begin(); it != module->processes.end(); ++it) @@ -1441,7 +1686,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++) { @@ -1482,7 +1727,7 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module) struct VerilogBackend : public Backend { VerilogBackend() : Backend("verilog", "write design to Verilog file") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -1508,9 +1753,13 @@ struct VerilogBackend : public Backend { log(" without this option all internal cells are converted to Verilog\n"); log(" expressions.\n"); log("\n"); + log(" -siminit\n"); + log(" add initial statements with hierarchical refs to initialize FFs when\n"); + log(" in -noexpr mode.\n"); + log("\n"); log(" -nodec\n"); log(" 32-bit constant values are by default dumped as decimal numbers,\n"); - log(" not bit pattern. This option decativates this feature and instead\n"); + log(" not bit pattern. This option deactivates this feature and instead\n"); log(" will write out all constants in binary.\n"); log("\n"); log(" -decimal\n"); @@ -1518,13 +1767,13 @@ struct VerilogBackend : public Backend { log("\n"); log(" -nohex\n"); log(" constant values that are compatible with hex output are usually\n"); - log(" dumped as hex values. This option decativates this feature and\n"); + log(" dumped as hex values. This option deactivates this feature and\n"); log(" instead will write out all constants in binary.\n"); log("\n"); log(" -nostr\n"); log(" Parameters and attributes that are specified as strings in the\n"); log(" original input will be output as strings by this back-end. This\n"); - log(" decativates this feature and instead will write string constants\n"); + log(" deactivates this feature and instead will write string constants\n"); log(" as binary numbers.\n"); log("\n"); log(" -defparam\n"); @@ -1550,7 +1799,7 @@ struct VerilogBackend : public Backend { log("this command is called on a design with RTLIL processes.\n"); log("\n"); } - virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) + void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing Verilog backend.\n"); @@ -1564,11 +1813,14 @@ struct VerilogBackend : public Backend { nostr = false; defparam = false; decimal = false; + siminit = false; auto_prefix = ""; bool blackboxes = false; bool selected = false; + auto_name_map.clear(); + reg_wires.clear(); reg_ct.clear(); reg_ct.insert("$dff"); @@ -1640,6 +1892,10 @@ struct VerilogBackend : public Backend { decimal = true; continue; } + if (arg == "-siminit") { + siminit = true; + continue; + } if (arg == "-blackboxes") { blackboxes = true; continue; @@ -1660,7 +1916,7 @@ struct VerilogBackend : public Backend { *f << stringf("/* Generated by %s */\n", yosys_version_str); for (auto it = design->modules_.begin(); it != design->modules_.end(); ++it) { - if (it->second->get_bool_attribute("\\blackbox") != blackboxes) + if (it->second->get_blackbox_attribute() != blackboxes) continue; if (selected && !design->selected_whole_module(it->first)) { if (design->selected_module(it->first)) @@ -1671,6 +1927,8 @@ struct VerilogBackend : public Backend { dump_module(*f, "", it->second); } + auto_name_map.clear(); + reg_wires.clear(); reg_ct.clear(); } } VerilogBackend; diff --git a/examples/anlogic/.gitignore b/examples/anlogic/.gitignore new file mode 100644 index 000000000..97c978a15 --- /dev/null +++ b/examples/anlogic/.gitignore @@ -0,0 +1,7 @@ +demo.bit +demo_phy.area +full.v +*.log +*.h +*.tde +*.svf diff --git a/examples/anlogic/README b/examples/anlogic/README new file mode 100644 index 000000000..35d8e9cb1 --- /dev/null +++ b/examples/anlogic/README @@ -0,0 +1,12 @@ +LED Blink project for Anlogic Lichee Tang board. + +Follow the install instructions for the Tang Dynasty IDE from given link below. + +https://tang.sipeed.com/en/getting-started/installing-td-ide/linux/ + + +set TD_HOME env variable to the full path to the TD <TD Install Directory> as follow. + +export TD_HOME=<TD Install Directory> + +then run "bash build.sh" in this directory. diff --git a/examples/anlogic/build.sh b/examples/anlogic/build.sh new file mode 100755 index 000000000..e0f6b4cfe --- /dev/null +++ b/examples/anlogic/build.sh @@ -0,0 +1,4 @@ +#!/bin/bash +set -ex +yosys demo.ys +$TD_HOME/bin/td build.tcl diff --git a/examples/anlogic/build.tcl b/examples/anlogic/build.tcl new file mode 100644 index 000000000..06db525c9 --- /dev/null +++ b/examples/anlogic/build.tcl @@ -0,0 +1,11 @@ +import_device eagle_s20.db -package BG256 +read_verilog full.v -top demo +read_adc demo.adc +optimize_rtl +map_macro +map +pack +place +route +report_area -io_info -file demo_phy.area +bitgen -bit demo.bit -version 0X0000 -svf demo.svf -svf_comment_on -g ucode:00000000000000000000000000000000 diff --git a/examples/anlogic/demo.adc b/examples/anlogic/demo.adc new file mode 100644 index 000000000..ec802502e --- /dev/null +++ b/examples/anlogic/demo.adc @@ -0,0 +1,2 @@ +set_pin_assignment {CLK_IN} { LOCATION = K14; } ##24MHZ +set_pin_assignment {R_LED} { LOCATION = R3; } ##R_LED diff --git a/examples/anlogic/demo.v b/examples/anlogic/demo.v new file mode 100644 index 000000000..e17db771e --- /dev/null +++ b/examples/anlogic/demo.v @@ -0,0 +1,18 @@ +module demo ( + input wire CLK_IN, + output wire R_LED +); + parameter time1 = 30'd12_000_000; + reg led_state; + reg [29:0] count; + + always @(posedge CLK_IN)begin + if(count == time1)begin + count<= 30'd0; + led_state <= ~led_state; + end + else + count <= count + 1'b1; + end + assign R_LED = led_state; +endmodule diff --git a/examples/anlogic/demo.ys b/examples/anlogic/demo.ys new file mode 100644 index 000000000..cb396cc2b --- /dev/null +++ b/examples/anlogic/demo.ys @@ -0,0 +1,3 @@ +read_verilog demo.v +synth_anlogic -top demo +write_verilog full.v diff --git a/examples/basys3/example.xdc b/examples/basys3/example.xdc index c1fd0e925..8cdaa1996 100644 --- a/examples/basys3/example.xdc +++ b/examples/basys3/example.xdc @@ -19,3 +19,6 @@ set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN L1 } [get_ports {LD[15]}] create_clock -add -name sys_clk_pin -period 10.00 -waveform {0 5} [get_ports CLK] +set_property CONFIG_VOLTAGE 3.3 [current_design] +set_property CFGBVS VCCO [current_design] + diff --git a/examples/basys3/run_prog.tcl b/examples/basys3/run_prog.tcl index d711af840..b078ad511 100644 --- a/examples/basys3/run_prog.tcl +++ b/examples/basys3/run_prog.tcl @@ -1,3 +1,4 @@ +open_hw connect_hw_server open_hw_target [lindex [get_hw_targets] 0] set_property PROGRAM.FILE example.bit [lindex [get_hw_devices] 0] diff --git a/examples/cxx-api/evaldemo.cc b/examples/cxx-api/evaldemo.cc index e5cc8d8e7..34373487d 100644 --- a/examples/cxx-api/evaldemo.cc +++ b/examples/cxx-api/evaldemo.cc @@ -22,7 +22,7 @@ struct EvalDemoPass : public Pass { EvalDemoPass() : Pass("evaldemo") { } - virtual void execute(vector<string>, Design *design) + void execute(vector<string>, Design *design) YS_OVERRIDE { Module *module = design->top_module(); diff --git a/examples/igloo2/.gitignore b/examples/igloo2/.gitignore new file mode 100644 index 000000000..33b7182d3 --- /dev/null +++ b/examples/igloo2/.gitignore @@ -0,0 +1,4 @@ +/netlist.edn +/netlist.vm +/example.stp +/proj diff --git a/examples/igloo2/example.pdc b/examples/igloo2/example.pdc new file mode 100644 index 000000000..298d9e934 --- /dev/null +++ b/examples/igloo2/example.pdc @@ -0,0 +1,20 @@ +# Add placement constraints here + +set_io clk -pinname H16 -fixed yes -DIRECTION INPUT + +set_io SW1 -pinname H12 -fixed yes -DIRECTION INPUT +set_io SW2 -pinname H13 -fixed yes -DIRECTION INPUT + +set_io LED1 -pinname J16 -fixed yes -DIRECTION OUTPUT +set_io LED2 -pinname M16 -fixed yes -DIRECTION OUTPUT +set_io LED3 -pinname K16 -fixed yes -DIRECTION OUTPUT +set_io LED4 -pinname N16 -fixed yes -DIRECTION OUTPUT + +set_io AA -pinname L12 -fixed yes -DIRECTION OUTPUT +set_io AB -pinname L13 -fixed yes -DIRECTION OUTPUT +set_io AC -pinname M13 -fixed yes -DIRECTION OUTPUT +set_io AD -pinname N15 -fixed yes -DIRECTION OUTPUT +set_io AE -pinname L11 -fixed yes -DIRECTION OUTPUT +set_io AF -pinname L14 -fixed yes -DIRECTION OUTPUT +set_io AG -pinname N14 -fixed yes -DIRECTION OUTPUT +set_io CA -pinname M15 -fixed yes -DIRECTION OUTPUT diff --git a/examples/igloo2/example.sdc b/examples/igloo2/example.sdc new file mode 100644 index 000000000..f8b487316 --- /dev/null +++ b/examples/igloo2/example.sdc @@ -0,0 +1,2 @@ +# Add timing constraints here +create_clock -period 10.000 -waveform {0.000 5.000} [get_ports {clk}] diff --git a/examples/igloo2/example.v b/examples/igloo2/example.v new file mode 100644 index 000000000..4a9486e50 --- /dev/null +++ b/examples/igloo2/example.v @@ -0,0 +1,64 @@ +module example ( + input clk, + input SW1, + input SW2, + output LED1, + output LED2, + output LED3, + output LED4, + + output AA, AB, AC, AD, + output AE, AF, AG, CA +); + + localparam BITS = 8; + localparam LOG2DELAY = 22; + + reg [BITS+LOG2DELAY-1:0] counter = 0; + reg [BITS-1:0] outcnt; + + always @(posedge clk) begin + counter <= counter + SW1 + SW2 + 1; + outcnt <= counter >> LOG2DELAY; + end + + assign {LED1, LED2, LED3, LED4} = outcnt ^ (outcnt >> 1); + + // assign CA = counter[10]; + // seg7enc seg7encinst ( + // .seg({AA, AB, AC, AD, AE, AF, AG}), + // .dat(CA ? outcnt[3:0] : outcnt[7:4]) + // ); + + assign {AA, AB, AC, AD, AE, AF, AG} = ~(7'b 100_0000 >> outcnt[6:4]); + assign CA = outcnt[7]; +endmodule + +module seg7enc ( + input [3:0] dat, + output [6:0] seg +); + reg [6:0] seg_inv; + always @* begin + seg_inv = 0; + case (dat) + 4'h0: seg_inv = 7'b 0111111; + 4'h1: seg_inv = 7'b 0000110; + 4'h2: seg_inv = 7'b 1011011; + 4'h3: seg_inv = 7'b 1001111; + 4'h4: seg_inv = 7'b 1100110; + 4'h5: seg_inv = 7'b 1101101; + 4'h6: seg_inv = 7'b 1111101; + 4'h7: seg_inv = 7'b 0000111; + 4'h8: seg_inv = 7'b 1111111; + 4'h9: seg_inv = 7'b 1101111; + 4'hA: seg_inv = 7'b 1110111; + 4'hB: seg_inv = 7'b 1111100; + 4'hC: seg_inv = 7'b 0111001; + 4'hD: seg_inv = 7'b 1011110; + 4'hE: seg_inv = 7'b 1111001; + 4'hF: seg_inv = 7'b 1110001; + endcase + end + assign seg = ~seg_inv; +endmodule diff --git a/examples/igloo2/libero.tcl b/examples/igloo2/libero.tcl new file mode 100644 index 000000000..abc94e479 --- /dev/null +++ b/examples/igloo2/libero.tcl @@ -0,0 +1,57 @@ +# Run with "libero SCRIPT:libero.tcl" + +file delete -force proj + +new_project \ + -name example \ + -location proj \ + -block_mode 0 \ + -hdl "VERILOG" \ + -family IGLOO2 \ + -die PA4MGL2500 \ + -package vf256 \ + -speed -1 + +import_files -hdl_source {netlist.vm} +import_files -sdc {example.sdc} +import_files -io_pdc {example.pdc} +build_design_hierarchy +set_option -synth 0 + +organize_tool_files -tool PLACEROUTE \ + -file {proj/constraint/example.sdc} \ + -file {proj/constraint/io/example.pdc} \ + -input_type constraint + +organize_tool_files -tool VERIFYTIMING \ + -file {proj/constraint/example.sdc} \ + -input_type constraint + +configure_tool -name PLACEROUTE \ + -params TDPR:true \ + -params PDPR:false \ + -params EFFORT_LEVEL:false \ + -params REPAIR_MIN_DELAY:false + +puts "" +puts "**> COMPILE" +run_tool -name {COMPILE} +puts "<** COMPILE" + +puts "" +puts "**> PLACEROUTE" +run_tool -name {PLACEROUTE} +puts "<** PLACEROUTE" + +puts "" +puts "**> VERIFYTIMING" +run_tool -name {VERIFYTIMING} +puts "<** VERIFYTIMING" + +puts "" +puts "**> BITSTREAM" +export_bitstream_file -trusted_facility_file 1 -trusted_facility_file_components {FABRIC} +puts "<** BITSTREAM" + +puts "" +exit 0 diff --git a/examples/igloo2/runme.sh b/examples/igloo2/runme.sh new file mode 100644 index 000000000..a08894e0a --- /dev/null +++ b/examples/igloo2/runme.sh @@ -0,0 +1,6 @@ +#!/bin/bash +set -ex +yosys -p 'synth_sf2 -top example -edif netlist.edn -vlog netlist.vm' example.v +export LM_LICENSE_FILE=${LM_LICENSE_FILE:-1702@localhost} +/opt/microsemi/Libero_SoC_v12.0/Libero/bin/libero SCRIPT:libero.tcl +cp proj/designer/example/export/example.stp . diff --git a/examples/mimas2/README b/examples/mimas2/README new file mode 100644 index 000000000..b12875cbc --- /dev/null +++ b/examples/mimas2/README @@ -0,0 +1,8 @@ +A simple example design, based on the Numato Labs Mimas V2 board +================================================================ + +This example uses Yosys for synthesis and Xilinx ISE +for place&route and bit-stream creation. + +To synthesize: + bash run.sh diff --git a/examples/mimas2/example.ucf b/examples/mimas2/example.ucf new file mode 100644 index 000000000..4e31b74ab --- /dev/null +++ b/examples/mimas2/example.ucf @@ -0,0 +1,13 @@ +CONFIG VCCAUX = "3.3" ; + + +NET "CLK" LOC = D9 | IOSTANDARD = LVCMOS33 | PERIOD = 12MHz ; + +NET "LED[7]" LOC = P15 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; +NET "LED[6]" LOC = P16 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; +NET "LED[5]" LOC = N15 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; +NET "LED[4]" LOC = N16 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; +NET "LED[3]" LOC = U17 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; +NET "LED[2]" LOC = U18 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; +NET "LED[1]" LOC = T17 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; +NET "LED[0]" LOC = T18 | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = SLOW ; diff --git a/examples/mimas2/example.v b/examples/mimas2/example.v new file mode 100644 index 000000000..2a9117393 --- /dev/null +++ b/examples/mimas2/example.v @@ -0,0 +1,14 @@ +module example( + input wire CLK, + output wire [7:0] LED +); + +reg [27:0] ctr; +initial ctr = 0; + +always @(posedge CLK) + ctr <= ctr + 1; + +assign LED = ctr[27:20]; + +endmodule diff --git a/examples/mimas2/run.sh b/examples/mimas2/run.sh new file mode 100644 index 000000000..aafde78ed --- /dev/null +++ b/examples/mimas2/run.sh @@ -0,0 +1,8 @@ +#!/bin/sh +set -e +yosys run_yosys.ys +edif2ngd example.edif +ngdbuild example -uc example.ucf -p xc6slx9csg324-3 +map -w example +par -w example.ncd example_par.ncd +bitgen -w example_par.ncd -g StartupClk:JTAGClk diff --git a/examples/mimas2/run_yosys.ys b/examples/mimas2/run_yosys.ys new file mode 100644 index 000000000..b48877811 --- /dev/null +++ b/examples/mimas2/run_yosys.ys @@ -0,0 +1,3 @@ +read_verilog example.v +synth_xilinx -top example -family xc6s -ise +write_edif -pvector bra example.edif diff --git a/examples/python-api/.gitignore b/examples/python-api/.gitignore new file mode 100644 index 000000000..758de1134 --- /dev/null +++ b/examples/python-api/.gitignore @@ -0,0 +1 @@ +out/** diff --git a/examples/python-api/pass.py b/examples/python-api/pass.py new file mode 100755 index 000000000..d67cf4a23 --- /dev/null +++ b/examples/python-api/pass.py @@ -0,0 +1,32 @@ +#!/usr/bin/python3 + +from pyosys import libyosys as ys + +import matplotlib.pyplot as plt +import numpy as np + +class CellStatsPass(ys.Pass): + + def __init__(self): + super().__init__("cell_stats", "Shows cell stats as plot") + + def py_help(self): + ys.log("This pass uses the matplotlib library to display cell stats\n") + + def py_execute(self, args, design): + ys.log_header(design, "Plotting cell stats\n") + cell_stats = {} + for module in design.selected_whole_modules_warn(): + for cell in module.selected_cells(): + if cell.type.str() in cell_stats: + cell_stats[cell.type.str()] += 1 + else: + cell_stats[cell.type.str()] = 1 + plt.bar(range(len(cell_stats)), height = list(cell_stats.values()),align='center') + plt.xticks(range(len(cell_stats)), list(cell_stats.keys())) + plt.show() + + def py_clear_flags(self): + ys.log("Clear Flags - CellStatsPass\n") + +p = CellStatsPass() diff --git a/examples/python-api/script.py b/examples/python-api/script.py new file mode 100755 index 000000000..f0fa5a0b8 --- /dev/null +++ b/examples/python-api/script.py @@ -0,0 +1,22 @@ +#!/usr/bin/python3 + +from pyosys import libyosys as ys + +import matplotlib.pyplot as plt +import numpy as np + +design = ys.Design() +ys.run_pass("read_verilog ../../tests/simple/fiedler-cooley.v", design); +ys.run_pass("prep", design) +ys.run_pass("opt -full", design) + +cell_stats = {} +for module in design.selected_whole_modules_warn(): + for cell in module.selected_cells(): + if cell.type.str() in cell_stats: + cell_stats[cell.type.str()] += 1 + else: + cell_stats[cell.type.str()] = 1 +plt.bar(range(len(cell_stats)), height = list(cell_stats.values()),align='center') +plt.xticks(range(len(cell_stats)), list(cell_stats.keys())) +plt.show() diff --git a/frontends/aiger/Makefile.inc b/frontends/aiger/Makefile.inc new file mode 100644 index 000000000..bc1112452 --- /dev/null +++ b/frontends/aiger/Makefile.inc @@ -0,0 +1,3 @@ + +OBJS += frontends/aiger/aigerparse.o + diff --git a/frontends/aiger/aigerparse.cc b/frontends/aiger/aigerparse.cc new file mode 100644 index 000000000..e8ee487e5 --- /dev/null +++ b/frontends/aiger/aigerparse.cc @@ -0,0 +1,1078 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * 2019 Eddie Hung <eddie@fpgeh.com> + * + * 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. + * + */ + +// [[CITE]] The AIGER And-Inverter Graph (AIG) Format Version 20071012 +// Armin Biere. The AIGER And-Inverter Graph (AIG) Format Version 20071012. Technical Report 07/1, October 2011, FMV Reports Series, Institute for Formal Models and Verification, Johannes Kepler University, Altenbergerstr. 69, 4040 Linz, Austria. +// http://fmv.jku.at/papers/Biere-FMV-TR-07-1.pdf + +// https://stackoverflow.com/a/46137633 +#ifdef _MSC_VER +#include <stdlib.h> +#define __builtin_bswap32 _byteswap_ulong +#elif defined(__APPLE__) +#include <libkern/OSByteOrder.h> +#define __builtin_bswap32 OSSwapInt32 +#endif +#define __STDC_FORMAT_MACROS +#include <inttypes.h> + +#include "kernel/yosys.h" +#include "kernel/sigtools.h" +#include "kernel/celltypes.h" +#include "aigerparse.h" + +YOSYS_NAMESPACE_BEGIN + +inline int32_t from_big_endian(int32_t i32) { +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + return __builtin_bswap32(i32); +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + return i32; +#else +#error "Unknown endianness" +#endif +} + +#define log_debug2(...) ; +//#define log_debug2(...) log_debug(__VA_ARGS__) + +struct ConstEvalAig +{ + RTLIL::Module *module; + dict<RTLIL::SigBit, RTLIL::State> values_map; + dict<RTLIL::SigBit, RTLIL::Cell*> sig2driver; + dict<SigBit, pool<RTLIL::SigBit>> sig2deps; + + ConstEvalAig(RTLIL::Module *module) : module(module) + { + for (auto &it : module->cells_) { + if (!yosys_celltypes.cell_known(it.second->type)) + continue; + for (auto &it2 : it.second->connections()) + if (yosys_celltypes.cell_output(it.second->type, it2.first)) { + auto r YS_ATTRIBUTE(unused) = sig2driver.insert(std::make_pair(it2.second, it.second)); + log_assert(r.second); + } + } + } + + void clear() + { + values_map.clear(); + sig2deps.clear(); + } + + void set(RTLIL::SigBit sig, RTLIL::State value) + { + auto it = values_map.find(sig); +#ifndef NDEBUG + if (it != values_map.end()) { + RTLIL::State current_val = it->second; + log_assert(current_val == value); + } +#endif + if (it != values_map.end()) + it->second = value; + else + values_map[sig] = value; + } + + void set_incremental(RTLIL::SigSpec sig, RTLIL::Const value) + { + log_assert(GetSize(sig) == GetSize(value)); + + for (int i = 0; i < GetSize(sig); i++) { + auto it = values_map.find(sig[i]); + if (it != values_map.end()) { + RTLIL::State current_val = it->second; + if (current_val != value[i]) + for (auto dep : sig2deps[sig[i]]) + values_map.erase(dep); + it->second = value[i]; + } + else + values_map[sig[i]] = value[i]; + } + } + + void compute_deps(RTLIL::SigBit output, const pool<RTLIL::SigBit> &inputs) + { + sig2deps[output].insert(output); + + RTLIL::Cell *cell = sig2driver.at(output); + RTLIL::SigBit sig_a = cell->getPort("\\A"); + sig2deps[sig_a].reserve(sig2deps[sig_a].size() + sig2deps[output].size()); // Reserve so that any invalidation + // that may occur does so here, and + // not mid insertion (below) + sig2deps[sig_a].insert(sig2deps[output].begin(), sig2deps[output].end()); + if (!inputs.count(sig_a)) + compute_deps(sig_a, inputs); + + if (cell->type == "$_AND_") { + RTLIL::SigSpec sig_b = cell->getPort("\\B"); + sig2deps[sig_b].reserve(sig2deps[sig_b].size() + sig2deps[output].size()); // Reserve so that any invalidation + // that may occur does so here, and + // not mid insertion (below) + sig2deps[sig_b].insert(sig2deps[output].begin(), sig2deps[output].end()); + + if (!inputs.count(sig_b)) + compute_deps(sig_b, inputs); + } + else if (cell->type == "$_NOT_") { + } + else log_abort(); + } + + bool eval(RTLIL::Cell *cell) + { + RTLIL::SigBit sig_y = cell->getPort("\\Y"); + if (values_map.count(sig_y)) + return true; + + RTLIL::SigBit sig_a = cell->getPort("\\A"); + if (!eval(sig_a)) + return false; + + RTLIL::State eval_ret = RTLIL::Sx; + if (cell->type == "$_NOT_") { + if (sig_a == State::S0) eval_ret = State::S1; + else if (sig_a == State::S1) eval_ret = State::S0; + } + else if (cell->type == "$_AND_") { + if (sig_a == State::S0) { + eval_ret = State::S0; + goto eval_end; + } + + { + RTLIL::SigBit sig_b = cell->getPort("\\B"); + if (!eval(sig_b)) + return false; + if (sig_b == State::S0) { + eval_ret = State::S0; + goto eval_end; + } + + if (sig_a != State::S1 || sig_b != State::S1) + goto eval_end; + + eval_ret = State::S1; + } + } + else log_abort(); + +eval_end: + set(sig_y, eval_ret); + return true; + } + + bool eval(RTLIL::SigBit &sig) + { + auto it = values_map.find(sig); + if (it != values_map.end()) { + sig = it->second; + return true; + } + + RTLIL::Cell *cell = sig2driver.at(sig); + if (!eval(cell)) + return false; + + it = values_map.find(sig); + if (it != values_map.end()) { + sig = it->second; + return true; + } + + return false; + } +}; + +AigerReader::AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name, std::string map_filename, bool wideports) + : design(design), f(f), clk_name(clk_name), map_filename(map_filename), wideports(wideports) +{ + 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"); + + // 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"); +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 + + 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; + piNum = 0; + flopNum = 0; + + if (header == "aag") + parse_aiger_ascii(); + else if (header == "aig") + parse_aiger_binary(); + else + log_abort(); + + RTLIL::Wire* n0 = module->wire("\\__0__"); + if (n0) + module->connect(n0, State::S0); + + // 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); + + 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); + + 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 + } + + post_process(); +} + +static uint32_t parse_xaiger_literal(std::istream &f) +{ + uint32_t l; + f.read(reinterpret_cast<char*>(&l), sizeof(l)); + if (f.gcount() != sizeof(l)) +#if defined(_WIN32) && defined(__MINGW32__) + log_error("Offset %I64d: unable to read literal!\n", static_cast<int64_t>(f.tellg())); +#else + log_error("Offset %" PRId64 ": unable to read literal!\n", static_cast<int64_t>(f.tellg())); +#endif + return from_big_endian(l); +} + +static RTLIL::Wire* createWireIfNotExists(RTLIL::Module *module, unsigned literal) +{ + const unsigned variable = literal >> 1; + const bool invert = literal & 1; + RTLIL::IdString wire_name(stringf("\\__%d%s__", variable, invert ? "b" : "")); + RTLIL::Wire *wire = module->wire(wire_name); + if (wire) return wire; + log_debug2("Creating %s\n", wire_name.c_str()); + wire = module->addWire(wire_name); + wire->port_input = wire->port_output = false; + if (!invert) return wire; + RTLIL::IdString wire_inv_name(stringf("\\__%d__", variable)); + RTLIL::Wire *wire_inv = module->wire(wire_inv_name); + if (wire_inv) { + if (module->cell(wire_inv_name)) return wire; + } + else { + log_debug2("Creating %s\n", wire_inv_name.c_str()); + wire_inv = module->addWire(wire_inv_name); + wire_inv->port_input = wire_inv->port_output = false; + } + + log_debug2("Creating %s = ~%s\n", wire_name.c_str(), wire_inv_name.c_str()); + module->addNotGate(stringf("\\__%d__$not", variable), wire_inv, wire); + + return wire; +} + +void AigerReader::parse_xaiger(const dict<int,IdString> &box_lookup) +{ + 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"); + + // Optional values + B = C = J = F = 0; + + 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\n", M, I, L, O, A); + + line_count = 1; + piNum = 0; + flopNum = 0; + + if (header == "aag") + parse_aiger_ascii(); + else if (header == "aig") + parse_aiger_binary(); + else + log_abort(); + + RTLIL::Wire* n0 = module->wire("\\__0__"); + if (n0) + module->connect(n0, State::S0); + + // Parse footer (symbol table, comments, etc.) + std::string s; + bool comment_seen = false; + for (int c = f.peek(); c != EOF; c = f.peek()) { + if (comment_seen || c == 'c') { + if (!comment_seen) { + f.ignore(1); + c = f.peek(); + comment_seen = true; + } + if (c == '\n') + break; + f.ignore(1); + // XAIGER extensions + if (c == 'm') { + uint32_t dataSize YS_ATTRIBUTE(unused) = parse_xaiger_literal(f); + uint32_t lutNum = parse_xaiger_literal(f); + uint32_t lutSize YS_ATTRIBUTE(unused) = parse_xaiger_literal(f); + log_debug("m: dataSize=%u lutNum=%u lutSize=%u\n", dataSize, lutNum, lutSize); + ConstEvalAig ce(module); + for (unsigned i = 0; i < lutNum; ++i) { + uint32_t rootNodeID = parse_xaiger_literal(f); + uint32_t cutLeavesM = parse_xaiger_literal(f); + log_debug2("rootNodeID=%d cutLeavesM=%d\n", rootNodeID, cutLeavesM); + RTLIL::Wire *output_sig = module->wire(stringf("\\__%d__", rootNodeID)); + uint32_t nodeID; + RTLIL::SigSpec input_sig; + for (unsigned j = 0; j < cutLeavesM; ++j) { + nodeID = parse_xaiger_literal(f); + log_debug2("\t%u\n", nodeID); + RTLIL::Wire *wire = module->wire(stringf("\\__%d__", nodeID)); + log_assert(wire); + input_sig.append(wire); + } + // TODO: Compute LUT mask from AIG in less than O(2 ** input_sig.size()) + ce.clear(); + ce.compute_deps(output_sig, input_sig.to_sigbit_pool()); + RTLIL::Const lut_mask(RTLIL::State::Sx, 1 << input_sig.size()); + for (int j = 0; j < (1 << cutLeavesM); ++j) { + int gray = j ^ (j >> 1); + ce.set_incremental(input_sig, RTLIL::Const{gray, static_cast<int>(cutLeavesM)}); + RTLIL::SigBit o(output_sig); + bool success YS_ATTRIBUTE(unused) = ce.eval(o); + log_assert(success); + log_assert(o.wire == nullptr); + lut_mask[gray] = o.data; + } + RTLIL::Cell *output_cell = module->cell(stringf("\\__%d__$and", rootNodeID)); + log_assert(output_cell); + module->remove(output_cell); + module->addLut(stringf("\\__%d__$lut", rootNodeID), input_sig, output_sig, std::move(lut_mask)); + } + } + else if (c == 'r') { + uint32_t dataSize YS_ATTRIBUTE(unused) = parse_xaiger_literal(f); + flopNum = parse_xaiger_literal(f); + log_debug("flopNum: %u\n", flopNum); + log_assert(dataSize == (flopNum+1) * sizeof(uint32_t)); + f.ignore(flopNum * sizeof(uint32_t)); + } + else if (c == 'n') { + parse_xaiger_literal(f); + f >> s; + log_debug("n: '%s'\n", s.c_str()); + } + else if (c == 'h') { + f.ignore(sizeof(uint32_t)); + uint32_t version YS_ATTRIBUTE(unused) = parse_xaiger_literal(f); + log_assert(version == 1); + uint32_t ciNum YS_ATTRIBUTE(unused) = parse_xaiger_literal(f); + log_debug("ciNum = %u\n", ciNum); + uint32_t coNum YS_ATTRIBUTE(unused) = parse_xaiger_literal(f); + log_debug("coNum = %u\n", coNum); + piNum = parse_xaiger_literal(f); + log_debug("piNum = %u\n", piNum); + uint32_t poNum YS_ATTRIBUTE(unused) = parse_xaiger_literal(f); + log_debug("poNum = %u\n", poNum); + uint32_t boxNum = parse_xaiger_literal(f); + log_debug("boxNum = %u\n", boxNum); + for (unsigned i = 0; i < boxNum; i++) { + f.ignore(2*sizeof(uint32_t)); + uint32_t boxUniqueId = parse_xaiger_literal(f); + log_assert(boxUniqueId > 0); + uint32_t oldBoxNum = parse_xaiger_literal(f); + RTLIL::Cell* cell = module->addCell(stringf("$__box%u__", oldBoxNum), box_lookup.at(boxUniqueId)); + boxes.emplace_back(cell); + } + } + else if (c == 'a' || c == 'i' || c == 'o') { + uint32_t dataSize = parse_xaiger_literal(f); + f.ignore(dataSize); + } + else { + break; + } + } + else + log_error("Line %u: cannot interpret first character '%c'!\n", line_count, c); + } + + post_process(); +} + +void AigerReader::parse_aiger_ascii() +{ + std::string line; + std::stringstream ss; + + unsigned l1, l2, l3; + + // 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_debug2("%d is an input\n", l1); + log_assert(!(l1 & 1)); // 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_name.empty()) { + clk_wire = module->wire(clk_name); + log_assert(!clk_wire); + log_debug2("Creating %s\n", clk_name.c_str()); + clk_wire = module->addWire(clk_name); + clk_wire->port_input = true; + clk_wire->port_output = false; + } + 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_debug2("%d %d is a latch\n", l1, l2); + log_assert(!(l1 & 1)); + RTLIL::Wire *q_wire = createWireIfNotExists(module, l1); + RTLIL::Wire *d_wire = createWireIfNotExists(module, l2); + + if (clk_wire) + module->addDffGate(NEW_ID, clk_wire, d_wire, q_wire); + else + module->addFfGate(NEW_ID, 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); + + if (l3 == 0) + q_wire->attributes["\\init"] = State::S0; + else if (l3 == 1) + q_wire->attributes["\\init"] = State::S1; + else if (l3 == l1) { + //q_wire->attributes["\\init"] = RTLIL::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"] = State::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); + + log_debug2("%d is an output\n", l1); + const unsigned variable = l1 >> 1; + const bool invert = l1 & 1; + RTLIL::IdString wire_name(stringf("\\__%d%s__", variable, invert ? "b" : "")); // FIXME: is "b" the right suffix? + RTLIL::Wire *wire = module->wire(wire_name); + if (!wire) + wire = createWireIfNotExists(module, l1); + else if (wire->port_input || wire->port_output) { + RTLIL::Wire *new_wire = module->addWire(NEW_ID); + module->connect(new_wire, wire); + wire = new_wire; + } + wire->port_output = true; + outputs.push_back(wire); + } + + // 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); + + log_debug2("%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 invariant constraints + for (unsigned i = 0; i < C; ++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 + + // TODO: Parse fairness constraints + for (unsigned i = 0; i < F; ++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); + + log_debug2("%d %d %d is an AND\n", l1, l2, l3); + log_assert(!(l1 & 1)); + RTLIL::Wire *o_wire = createWireIfNotExists(module, l1); + RTLIL::Wire *i1_wire = createWireIfNotExists(module, l2); + RTLIL::Wire *i2_wire = createWireIfNotExists(module, l3); + module->addAndGate(o_wire->name.str() + "$and", 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))); +} + +void AigerReader::parse_aiger_binary() +{ + unsigned l1, l2, l3; + std::string line; + + // Parse inputs + for (unsigned i = 1; i <= I; ++i) { + log_debug2("%d is an input\n", i); + RTLIL::Wire *wire = createWireIfNotExists(module, i << 1); + wire->port_input = true; + log_assert(!wire->port_output); + inputs.push_back(wire); + } + + // Parse latches + RTLIL::Wire *clk_wire = nullptr; + if (L > 0 && !clk_name.empty()) { + clk_wire = module->wire(clk_name); + log_assert(!clk_wire); + log_debug2("Creating %s\n", clk_name.c_str()); + clk_wire = module->addWire(clk_name); + clk_wire->port_input = true; + clk_wire->port_output = false; + } + 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); + + if (clk_wire) + module->addDff(NEW_ID, clk_wire, d_wire, q_wire); + else + module->addFf(NEW_ID, 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); + + if (l3 == 0) + q_wire->attributes["\\init"] = State::S0; + else if (l3 == 1) + q_wire->attributes["\\init"] = State::S1; + else if (l3 == l1) { + //q_wire->attributes["\\init"] = RTLIL::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"] = State::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); + + log_debug2("%d is an output\n", l1); + const unsigned variable = l1 >> 1; + const bool invert = l1 & 1; + RTLIL::IdString wire_name(stringf("\\__%d%s__", variable, invert ? "b" : "")); // FIXME: is "_b" the right suffix? + RTLIL::Wire *wire = module->wire(wire_name); + if (!wire) + wire = createWireIfNotExists(module, l1); + else if (wire->port_input || wire->port_output) { + RTLIL::Wire *new_wire = module->addWire(NEW_ID); + module->connect(new_wire, wire); + wire = new_wire; + } + wire->port_output = true; + outputs.push_back(wire); + } + 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); + + log_debug2("%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 invariant constraints + for (unsigned i = 0; i < C; ++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 + + // TODO: Parse fairness constraints + for (unsigned i = 0; i < F; ++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); + + log_debug2("%d %d %d is an AND\n", l1, l2, l3); + log_assert(!(l1 & 1)); + RTLIL::Wire *o_wire = createWireIfNotExists(module, l1); + RTLIL::Wire *i1_wire = createWireIfNotExists(module, l2); + RTLIL::Wire *i2_wire = createWireIfNotExists(module, l3); + module->addAndGate(o_wire->name.str() + "$and", i1_wire, i2_wire, o_wire); + } +} + +void AigerReader::post_process() +{ + pool<IdString> seen_boxes; + unsigned ci_count = 0, co_count = 0; + for (auto cell : boxes) { + RTLIL::Module* box_module = design->module(cell->type); + log_assert(box_module); + + if (seen_boxes.insert(cell->type).second) { + auto it = box_module->attributes.find("\\abc_carry"); + if (it != box_module->attributes.end()) { + RTLIL::Wire *carry_in = nullptr, *carry_out = nullptr; + auto carry_in_out = it->second.decode_string(); + auto pos = carry_in_out.find(','); + if (pos == std::string::npos) + log_error("'abc_carry' attribute on module '%s' does not contain ','.\n", log_id(cell->type)); + auto carry_in_name = RTLIL::escape_id(carry_in_out.substr(0, pos)); + carry_in = box_module->wire(carry_in_name); + if (!carry_in || !carry_in->port_input) + log_error("'abc_carry' on module '%s' contains '%s' which does not exist or is not an input port.\n", log_id(cell->type), carry_in_name.c_str()); + + auto carry_out_name = RTLIL::escape_id(carry_in_out.substr(pos+1)); + carry_out = box_module->wire(carry_out_name); + if (!carry_out || !carry_out->port_output) + log_error("'abc_carry' on module '%s' contains '%s' which does not exist or is not an output port.\n", log_id(cell->type), carry_out_name.c_str()); + + auto &ports = box_module->ports; + for (auto jt = ports.begin(); jt != ports.end(); ) { + RTLIL::Wire* w = box_module->wire(*jt); + log_assert(w); + if (w == carry_in || w == carry_out) { + jt = ports.erase(jt); + continue; + } + if (w->port_id > carry_in->port_id) + --w->port_id; + if (w->port_id > carry_out->port_id) + --w->port_id; + log_assert(w->port_input || w->port_output); + log_assert(ports[w->port_id-1] == w->name); + ++jt; + } + ports.push_back(carry_in->name); + carry_in->port_id = ports.size(); + ports.push_back(carry_out->name); + carry_out->port_id = ports.size(); + } + } + + // NB: Assume box_module->ports are sorted alphabetically + // (as RTLIL::Module::fixup_ports() would do) + for (auto port_name : box_module->ports) { + RTLIL::Wire* port = box_module->wire(port_name); + log_assert(port); + RTLIL::SigSpec rhs; + for (int i = 0; i < GetSize(port); i++) { + RTLIL::Wire* wire = nullptr; + if (port->port_input) { + log_assert(co_count < outputs.size()); + wire = outputs[co_count++]; + log_assert(wire); + log_assert(wire->port_output); + wire->port_output = false; + } + if (port->port_output) { + log_assert((piNum + ci_count) < inputs.size()); + wire = inputs[piNum + ci_count++]; + log_assert(wire); + log_assert(wire->port_input); + wire->port_input = false; + } + rhs.append(wire); + } + + cell->setPort(port_name, rhs); + } + } + + dict<RTLIL::IdString, int> wideports_cache; + + if (!map_filename.empty()) { + std::ifstream mf(map_filename); + std::string type, symbol; + int variable, index; + while (mf >> type >> variable >> index >> symbol) { + RTLIL::IdString escaped_s = RTLIL::escape_id(symbol); + if (type == "input") { + log_assert(static_cast<unsigned>(variable) < inputs.size()); + RTLIL::Wire* wire = inputs[variable]; + log_assert(wire); + log_assert(wire->port_input); + log_debug("Renaming input %s", log_id(wire)); + + if (index == 0) { + // Cope with the fact that a CI might be identical + // to a PI (necessary due to ABC); in those cases + // simply connect the latter to the former + RTLIL::Wire* existing = module->wire(escaped_s); + if (!existing) + module->rename(wire, escaped_s); + else { + wire->port_input = false; + module->connect(wire, existing); + } + } + else if (index > 0) { + std::string indexed_name = stringf("%s[%d]", escaped_s.c_str(), index); + RTLIL::Wire* existing = module->wire(indexed_name); + if (!existing) { + module->rename(wire, indexed_name); + if (wideports) + wideports_cache[escaped_s] = std::max(wideports_cache[escaped_s], index); + } + else { + module->connect(wire, existing); + wire->port_input = false; + } + } + log_debug(" -> %s\n", log_id(wire)); + } + else if (type == "output") { + log_assert(static_cast<unsigned>(variable + co_count) < outputs.size()); + RTLIL::Wire* wire = outputs[variable + co_count]; + log_assert(wire); + log_assert(wire->port_output); + if (escaped_s == "$__dummy__") { + wire->port_output = false; + continue; + } + log_debug("Renaming output %s", log_id(wire)); + + if (index == 0) { + // Cope with the fact that a CO might be identical + // to a PO (necessary due to ABC); in those cases + // simply connect the latter to the former + RTLIL::Wire* existing = module->wire(escaped_s); + if (!existing) { + if (escaped_s.ends_with("$inout.out")) { + wire->port_output = false; + RTLIL::Wire *in_wire = module->wire(escaped_s.substr(0, escaped_s.size()-10)); + log_assert(in_wire); + log_assert(in_wire->port_input && !in_wire->port_output); + in_wire->port_output = true; + module->connect(in_wire, wire); + } + else + module->rename(wire, escaped_s); + } + else { + wire->port_output = false; + module->connect(wire, existing); + wire = existing; + } + } + else if (index > 0) { + std::string indexed_name = stringf("%s[%d]", escaped_s.c_str(), index); + RTLIL::Wire* existing = module->wire(indexed_name); + if (!existing) { + if (escaped_s.ends_with("$inout.out")) { + wire->port_output = false; + RTLIL::Wire *in_wire = module->wire(stringf("%s[%d]", escaped_s.substr(0, escaped_s.size()-10).c_str(), index)); + log_assert(in_wire); + log_assert(in_wire->port_input && !in_wire->port_output); + in_wire->port_output = true; + module->connect(in_wire, wire); + } + else { + module->rename(wire, indexed_name); + if (wideports) + wideports_cache[escaped_s] = std::max(wideports_cache[escaped_s], index); + } + } + else { + module->connect(wire, existing); + wire->port_output = false; + } + } + log_debug(" -> %s\n", log_id(wire)); + } + else if (type == "box") { + RTLIL::Cell* cell = module->cell(stringf("$__box%d__", variable)); + if (cell) { // ABC could have optimised this box away + module->rename(cell, escaped_s); + for (const auto &i : cell->connections()) { + RTLIL::IdString port_name = i.first; + RTLIL::SigSpec rhs = i.second; + int index = 0; + for (auto bit : rhs.bits()) { + RTLIL::Wire* wire = bit.wire; + RTLIL::IdString escaped_s = RTLIL::escape_id(stringf("%s.%s", log_id(cell), log_id(port_name))); + if (index == 0) + module->rename(wire, escaped_s); + else if (index > 0) { + module->rename(wire, stringf("%s[%d]", escaped_s.c_str(), index)); + if (wideports) + wideports_cache[escaped_s] = std::max(wideports_cache[escaped_s], index); + } + index++; + } + } + } + } + else + log_error("Symbol type '%s' not recognised.\n", type.c_str()); + } + } + + for (auto &wp : wideports_cache) { + auto name = wp.first; + int width = wp.second + 1; + + RTLIL::Wire *wire = module->wire(name); + if (wire) + module->rename(wire, RTLIL::escape_id(stringf("%s[%d]", name.c_str(), 0))); + + // Do not make ports with a mix of input/output into + // wide ports + bool port_input = false, port_output = false; + for (int i = 0; i < width; i++) { + RTLIL::IdString other_name = name.str() + stringf("[%d]", i); + RTLIL::Wire *other_wire = module->wire(other_name); + if (other_wire) { + port_input = port_input || other_wire->port_input; + port_output = port_output || other_wire->port_output; + } + } + + wire = module->addWire(name, width); + wire->port_input = port_input; + wire->port_output = port_output; + + for (int i = 0; i < width; i++) { + RTLIL::IdString other_name = name.str() + stringf("[%d]", i); + RTLIL::Wire *other_wire = module->wire(other_name); + if (other_wire) { + other_wire->port_input = false; + other_wire->port_output = false; + } + if (wire->port_input) { + if (other_wire) + module->connect(other_wire, SigSpec(wire, i)); + } + else { + // Since we skip POs that are connected to Sx, + // re-connect them here + module->connect(SigSpec(wire, i), other_wire ? other_wire : SigSpec(RTLIL::Sx)); + } + } + } + + module->fixup_ports(); + + // Insert into a new (temporary) design so that "clean" will only + // operate (and run checks on) this one module + RTLIL::Design *mapped_design = new RTLIL::Design; + mapped_design->add(module); + Pass::call(mapped_design, "clean"); + mapped_design->modules_.erase(module->name); + delete mapped_design; + + design->add(module); + + for (auto cell : module->cells().to_vector()) { + if (cell->type != "$lut") continue; + auto y_port = cell->getPort("\\Y").as_bit(); + if (y_port.wire->width == 1) + module->rename(cell, stringf("%s$lut", y_port.wire->name.c_str())); + else + module->rename(cell, stringf("%s[%d]$lut", y_port.wire->name.c_str(), y_port.offset)); + } +} + +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 <module_name>\n"); + log(" Name of module to be created (default: <filename>)\n"); + log("\n"); + log(" -clk_name <wire_name>\n"); + log(" If specified, AIGER latches to be transformed into $_DFF_P_ cells\n"); + log(" clocked by wire of this name. Otherwise, $_FF_ cells will be used.\n"); + log("\n"); + log(" -map <filename>\n"); + log(" read file with port and latch symbols\n"); + log("\n"); + log(" -wideports\n"); + log(" Merge ports that match the pattern 'name[int]' into a single\n"); + log(" multi-bit port 'name'.\n"); + log("\n"); + } + void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + log_header(design, "Executing AIGER frontend.\n"); + + RTLIL::IdString clk_name = "\\clk"; + RTLIL::IdString module_name; + std::string map_filename; + bool wideports = false; + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + std::string arg = args[argidx]; + if (arg == "-module_name" && argidx+1 < args.size()) { + module_name = RTLIL::escape_id(args[++argidx]); + continue; + } + if (arg == "-clk_name" && argidx+1 < args.size()) { + clk_name = RTLIL::escape_id(args[++argidx]); + continue; + } + if (map_filename.empty() && arg == "-map" && argidx+1 < args.size()) { + map_filename = args[++argidx]; + continue; + } + if (arg == "-wideports") { + wideports = true; + continue; + } + break; + } + extra_args(f, filename, args, argidx); + + if (module_name.empty()) { +#ifdef _WIN32 + char fname[_MAX_FNAME]; + _splitpath(filename.c_str(), NULL /* drive */, NULL /* dir */, fname, NULL /* ext */); + module_name = fname; +#else + char* bn = strdup(filename.c_str()); + module_name = RTLIL::escape_id(bn); + free(bn); +#endif + } + + AigerReader reader(design, *f, module_name, clk_name, map_filename, wideports); + reader.parse_aiger(); + } +} AigerFrontend; + +YOSYS_NAMESPACE_END diff --git a/frontends/aiger/aigerparse.h b/frontends/aiger/aigerparse.h new file mode 100644 index 000000000..583c9d0f9 --- /dev/null +++ b/frontends/aiger/aigerparse.h @@ -0,0 +1,58 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * 2019 Eddie Hung <eddie@fpgeh.com> + * + * 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. + * + */ + +#ifndef ABC_AIGERPARSE +#define ABC_AIGERPARSE + +#include "kernel/yosys.h" + +YOSYS_NAMESPACE_BEGIN + +struct AigerReader +{ + RTLIL::Design *design; + std::istream &f; + RTLIL::IdString clk_name; + RTLIL::Module *module; + std::string map_filename; + bool wideports; + + unsigned M, I, L, O, A; + unsigned B, C, J, F; // Optional in AIGER 1.9 + unsigned line_count; + uint32_t piNum, flopNum; + + std::vector<RTLIL::Wire*> inputs; + std::vector<RTLIL::Wire*> latches; + std::vector<RTLIL::Wire*> outputs; + std::vector<RTLIL::Wire*> bad_properties; + std::vector<RTLIL::Cell*> boxes; + + AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name, std::string map_filename, bool wideports); + void parse_aiger(); + void parse_xaiger(const dict<int,IdString> &box_lookup); + void parse_aiger_ascii(); + void parse_aiger_binary(); + void post_process(); +}; + +YOSYS_NAMESPACE_END + +#endif diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 999202b47..21279cbfa 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -2,6 +2,7 @@ * yosys -- Yosys Open SYnthesis Suite * * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * Copyright (C) 2018 Ruben Undheim <ruben.undheim@gmail.com> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -35,17 +36,17 @@ YOSYS_NAMESPACE_BEGIN using namespace AST; using namespace AST_INTERNAL; -// instanciate global variables (public API) +// instantiate global variables (public API) namespace AST { std::string current_filename; void (*set_line_num)(int) = NULL; int (*get_line_num)() = NULL; } -// instanciate global variables (private API) +// instantiate global variables (private API) namespace AST_INTERNAL { - bool flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, flag_dump_rtlil, flag_nolatches, flag_nomeminit; - bool flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire; + 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_pwires, flag_autowire; AstNode *current_ast, *current_ast_mod; std::map<std::string, AstNode*> current_scope; const dict<RTLIL::SigBit, RTLIL::SigBit> *genRTLIL_subst_ptr = NULL; @@ -153,9 +154,15 @@ 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) + X(AST_INTERFACE) + X(AST_INTERFACEPORT) + X(AST_INTERFACEPORTTYPE) + X(AST_MODPORT) + X(AST_MODPORTMEMBER) X(AST_PACKAGE) #undef X default: @@ -171,8 +178,7 @@ bool AstNode::get_bool_attribute(RTLIL::IdString id) AstNode *attr = attributes.at(id); if (attr->type != AST_CONSTANT) - log_error("Attribute `%s' with non-constant value at %s:%d!\n", - id.c_str(), attr->filename.c_str(), attr->linenum); + log_file_error(attr->filename, attr->linenum, "Attribute `%s' with non-constant value!\n", id.c_str()); return attr->integer != 0; } @@ -191,8 +197,13 @@ AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *ch is_input = false; is_output = false; is_reg = false; + 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; port_id = 0; @@ -265,18 +276,20 @@ void AstNode::dumpAst(FILE *f, std::string indent) const std::string type_name = type2str(type); fprintf(f, "%s%s <%s:%d>", indent.c_str(), type_name.c_str(), filename.c_str(), linenum); - if (id2ast) - fprintf(f, " [%p -> %p]", this, id2ast); - else - fprintf(f, " [%p]", this); + if (!flag_no_dump_ptr) { + if (id2ast) + fprintf(f, " [%p -> %p]", this, id2ast); + else + fprintf(f, " [%p]", this); + } if (!str.empty()) fprintf(f, " str='%s'", str.c_str()); if (!bits.empty()) { fprintf(f, " bits='"); for (size_t i = bits.size(); i > 0; i--) - fprintf(f, "%c", bits[i-1] == RTLIL::S0 ? '0' : - bits[i-1] == RTLIL::S1 ? '1' : + fprintf(f, "%c", bits[i-1] == State::S0 ? '0' : + bits[i-1] == State::S1 ? '1' : bits[i-1] == RTLIL::Sx ? 'x' : bits[i-1] == RTLIL::Sz ? 'z' : '?'); fprintf(f, "'(%d)", GetSize(bits)); @@ -285,7 +298,9 @@ void AstNode::dumpAst(FILE *f, std::string indent) const fprintf(f, " input"); if (is_output) fprintf(f, " output"); - if (is_reg) + if (is_logic) + fprintf(f, " logic"); + if (is_reg) // this is an AST dump, not Verilog - if we see "logic reg" that's fine. fprintf(f, " reg"); if (is_signed) fprintf(f, " signed"); @@ -425,9 +440,12 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const break; case AST_RANGE: - if (range_valid) - fprintf(f, "[%d:%d]", range_left, range_right); - else { + if (range_valid) { + if (range_swapped) + fprintf(f, "[%d:%d]", range_right, range_left); + else + fprintf(f, "[%d:%d]", range_left, range_right); + } else { for (auto child : children) { fprintf(f, "%c", first ? '[' : ':'); child->dumpVlog(f, ""); @@ -556,7 +574,8 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const case AST_CONCAT: fprintf(f, "{"); - for (auto child : children) { + for (int i = GetSize(children)-1; i >= 0; i--) { + auto child = children[i]; if (!first) fprintf(f, ", "); child->dumpVlog(f, ""); @@ -652,6 +671,8 @@ bool AstNode::operator==(const AstNode &other) const return false; if (is_output != other.is_output) return false; + if (is_logic != other.is_logic) + return false; if (is_reg != other.is_reg) return false; if (is_signed != other.is_signed) @@ -700,7 +721,7 @@ AstNode *AstNode::mkconst_int(uint32_t v, bool is_signed, int width) node->integer = v; node->is_signed = is_signed; for (int i = 0; i < width; i++) { - node->bits.push_back((v & 1) ? RTLIL::S1 : RTLIL::S0); + node->bits.push_back((v & 1) ? State::S1 : State::S0); v = v >> 1; } node->range_valid = true; @@ -710,23 +731,29 @@ 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<RTLIL::State> &v, bool is_signed) +AstNode *AstNode::mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed, bool is_unsized) { AstNode *node = new AstNode(AST_CONSTANT); node->is_signed = is_signed; node->bits = v; for (size_t i = 0; i < 32; i++) { if (i < node->bits.size()) - node->integer |= (node->bits[i] == RTLIL::S1) << i; + node->integer |= (node->bits[i] == State::S1) << i; else if (is_signed && !node->bits.empty()) - node->integer |= (node->bits.back() == RTLIL::S1) << i; + node->integer |= (node->bits.back() == State::S1) << i; } 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<RTLIL::State> &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<RTLIL::State> &v) { @@ -745,7 +772,7 @@ AstNode *AstNode::mkconst_str(const std::string &str) for (size_t i = 0; i < str.size(); i++) { unsigned char ch = str[str.size() - i - 1]; for (int j = 0; j < 8; j++) { - data.push_back((ch & 1) ? RTLIL::S1 : RTLIL::S0); + data.push_back((ch & 1) ? State::S1 : State::S0); ch = ch >> 1; } } @@ -758,11 +785,19 @@ AstNode *AstNode::mkconst_str(const std::string &str) bool AstNode::bits_only_01() const { for (auto bit : bits) - if (bit != RTLIL::S0 && bit != RTLIL::S1) + if (bit != State::S0 && bit != State::S1) return false; 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<RTLIL::State> bits = this->bits; @@ -895,9 +930,9 @@ RTLIL::Const AstNode::realAsConst(int width) } // create a new AstModule from an AST_MODULE AST node -static AstModule* process_module(AstNode *ast, bool defer) +static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast = NULL) { - log_assert(ast->type == AST_MODULE); + log_assert(ast->type == AST_MODULE || ast->type == AST_INTERFACE); if (defer) log("Storing AST representation for module `%s'.\n", ast->str.c_str()); @@ -908,33 +943,116 @@ static AstModule* process_module(AstNode *ast, bool defer) current_module->ast = NULL; current_module->name = ast->str; current_module->attributes["\\src"] = stringf("%s:%d", ast->filename.c_str(), ast->linenum); + current_module->set_bool_attribute("\\cells_not_processed"); current_ast_mod = ast; - AstNode *ast_before_simplify = ast->clone(); + AstNode *ast_before_simplify; + if (original_ast != NULL) + ast_before_simplify = original_ast; + else + ast_before_simplify = ast->clone(); if (flag_dump_ast1) { - log("Dumping Verilog AST before simplification:\n"); + log("Dumping AST before simplification:\n"); ast->dumpAst(NULL, " "); log("--- END OF AST DUMP ---\n"); } + if (flag_dump_vlog1) { + log("Dumping Verilog AST before simplification:\n"); + ast->dumpVlog(NULL, " "); + log("--- END OF AST DUMP ---\n"); + } if (!defer) { + bool blackbox_module = flag_lib; + + if (!blackbox_module && !flag_noblackbox) { + blackbox_module = true; + for (auto child : ast->children) { + if (child->type == AST_WIRE && (child->is_input || child->is_output)) + continue; + if (child->type == AST_PARAMETER || child->type == AST_LOCALPARAM) + continue; + if (child->type == AST_CELL && child->children.size() > 0 && child->children[0]->type == AST_CELLTYPE && + (child->children[0]->str == "$specify2" || child->children[0]->str == "$specify3" || child->children[0]->str == "$specrule")) + continue; + blackbox_module = false; + break; + } + } + while (ast->simplify(!flag_noopt, false, false, 0, -1, false, false)) { } if (flag_dump_ast2) { - log("Dumping Verilog AST after simplification:\n"); + log("Dumping AST after simplification:\n"); ast->dumpAst(NULL, " "); log("--- END OF AST DUMP ---\n"); } - if (flag_dump_vlog) { - log("Dumping Verilog AST (as requested by dump_vlog option):\n"); + if (flag_dump_vlog2) { + log("Dumping Verilog AST after simplification:\n"); ast->dumpVlog(NULL, " "); log("--- END OF AST DUMP ---\n"); } - if (flag_lib) { + if (flag_nowb && ast->attributes.count("\\whitebox")) { + delete ast->attributes.at("\\whitebox"); + ast->attributes.erase("\\whitebox"); + } + + if (ast->attributes.count("\\lib_whitebox")) { + if (!flag_lib || flag_nowb) { + delete ast->attributes.at("\\lib_whitebox"); + ast->attributes.erase("\\lib_whitebox"); + } else { + if (ast->attributes.count("\\whitebox")) { + delete ast->attributes.at("\\whitebox"); + ast->attributes.erase("\\whitebox"); + } + AstNode *n = ast->attributes.at("\\lib_whitebox"); + ast->attributes["\\whitebox"] = n; + ast->attributes.erase("\\lib_whitebox"); + } + } + + if (!blackbox_module && ast->attributes.count("\\blackbox")) { + AstNode *n = ast->attributes.at("\\blackbox"); + if (n->type != AST_CONSTANT) + log_file_error(ast->filename, ast->linenum, "Got blackbox attribute with non-constant value!\n"); + blackbox_module = n->asBool(); + } + + if (blackbox_module && ast->attributes.count("\\whitebox")) { + AstNode *n = ast->attributes.at("\\whitebox"); + if (n->type != AST_CONSTANT) + log_file_error(ast->filename, ast->linenum, "Got whitebox attribute with non-constant value!\n"); + blackbox_module = !n->asBool(); + } + + if (ast->attributes.count("\\noblackbox")) { + if (blackbox_module) { + AstNode *n = ast->attributes.at("\\noblackbox"); + if (n->type != AST_CONSTANT) + log_file_error(ast->filename, ast->linenum, "Got noblackbox attribute with non-constant value!\n"); + blackbox_module = !n->asBool(); + } + delete ast->attributes.at("\\noblackbox"); + ast->attributes.erase("\\noblackbox"); + } + + if (blackbox_module) + { + if (ast->attributes.count("\\whitebox")) { + delete ast->attributes.at("\\whitebox"); + ast->attributes.erase("\\whitebox"); + } + + if (ast->attributes.count("\\lib_whitebox")) { + delete ast->attributes.at("\\lib_whitebox"); + ast->attributes.erase("\\lib_whitebox"); + } + std::vector<AstNode*> new_children; for (auto child : ast->children) { if (child->type == AST_WIRE && (child->is_input || child->is_output)) { @@ -943,20 +1061,26 @@ static AstModule* process_module(AstNode *ast, bool defer) child->delete_children(); child->children.push_back(AstNode::mkconst_int(0, false, 0)); new_children.push_back(child); + } else if (child->type == AST_CELL && child->children.size() > 0 && child->children[0]->type == AST_CELLTYPE && + (child->children[0]->str == "$specify2" || child->children[0]->str == "$specify3" || child->children[0]->str == "$specrule")) { + new_children.push_back(child); } else { delete child; } } + ast->children.swap(new_children); - ast->attributes["\\blackbox"] = AstNode::mkconst_int(1, false); + + if (ast->attributes.count("\\blackbox") == 0) { + ast->attributes["\\blackbox"] = AstNode::mkconst_int(1, false); + } } ignoreThisSignalsInInitial = RTLIL::SigSpec(); for (auto &attr : ast->attributes) { if (attr.second->type != AST_CONSTANT) - log_error("Attribute `%s' with non-constant value at %s:%d!\n", - attr.first.c_str(), ast->filename.c_str(), ast->linenum); + log_file_error(ast->filename, ast->linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str()); current_module->attributes[attr.first] = attr.second->asAttrConst(); } for (size_t i = 0; i < ast->children.size(); i++) { @@ -980,15 +1104,27 @@ static AstModule* process_module(AstNode *ast, bool defer) ignoreThisSignalsInInitial = RTLIL::SigSpec(); } + else { + for (auto &attr : ast->attributes) { + if (attr.second->type != AST_CONSTANT) + continue; + current_module->attributes[attr.first] = attr.second->asAttrConst(); + } + } + if (ast->type == AST_INTERFACE) + current_module->set_bool_attribute("\\is_interface"); current_module->ast = ast_before_simplify; current_module->nolatches = flag_nolatches; current_module->nomeminit = flag_nomeminit; current_module->nomem2reg = flag_nomem2reg; current_module->mem2reg = flag_mem2reg; + current_module->noblackbox = flag_noblackbox; current_module->lib = flag_lib; + 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(); @@ -1002,27 +1138,32 @@ static AstModule* process_module(AstNode *ast, bool defer) } // 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 dump_vlog, bool dump_rtlil, - bool nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool nooverwrite, bool overwrite, bool defer, bool autowire) +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 pwires, bool nooverwrite, bool overwrite, bool defer, bool autowire) { current_ast = ast; flag_dump_ast1 = dump_ast1; flag_dump_ast2 = dump_ast2; - flag_dump_vlog = dump_vlog; + flag_no_dump_ptr = no_dump_ptr; + flag_dump_vlog1 = dump_vlog1; + flag_dump_vlog2 = dump_vlog2; flag_dump_rtlil = dump_rtlil; flag_nolatches = nolatches; flag_nomeminit = nomeminit; flag_nomem2reg = nomem2reg; flag_mem2reg = mem2reg; + flag_noblackbox = noblackbox; flag_lib = lib; + flag_nowb = nowb; flag_noopt = noopt; flag_icells = icells; + flag_pwires = pwires; flag_autowire = autowire; log_assert(current_ast->type == AST_DESIGN); for (auto it = current_ast->children.begin(); it != current_ast->children.end(); it++) { - if ((*it)->type == AST_MODULE) + if ((*it)->type == AST_MODULE || (*it)->type == AST_INTERFACE) { for (auto n : design->verilog_globals) (*it)->children.push_back(n->clone()); @@ -1035,7 +1176,7 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump } } - if (flag_icells && (*it)->str.substr(0, 2) == "\\$") + if (flag_icells && (*it)->str.compare(0, 2, "\\$") == 0) (*it)->str = (*it)->str.substr(1); if (defer) @@ -1043,9 +1184,8 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump if (design->has((*it)->str)) { RTLIL::Module *existing_mod = design->module((*it)->str); - if (!nooverwrite && !overwrite && !existing_mod->get_bool_attribute("\\blackbox")) { - log_error("Re-definition of module `%s' at %s:%d!\n", - (*it)->str.c_str(), (*it)->filename.c_str(), (*it)->linenum); + if (!nooverwrite && !overwrite && !existing_mod->get_blackbox_attribute()) { + log_file_error((*it)->filename, (*it)->linenum, "Re-definition of module `%s'!\n", (*it)->str.c_str()); } else if (nooverwrite) { log("Ignoring re-definition of module `%s' at %s:%d.\n", (*it)->str.c_str(), (*it)->filename.c_str(), (*it)->linenum); @@ -1074,29 +1214,274 @@ AstModule::~AstModule() delete ast; } + +// An interface port with modport is specified like this: +// <interface_name>.<modport_name> +// This function splits the interface_name from the modport_name, and fails if it is not a valid combination +std::pair<std::string,std::string> AST::split_modport_from_type(std::string name_type) +{ + std::string interface_type = ""; + std::string interface_modport = ""; + size_t ndots = std::count(name_type.begin(), name_type.end(), '.'); + // Separate the interface instance name from any modports: + if (ndots == 0) { // Does not have modport + interface_type = name_type; + } + else { + std::stringstream name_type_stream(name_type); + std::string segment; + std::vector<std::string> seglist; + while(std::getline(name_type_stream, segment, '.')) { + seglist.push_back(segment); + } + if (ndots == 1) { // Has modport + interface_type = seglist[0]; + interface_modport = seglist[1]; + } + else { // Erroneous port type + log_error("More than two '.' in signal port type (%s)\n", name_type.c_str()); + } + } + return std::pair<std::string,std::string>(interface_type, interface_modport); + +} + +AstNode * AST::find_modport(AstNode *intf, std::string name) +{ + for (auto &ch : intf->children) + if (ch->type == AST_MODPORT) + if (ch->str == name) // Modport found + return ch; + return NULL; +} + +// Iterate over all wires in an interface and add them as wires in the AST module: +void AST::explode_interface_port(AstNode *module_ast, RTLIL::Module * intfmodule, std::string intfname, AstNode *modport) +{ + for (auto &wire_it : intfmodule->wires_){ + AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, AstNode::mkconst_int(wire_it.second->width -1, true), AstNode::mkconst_int(0, true))); + std::string origname = log_id(wire_it.first); + std::string newname = intfname + "." + origname; + wire->str = newname; + if (modport != NULL) { + bool found_in_modport = false; + // Search for the current wire in the wire list for the current modport + for (auto &ch : modport->children) { + if (ch->type == AST_MODPORTMEMBER) { + std::string compare_name = "\\" + origname; + if (ch->str == compare_name) { // Found signal. The modport decides whether it is input or output + found_in_modport = true; + wire->is_input = ch->is_input; + wire->is_output = ch->is_output; + break; + } + } + } + if (found_in_modport) { + module_ast->children.push_back(wire); + } + else { // If not found in modport, do not create port + delete wire; + } + } + else { // If no modport, set inout + wire->is_input = true; + wire->is_output = true; + module_ast->children.push_back(wire); + } + } +} + +// When an interface instance is found in a module, the whole RTLIL for the module will be rederived again +// from AST. The interface members are copied into the AST module with the prefix of the interface. +void AstModule::reprocess_module(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Module*> local_interfaces) +{ + loadconfig(); + + bool is_top = false; + AstNode *new_ast = ast->clone(); + for (auto &intf : local_interfaces) { + std::string intfname = intf.first.str(); + RTLIL::Module *intfmodule = intf.second; + for (auto &wire_it : intfmodule->wires_){ + AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, AstNode::mkconst_int(wire_it.second->width -1, true), AstNode::mkconst_int(0, true))); + std::string newname = log_id(wire_it.first); + newname = intfname + "." + newname; + wire->str = newname; + new_ast->children.push_back(wire); + } + } + + AstNode *ast_before_replacing_interface_ports = new_ast->clone(); + + // Explode all interface ports. Note this will only have an effect on 'top + // level' modules. Other sub-modules will have their interface ports + // exploded via the derive(..) function + for (size_t i =0; i<new_ast->children.size(); i++) + { + AstNode *ch2 = new_ast->children[i]; + if (ch2->type == AST_INTERFACEPORT) { // Is an interface port + std::string name_port = ch2->str; // Name of the interface port + if (ch2->children.size() > 0) { + for(size_t j=0; j<ch2->children.size();j++) { + AstNode *ch = ch2->children[j]; + if(ch->type == AST_INTERFACEPORTTYPE) { // Found the AST node containing the type of the interface + std::pair<std::string,std::string> res = split_modport_from_type(ch->str); + std::string interface_type = res.first; + std::string interface_modport = res.second; // Is "", if no modport + if (design->modules_.count(interface_type) > 0) { + // Add a cell to the module corresponding to the interface port such that + // it can further propagated down if needed: + AstNode *celltype_for_intf = new AstNode(AST_CELLTYPE); + celltype_for_intf->str = interface_type; + AstNode *cell_for_intf = new AstNode(AST_CELL, celltype_for_intf); + cell_for_intf->str = name_port + "_inst_from_top_dummy"; + new_ast->children.push_back(cell_for_intf); + + // Get all members of this non-overridden dummy interface instance: + RTLIL::Module *intfmodule = design->modules_[interface_type]; // All interfaces should at this point in time (assuming + // reprocess_module is called from the hierarchy pass) be + // present in design->modules_ + AstModule *ast_module_of_interface = (AstModule*)intfmodule; + std::string interface_modport_compare_str = "\\" + interface_modport; + AstNode *modport = find_modport(ast_module_of_interface->ast, interface_modport_compare_str); // modport == NULL if no modport + // Iterate over all wires in the interface and add them to the module: + explode_interface_port(new_ast, intfmodule, name_port, modport); + } + break; + } + } + } + } + } + + // The old module will be deleted. Rename and mark for deletion: + std::string original_name = this->name.str(); + std::string changed_name = original_name + "_before_replacing_local_interfaces"; + design->rename(this, changed_name); + this->set_bool_attribute("\\to_delete"); + + // Check if the module was the top module. If it was, we need to remove the top attribute and put it on the + // new module. + if (this->get_bool_attribute("\\initial_top")) { + this->attributes.erase("\\initial_top"); + is_top = true; + } + + // Generate RTLIL from AST for the new module and add to the design: + AstModule *newmod = process_module(new_ast, false, ast_before_replacing_interface_ports); + delete(new_ast); + design->add(newmod); + RTLIL::Module* mod = design->module(original_name); + if (is_top) + mod->set_bool_attribute("\\top"); + + // Set the attribute "interfaces_replaced_in_module" so that it does not happen again. + mod->set_bool_attribute("\\interfaces_replaced_in_module"); +} + +// create a new parametric module (when needed) and return the name of the generated module - WITH support for interfaces +// This method is used to explode the interface when the interface is a port of the module (not instantiated inside) +RTLIL::IdString AstModule::derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, dict<RTLIL::IdString, RTLIL::Module*> interfaces, dict<RTLIL::IdString, RTLIL::IdString> modports, bool mayfail) +{ + AstNode *new_ast = NULL; + std::string modname = derive_common(design, parameters, &new_ast, mayfail); + + // Since interfaces themselves may be instantiated with different parameters, + // "modname" must also take those into account, so that unique modules + // are derived for any variant of interface connections: + std::string interf_info = ""; + + bool has_interfaces = false; + for(auto &intf : interfaces) { + interf_info += log_id(intf.second->name); + has_interfaces = true; + } + + if (has_interfaces) + modname += "$interfaces$" + interf_info; + + + if (!design->has(modname)) { + new_ast->str = modname; + + // Iterate over all interfaces which are ports in this module: + for(auto &intf : interfaces) { + RTLIL::Module * intfmodule = intf.second; + std::string intfname = intf.first.str(); + // Check if a modport applies for the interface port: + AstNode *modport = NULL; + if (modports.count(intfname) > 0) { + std::string interface_modport = modports.at(intfname).str(); + AstModule *ast_module_of_interface = (AstModule*)intfmodule; + AstNode *ast_node_of_interface = ast_module_of_interface->ast; + modport = find_modport(ast_node_of_interface, interface_modport); + } + // Iterate over all wires in the interface and add them to the module: + explode_interface_port(new_ast, intfmodule, intfname, modport); + } + + design->add(process_module(new_ast, false)); + design->module(modname)->check(); + + RTLIL::Module* mod = design->module(modname); + + // Now that the interfaces have been exploded, we can delete the dummy port related to every interface. + for(auto &intf : interfaces) { + if(mod->wires_.count(intf.first)) { + mod->wires_.erase(intf.first); + mod->fixup_ports(); + // We copy the cell of the interface to the sub-module such that it can further be found if it is propagated + // down to sub-sub-modules etc. + RTLIL::Cell * new_subcell = mod->addCell(intf.first, intf.second->name); + new_subcell->set_bool_attribute("\\is_interface"); + } + else { + log_error("No port with matching name found (%s) in %s. Stopping\n", log_id(intf.first), modname.c_str()); + } + } + + // If any interfaces were replaced, set the attribute 'interfaces_replaced_in_module': + if (interfaces.size() > 0) { + mod->set_bool_attribute("\\interfaces_replaced_in_module"); + } + + } else { + log("Found cached RTLIL representation for module `%s'.\n", modname.c_str()); + } + + delete new_ast; + return modname; +} + +// create a new parametric module (when needed) and return the name of the generated module - without support for interfaces +RTLIL::IdString AstModule::derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, bool mayfail) +{ + AstNode *new_ast = NULL; + std::string modname = derive_common(design, parameters, &new_ast, mayfail); + + if (!design->has(modname)) { + new_ast->str = modname; + design->add(process_module(new_ast, false)); + design->module(modname)->check(); + } else { + log("Found cached RTLIL representation for module `%s'.\n", modname.c_str()); + } + + delete new_ast; + return modname; +} + // create a new parametric module (when needed) and return the name of the generated module -RTLIL::IdString AstModule::derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, bool) +std::string AstModule::derive_common(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, AstNode **new_ast_out, bool) { std::string stripped_name = name.str(); - if (stripped_name.substr(0, 9) == "$abstract") + if (stripped_name.compare(0, 9, "$abstract") == 0) stripped_name = stripped_name.substr(9); log_header(design, "Executing AST frontend in derive mode using pre-parsed AST for module `%s'.\n", stripped_name.c_str()); - - current_ast = NULL; - flag_dump_ast1 = false; - flag_dump_ast2 = false; - flag_dump_vlog = false; - flag_nolatches = nolatches; - flag_nomeminit = nomeminit; - flag_nomem2reg = nomem2reg; - flag_mem2reg = mem2reg; - flag_lib = lib; - flag_noopt = noopt; - flag_icells = icells; - flag_autowire = autowire; - use_internal_line_num(); + loadconfig(); std::string para_info; AstNode *new_ast = ast->clone(); @@ -1114,7 +1499,10 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, dict<RTLIL::IdString, R rewrite_parameter: para_info += stringf("%s=%s", child->str.c_str(), log_signal(RTLIL::SigSpec(parameters[para_id]))); delete child->children.at(0); - if ((parameters[para_id].flags & RTLIL::CONST_FLAG_STRING) != 0) + if ((parameters[para_id].flags & RTLIL::CONST_FLAG_REAL) != 0) { + child->children[0] = new AstNode(AST_REALVALUE); + child->children[0]->realvalue = std::stod(parameters[para_id].decode_string()); + } else if ((parameters[para_id].flags & RTLIL::CONST_FLAG_STRING) != 0) child->children[0] = AstNode::mkconst_str(parameters[para_id].decode_string()); else child->children[0] = AstNode::mkconst_bits(parameters[para_id].bits, (parameters[para_id].flags & RTLIL::CONST_FLAG_SIGNED) != 0); @@ -1147,15 +1535,8 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, dict<RTLIL::IdString, R else modname = "$paramod" + stripped_name + para_info; - if (!design->has(modname)) { - new_ast->str = modname; - design->add(process_module(new_ast, false)); - design->module(modname)->check(); - } else { - log("Found cached RTLIL representation for module `%s'.\n", modname.c_str()); - } - delete new_ast; + (*new_ast_out) = new_ast; return modname; } @@ -1170,14 +1551,38 @@ RTLIL::Module *AstModule::clone() const new_mod->nomeminit = nomeminit; new_mod->nomem2reg = nomem2reg; new_mod->mem2reg = mem2reg; + new_mod->noblackbox = noblackbox; new_mod->lib = lib; + new_mod->nowb = nowb; new_mod->noopt = noopt; new_mod->icells = icells; + new_mod->pwires = pwires; new_mod->autowire = autowire; return new_mod; } +void AstModule::loadconfig() const +{ + current_ast = NULL; + flag_dump_ast1 = false; + flag_dump_ast2 = false; + flag_dump_vlog1 = false; + flag_dump_vlog2 = false; + flag_nolatches = nolatches; + flag_nomeminit = nomeminit; + flag_nomem2reg = nomem2reg; + flag_mem2reg = mem2reg; + flag_noblackbox = noblackbox; + flag_lib = lib; + flag_nowb = nowb; + flag_noopt = noopt; + flag_icells = icells; + flag_pwires = pwires; + flag_autowire = autowire; + use_internal_line_num(); +} + // internal dummy line number callbacks namespace { int internal_line_num; @@ -1197,4 +1602,3 @@ void AST::use_internal_line_num() } YOSYS_NAMESPACE_END - diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index 756629aca..93fee913e 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -1,4 +1,4 @@ -/* +/* -*- c++ -*- * yosys -- Yosys Open SYnthesis Suite * * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> @@ -137,11 +137,17 @@ namespace AST AST_GENIF, AST_GENCASE, AST_GENBLOCK, - + AST_TECALL, + AST_POSEDGE, AST_NEGEDGE, AST_EDGE, + AST_INTERFACE, + AST_INTERFACEPORT, + AST_INTERFACEPORTTYPE, + AST_MODPORT, + AST_MODPORTMEMBER, AST_PACKAGE }; @@ -168,7 +174,7 @@ namespace AST // node content - most of it is unused in most node types std::string str; std::vector<RTLIL::State> bits; - bool is_input, is_output, is_reg, is_signed, is_string, range_valid, range_swapped; + 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; @@ -209,6 +215,8 @@ namespace AST MEM2REG_FL_SET_ASYNC = 0x00000800, MEM2REG_FL_EQ2 = 0x00001000, MEM2REG_FL_CMPLX_LHS = 0x00002000, + MEM2REG_FL_CONST_LHS = 0x00004000, + MEM2REG_FL_VAR_LHS = 0x00008000, /* proc flags */ MEM2REG_FL_EQ1 = 0x01000000, @@ -232,6 +240,7 @@ namespace AST bool has_const_only_constructs(bool &recommend_const_eval); void replace_variables(std::map<std::string, varinfo_t> &variables, AstNode *fcall); AstNode *eval_const_function(AstNode *fcall); + bool is_simple_const_expr(); // create a human-readable text representation of the AST (for debugging) void dumpAst(FILE *f, std::string indent) const; @@ -254,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<RTLIL::State> &v, bool is_signed, bool is_unsized); static AstNode *mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signed); static AstNode *mkconst_str(const std::vector<RTLIL::State> &v); static AstNode *mkconst_str(const std::string &str); @@ -261,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); @@ -274,17 +285,21 @@ 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 dump_vlog, bool dump_rtlil, bool nolatches, bool nomeminit, - bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool nooverwrite, bool overwrite, bool defer, bool autowire); + 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 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, lib, noopt, icells, autowire; - virtual ~AstModule(); - virtual RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, bool mayfail); - virtual RTLIL::Module *clone() const; + bool nolatches, nomeminit, nomem2reg, mem2reg, noblackbox, lib, nowb, noopt, icells, pwires, autowire; + ~AstModule() YS_OVERRIDE; + RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, bool mayfail) YS_OVERRIDE; + RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, dict<RTLIL::IdString, RTLIL::Module*> interfaces, dict<RTLIL::IdString, RTLIL::IdString> modports, bool mayfail) YS_OVERRIDE; + std::string derive_common(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, AstNode **new_ast_out, bool mayfail); + void reprocess_module(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Module *> local_interfaces) YS_OVERRIDE; + RTLIL::Module *clone() const YS_OVERRIDE; + void loadconfig() const; }; // this must be set by the language frontend before parsing the sources @@ -300,13 +315,18 @@ namespace AST // call a DPI function AstNode *dpi_call(const std::string &rtype, const std::string &fname, const std::vector<std::string> &argtypes, const std::vector<AstNode*> &args); + + // Helper functions related to handling SystemVerilog interfaces + std::pair<std::string,std::string> split_modport_from_type(std::string name_type); + AstNode * find_modport(AstNode *intf, std::string name); + void explode_interface_port(AstNode *module_ast, RTLIL::Module * intfmodule, std::string intfname, AstNode *modport); } namespace AST_INTERNAL { // internal state variables - extern bool flag_dump_ast1, flag_dump_ast2, flag_dump_rtlil, flag_nolatches, flag_nomeminit; - extern bool flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire; + 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_pwires, flag_autowire; extern AST::AstNode *current_ast, *current_ast_mod; extern std::map<std::string, AST::AstNode*> current_scope; extern const dict<RTLIL::SigBit, RTLIL::SigBit> *genRTLIL_subst_ptr; diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index d9f0039af..407a34472 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -55,8 +55,7 @@ static RTLIL::SigSpec uniop2rtlil(AstNode *that, std::string type, int result_wi if (gen_attributes) for (auto &attr : that->attributes) { if (attr.second->type != AST_CONSTANT) - log_error("Attribute `%s' with non-constant value at %s:%d!\n", - attr.first.c_str(), that->filename.c_str(), that->linenum); + log_file_error(that->filename, that->linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str()); cell->attributes[attr.first] = attr.second->asAttrConst(); } @@ -89,8 +88,7 @@ static void widthExtend(AstNode *that, RTLIL::SigSpec &sig, int width, bool is_s if (that != NULL) for (auto &attr : that->attributes) { if (attr.second->type != AST_CONSTANT) - log_error("Attribute `%s' with non-constant value at %s:%d!\n", - attr.first.c_str(), that->filename.c_str(), that->linenum); + log_file_error(that->filename, that->linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str()); cell->attributes[attr.first] = attr.second->asAttrConst(); } @@ -117,8 +115,7 @@ static RTLIL::SigSpec binop2rtlil(AstNode *that, std::string type, int result_wi for (auto &attr : that->attributes) { if (attr.second->type != AST_CONSTANT) - log_error("Attribute `%s' with non-constant value at %s:%d!\n", - attr.first.c_str(), that->filename.c_str(), that->linenum); + log_file_error(that->filename, that->linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str()); cell->attributes[attr.first] = attr.second->asAttrConst(); } @@ -152,8 +149,7 @@ static RTLIL::SigSpec mux2rtlil(AstNode *that, const RTLIL::SigSpec &cond, const for (auto &attr : that->attributes) { if (attr.second->type != AST_CONSTANT) - log_error("Attribute `%s' with non-constant value at %s:%d!\n", - attr.first.c_str(), that->filename.c_str(), that->linenum); + log_file_error(that->filename, that->linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str()); cell->attributes[attr.first] = attr.second->asAttrConst(); } @@ -207,8 +203,8 @@ struct AST_INTERNAL::ProcessGenerator proc->name = stringf("$proc$%s:%d$%d", always->filename.c_str(), always->linenum, autoidx++); for (auto &attr : always->attributes) { if (attr.second->type != AST_CONSTANT) - log_error("Attribute `%s' with non-constant value at %s:%d!\n", - attr.first.c_str(), always->filename.c_str(), always->linenum); + log_file_error(always->filename, always->linenum, "Attribute `%s' with non-constant value!\n", + attr.first.c_str()); proc->attributes[attr.first] = attr.second->asAttrConst(); } current_module->processes[proc->name] = proc; @@ -238,7 +234,7 @@ struct AST_INTERNAL::ProcessGenerator if (found_anyedge_syncs) { if (found_global_syncs) - log_error("Found non-synthesizable event list at %s:%d!\n", always->filename.c_str(), always->linenum); + log_file_error(always->filename, always->linenum, "Found non-synthesizable event list!\n"); log("Note: Assuming pure combinatorial block at %s:%d in\n", always->filename.c_str(), always->linenum); log("compliance with IEC 62142(E):2005 / IEEE Std. 1364.1(E):2002. Recommending\n"); log("use of @* instead of @(...) for better match of synthesis and simulation.\n"); @@ -253,12 +249,12 @@ struct AST_INTERNAL::ProcessGenerator continue; found_clocked_sync = true; if (found_global_syncs || found_anyedge_syncs) - log_error("Found non-synthesizable event list at %s:%d!\n", always->filename.c_str(), always->linenum); + log_file_error(always->filename, always->linenum, "Found non-synthesizable event list!\n"); RTLIL::SyncRule *syncrule = new RTLIL::SyncRule; syncrule->type = child->type == AST_POSEDGE ? RTLIL::STp : RTLIL::STn; syncrule->signal = child->children[0]->genRTLIL(); if (GetSize(syncrule->signal) != 1) - log_error("Found posedge/negedge event on a signal that is not 1 bit wide at %s:%d!\n", always->filename.c_str(), always->linenum); + log_file_error(always->filename, always->linenum, "Found posedge/negedge event on a signal that is not 1 bit wide!\n"); addChunkActions(syncrule->actions, subst_lvalue_from, subst_lvalue_to, true); proc->syncs.push_back(syncrule); } @@ -480,8 +476,7 @@ struct AST_INTERNAL::ProcessGenerator for (auto &attr : ast->attributes) { if (attr.second->type != AST_CONSTANT) - log_error("Attribute `%s' with non-constant value at %s:%d!\n", - attr.first.c_str(), ast->filename.c_str(), ast->linenum); + log_file_error(ast->filename, ast->linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str()); sw->attributes[attr.first] = attr.second->asAttrConst(); } @@ -509,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) { @@ -530,7 +526,16 @@ struct AST_INTERNAL::ProcessGenerator } if (last_generated_case != NULL && ast->get_bool_attribute("\\full_case") && default_case == NULL) { + #if 0 + // this is a valid transformation, but as optimization it is premature. + // better: add a default case that assigns 'x' to everything, and let later + // optimizations take care of the rest last_generated_case->compare.clear(); + #else + default_case = new RTLIL::CaseRule; + addChunkActions(default_case->actions, this_case_eq_ltemp, SigSpec(State::Sx, GetSize(this_case_eq_rvalue))); + sw->cases.push_back(default_case); + #endif } else { if (default_case == NULL) { default_case = new RTLIL::CaseRule; @@ -549,12 +554,16 @@ struct AST_INTERNAL::ProcessGenerator break; case AST_WIRE: - log_error("Found wire declaration in block without label at at %s:%d!\n", ast->filename.c_str(), ast->linenum); + log_file_error(ast->filename, ast->linenum, "Found reg declaration in block without label!\n"); + break; + + case AST_ASSIGN: + log_file_error(ast->filename, ast->linenum, "Found continous assignment in always/initial block!\n"); break; case AST_PARAMETER: case AST_LOCALPARAM: - log_error("Found parameter declaration in block without label at at %s:%d!\n", ast->filename.c_str(), ast->linenum); + log_file_error(ast->filename, ast->linenum, "Found parameter declaration in block without label!\n"); break; case AST_NONE: @@ -602,7 +611,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun if (id_ast == NULL && current_scope.count(str)) id_ast = current_scope.at(str); if (!id_ast) - log_error("Failed to resolve identifier %s for width detection at %s:%d!\n", str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Failed to resolve identifier %s for width detection!\n", str.c_str()); if (id_ast->type == AST_PARAMETER || id_ast->type == AST_LOCALPARAM) { if (id_ast->children.size() > 1 && id_ast->children[1]->range_valid) { this_width = id_ast->children[1]->range_left - id_ast->children[1]->range_right + 1; @@ -612,7 +621,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun if (id_ast->children[0]->type == AST_CONSTANT) this_width = id_ast->children[0]->bits.size(); else - log_error("Failed to detect width for parameter %s at %s:%d!\n", str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Failed to detect width for parameter %s!\n", str.c_str()); if (children.size() != 0) range = children[0]; } else if (id_ast->type == AST_WIRE || id_ast->type == AST_AUTOWIRE) { @@ -624,7 +633,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun // log("---\n"); // id_ast->dumpAst(NULL, "decl> "); // dumpAst(NULL, "ref> "); - log_error("Failed to detect width of signal access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Failed to detect width of signal access `%s'!\n", str.c_str()); } } else { this_width = id_ast->range_left - id_ast->range_right + 1; @@ -635,10 +644,12 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun this_width = 32; } else if (id_ast->type == AST_MEMORY) { if (!id_ast->children[0]->range_valid) - log_error("Failed to detect width of memory access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Failed to detect width of memory access `%s'!\n", str.c_str()); this_width = id_ast->children[0]->range_left - id_ast->children[0]->range_right + 1; + if (children.size() > 1) + range = children[1]; } else - log_error("Failed to detect width for identifier %s at %s:%d!\n", str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Failed to detect width for identifier %s!\n", str.c_str()); if (range) { if (range->children.size() == 1) this_width = 1; @@ -648,9 +659,8 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun while (left_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { } while (right_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { } if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT) - log_error("Unsupported expression on dynamic range select on signal `%s' at %s:%d!\n", - str.c_str(), filename.c_str(), linenum); - this_width = left_at_zero_ast->integer - right_at_zero_ast->integer + 1; + log_file_error(filename, linenum, "Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str()); + this_width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1; delete left_at_zero_ast; delete right_at_zero_ast; } else @@ -665,7 +675,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun case AST_TO_BITS: while (children[0]->simplify(true, false, false, 1, -1, false, false) == true) { } if (children[0]->type != AST_CONSTANT) - log_error("Left operand of tobits expression is not constant at %s:%d!\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Left operand of tobits expression is not constant!\n"); children[1]->detectSignWidthWorker(sub_width_hint, sign_hint); width_hint = max(width_hint, children[0]->bitsAsConst().as_int()); break; @@ -693,7 +703,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun case AST_REPLICATE: while (children[0]->simplify(true, false, false, 1, -1, false, true) == true) { } if (children[0]->type != AST_CONSTANT) - log_error("Left operand of replicate expression is not constant at %s:%d!\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Left operand of replicate expression is not constant!\n"); children[1]->detectSignWidthWorker(sub_width_hint, sub_sign_hint); width_hint = max(width_hint, children[0]->bitsAsConst().as_int() * sub_width_hint); sign_hint = false; @@ -767,7 +777,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun if (!id2ast->is_signed) sign_hint = false; if (!id2ast->children[0]->range_valid) - log_error("Failed to detect width of memory access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Failed to detect width of memory access `%s'!\n", str.c_str()); this_width = id2ast->children[0]->range_left - id2ast->children[0]->range_right + 1; width_hint = max(width_hint, this_width); break; @@ -777,8 +787,8 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun if (GetSize(children) == 1) { while (children[0]->simplify(true, false, false, 1, -1, false, true) == true) { } if (children[0]->type != AST_CONSTANT) - log_error("System function %s called with non-const argument at %s:%d!\n", - RTLIL::unescape_id(str).c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "System function %s called with non-const argument!\n", + RTLIL::unescape_id(str).c_str()); width_hint = max(width_hint, int(children[0]->asInt(true))); } break; @@ -798,9 +808,8 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun // everything should have been handled above -> print error if not. default: for (auto f : log_files) - current_ast->dumpAst(f, "verilog-ast> "); - log_error("Don't know how to detect sign and width for %s node at %s:%d!\n", - type2str(type).c_str(), filename.c_str(), linenum); + current_ast_mod->dumpAst(f, "verilog-ast> "); + log_file_error(filename, linenum, "Don't know how to detect sign and width for %s node!\n", type2str(type).c_str()); } if (*found_real) @@ -845,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: @@ -853,23 +861,71 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) case AST_GENIF: case AST_GENCASE: case AST_PACKAGE: + case AST_MODPORT: + case AST_MODPORTMEMBER: + break; + case AST_INTERFACEPORT: { + // If a port in a module with unknown type is found, mark it with the attribute 'is_interface' + // This is used by the hierarchy pass to know when it can replace interface connection with the individual + // signals. + RTLIL::Wire *wire = current_module->addWire(str, 1); + wire->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum); + wire->start_offset = 0; + wire->port_id = port_id; + wire->port_input = true; + wire->port_output = true; + wire->set_bool_attribute("\\is_interface"); + if (children.size() > 0) { + for(size_t i=0; i<children.size();i++) { + if(children[i]->type == AST_INTERFACEPORTTYPE) { + std::pair<std::string,std::string> res = AST::split_modport_from_type(children[i]->str); + wire->attributes["\\interface_type"] = res.first; + if (res.second != "") + wire->attributes["\\interface_modport"] = res.second; + break; + } + } + } + wire->upto = 0; + } + break; + case AST_INTERFACEPORTTYPE: break; // 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 case AST_WIRE: { if (current_module->wires_.count(str) != 0) - log_error("Re-definition of signal `%s' at %s:%d!\n", - str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Re-definition of signal `%s'!\n", str.c_str()); if (!range_valid) - log_error("Signal `%s' with non-constant width at %s:%d!\n", - str.c_str(), filename.c_str(), linenum); + 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); @@ -881,26 +937,26 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) for (auto &attr : attributes) { if (attr.second->type != AST_CONSTANT) - log_error("Attribute `%s' with non-constant value at %s:%d!\n", - attr.first.c_str(), filename.c_str(), linenum); + 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; // create an RTLIL::Memory for an AST_MEMORY node case AST_MEMORY: { if (current_module->memories.count(str) != 0) - log_error("Re-definition of memory `%s' at %s:%d!\n", - str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Re-definition of memory `%s'!\n", str.c_str()); log_assert(children.size() >= 2); log_assert(children[0]->type == AST_RANGE); log_assert(children[1]->type == AST_RANGE); if (!children[0]->range_valid || !children[1]->range_valid) - log_error("Memory `%s' with non-constant width or size at %s:%d!\n", - str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Memory `%s' with non-constant width or size!\n", str.c_str()); RTLIL::Memory *memory = new RTLIL::Memory; memory->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum); @@ -917,8 +973,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) for (auto &attr : attributes) { if (attr.second->type != AST_CONSTANT) - log_error("Attribute `%s' with non-constant value at %s:%d!\n", - attr.first.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str()); memory->attributes[attr.first] = attr.second->asAttrConst(); } } @@ -926,19 +981,22 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) // simply return the corresponding RTLIL::SigSpec for an AST_CONSTANT node case AST_CONSTANT: + case AST_REALVALUE: { if (width_hint < 0) detectSignWidth(width_hint, sign_hint); - is_signed = sign_hint; - return RTLIL::SigSpec(bitsAsConst()); - } - case AST_REALVALUE: - { + 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_warning("converting real value %e to binary %s at %s:%d.\n", - realvalue, log_signal(sig), filename.c_str(), linenum); + log_file_warning(filename, linenum, "converting real value %e to binary %s.\n", realvalue, log_signal(sig)); return sig; } @@ -949,6 +1007,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) { RTLIL::Wire *wire = NULL; RTLIL::SigChunk chunk; + bool is_interface = false; int add_undef_bits_msb = 0; int add_undef_bits_lsb = 0; @@ -958,25 +1017,48 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) wire->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum); wire->name = str; if (flag_autowire) - log_warning("Identifier `%s' is implicitly declared at %s:%d.\n", str.c_str(), filename.c_str(), linenum); + log_file_warning(filename, linenum, "Identifier `%s' is implicitly declared.\n", str.c_str()); else - log_error("Identifier `%s' is implicitly declared at %s:%d and `default_nettype is set to none.\n", str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Identifier `%s' is implicitly declared and `default_nettype is set to none.\n", str.c_str()); } else if (id2ast->type == AST_PARAMETER || id2ast->type == AST_LOCALPARAM) { if (id2ast->children[0]->type != AST_CONSTANT) - log_error("Parameter %s does not evaluate to constant value at %s:%d!\n", - str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Parameter %s does not evaluate to constant value!\n", str.c_str()); chunk = RTLIL::Const(id2ast->children[0]->bits); goto use_const_chunk; } - else if (!id2ast || (id2ast->type != AST_WIRE && id2ast->type != AST_AUTOWIRE && - id2ast->type != AST_MEMORY) || current_module->wires_.count(str) == 0) - log_error("Identifier `%s' doesn't map to any signal at %s:%d!\n", - str.c_str(), filename.c_str(), linenum); + else if (id2ast && (id2ast->type == AST_WIRE || id2ast->type == AST_AUTOWIRE || id2ast->type == AST_MEMORY) && current_module->wires_.count(str) != 0) { + RTLIL::Wire *current_wire = current_module->wire(str); + if (current_wire->get_bool_attribute("\\is_interface")) + is_interface = true; + // Ignore + } + // If an identifier is found that is not already known, assume that it is an interface: + else if (1) { // FIXME: Check if sv_mode first? + is_interface = true; + } + else { + log_file_error(filename, linenum, "Identifier `%s' doesn't map to any signal!\n", str.c_str()); + } if (id2ast->type == AST_MEMORY) - log_error("Identifier `%s' does map to an unexpanded memory at %s:%d!\n", - str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Identifier `%s' does map to an unexpanded memory!\n", str.c_str()); + + // If identifier is an interface, create a RTLIL::SigSpec with a dummy wire with a attribute called 'is_interface' + // This makes it possible for the hierarchy pass to see what are interface connections and then replace them + // with the individual signals: + if (is_interface) { + RTLIL::Wire *dummy_wire; + std::string dummy_wire_name = "$dummywireforinterface" + str; + if (current_module->wires_.count(dummy_wire_name)) + dummy_wire = current_module->wires_[dummy_wire_name]; + else { + dummy_wire = current_module->addWire(dummy_wire_name); + dummy_wire->set_bool_attribute("\\is_interface"); + } + RTLIL::SigSpec tmp = RTLIL::SigSpec(dummy_wire); + return tmp; + } wire = current_module->wires_[str]; chunk.wire = wire; @@ -985,7 +1067,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) use_const_chunk: if (children.size() != 0) { - log_assert(children[0]->type == AST_RANGE); + if (children[0]->type != AST_RANGE) + log_file_error(filename, linenum, "Single range expected.\n"); int source_width = id2ast->range_left - id2ast->range_right + 1; int source_offset = id2ast->range_right; if (!children[0]->range_valid) { @@ -994,9 +1077,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) while (left_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { } while (right_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { } if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT) - log_error("Unsupported expression on dynamic range select on signal `%s' at %s:%d!\n", - str.c_str(), filename.c_str(), linenum); - int width = left_at_zero_ast->integer - right_at_zero_ast->integer + 1; + log_file_error(filename, linenum, "Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str()); + int width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1; AstNode *fake_ast = new AstNode(AST_NONE, clone(), children[0]->children.size() >= 2 ? children[0]->children[1]->clone() : children[0]->children[0]->clone()); fake_ast->children[0]->delete_children(); @@ -1023,11 +1105,11 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) chunk.offset = (id2ast->range_left - id2ast->range_right + 1) - (chunk.offset + chunk.width); if (chunk.offset >= source_width || chunk.offset + chunk.width < 0) { if (chunk.width == 1) - log_warning("Range select out of bounds on signal `%s' at %s:%d: Setting result bit to undef.\n", - str.c_str(), filename.c_str(), linenum); + log_file_warning(filename, linenum, "Range select out of bounds on signal `%s': Setting result bit to undef.\n", + str.c_str()); else - log_warning("Range select out of bounds on signal `%s' at %s:%d: Setting all %d result bits to undef.\n", - str.c_str(), filename.c_str(), linenum, chunk.width); + log_file_warning(filename, linenum, "Range select [%d:%d] out of bounds on signal `%s': Setting all %d result bits to undef.\n", + children[0]->range_left, children[0]->range_right, str.c_str(), chunk.width); chunk = RTLIL::SigChunk(RTLIL::State::Sx, chunk.width); } else { if (chunk.width + chunk.offset > source_width) { @@ -1040,11 +1122,11 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) chunk.offset += add_undef_bits_lsb; } if (add_undef_bits_lsb) - log_warning("Range select out of bounds on signal `%s' at %s:%d: Setting %d LSB bits to undef.\n", - str.c_str(), filename.c_str(), linenum, add_undef_bits_lsb); + log_file_warning(filename, linenum, "Range [%d:%d] select out of bounds on signal `%s': Setting %d LSB bits to undef.\n", + children[0]->range_left, children[0]->range_right, str.c_str(), add_undef_bits_lsb); if (add_undef_bits_msb) - log_warning("Range select out of bounds on signal `%s' at %s:%d: Setting %d MSB bits to undef.\n", - str.c_str(), filename.c_str(), linenum, add_undef_bits_msb); + log_file_warning(filename, linenum, "Range [%d:%d] select out of bounds on signal `%s': Setting %d MSB bits to undef.\n", + children[0]->range_left, children[0]->range_right, str.c_str(), add_undef_bits_msb); } } } @@ -1083,7 +1165,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) RTLIL::SigSpec left = children[0]->genRTLIL(); RTLIL::SigSpec right = children[1]->genRTLIL(); if (!left.is_fully_const()) - log_error("Left operand of replicate expression is not constant at %s:%d!\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Left operand of replicate expression is not constant!\n"); int count = left.as_int(); RTLIL::SigSpec sig; for (int i = 0; i < count; i++) @@ -1322,7 +1404,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) int num_words = 1; if (type == AST_MEMINIT) { if (children[2]->type != AST_CONSTANT) - log_error("Memory init with non-constant word count at %s:%d!\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Memory init with non-constant word count!\n"); num_words = int(children[2]->asInt(false)); cell->parameters["\\WORDS"] = RTLIL::Const(num_words); } @@ -1371,16 +1453,21 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) if (GetSize(en) != 1) en = current_module->ReduceBool(NEW_ID, en); - std::stringstream sstr; - sstr << celltype << "$" << filename << ":" << linenum << "$" << (autoidx++); + IdString cellname; + if (str.empty()) { + std::stringstream sstr; + sstr << celltype << "$" << filename << ":" << linenum << "$" << (autoidx++); + cellname = sstr.str(); + } else { + cellname = str; + } - RTLIL::Cell *cell = current_module->addCell(sstr.str(), celltype); + RTLIL::Cell *cell = current_module->addCell(cellname, celltype); cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum); for (auto &attr : attributes) { if (attr.second->type != AST_CONSTANT) - log_error("Attribute `%s' with non-constant value at %s:%d!\n", - attr.first.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str()); cell->attributes[attr.first] = attr.second->asAttrConst(); } @@ -1401,9 +1488,9 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) new_left.append(left[i]); new_right.append(right[i]); } - log_warning("Ignoring assignment to constant bits at %s:%d:\n" + log_file_warning(filename, linenum, "Ignoring assignment to constant bits:\n" " old assignment: %s = %s\n new assignment: %s = %s.\n", - filename.c_str(), linenum, log_signal(left), log_signal(right), + log_signal(left), log_signal(right), log_signal(new_left), log_signal(new_right)); left = new_left; right = new_right; @@ -1418,34 +1505,37 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) int port_counter = 0, para_counter = 0; if (current_module->count_id(str) != 0) - log_error("Re-definition of cell `%s' at %s:%d!\n", - str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Re-definition of cell `%s'!\n", str.c_str()); RTLIL::Cell *cell = current_module->addCell(str, ""); cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum); + // Set attribute 'module_not_derived' which will be cleared again after the hierarchy pass + cell->set_bool_attribute("\\module_not_derived"); for (auto it = children.begin(); it != children.end(); it++) { AstNode *child = *it; if (child->type == AST_CELLTYPE) { cell->type = child->str; - if (flag_icells && cell->type.substr(0, 2) == "\\$") + if (flag_icells && cell->type.begins_with("\\$")) cell->type = cell->type.substr(1); continue; } if (child->type == AST_PARASET) { + int extra_const_flags = 0; IdString paraname = child->str.empty() ? stringf("$%d", ++para_counter) : child->str; if (child->children[0]->type == AST_REALVALUE) { - log_warning("Replacing floating point parameter %s.%s = %f with string at %s:%d.\n", - log_id(cell), log_id(paraname), child->children[0]->realvalue, - filename.c_str(), linenum); + log_file_warning(filename, linenum, "Replacing floating point parameter %s.%s = %f with string.\n", + log_id(cell), log_id(paraname), child->children[0]->realvalue); + extra_const_flags = RTLIL::CONST_FLAG_REAL; auto strnode = AstNode::mkconst_str(stringf("%f", child->children[0]->realvalue)); strnode->cloneInto(child->children[0]); delete strnode; } if (child->children[0]->type != AST_CONSTANT) - log_error("Parameter %s.%s with non-constant value at %s:%d!\n", - log_id(cell), log_id(paraname), filename.c_str(), linenum); + log_file_error(filename, linenum, "Parameter %s.%s with non-constant value!\n", + log_id(cell), log_id(paraname)); cell->parameters[paraname] = child->children[0]->asParaConst(); + cell->parameters[paraname].flags |= extra_const_flags; continue; } if (child->type == AST_ARGUMENT) { @@ -1465,10 +1555,29 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) } for (auto &attr : attributes) { if (attr.second->type != AST_CONSTANT) - log_error("Attribute `%s' with non-constant value at %s:%d!\n", - attr.first.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Attribute `%s' with non-constant value.\n", attr.first.c_str()); cell->attributes[attr.first] = attr.second->asAttrConst(); } + if (cell->type.in("$specify2", "$specify3")) { + int src_width = GetSize(cell->getPort("\\SRC")); + int dst_width = GetSize(cell->getPort("\\DST")); + bool full = cell->getParam("\\FULL").as_bool(); + if (!full && src_width != dst_width) + log_file_error(filename, linenum, "Parallel specify SRC width does not match DST width.\n"); + if (cell->type == "$specify3") { + int dat_width = GetSize(cell->getPort("\\DAT")); + if (dat_width != dst_width) + log_file_error(filename, linenum, "Specify DAT width does not match DST width.\n"); + } + cell->setParam("\\SRC_WIDTH", Const(src_width)); + cell->setParam("\\DST_WIDTH", Const(dst_width)); + } + if (cell->type == "$specrule") { + int src_width = GetSize(cell->getPort("\\SRC")); + int dst_width = GetSize(cell->getPort("\\DST")); + cell->setParam("\\SRC_WIDTH", Const(src_width)); + cell->setParam("\\DST_WIDTH", Const(dst_width)); + } } break; @@ -1486,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") { @@ -1493,19 +1633,18 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) int width = width_hint; if (GetSize(children) > 1) - log_error("System function %s got %d arguments, expected 1 or 0 at %s:%d.\n", - RTLIL::unescape_id(str).c_str(), GetSize(children), filename.c_str(), linenum); + log_file_error(filename, linenum, "System function %s got %d arguments, expected 1 or 0.\n", + RTLIL::unescape_id(str).c_str(), GetSize(children)); if (GetSize(children) == 1) { if (children[0]->type != AST_CONSTANT) - log_error("System function %s called with non-const argument at %s:%d!\n", - RTLIL::unescape_id(str).c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "System function %s called with non-const argument!\n", + RTLIL::unescape_id(str).c_str()); width = children[0]->asInt(true); } if (width <= 0) - log_error("Failed to detect width of %s at %s:%d!\n", - RTLIL::unescape_id(str).c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Failed to detect width of %s!\n", RTLIL::unescape_id(str).c_str()); Cell *cell = current_module->addCell(myid, str.substr(1)); cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum); @@ -1514,7 +1653,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) if (attributes.count("\\reg")) { auto &attr = attributes.at("\\reg"); if (attr->type != AST_CONSTANT) - log_error("Attribute `reg' with non-constant value at %s:%d!\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Attribute `reg' with non-constant value!\n"); cell->attributes["\\reg"] = attr->asAttrConst(); } @@ -1530,10 +1669,9 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) // everything should have been handled above -> print error if not. default: for (auto f : log_files) - current_ast->dumpAst(f, "verilog-ast> "); + current_ast_mod->dumpAst(f, "verilog-ast> "); type_name = type2str(type); - log_error("Don't know how to generate RTLIL code for %s node at %s:%d!\n", - type_name.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Don't know how to generate RTLIL code for %s node!\n", type_name.c_str()); } return RTLIL::SigSpec(); @@ -1563,4 +1701,3 @@ RTLIL::SigSpec AstNode::genWidthRTLIL(int width, const dict<RTLIL::SigBit, RTLIL } YOSYS_NAMESPACE_END - diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index a16fdfeeb..b1ee22f42 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -50,7 +50,6 @@ using namespace AST_INTERNAL; bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, int width_hint, bool sign_hint, bool in_param) { static int recursion_counter = 0; - static pair<string, int> last_blocking_assignment_warn; static bool deep_recursion_warning = false; if (recursion_counter++ == 1000 && deep_recursion_warning) { @@ -71,8 +70,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, if (stage == 0) { - log_assert(type == AST_MODULE); - last_blocking_assignment_warn = pair<string, int>(); + log_assert(type == AST_MODULE || type == AST_INTERFACE); deep_recursion_warning = true; while (simplify(const_fold, at_zero, in_lvalue, 1, width_hint, sign_hint, in_param)) { } @@ -113,6 +111,9 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, if (memflags & AstNode::MEM2REG_FL_CMPLX_LHS) goto verbose_activate; + if ((memflags & AstNode::MEM2REG_FL_CONST_LHS) && !(memflags & AstNode::MEM2REG_FL_VAR_LHS)) + goto verbose_activate; + // log("Note: Not replacing memory %s with list of registers (flags=0x%08lx).\n", mem->str.c_str(), long(memflags)); continue; @@ -137,12 +138,23 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, int mem_width, mem_size, addr_bits; node->meminfo(mem_width, mem_size, addr_bits); + int data_range_left = node->children[0]->range_left; + int data_range_right = node->children[0]->range_right; + + if (node->children[0]->range_swapped) + std::swap(data_range_left, data_range_right); + for (int i = 0; i < mem_size; i++) { AstNode *reg = new AstNode(AST_WIRE, new AstNode(AST_RANGE, - mkconst_int(mem_width-1, true), mkconst_int(0, true))); + mkconst_int(data_range_left, true), mkconst_int(data_range_right, true))); reg->str = stringf("%s[%d]", node->str.c_str(), i); reg->is_reg = true; reg->is_signed = node->is_signed; + for (auto &it : node->attributes) + if (it.first != ID(mem2reg)) + reg->attributes.emplace(it.first, it.second->clone()); + reg->filename = node->filename; + reg->linenum = node->linenum; children.push_back(reg); while (reg->simplify(true, false, false, 1, -1, false, false)) { } } @@ -177,13 +189,13 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, // note that $display, $finish, and $stop are used for synthesis-time DRC so they're not in this list if ((type == AST_FCALL || type == AST_TCALL) && (str == "$strobe" || str == "$monitor" || str == "$time" || str == "$dumpfile" || str == "$dumpvars" || str == "$dumpon" || str == "$dumpoff" || str == "$dumpall")) { - log_warning("Ignoring call to system %s %s at %s:%d.\n", type == AST_FCALL ? "function" : "task", str.c_str(), filename.c_str(), linenum); + log_file_warning(filename, linenum, "Ignoring call to system %s %s.\n", type == AST_FCALL ? "function" : "task", str.c_str()); delete_children(); str = std::string(); } if ((type == AST_TCALL) && (str == "$display" || str == "$write") && (!current_always || current_always->type != AST_INITIAL)) { - log_warning("System task `%s' outside initial block is unsupported at %s:%d.\n", str.c_str(), filename.c_str(), linenum); + log_file_warning(filename, linenum, "System task `%s' outside initial block is unsupported.\n", str.c_str()); delete_children(); str = std::string(); } @@ -195,14 +207,14 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, { int nargs = GetSize(children); if (nargs < 1) - log_error("System task `%s' got %d arguments, expected >= 1 at %s:%d.\n", - str.c_str(), int(children.size()), filename.c_str(), linenum); + log_file_error(filename, linenum, "System task `%s' got %d arguments, expected >= 1.\n", + str.c_str(), int(children.size())); // First argument is the format string AstNode *node_string = children[0]; while (node_string->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } if (node_string->type != AST_CONSTANT) - log_error("Failed to evaluate system task `%s' with non-constant 1st argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Failed to evaluate system task `%s' with non-constant 1st argument.\n", str.c_str()); std::string sformat = node_string->bitsAsConst().decode_string(); // Other arguments are placeholders. Process the string as we go through it @@ -215,7 +227,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, { // If there's no next character, that's a problem if (i+1 >= sformat.length()) - log_error("System task `%s' called with `%%' at end of string at %s:%d.\n", str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "System task `%s' called with `%%' at end of string.\n", str.c_str()); char cformat = sformat[++i]; @@ -239,13 +251,13 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, case 'x': case 'X': if (next_arg >= GetSize(children)) - log_error("Missing argument for %%%c format specifier in system task `%s' at %s:%d.\n", - cformat, str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Missing argument for %%%c format specifier in system task `%s'.\n", + cformat, str.c_str()); node_arg = children[next_arg++]; while (node_arg->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } if (node_arg->type != AST_CONSTANT) - log_error("Failed to evaluate system task `%s' with non-constant argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Failed to evaluate system task `%s' with non-constant argument.\n", str.c_str()); break; case 'm': @@ -253,7 +265,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, break; default: - log_error("System task `%s' called with invalid/unsupported format specifier at %s:%d.\n", str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "System task `%s' called with invalid/unsupported format specifier.\n", str.c_str()); break; } @@ -325,8 +337,19 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, for (size_t i = 0; i < children.size(); i++) { AstNode *node = children[i]; if (node->type == AST_WIRE) { + if (node->children.size() == 1 && node->children[0]->type == AST_RANGE) { + for (auto c : node->children[0]->children) { + if (!c->is_simple_const_expr()) { + if (attributes.count("\\dynports")) + delete attributes.at("\\dynports"); + attributes["\\dynports"] = AstNode::mkconst_int(1, true); + } + } + } if (this_wire_scope.count(node->str) > 0) { AstNode *first_node = this_wire_scope[node->str]; + if (first_node->is_input && node->is_reg) + goto wires_are_incompatible; if (!node->is_input && !node->is_output && node->is_reg && node->children.size() == 0) goto wires_are_compatible; if (first_node->children.size() == 0 && node->children.size() == 1 && node->children[0]->type == AST_RANGE) { @@ -361,6 +384,8 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, first_node->is_output = true; if (node->is_reg) first_node->is_reg = true; + if (node->is_logic) + first_node->is_logic = true; if (node->is_signed) first_node->is_signed = true; for (auto &it : node->attributes) { @@ -374,7 +399,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, continue; wires_are_incompatible: if (stage > 1) - log_error("Incompatible re-declaration of wire %s at %s:%d.\n", node->str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Incompatible re-declaration of wire %s.\n", node->str.c_str()); continue; } this_wire_scope[node->str] = node; @@ -402,7 +427,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, if (type == AST_ALWAYS || type == AST_INITIAL) { if (current_always != nullptr) - log_error("Invalid nesting of always blocks and/or initializations at %s:%d.\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Invalid nesting of always blocks and/or initializations.\n"); current_always = this; current_always_clocked = false; @@ -440,6 +465,29 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, children[1]->detectSignWidth(width_hint, sign_hint); width_hint = max(width_hint, backup_width_hint); child_0_is_self_determined = true; + // test only once, before optimizations and memory mappings but after assignment LHS was mapped to an identifier + if (children[0]->id2ast && !children[0]->was_checked) { + if ((type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ) && children[0]->id2ast->is_logic) + children[0]->id2ast->is_reg = true; // if logic type is used in a block asignment + if ((type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ) && !children[0]->id2ast->is_reg) + log_warning("wire '%s' is assigned in a block at %s:%d.\n", children[0]->str.c_str(), filename.c_str(), linenum); + if (type == AST_ASSIGN && children[0]->id2ast->is_reg) { + bool is_rand_reg = false; + if (children[1]->type == AST_FCALL) { + if (children[1]->str == "\\$anyconst") + is_rand_reg = true; + if (children[1]->str == "\\$anyseq") + is_rand_reg = true; + if (children[1]->str == "\\$allconst") + is_rand_reg = true; + if (children[1]->str == "\\$allseq") + is_rand_reg = true; + } + if (!is_rand_reg) + log_warning("reg '%s' is assigned in a continuous assignment at %s:%d.\n", children[0]->str.c_str(), filename.c_str(), linenum); + } + children[0]->was_checked = true; + } break; case AST_PARAMETER: @@ -451,7 +499,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, while (!children[1]->basic_prep && children[1]->simplify(false, false, false, stage, -1, false, true) == true) did_something = true; if (!children[1]->range_valid) - log_error("Non-constant width range on parameter decl at %s:%d.\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Non-constant width range on parameter decl.\n"); width_hint = max(width_hint, children[1]->range_left - children[1]->range_right + 1); } break; @@ -615,6 +663,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, // (iterate by index as e.g. auto wires can add new children in the process) for (size_t i = 0; i < children.size(); i++) { bool did_something_here = true; + bool backup_flag_autowire = flag_autowire; if ((type == AST_GENFOR || type == AST_FOR) && i >= 3) break; if ((type == AST_GENIF || type == AST_GENCASE) && i >= 1) @@ -625,6 +674,8 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, break; if (type == AST_PREFIX && i >= 1) break; + if (type == AST_DEFPARAM && i == 0) + flag_autowire = true; while (did_something_here && i < children.size()) { bool const_fold_here = const_fold, in_lvalue_here = in_lvalue; int width_hint_here = width_hint; @@ -659,6 +710,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, children.erase(children.begin() + (i--)); did_something = true; } + flag_autowire = backup_flag_autowire; } for (auto &attr : attributes) { while (attr.second->simplify(true, false, false, stage, -1, false, true)) @@ -695,7 +747,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, if (type == AST_DEFPARAM && !children.empty()) { if (children[0]->type != AST_IDENTIFIER) - log_error("Module name in defparam at %s:%d contains non-constant expressions!\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Module name in defparam contains non-constant expressions!\n"); string modname, paramname = children[0]->str; @@ -712,13 +764,13 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, } if (pos == std::string::npos) - log_error("Can't find object for defparam `%s` at %s:%d!\n", RTLIL::unescape_id(paramname).c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Can't find object for defparam `%s`!\n", RTLIL::unescape_id(paramname).c_str()); paramname = "\\" + paramname.substr(pos+1); if (current_scope.at(modname)->type != AST_CELL) - log_error("Defparam argument `%s . %s` does not match a cell at %s:%d!\n", - RTLIL::unescape_id(modname).c_str(), RTLIL::unescape_id(paramname).c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Defparam argument `%s . %s` does not match a cell!\n", + RTLIL::unescape_id(modname).c_str(), RTLIL::unescape_id(paramname).c_str()); AstNode *paraset = new AstNode(AST_PARASET, children[1]->clone(), GetSize(children) > 2 ? children[2]->clone() : NULL); paraset->str = paramname; @@ -732,7 +784,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, if (type == AST_PREFIX) { if (children[0]->type != AST_CONSTANT) { // dumpAst(NULL, "> "); - log_error("Index in generate block prefix syntax at %s:%d is not constant!\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Index in generate block prefix syntax is not constant!\n"); } if (children[1]->type == AST_PREFIX) children[1]->simplify(const_fold, at_zero, in_lvalue, stage, width_hint, sign_hint, in_param); @@ -748,9 +800,9 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, // evaluate TO_BITS nodes if (type == AST_TO_BITS) { if (children[0]->type != AST_CONSTANT) - log_error("Left operand of to_bits expression is not constant at %s:%d!\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Left operand of to_bits expression is not constant!\n"); if (children[1]->type != AST_CONSTANT) - log_error("Right operand of to_bits expression is not constant at %s:%d!\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Right operand of to_bits expression is not constant!\n"); RTLIL::Const new_value = children[1]->bitsAsConst(children[0]->bitsAsConst().as_int(), children[1]->is_signed); newNode = mkconst_bits(new_value.bits, children[1]->is_signed); goto apply_newNode; @@ -814,7 +866,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, multirange_dimensions.clear(); for (auto range : children[1]->children) { if (!range->range_valid) - log_error("Non-constant range on memory decl at %s:%d.\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Non-constant range on memory decl.\n"); multirange_dimensions.push_back(min(range->range_left, range->range_right)); multirange_dimensions.push_back(max(range->range_left, range->range_right) - min(range->range_left, range->range_right) + 1); total_size *= multirange_dimensions.back(); @@ -832,7 +884,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, for (int i = 0; 2*i < GetSize(id2ast->multirange_dimensions); i++) { if (GetSize(children[0]->children) < i) - log_error("Insufficient number of array indices for %s at %s:%d.\n", log_id(str), filename.c_str(), linenum); + log_file_error(filename, linenum, "Insufficient number of array indices for %s.\n", log_id(str)); AstNode *new_index_expr = children[0]->children[i]->children.at(0)->clone(); @@ -861,12 +913,12 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, if (type == AST_PARAMETER || type == AST_LOCALPARAM) { if (children.size() > 1 && children[1]->type == AST_RANGE) { if (!children[1]->range_valid) - log_error("Non-constant width range on parameter decl at %s:%d.\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Non-constant width range on parameter decl.\n"); int width = std::abs(children[1]->range_left - children[1]->range_right) + 1; if (children[0]->type == AST_REALVALUE) { RTLIL::Const constvalue = children[0]->realAsConst(width); - log_warning("converting real value %e to binary %s at %s:%d.\n", - children[0]->realvalue, log_signal(constvalue), filename.c_str(), linenum); + log_file_warning(filename, linenum, "converting real value %e to binary %s.\n", + children[0]->realvalue, log_signal(constvalue)); delete children[0]; children[0] = mkconst_bits(constvalue.bits, sign_hint); did_something = true; @@ -907,12 +959,15 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, } } if (current_scope.count(str) == 0) { - // log_warning("Creating auto-wire `%s' in module `%s'.\n", str.c_str(), current_ast_mod->str.c_str()); - AstNode *auto_wire = new AstNode(AST_AUTOWIRE); - auto_wire->str = str; - current_ast_mod->children.push_back(auto_wire); - current_scope[str] = auto_wire; - did_something = true; + if (flag_autowire || str == "\\$global_clock") { + AstNode *auto_wire = new AstNode(AST_AUTOWIRE); + auto_wire->str = str; + current_ast_mod->children.push_back(auto_wire); + current_scope[str] = auto_wire; + did_something = true; + } else { + log_file_error(filename, linenum, "Identifier `%s' is implicitly declared and `default_nettype is set to none.\n", str.c_str()); + } } if (id2ast != current_scope[str]) { id2ast = current_scope[str]; @@ -924,7 +979,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, if (type == AST_IDENTIFIER && children.size() == 2 && children[0]->type == AST_RANGE && children[1]->type == AST_RANGE && !in_lvalue) { if (id2ast == NULL || id2ast->type != AST_MEMORY || children[0]->children.size() != 1) - log_error("Invalid bit-select on memory access at %s:%d!\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Invalid bit-select on memory access!\n"); int mem_width, mem_size, addr_bits; id2ast->meminfo(mem_width, mem_size, addr_bits); @@ -932,6 +987,9 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, int data_range_left = id2ast->children[0]->range_left; int data_range_right = id2ast->children[0]->range_right; + if (id2ast->children[0]->range_swapped) + std::swap(data_range_left, data_range_right); + std::stringstream sstr; sstr << "$mem2bits$" << str << "$" << filename << ":" << linenum << "$" << (autoidx++); std::string wire_id = sstr.str(); @@ -949,6 +1007,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, AstNode *assign = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), data); assign->children[0]->str = wire_id; + assign->children[0]->was_checked = true; if (current_block) { @@ -973,10 +1032,29 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, } if (type == AST_WHILE) - log_error("While loops are only allowed in constant functions at %s:%d!\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "While loops are only allowed in constant functions!\n"); if (type == AST_REPEAT) - log_error("Repeat loops are only allowed in constant functions at %s:%d!\n", filename.c_str(), linenum); + { + AstNode *count = children[0]; + AstNode *body = children[1]; + + // eval count expression + while (count->simplify(true, false, false, stage, 32, true, false)) { } + + if (count->type != AST_CONSTANT) + log_file_error(filename, linenum, "Repeat loops outside must have constant repeat counts!\n"); + + // convert to a block with the body repeated n times + type = AST_BLOCK; + children.clear(); + for (int i = 0; i < count->bitsAsConst().as_int(); i++) + children.insert(children.begin(), body->clone()); + + delete count; + delete body; + did_something = true; + } // unroll for loops and generate-for blocks if ((type == AST_GENFOR || type == AST_FOR) && children.size() != 0) @@ -991,31 +1069,36 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, body_ast = body_ast->children.at(0); if (init_ast->type != AST_ASSIGN_EQ) - log_error("Unsupported 1st expression of generate for-loop at %s:%d!\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Unsupported 1st expression of generate for-loop!\n"); if (next_ast->type != AST_ASSIGN_EQ) - log_error("Unsupported 3rd expression of generate for-loop at %s:%d!\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Unsupported 3rd expression of generate for-loop!\n"); if (type == AST_GENFOR) { if (init_ast->children[0]->id2ast == NULL || init_ast->children[0]->id2ast->type != AST_GENVAR) - log_error("Left hand side of 1st expression of generate for-loop at %s:%d is not a gen var!\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Left hand side of 1st expression of generate for-loop is not a gen var!\n"); if (next_ast->children[0]->id2ast == NULL || next_ast->children[0]->id2ast->type != AST_GENVAR) - log_error("Left hand side of 3rd expression of generate for-loop at %s:%d is not a gen var!\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Left hand side of 3rd expression of generate for-loop is not a gen var!\n"); } else { if (init_ast->children[0]->id2ast == NULL || init_ast->children[0]->id2ast->type != AST_WIRE) - log_error("Left hand side of 1st expression of generate for-loop at %s:%d is not a register!\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Left hand side of 1st expression of generate for-loop is not a register!\n"); if (next_ast->children[0]->id2ast == NULL || next_ast->children[0]->id2ast->type != AST_WIRE) - log_error("Left hand side of 3rd expression of generate for-loop at %s:%d is not a register!\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Left hand side of 3rd expression of generate for-loop is not a register!\n"); } if (init_ast->children[0]->id2ast != next_ast->children[0]->id2ast) - log_error("Incompatible left-hand sides in 1st and 3rd expression of generate for-loop at %s:%d!\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Incompatible left-hand sides in 1st and 3rd expression of generate for-loop!\n"); // eval 1st expression AstNode *varbuf = init_ast->children[1]->clone(); - while (varbuf->simplify(true, false, false, stage, 32, true, false)) { } + { + int expr_width_hint = -1; + bool expr_sign_hint = true; + varbuf->detectSignWidth(expr_width_hint, expr_sign_hint); + while (varbuf->simplify(true, false, false, stage, 32, true, false)) { } + } if (varbuf->type != AST_CONSTANT) - log_error("Right hand side of 1st expression of generate for-loop at %s:%d is not constant!\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Right hand side of 1st expression of generate for-loop is not constant!\n"); varbuf = new AstNode(AST_LOCALPARAM, varbuf); varbuf->str = init_ast->children[0]->str; @@ -1034,10 +1117,15 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, { // eval 2nd expression AstNode *buf = while_ast->clone(); - while (buf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } + { + int expr_width_hint = -1; + bool expr_sign_hint = true; + buf->detectSignWidth(expr_width_hint, expr_sign_hint); + while (buf->simplify(true, false, false, stage, expr_width_hint, expr_sign_hint, false)) { } + } if (buf->type != AST_CONSTANT) - log_error("2nd expression of generate for-loop at %s:%d is not constant!\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "2nd expression of generate for-loop is not constant!\n"); if (buf->integer == 0) { delete buf; @@ -1075,15 +1163,27 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, // eval 3rd expression buf = next_ast->children[1]->clone(); - while (buf->simplify(true, false, false, stage, 32, true, false)) { } + { + int expr_width_hint = -1; + bool expr_sign_hint = true; + buf->detectSignWidth(expr_width_hint, expr_sign_hint); + while (buf->simplify(true, false, false, stage, expr_width_hint, expr_sign_hint, true)) { } + } if (buf->type != AST_CONSTANT) - log_error("Right hand side of 3rd expression of generate for-loop at %s:%d is not constant!\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Right hand side of 3rd expression of generate for-loop is not constant!\n"); delete varbuf->children[0]; varbuf->children[0] = buf; } + if (type == AST_FOR) { + AstNode *buf = next_ast->clone(); + delete buf->children[1]; + buf->children[1] = varbuf->children[0]->clone(); + current_block->children.insert(current_block->children.begin() + current_block_idx++, buf); + } + current_scope[varbuf->str] = backup_scope_varbuf; delete varbuf; delete_children(); @@ -1095,8 +1195,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, { for (size_t i = 0; i < children.size(); i++) if (children[i]->type == AST_WIRE || children[i]->type == AST_MEMORY || children[i]->type == AST_PARAMETER || children[i]->type == AST_LOCALPARAM) - log_error("Local declaration in unnamed block at %s:%d is an unsupported SystemVerilog feature!\n", - children[i]->filename.c_str(), children[i]->linenum); + log_file_error(children[i]->filename, children[i]->linenum, "Local declaration in unnamed block is an unsupported SystemVerilog feature!\n"); } // transform block with name @@ -1144,7 +1243,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, if (buf->type != AST_CONSTANT) { // for (auto f : log_files) // dumpAst(f, "verilog-ast> "); - log_error("Condition for generate if at %s:%d is not constant!\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Condition for generate if is not constant!\n"); } if (buf->asBool() != 0) { delete buf; @@ -1185,7 +1284,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, if (buf->type != AST_CONSTANT) { // for (auto f : log_files) // dumpAst(f, "verilog-ast> "); - log_error("Condition for generate case at %s:%d is not constant!\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Condition for generate case is not constant!\n"); } bool ref_signed = buf->is_signed; @@ -1219,7 +1318,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, if (buf->type != AST_CONSTANT) { // for (auto f : log_files) // dumpAst(f, "verilog-ast> "); - log_error("Expression in generate case at %s:%d is not constant!\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Expression in generate case is not constant!\n"); } bool is_selected = RTLIL::const_eq(ref_value, buf->bitsAsConst(), ref_signed && buf->is_signed, ref_signed && buf->is_signed, 1).as_bool(); @@ -1260,7 +1359,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, if (type == AST_CELLARRAY) { if (!children.at(0)->range_valid) - log_error("Non-constant array range on cell array at %s:%d.\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Non-constant array range on cell array.\n"); newNode = new AstNode(AST_GENBLOCK); int num = max(children.at(0)->range_left, children.at(0)->range_right) - min(children.at(0)->range_left, children.at(0)->range_right) + 1; @@ -1271,7 +1370,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, newNode->children.push_back(new_cell); new_cell->str += stringf("[%d]", idx); if (new_cell->type == AST_PRIMITIVE) { - log_error("Cell arrays of primitives are currently not supported at %s:%d.\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Cell arrays of primitives are currently not supported.\n"); } else { log_assert(new_cell->children.at(0)->type == AST_CELLTYPE); new_cell->children.at(0)->str = stringf("$array:%d:%d:%s", i, num, new_cell->children.at(0)->str.c_str()); @@ -1285,8 +1384,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, if (type == AST_PRIMITIVE) { if (children.size() < 2) - log_error("Insufficient number of arguments for primitive `%s' at %s:%d!\n", - str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Insufficient number of arguments for primitive `%s'!\n", str.c_str()); std::vector<AstNode*> children_list; for (auto child : children) { @@ -1301,8 +1399,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, if (str == "bufif0" || str == "bufif1" || str == "notif0" || str == "notif1") { if (children_list.size() != 3) - log_error("Invalid number of arguments for primitive `%s' at %s:%d!\n", - str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Invalid number of arguments for primitive `%s'!\n", str.c_str()); std::vector<RTLIL::State> z_const(1, RTLIL::State::Sz); @@ -1322,6 +1419,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, str.clear(); type = AST_ASSIGN; children.push_back(children_list.at(0)); + children.back()->was_checked = true; children.push_back(node); did_something = true; } @@ -1358,6 +1456,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, str.clear(); type = AST_ASSIGN; children.push_back(children_list[0]); + children.back()->was_checked = true; children.push_back(node); did_something = true; } @@ -1387,8 +1486,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, while (left_at_zero_ast->simplify(true, true, false, stage, -1, false, false)) { } while (right_at_zero_ast->simplify(true, true, false, stage, -1, false, false)) { } if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT) - log_error("Unsupported expression on dynamic range select on signal `%s' at %s:%d!\n", - str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str()); result_width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1; } did_something = true; @@ -1415,36 +1513,52 @@ skip_dynamic_range_lvalue_expansion:; AstNode *wire_check = new AstNode(AST_WIRE); wire_check->str = id_check; + wire_check->was_checked = true; current_ast_mod->children.push_back(wire_check); current_scope[wire_check->str] = wire_check; while (wire_check->simplify(true, false, false, 1, -1, false, false)) { } AstNode *wire_en = new AstNode(AST_WIRE); wire_en->str = id_en; + wire_en->was_checked = true; current_ast_mod->children.push_back(wire_en); if (current_always_clocked) { current_ast_mod->children.push_back(new AstNode(AST_INITIAL, new AstNode(AST_BLOCK, new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), AstNode::mkconst_int(0, false, 1))))); current_ast_mod->children.back()->children[0]->children[0]->children[0]->str = id_en; + current_ast_mod->children.back()->children[0]->children[0]->children[0]->was_checked = true; } current_scope[wire_en->str] = wire_en; while (wire_en->simplify(true, false, false, 1, -1, false, false)) { } - std::vector<RTLIL::State> x_bit; - x_bit.push_back(RTLIL::State::Sx); + AstNode *check_defval; + if (type == AST_LIVE || type == AST_FAIR) { + check_defval = new AstNode(AST_REDUCE_BOOL, children[0]->clone()); + } else { + std::vector<RTLIL::State> x_bit; + x_bit.push_back(RTLIL::State::Sx); + check_defval = mkconst_bits(x_bit, false); + } - AstNode *assign_check = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bit, false)); + AstNode *assign_check = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), check_defval); assign_check->children[0]->str = id_check; + assign_check->children[0]->was_checked = true; AstNode *assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(0, false, 1)); assign_en->children[0]->str = id_en; + assign_en->children[0]->was_checked = true; AstNode *default_signals = new AstNode(AST_BLOCK); default_signals->children.push_back(assign_check); default_signals->children.push_back(assign_en); current_top_block->children.insert(current_top_block->children.begin(), default_signals); - assign_check = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), new AstNode(AST_REDUCE_BOOL, children[0]->clone())); - assign_check->children[0]->str = id_check; + if (type == AST_LIVE || type == AST_FAIR) { + assign_check = nullptr; + } else { + assign_check = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), new AstNode(AST_REDUCE_BOOL, children[0]->clone())); + assign_check->children[0]->str = id_check; + assign_check->children[0]->was_checked = true; + } if (current_always == nullptr || current_always->type != AST_INITIAL) { assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(1, false, 1)); @@ -1453,12 +1567,15 @@ skip_dynamic_range_lvalue_expansion:; assign_en->children[1]->str = "\\$initstate"; } assign_en->children[0]->str = id_en; + assign_en->children[0]->was_checked = true; newNode = new AstNode(AST_BLOCK); - newNode->children.push_back(assign_check); + if (assign_check != nullptr) + newNode->children.push_back(assign_check); newNode->children.push_back(assign_en); AstNode *assertnode = new AstNode(type); + assertnode->str = str; assertnode->children.push_back(new AstNode(AST_IDENTIFIER)); assertnode->children.push_back(new AstNode(AST_IDENTIFIER)); assertnode->children[0]->str = id_check; @@ -1504,11 +1621,13 @@ skip_dynamic_range_lvalue_expansion:; current_scope[wire_tmp->str] = wire_tmp; wire_tmp->attributes["\\nosync"] = AstNode::mkconst_int(1, false); while (wire_tmp->simplify(true, false, false, 1, -1, false, false)) { } + wire_tmp->is_logic = true; AstNode *wire_tmp_id = new AstNode(AST_IDENTIFIER); wire_tmp_id->str = wire_tmp->str; newNode->children.push_back(new AstNode(AST_ASSIGN_EQ, wire_tmp_id, children[1]->clone())); + newNode->children.back()->was_checked = true; int cursor = 0; for (auto child : children[0]->children) @@ -1538,14 +1657,6 @@ skip_dynamic_range_lvalue_expansion:; sstr << "$memwr$" << children[0]->str << "$" << filename << ":" << linenum << "$" << (autoidx++); std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA", id_en = sstr.str() + "_EN"; - if (type == AST_ASSIGN_EQ) { - pair<string, int> this_blocking_assignment_warn(filename, linenum); - if (this_blocking_assignment_warn != last_blocking_assignment_warn) - log_warning("Blocking assignment to memory in line %s:%d is handled like a non-blocking assignment.\n", - filename.c_str(), linenum); - last_blocking_assignment_warn = this_blocking_assignment_warn; - } - int mem_width, mem_size, addr_bits; bool mem_signed = children[0]->id2ast->is_signed; children[0]->id2ast->meminfo(mem_width, mem_size, addr_bits); @@ -1561,12 +1672,14 @@ skip_dynamic_range_lvalue_expansion:; AstNode *wire_addr = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(addr_bits-1, true), mkconst_int(0, true))); wire_addr->str = id_addr; + wire_addr->was_checked = true; current_ast_mod->children.push_back(wire_addr); current_scope[wire_addr->str] = wire_addr; while (wire_addr->simplify(true, false, false, 1, -1, false, false)) { } AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); wire_data->str = id_data; + wire_data->was_checked = true; wire_data->is_signed = mem_signed; current_ast_mod->children.push_back(wire_data); current_scope[wire_data->str] = wire_data; @@ -1576,6 +1689,7 @@ skip_dynamic_range_lvalue_expansion:; if (current_always->type != AST_INITIAL) { wire_en = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); wire_en->str = id_en; + wire_en->was_checked = true; current_ast_mod->children.push_back(wire_en); current_scope[wire_en->str] = wire_en; while (wire_en->simplify(true, false, false, 1, -1, false, false)) { } @@ -1591,14 +1705,17 @@ skip_dynamic_range_lvalue_expansion:; AstNode *assign_addr = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bits_addr, false)); assign_addr->children[0]->str = id_addr; + assign_addr->children[0]->was_checked = true; AstNode *assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bits_data, false)); assign_data->children[0]->str = id_data; + assign_data->children[0]->was_checked = true; AstNode *assign_en = nullptr; if (current_always->type != AST_INITIAL) { assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(0, false, mem_width)); assign_en->children[0]->str = id_en; + assign_en->children[0]->was_checked = true; } AstNode *default_signals = new AstNode(AST_BLOCK); @@ -1610,6 +1727,7 @@ skip_dynamic_range_lvalue_expansion:; assign_addr = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), children[0]->children[0]->children[0]->clone()); assign_addr->children[0]->str = id_addr; + assign_addr->children[0]->was_checked = true; if (children[0]->children.size() == 2) { @@ -1624,12 +1742,14 @@ skip_dynamic_range_lvalue_expansion:; assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), new AstNode(AST_CONCAT, mkconst_bits(padding_x, false), children[1]->clone())); assign_data->children[0]->str = id_data; + assign_data->children[0]->was_checked = true; if (current_always->type != AST_INITIAL) { for (int i = 0; i < mem_width; i++) set_bits_en[i] = offset <= i && i < offset+width ? RTLIL::State::S1 : RTLIL::State::S0; assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(set_bits_en, false)); assign_en->children[0]->str = id_en; + assign_en->children[0]->was_checked = true; } } else @@ -1645,12 +1765,13 @@ skip_dynamic_range_lvalue_expansion:; while (left_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { } while (right_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { } if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT) - log_error("Unsupported expression on dynamic range select on signal `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum); - int width = left_at_zero_ast->integer - right_at_zero_ast->integer + 1; + log_file_error(filename, linenum, "Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str()); + int width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1; assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), new AstNode(AST_SHIFT_LEFT, children[1]->clone(), offset_ast->clone())); assign_data->children[0]->str = id_data; + assign_data->children[0]->was_checked = true; if (current_always->type != AST_INITIAL) { for (int i = 0; i < mem_width; i++) @@ -1658,6 +1779,7 @@ skip_dynamic_range_lvalue_expansion:; assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), new AstNode(AST_SHIFT_LEFT, mkconst_bits(set_bits_en, false), offset_ast->clone())); assign_en->children[0]->str = id_en; + assign_en->children[0]->was_checked = true; } delete left_at_zero_ast; @@ -1669,10 +1791,12 @@ skip_dynamic_range_lvalue_expansion:; { assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), children[1]->clone()); assign_data->children[0]->str = id_data; + assign_data->children[0]->was_checked = true; if (current_always->type != AST_INITIAL) { assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(set_bits_en, false)); assign_en->children[0]->str = id_en; + assign_en->children[0]->was_checked = true; } } @@ -1731,25 +1855,25 @@ skip_dynamic_range_lvalue_expansion:; if (str == "\\$past") { - if (width_hint <= 0) + if (width_hint < 0) goto replace_fcall_later; int num_steps = 1; if (GetSize(children) != 1 && GetSize(children) != 2) - log_error("System function %s got %d arguments, expected 1 or 2 at %s:%d.\n", - RTLIL::unescape_id(str).c_str(), int(children.size()), filename.c_str(), linenum); + log_file_error(filename, linenum, "System function %s got %d arguments, expected 1 or 2.\n", + RTLIL::unescape_id(str).c_str(), int(children.size())); if (!current_always_clocked) - log_error("System function %s is only allowed in clocked blocks at %s:%d.\n", - RTLIL::unescape_id(str).c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "System function %s is only allowed in clocked blocks.\n", + RTLIL::unescape_id(str).c_str()); if (GetSize(children) == 2) { AstNode *buf = children[1]->clone(); - while (buf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } + while (buf->simplify(true, false, false, stage, -1, false, false)) { } if (buf->type != AST_CONSTANT) - log_error("Failed to evaluate system function `%s' with non-constant value at %s:%d.\n", str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-constant value.\n", str.c_str()); num_steps = buf->asInt(true); delete buf; @@ -1763,6 +1887,11 @@ skip_dynamic_range_lvalue_expansion:; log_assert(block != nullptr); + if (num_steps == 0) { + newNode = children[0]->clone(); + goto apply_newNode; + } + int myidx = autoidx++; AstNode *outreg = nullptr; @@ -1781,6 +1910,7 @@ skip_dynamic_range_lvalue_expansion:; AstNode *regid = new AstNode(AST_IDENTIFIER); regid->str = reg->str; regid->id2ast = reg; + regid->was_checked = true; AstNode *rhs = nullptr; @@ -1802,15 +1932,15 @@ skip_dynamic_range_lvalue_expansion:; goto apply_newNode; } - if (str == "\\$stable" || str == "\\$rose" || str == "\\$fell") + if (str == "\\$stable" || str == "\\$rose" || str == "\\$fell" || str == "\\$changed") { if (GetSize(children) != 1) - log_error("System function %s got %d arguments, expected 1 at %s:%d.\n", - RTLIL::unescape_id(str).c_str(), int(children.size()), filename.c_str(), linenum); + log_file_error(filename, linenum, "System function %s got %d arguments, expected 1.\n", + RTLIL::unescape_id(str).c_str(), int(children.size())); if (!current_always_clocked) - log_error("System function %s is only allowed in clocked blocks at %s:%d.\n", - RTLIL::unescape_id(str).c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "System function %s is only allowed in clocked blocks.\n", + RTLIL::unescape_id(str).c_str()); AstNode *present = children.at(0)->clone(); AstNode *past = clone(); @@ -1819,11 +1949,18 @@ skip_dynamic_range_lvalue_expansion:; if (str == "\\$stable") newNode = new AstNode(AST_EQ, past, present); + else if (str == "\\$changed") + newNode = new AstNode(AST_NE, past, present); + else if (str == "\\$rose") - newNode = new AstNode(AST_LOGIC_AND, new AstNode(AST_LOGIC_NOT, past), present); + newNode = new AstNode(AST_LOGIC_AND, + new AstNode(AST_LOGIC_NOT, new AstNode(AST_BIT_AND, past, mkconst_int(1,false))), + new AstNode(AST_BIT_AND, present, mkconst_int(1,false))); else if (str == "\\$fell") - newNode = new AstNode(AST_LOGIC_AND, past, new AstNode(AST_LOGIC_NOT, present)); + newNode = new AstNode(AST_LOGIC_AND, + new AstNode(AST_BIT_AND, past, mkconst_int(1,false)), + new AstNode(AST_LOGIC_NOT, new AstNode(AST_BIT_AND, present, mkconst_int(1,false)))); else log_abort(); @@ -1840,13 +1977,13 @@ skip_dynamic_range_lvalue_expansion:; if (str == "\\$clog2") { if (children.size() != 1) - log_error("System function %s got %d arguments, expected 1 at %s:%d.\n", - RTLIL::unescape_id(str).c_str(), int(children.size()), filename.c_str(), linenum); + log_file_error(filename, linenum, "System function %s got %d arguments, expected 1.\n", + RTLIL::unescape_id(str).c_str(), int(children.size())); AstNode *buf = children[0]->clone(); while (buf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } if (buf->type != AST_CONSTANT) - log_error("Failed to evaluate system function `%s' with non-constant value at %s:%d.\n", str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-constant value.\n", str.c_str()); RTLIL::Const arg_value = buf->bitsAsConst(); if (arg_value.as_bool()) @@ -1858,19 +1995,19 @@ skip_dynamic_range_lvalue_expansion:; if (arg_value.bits.at(i) == RTLIL::State::S1) result = i + 1; - newNode = mkconst_int(result, false); + newNode = mkconst_int(result, true); goto apply_newNode; } if (str == "\\$size" || str == "\\$bits") { if (str == "\\$bits" && children.size() != 1) - log_error("System function %s got %d arguments, expected 1 at %s:%d.\n", - RTLIL::unescape_id(str).c_str(), int(children.size()), filename.c_str(), linenum); + log_file_error(filename, linenum, "System function %s got %d arguments, expected 1.\n", + RTLIL::unescape_id(str).c_str(), int(children.size())); if (str == "\\$size" && children.size() != 1 && children.size() != 2) - log_error("System function %s got %d arguments, expected 1 or 2 at %s:%d.\n", - RTLIL::unescape_id(str).c_str(), int(children.size()), filename.c_str(), linenum); + log_file_error(filename, linenum, "System function %s got %d arguments, expected 1 or 2.\n", + RTLIL::unescape_id(str).c_str(), int(children.size())); int dim = 1; if (str == "\\$size" && children.size() == 2) { @@ -1893,7 +2030,7 @@ skip_dynamic_range_lvalue_expansion:; if (id_ast == NULL && current_scope.count(buf->str)) id_ast = current_scope.at(buf->str); if (!id_ast) - log_error("Failed to resolve identifier %s for width detection at %s:%d!\n", buf->str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Failed to resolve identifier %s for width detection!\n", buf->str.c_str()); if (id_ast->type == AST_MEMORY) { // We got here only if the argument is a memory // Otherwise $size() and $bits() return the expression width @@ -1901,15 +2038,15 @@ skip_dynamic_range_lvalue_expansion:; if (str == "\\$bits") { if (mem_range->type == AST_RANGE) { if (!mem_range->range_valid) - log_error("Failed to detect width of memory access `%s' at %s:%d!\n", buf->str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Failed to detect width of memory access `%s'!\n", buf->str.c_str()); mem_depth = mem_range->range_left - mem_range->range_right + 1; } else - log_error("Unknown memory depth AST type in `%s' at %s:%d!\n", buf->str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Unknown memory depth AST type in `%s'!\n", buf->str.c_str()); } else { // $size() if (mem_range->type == AST_RANGE) { if (!mem_range->range_valid) - log_error("Failed to detect width of memory access `%s' at %s:%d!\n", buf->str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Failed to detect width of memory access `%s'!\n", buf->str.c_str()); int dims; if (id_ast->multirange_dimensions.empty()) dims = 1; @@ -1920,9 +2057,9 @@ skip_dynamic_range_lvalue_expansion:; else if (dim <= dims) { width_hint = id_ast->multirange_dimensions[2*dim-1]; } else if ((dim > dims+1) || (dim < 0)) - log_error("Dimension %d out of range in `%s', as it only has dimensions 1..%d at %s:%d!\n", dim, buf->str.c_str(), dims+1, filename.c_str(), linenum); + log_file_error(filename, linenum, "Dimension %d out of range in `%s', as it only has dimensions 1..%d!\n", dim, buf->str.c_str(), dims+1); } else - log_error("Unknown memory depth AST type in `%s' at %s:%d!\n", buf->str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Unknown memory depth AST type in `%s'!\n", buf->str.c_str()); } } } @@ -1943,19 +2080,19 @@ skip_dynamic_range_lvalue_expansion:; if (func_with_two_arguments) { if (children.size() != 2) - log_error("System function %s got %d arguments, expected 2 at %s:%d.\n", - RTLIL::unescape_id(str).c_str(), int(children.size()), filename.c_str(), linenum); + log_file_error(filename, linenum, "System function %s got %d arguments, expected 2.\n", + RTLIL::unescape_id(str).c_str(), int(children.size())); } else { if (children.size() != 1) - log_error("System function %s got %d arguments, expected 1 at %s:%d.\n", - RTLIL::unescape_id(str).c_str(), int(children.size()), filename.c_str(), linenum); + log_file_error(filename, linenum, "System function %s got %d arguments, expected 1.\n", + RTLIL::unescape_id(str).c_str(), int(children.size())); } if (children.size() >= 1) { while (children[0]->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } if (!children[0]->isConst()) - log_error("Failed to evaluate system function `%s' with non-constant argument at %s:%d.\n", - RTLIL::unescape_id(str).c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-constant argument.\n", + RTLIL::unescape_id(str).c_str()); int child_width_hint = width_hint; bool child_sign_hint = sign_hint; children[0]->detectSignWidth(child_width_hint, child_sign_hint); @@ -1965,8 +2102,8 @@ skip_dynamic_range_lvalue_expansion:; if (children.size() >= 2) { while (children[1]->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } if (!children[1]->isConst()) - log_error("Failed to evaluate system function `%s' with non-constant argument at %s:%d.\n", - RTLIL::unescape_id(str).c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-constant argument.\n", + RTLIL::unescape_id(str).c_str()); int child_width_hint = width_hint; bool child_sign_hint = sign_hint; children[1]->detectSignWidth(child_width_hint, child_sign_hint); @@ -2018,14 +2155,14 @@ skip_dynamic_range_lvalue_expansion:; for (int i = 2; i < GetSize(dpi_decl->children); i++) { if (i-2 >= GetSize(children)) - log_error("Insufficient number of arguments in DPI function call at %s:%d.\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Insufficient number of arguments in DPI function call.\n"); argtypes.push_back(RTLIL::unescape_id(dpi_decl->children.at(i)->str)); args.push_back(children.at(i-2)->clone()); while (args.back()->simplify(true, false, false, stage, -1, false, true)) { } if (args.back()->type != AST_CONSTANT && args.back()->type != AST_REALVALUE) - log_error("Failed to evaluate DPI function with non-constant argument at %s:%d.\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Failed to evaluate DPI function with non-constant argument.\n"); } newNode = dpi_call(rtype, fname, argtypes, args); @@ -2037,7 +2174,7 @@ skip_dynamic_range_lvalue_expansion:; } if (current_scope.count(str) == 0 || current_scope[str]->type != AST_FUNCTION) - log_error("Can't resolve function name `%s' at %s:%d.\n", str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Can't resolve function name `%s'.\n", str.c_str()); } if (type == AST_TCALL) @@ -2045,26 +2182,26 @@ skip_dynamic_range_lvalue_expansion:; if (str == "$finish" || str == "$stop") { if (!current_always || current_always->type != AST_INITIAL) - log_error("System task `%s' outside initial block is unsupported at %s:%d.\n", str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "System task `%s' outside initial block is unsupported.\n", str.c_str()); - log_error("System task `%s' executed at %s:%d.\n", str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "System task `%s' executed.\n", str.c_str()); } if (str == "\\$readmemh" || str == "\\$readmemb") { if (GetSize(children) < 2 || GetSize(children) > 4) - log_error("System function %s got %d arguments, expected 2-4 at %s:%d.\n", - RTLIL::unescape_id(str).c_str(), int(children.size()), filename.c_str(), linenum); + log_file_error(filename, linenum, "System function %s got %d arguments, expected 2-4.\n", + RTLIL::unescape_id(str).c_str(), int(children.size())); AstNode *node_filename = children[0]->clone(); while (node_filename->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } if (node_filename->type != AST_CONSTANT) - log_error("Failed to evaluate system function `%s' with non-constant 1st argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-constant 1st argument.\n", str.c_str()); AstNode *node_memory = children[1]->clone(); while (node_memory->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } if (node_memory->type != AST_IDENTIFIER || node_memory->id2ast == nullptr || node_memory->id2ast->type != AST_MEMORY) - log_error("Failed to evaluate system function `%s' with non-memory 2nd argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-memory 2nd argument.\n", str.c_str()); int start_addr = -1, finish_addr = -1; @@ -2072,7 +2209,7 @@ skip_dynamic_range_lvalue_expansion:; AstNode *node_addr = children[2]->clone(); while (node_addr->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } if (node_addr->type != AST_CONSTANT) - log_error("Failed to evaluate system function `%s' with non-constant 3rd argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-constant 3rd argument.\n", str.c_str()); start_addr = int(node_addr->asInt(false)); } @@ -2080,7 +2217,7 @@ skip_dynamic_range_lvalue_expansion:; AstNode *node_addr = children[3]->clone(); while (node_addr->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } if (node_addr->type != AST_CONSTANT) - log_error("Failed to evaluate system function `%s' with non-constant 4th argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-constant 4th argument.\n", str.c_str()); finish_addr = int(node_addr->asInt(false)); } @@ -2102,11 +2239,13 @@ skip_dynamic_range_lvalue_expansion:; } newNode = readmem(str == "\\$readmemh", node_filename->bitsAsConst().decode_string(), node_memory->id2ast, start_addr, finish_addr, unconditional_init); + delete node_filename; + delete node_memory; goto apply_newNode; } if (current_scope.count(str) == 0 || current_scope[str]->type != AST_TASK) - log_error("Can't resolve task name `%s' at %s:%d.\n", str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Can't resolve task name `%s'.\n", str.c_str()); } AstNode *decl = current_scope[str]; @@ -2134,15 +2273,17 @@ skip_dynamic_range_lvalue_expansion:; } if (in_param) - log_error("Non-constant function call in constant expression at %s:%d.\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Non-constant function call in constant expression.\n"); if (require_const_eval) - log_error("Function %s can only be called with constant arguments at %s:%d.\n", str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Function %s can only be called with constant arguments.\n", str.c_str()); } size_t arg_count = 0; std::map<std::string, std::string> replace_rules; vector<AstNode*> added_mod_children; dict<std::string, AstNode*> wire_cache; + vector<AstNode*> new_stmts; + vector<AstNode*> output_assignments; if (current_block == NULL) { @@ -2167,6 +2308,8 @@ skip_dynamic_range_lvalue_expansion:; AstNode *always = new AstNode(AST_ALWAYS, new AstNode(AST_BLOCK, new AstNode(AST_ASSIGN_EQ, lvalue, clone()))); + always->children[0]->children[0]->was_checked = true; + current_ast_mod->children.push_back(always); goto replace_fcall_with_id; @@ -2192,7 +2335,7 @@ skip_dynamic_range_lvalue_expansion:; if (attr.first.str().rfind("\\via_celltype_defparam_", 0) == 0) { AstNode *cell_arg = new AstNode(AST_PARASET, attr.second->clone()); - cell_arg->str = RTLIL::escape_id(attr.first.str().substr(strlen("\\via_celltype_defparam_"))); + cell_arg->str = RTLIL::escape_id(attr.first.substr(strlen("\\via_celltype_defparam_"))); cell->children.push_back(cell_arg); } @@ -2216,6 +2359,7 @@ skip_dynamic_range_lvalue_expansion:; AstNode *assign = child->is_input ? new AstNode(AST_ASSIGN_EQ, wire_id->clone(), arg) : new AstNode(AST_ASSIGN_EQ, arg, wire_id->clone()); + assign->children[0]->was_checked = true; for (auto it = current_block->children.begin(); it != current_block->children.end(); it++) { if (*it != current_block_child) @@ -2253,7 +2397,7 @@ skip_dynamic_range_lvalue_expansion:; goto tcall_incompatible_wires; } else { tcall_incompatible_wires: - log_error("Incompatible re-declaration of wire %s at %s:%d.\n", child->str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Incompatible re-declaration of wire %s.\n", child->str.c_str()); } } } @@ -2264,8 +2408,8 @@ skip_dynamic_range_lvalue_expansion:; wire->port_id = 0; wire->is_input = false; wire->is_output = false; - if (!child->is_output) - wire->attributes["\\nosync"] = AstNode::mkconst_int(1, false); + wire->is_reg = true; + wire->attributes["\\nosync"] = AstNode::mkconst_int(1, false); wire_cache[child->str] = wire; current_ast_mod->children.push_back(wire); @@ -2286,13 +2430,11 @@ skip_dynamic_range_lvalue_expansion:; AstNode *assign = child->is_input ? new AstNode(AST_ASSIGN_EQ, wire_id, arg) : new AstNode(AST_ASSIGN_EQ, arg, wire_id); - - for (auto it = current_block->children.begin(); it != current_block->children.end(); it++) { - if (*it != current_block_child) - continue; - current_block->children.insert(it, assign); - break; - } + assign->children[0]->was_checked = true; + if (child->is_input) + new_stmts.push_back(assign); + else + output_assignments.push_back(assign); } } @@ -2306,14 +2448,18 @@ skip_dynamic_range_lvalue_expansion:; { AstNode *stmt = child->clone(); stmt->replace_ids(prefix, replace_rules); + new_stmts.push_back(stmt); + } - for (auto it = current_block->children.begin(); it != current_block->children.end(); it++) { - if (*it != current_block_child) - continue; - current_block->children.insert(it, stmt); - break; - } + new_stmts.insert(new_stmts.end(), output_assignments.begin(), output_assignments.end()); + + for (auto it = current_block->children.begin(); ; it++) { + log_assert(it != current_block->children.end()); + if (*it == current_block_child) { + current_block->children.insert(it, new_stmts.begin(), new_stmts.end()); + break; } + } replace_fcall_with_id: if (type == AST_FCALL) { @@ -2641,7 +2787,7 @@ AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *m yosys_input_files.insert(mem_filename); if (f.fail()) - log_error("Can not open file `%s` for %s at %s:%d.\n", mem_filename.c_str(), str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Can not open file `%s` for %s.\n", mem_filename.c_str(), str.c_str()); log_assert(GetSize(memory->children) == 2 && memory->children[1]->type == AST_RANGE && memory->children[1]->range_valid); int range_left = memory->children[1]->range_left, range_right = memory->children[1]->range_right; @@ -2663,13 +2809,13 @@ AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *m std::getline(f, line); for (int i = 0; i < GetSize(line); i++) { - if (in_comment && line.substr(i, 2) == "*/") { + if (in_comment && line.compare(i, 2, "*/") == 0) { line[i] = ' '; line[i+1] = ' '; in_comment = false; continue; } - if (!in_comment && line.substr(i, 2) == "/*") + if (!in_comment && line.compare(i, 2, "/*") == 0) in_comment = true; if (in_comment) line[i] = ' '; @@ -2678,7 +2824,7 @@ AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *m while (1) { token = next_token(line, " \t\r\n"); - if (token.empty() || token.substr(0, 2) == "//") + if (token.empty() || token.compare(0, 2, "//") == 0) break; if (token[0] == '@') { @@ -2687,7 +2833,7 @@ AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *m char *endptr; cursor = strtol(nptr, &endptr, 16); if (!*nptr || *endptr) - log_error("Can not parse address `%s` for %s at %s:%d.\n", nptr, str.c_str(), filename.c_str(), linenum); + log_file_error(filename, linenum, "Can not parse address `%s` for %s.\n", nptr, str.c_str()); continue; } @@ -2725,6 +2871,7 @@ AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *m block->children.push_back(new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER, new AstNode(AST_RANGE, AstNode::mkconst_int(cursor, false))), value)); block->children.back()->children[0]->str = memory->str; block->children.back()->children[0]->id2ast = memory; + block->children.back()->children[0]->was_checked = true; } cursor += increment; @@ -2748,8 +2895,15 @@ AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *m void AstNode::expand_genblock(std::string index_var, std::string prefix, std::map<std::string, std::string> &name_map) { if (!index_var.empty() && type == AST_IDENTIFIER && str == index_var) { - current_scope[index_var]->children[0]->cloneInto(this); - return; + if (children.empty()) { + current_scope[index_var]->children[0]->cloneInto(this); + } else { + AstNode *p = new AstNode(AST_LOCALPARAM, current_scope[index_var]->children[0]->clone()); + p->str = stringf("$genval$%d", autoidx++); + current_ast_mod->children.push_back(p); + str = p->str; + id2ast = p; + } } if ((type == AST_IDENTIFIER || type == AST_FCALL || type == AST_TCALL) && name_map.count(str) > 0) @@ -2783,7 +2937,11 @@ void AstNode::expand_genblock(std::string index_var, std::string prefix, std::ma for (size_t i = 0; i < children.size(); i++) { AstNode *child = children[i]; - if (child->type != AST_FUNCTION && child->type != AST_TASK && child->type != AST_PREFIX) + // AST_PREFIX member names should not be prefixed; a nested AST_PREFIX + // still needs to recursed-into + if (type == AST_PREFIX && i == 1 && child->type == AST_IDENTIFIER) + continue; + if (child->type != AST_FUNCTION && child->type != AST_TASK) child->expand_genblock(index_var, prefix, name_map); } @@ -2838,7 +2996,7 @@ void AstNode::mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg dict<AstNode*, uint32_t> &mem2reg_candidates, dict<AstNode*, uint32_t> &proc_flags, uint32_t &flags) { uint32_t children_flags = 0; - int ignore_children_counter = 0; + int lhs_children_counter = 0; if (type == AST_ASSIGN || type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ) { @@ -2864,6 +3022,16 @@ void AstNode::mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg proc_flags[mem] |= AstNode::MEM2REG_FL_EQ1; } + // for proper (non-init) writes: remember if this is a constant index or not + if ((flags & MEM2REG_FL_INIT) == 0) { + if (children[0]->children.size() && children[0]->children[0]->type == AST_RANGE && children[0]->children[0]->children.size()) { + if (children[0]->children[0]->children[0]->type == AST_CONSTANT) + mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_CONST_LHS; + else + mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_VAR_LHS; + } + } + // remember where this is if (flags & MEM2REG_FL_INIT) { if (!(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_SET_INIT)) @@ -2876,7 +3044,7 @@ void AstNode::mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg } } - ignore_children_counter = 1; + lhs_children_counter = 1; } if (type == AST_IDENTIFIER && id2ast && id2ast->type == AST_MEMORY) @@ -2919,12 +3087,23 @@ void AstNode::mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg log_assert((flags & ~0x000000ff) == 0); for (auto child : children) - if (ignore_children_counter > 0) - ignore_children_counter--; - else if (proc_flags_p) + { + if (lhs_children_counter > 0) { + lhs_children_counter--; + if (child->children.size() && child->children[0]->type == AST_RANGE && child->children[0]->children.size()) { + for (auto c : child->children[0]->children) { + if (proc_flags_p) + c->mem2reg_as_needed_pass1(mem2reg_places, mem2reg_candidates, *proc_flags_p, flags); + else + c->mem2reg_as_needed_pass1(mem2reg_places, mem2reg_candidates, proc_flags, flags); + } + } + } else + if (proc_flags_p) child->mem2reg_as_needed_pass1(mem2reg_places, mem2reg_candidates, *proc_flags_p, flags); else child->mem2reg_as_needed_pass1(mem2reg_places, mem2reg_candidates, proc_flags, flags); + } flags &= ~children_flags | backup_flags; @@ -2943,7 +3122,7 @@ bool AstNode::mem2reg_check(pool<AstNode*> &mem2reg_set) return false; if (children.empty() || children[0]->type != AST_RANGE || GetSize(children[0]->children) != 1) - log_error("Invalid array access at %s:%d.\n", filename.c_str(), linenum); + log_file_error(filename, linenum, "Invalid array access.\n"); return true; } @@ -2976,6 +3155,39 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, if (type == AST_FUNCTION || type == AST_TASK) return false; + if (type == AST_MEMINIT && id2ast && mem2reg_set.count(id2ast)) + { + log_assert(children[0]->type == AST_CONSTANT); + log_assert(children[1]->type == AST_CONSTANT); + log_assert(children[2]->type == AST_CONSTANT); + + int cursor = children[0]->asInt(false); + Const data = children[1]->bitsAsConst(); + int length = children[2]->asInt(false); + + if (length != 0) + { + AstNode *block = new AstNode(AST_INITIAL, new AstNode(AST_BLOCK)); + mod->children.push_back(block); + block = block->children[0]; + + int wordsz = GetSize(data) / length; + + for (int i = 0; i < length; i++) { + block->children.push_back(new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER, new AstNode(AST_RANGE, AstNode::mkconst_int(cursor+i, false))), mkconst_bits(data.extract(i*wordsz, wordsz).bits, false))); + block->children.back()->children[0]->str = str; + block->children.back()->children[0]->id2ast = id2ast; + block->children.back()->children[0]->was_checked = true; + } + } + + AstNode *newNode = new AstNode(AST_NONE); + newNode->cloneInto(this); + delete newNode; + + did_something = true; + } + if (type == AST_ASSIGN && block == NULL && children[0]->mem2reg_check(mem2reg_set)) { if (async_block == NULL) { @@ -2985,6 +3197,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, AstNode *newNode = clone(); newNode->type = AST_ASSIGN_EQ; + newNode->children[0]->was_checked = true; async_block->children[0]->children.push_back(newNode); newNode = new AstNode(AST_NONE); @@ -3008,6 +3221,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, AstNode *wire_addr = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(addr_bits-1, true), mkconst_int(0, true))); wire_addr->str = id_addr; wire_addr->is_reg = true; + wire_addr->was_checked = true; wire_addr->attributes["\\nosync"] = AstNode::mkconst_int(1, false); mod->children.push_back(wire_addr); while (wire_addr->simplify(true, false, false, 1, -1, false, false)) { } @@ -3015,6 +3229,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); wire_data->str = id_data; wire_data->is_reg = true; + wire_data->was_checked = true; wire_data->is_signed = mem_signed; wire_data->attributes["\\nosync"] = AstNode::mkconst_int(1, false); mod->children.push_back(wire_data); @@ -3028,6 +3243,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, AstNode *assign_addr = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), children[0]->children[0]->children[0]->clone()); assign_addr->children[0]->str = id_addr; + assign_addr->children[0]->was_checked = true; block->children.insert(block->children.begin()+assign_idx+1, assign_addr); AstNode *case_node = new AstNode(AST_CASE, new AstNode(AST_IDENTIFIER)); @@ -3051,6 +3267,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, children[0]->id2ast = NULL; children[0]->str = id_data; type = AST_ASSIGN_EQ; + children[0]->was_checked = true; did_something = true; } @@ -3083,6 +3300,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, AstNode *wire_addr = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(addr_bits-1, true), mkconst_int(0, true))); wire_addr->str = id_addr; wire_addr->is_reg = true; + wire_addr->was_checked = true; if (block) wire_addr->attributes["\\nosync"] = AstNode::mkconst_int(1, false); mod->children.push_back(wire_addr); @@ -3091,6 +3309,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); wire_data->str = id_data; wire_data->is_reg = true; + wire_data->was_checked = true; wire_data->is_signed = mem_signed; if (block) wire_data->attributes["\\nosync"] = AstNode::mkconst_int(1, false); @@ -3099,6 +3318,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, AstNode *assign_addr = new AstNode(block ? AST_ASSIGN_EQ : AST_ASSIGN, new AstNode(AST_IDENTIFIER), children[0]->children[0]->clone()); assign_addr->children[0]->str = id_addr; + assign_addr->children[0]->was_checked = true; AstNode *case_node = new AstNode(AST_CASE, new AstNode(AST_IDENTIFIER)); case_node->children[0]->str = id_addr; @@ -3109,6 +3329,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, AstNode *cond_node = new AstNode(AST_COND, AstNode::mkconst_int(i, false, addr_bits), new AstNode(AST_BLOCK)); AstNode *assign_reg = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), new AstNode(AST_IDENTIFIER)); assign_reg->children[0]->str = id_data; + assign_reg->children[0]->was_checked = true; assign_reg->children[1]->str = stringf("%s[%d]", str.c_str(), i); cond_node->children[1]->children.push_back(assign_reg); case_node->children.push_back(cond_node); @@ -3121,6 +3342,7 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, AstNode *cond_node = new AstNode(AST_COND, new AstNode(AST_DEFAULT), new AstNode(AST_BLOCK)); AstNode *assign_reg = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), AstNode::mkconst_bits(x_bits, false)); assign_reg->children[0]->str = id_data; + assign_reg->children[0]->was_checked = true; cond_node->children[1]->children.push_back(assign_reg); case_node->children.push_back(cond_node); @@ -3195,6 +3417,16 @@ bool AstNode::has_const_only_constructs(bool &recommend_const_eval) return false; } +bool AstNode::is_simple_const_expr() +{ + if (type == AST_IDENTIFIER) + return false; + for (auto child : children) + if (!child->is_simple_const_expr()) + return false; + return true; +} + // helper function for AstNode::eval_const_function() void AstNode::replace_variables(std::map<std::string, AstNode::varinfo_t> &variables, AstNode *fcall) { @@ -3202,13 +3434,13 @@ void AstNode::replace_variables(std::map<std::string, AstNode::varinfo_t> &varia int offset = variables.at(str).offset, width = variables.at(str).val.bits.size(); if (!children.empty()) { if (children.size() != 1 || children.at(0)->type != AST_RANGE) - log_error("Memory access in constant function is not supported in %s:%d (called from %s:%d).\n", - filename.c_str(), linenum, fcall->filename.c_str(), fcall->linenum); + log_file_error(filename, linenum, "Memory access in constant function is not supported\n%s:%d: ...called from here.\n", + fcall->filename.c_str(), fcall->linenum); children.at(0)->replace_variables(variables, fcall); while (simplify(true, false, false, 1, -1, false, true)) { } if (!children.at(0)->range_valid) - log_error("Non-constant range in %s:%d (called from %s:%d).\n", - filename.c_str(), linenum, fcall->filename.c_str(), fcall->linenum); + log_file_error(filename, linenum, "Non-constant range\n%s:%d: ... called from here.\n", + fcall->filename.c_str(), fcall->linenum); offset = min(children.at(0)->range_left, children.at(0)->range_right); width = min(std::abs(children.at(0)->range_left - children.at(0)->range_right) + 1, width); } @@ -3230,25 +3462,17 @@ AstNode *AstNode::eval_const_function(AstNode *fcall) { std::map<std::string, AstNode*> backup_scope; std::map<std::string, AstNode::varinfo_t> variables; - bool delete_temp_block = false; - AstNode *block = NULL; + AstNode *block = new AstNode(AST_BLOCK); size_t argidx = 0; for (auto child : children) { - if (child->type == AST_BLOCK) - { - log_assert(block == NULL); - block = child; - continue; - } - if (child->type == AST_WIRE) { while (child->simplify(true, false, false, 1, -1, false, true)) { } if (!child->range_valid) - log_error("Can't determine size of variable %s in %s:%d (called from %s:%d).\n", - child->str.c_str(), child->filename.c_str(), child->linenum, fcall->filename.c_str(), fcall->linenum); + log_file_error(child->filename, child->linenum, "Can't determine size of variable %s\n%s:%d: ... called from here.\n", + child->str.c_str(), fcall->filename.c_str(), fcall->linenum); variables[child->str].val = RTLIL::Const(RTLIL::State::Sx, abs(child->range_left - child->range_right)+1); variables[child->str].offset = min(child->range_left, child->range_right); variables[child->str].is_signed = child->is_signed; @@ -3259,13 +3483,9 @@ AstNode *AstNode::eval_const_function(AstNode *fcall) continue; } - log_assert(block == NULL); - delete_temp_block = true; - block = new AstNode(AST_BLOCK); block->children.push_back(child->clone()); } - log_assert(block != NULL); log_assert(variables.count(str) != 0); while (!block->children.empty()) @@ -3291,24 +3511,24 @@ AstNode *AstNode::eval_const_function(AstNode *fcall) continue; if (stmt->children.at(1)->type != AST_CONSTANT) - log_error("Non-constant expression in constant function at %s:%d (called from %s:%d). X\n", - stmt->filename.c_str(), stmt->linenum, fcall->filename.c_str(), fcall->linenum); + log_file_error(stmt->filename, stmt->linenum, "Non-constant expression in constant function\n%s:%d: ... called from here. X\n", + fcall->filename.c_str(), fcall->linenum); if (stmt->children.at(0)->type != AST_IDENTIFIER) - log_error("Unsupported composite left hand side in constant function at %s:%d (called from %s:%d).\n", - stmt->filename.c_str(), stmt->linenum, fcall->filename.c_str(), fcall->linenum); + log_file_error(stmt->filename, stmt->linenum, "Unsupported composite left hand side in constant function\n%s:%d: ... called from here.\n", + fcall->filename.c_str(), fcall->linenum); if (!variables.count(stmt->children.at(0)->str)) - log_error("Assignment to non-local variable in constant function at %s:%d (called from %s:%d).\n", - stmt->filename.c_str(), stmt->linenum, fcall->filename.c_str(), fcall->linenum); + log_file_error(stmt->filename, stmt->linenum, "Assignment to non-local variable in constant function\n%s:%d: ... called from here.\n", + fcall->filename.c_str(), fcall->linenum); if (stmt->children.at(0)->children.empty()) { variables[stmt->children.at(0)->str].val = stmt->children.at(1)->bitsAsConst(variables[stmt->children.at(0)->str].val.bits.size()); } else { AstNode *range = stmt->children.at(0)->children.at(0); if (!range->range_valid) - log_error("Non-constant range in %s:%d (called from %s:%d).\n", - range->filename.c_str(), range->linenum, fcall->filename.c_str(), fcall->linenum); + log_file_error(range->filename, range->linenum, "Non-constant range\n%s:%d: ... called from here.\n", + fcall->filename.c_str(), fcall->linenum); int offset = min(range->range_left, range->range_right); int width = std::abs(range->range_left - range->range_right) + 1; varinfo_t &v = variables[stmt->children.at(0)->str]; @@ -3339,8 +3559,8 @@ AstNode *AstNode::eval_const_function(AstNode *fcall) while (cond->simplify(true, false, false, 1, -1, false, true)) { } if (cond->type != AST_CONSTANT) - log_error("Non-constant expression in constant function at %s:%d (called from %s:%d).\n", - stmt->filename.c_str(), stmt->linenum, fcall->filename.c_str(), fcall->linenum); + log_file_error(stmt->filename, stmt->linenum, "Non-constant expression in constant function\n%s:%d: ... called from here.\n", + fcall->filename.c_str(), fcall->linenum); if (cond->asBool()) { block->children.insert(block->children.begin(), stmt->children.at(1)->clone()); @@ -3360,8 +3580,8 @@ AstNode *AstNode::eval_const_function(AstNode *fcall) while (num->simplify(true, false, false, 1, -1, false, true)) { } if (num->type != AST_CONSTANT) - log_error("Non-constant expression in constant function at %s:%d (called from %s:%d).\n", - stmt->filename.c_str(), stmt->linenum, fcall->filename.c_str(), fcall->linenum); + log_file_error(stmt->filename, stmt->linenum, "Non-constant expression in constant function\n%s:%d: ... called from here.\n", + fcall->filename.c_str(), fcall->linenum); block->children.erase(block->children.begin()); for (int i = 0; i < num->bitsAsConst().as_int(); i++) @@ -3398,8 +3618,8 @@ AstNode *AstNode::eval_const_function(AstNode *fcall) while (cond->simplify(true, false, false, 1, -1, false, true)) { } if (cond->type != AST_CONSTANT) - log_error("Non-constant expression in constant function at %s:%d (called from %s:%d).\n", - stmt->filename.c_str(), stmt->linenum, fcall->filename.c_str(), fcall->linenum); + log_file_error(stmt->filename, stmt->linenum, "Non-constant expression in constant function\n%s:%d: ... called from here.\n", + fcall->filename.c_str(), fcall->linenum); found_match = cond->asBool(); delete cond; @@ -3428,13 +3648,12 @@ AstNode *AstNode::eval_const_function(AstNode *fcall) continue; } - log_error("Unsupported language construct in constant function at %s:%d (called from %s:%d).\n", - stmt->filename.c_str(), stmt->linenum, fcall->filename.c_str(), fcall->linenum); + log_file_error(stmt->filename, stmt->linenum, "Unsupported language construct in constant function\n%s:%d: ... called from here.\n", + fcall->filename.c_str(), fcall->linenum); log_abort(); } - if (delete_temp_block) - delete block; + delete block; for (auto &it : backup_scope) if (it.second == NULL) @@ -3446,4 +3665,3 @@ AstNode *AstNode::eval_const_function(AstNode *fcall) } YOSYS_NAMESPACE_END - diff --git a/frontends/blif/blifparse.cc b/frontends/blif/blifparse.cc index e6bb99954..d17cacf29 100644 --- a/frontends/blif/blifparse.cc +++ b/frontends/blif/blifparse.cc @@ -78,12 +78,14 @@ failed: return std::pair<RTLIL::IdString, int>("\\" + name, 0); } -void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bool run_clean, bool sop_mode, bool wideports) +void parse_blif(RTLIL::Design *design, std::istream &f, IdString dff_name, bool run_clean, bool sop_mode, bool wideports) { RTLIL::Module *module = nullptr; RTLIL::Const *lutptr = NULL; RTLIL::Cell *sopcell = NULL; + RTLIL::Cell *lastcell = nullptr; RTLIL::State lut_default_state = RTLIL::State::Sx; + std::string err_reason; int blif_maxnum = 0, sopmode = -1; auto blif_wire = [&](const std::string &wire_name) -> Wire* @@ -159,6 +161,7 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo if (module != nullptr) goto error; module = new RTLIL::Module; + lastcell = nullptr; module->name = RTLIL::escape_id(strtok(NULL, " \t\r\n")); obj_attributes = &module->attributes; obj_parameters = nullptr; @@ -232,6 +235,7 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo } module = nullptr; + lastcell = nullptr; obj_attributes = nullptr; obj_parameters = nullptr; continue; @@ -264,6 +268,22 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo continue; } + if (!strcmp(cmd, ".cname")) + { + char *p = strtok(NULL, " \t\r\n"); + if (p == NULL) + goto error; + + if(lastcell == nullptr || module == nullptr) + { + err_reason = stringf("No primitive object to attach .cname %s.", p); + goto error_with_reason; + } + + module->rename(lastcell, p); + continue; + } + if (!strcmp(cmd, ".attr") || !strcmp(cmd, ".param")) { char *n = strtok(NULL, " \t\r\n"); char *v = strtok(NULL, "\r\n"); @@ -281,12 +301,16 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo const_v.bits[i] = v[n-i-1] != '0' ? State::S1 : State::S0; } if (!strcmp(cmd, ".attr")) { - if (obj_attributes == nullptr) - goto error; + if (obj_attributes == nullptr) { + err_reason = stringf("No object to attach .attr too."); + goto error_with_reason; + } (*obj_attributes)[id_n] = const_v; } else { - if (obj_parameters == nullptr) - goto error; + if (obj_parameters == nullptr) { + err_reason = stringf("No object to attach .param too."); + goto error_with_reason; + } (*obj_parameters)[id_n] = const_v; } continue; @@ -331,6 +355,7 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo } } + lastcell = cell; obj_attributes = &cell->attributes; obj_parameters = &cell->parameters; continue; @@ -383,6 +408,7 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo cell->setPort(it.first, sig); } + lastcell = cell; obj_attributes = &cell->attributes; obj_parameters = &cell->parameters; continue; @@ -391,7 +417,7 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo obj_attributes = nullptr; obj_parameters = nullptr; - if (!strcmp(cmd, ".barbuf")) + if (!strcmp(cmd, ".barbuf") || !strcmp(cmd, ".conn")) { char *p = strtok(NULL, " \t\r\n"); if (p == NULL) @@ -459,6 +485,7 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo sopcell->setPort("\\A", input_sig); sopcell->setPort("\\Y", output_sig); sopmode = -1; + lastcell = sopcell; } else { @@ -469,6 +496,7 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo cell->setPort("\\Y", output_sig); lutptr = &cell->parameters.at("\\LUT"); lut_default_state = RTLIL::State::Sx; + lastcell = cell; } continue; } @@ -546,15 +574,17 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo error: log_error("Syntax error in line %d!\n", line_count); +error_with_reason: + log_error("Syntax error in line %d: %s\n", line_count, err_reason.c_str()); } struct BlifFrontend : public Frontend { BlifFrontend() : Frontend("blif", "read BLIF file") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); - log(" read_blif [filename]\n"); + log(" read_blif [options] [filename]\n"); log("\n"); log("Load modules from a BLIF file into the current design.\n"); log("\n"); @@ -566,7 +596,7 @@ struct BlifFrontend : public Frontend { log(" multi-bit port 'name'.\n"); log("\n"); } - virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) + void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { bool sop_mode = false; bool wideports = false; diff --git a/frontends/blif/blifparse.h b/frontends/blif/blifparse.h index 955b6aacf..2b84cb795 100644 --- a/frontends/blif/blifparse.h +++ b/frontends/blif/blifparse.h @@ -24,7 +24,7 @@ YOSYS_NAMESPACE_BEGIN -extern void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, +extern void parse_blif(RTLIL::Design *design, std::istream &f, IdString dff_name, bool run_clean = false, bool sop_mode = false, bool wideports = false); YOSYS_NAMESPACE_END diff --git a/frontends/ilang/.gitignore b/frontends/ilang/.gitignore index 43106a814..f586b33c7 100644 --- a/frontends/ilang/.gitignore +++ b/frontends/ilang/.gitignore @@ -1,4 +1,4 @@ ilang_lexer.cc ilang_parser.output ilang_parser.tab.cc -ilang_parser.tab.h +ilang_parser.tab.hh diff --git a/frontends/ilang/Makefile.inc b/frontends/ilang/Makefile.inc index e2a476c93..6f1f0e8fc 100644 --- a/frontends/ilang/Makefile.inc +++ b/frontends/ilang/Makefile.inc @@ -1,15 +1,14 @@ GENFILES += frontends/ilang/ilang_parser.tab.cc -GENFILES += frontends/ilang/ilang_parser.tab.h +GENFILES += frontends/ilang/ilang_parser.tab.hh GENFILES += frontends/ilang/ilang_parser.output GENFILES += frontends/ilang/ilang_lexer.cc frontends/ilang/ilang_parser.tab.cc: frontends/ilang/ilang_parser.y $(Q) mkdir -p $(dir $@) - $(P) $(BISON) -d -r all -b frontends/ilang/ilang_parser $< - $(Q) mv frontends/ilang/ilang_parser.tab.c frontends/ilang/ilang_parser.tab.cc + $(P) $(BISON) -o $@ -d -r all -b frontends/ilang/ilang_parser $< -frontends/ilang/ilang_parser.tab.h: frontends/ilang/ilang_parser.tab.cc +frontends/ilang/ilang_parser.tab.hh: frontends/ilang/ilang_parser.tab.cc frontends/ilang/ilang_lexer.cc: frontends/ilang/ilang_lexer.l $(Q) mkdir -p $(dir $@) diff --git a/frontends/ilang/ilang_frontend.cc b/frontends/ilang/ilang_frontend.cc index ed6789987..30d9ff79d 100644 --- a/frontends/ilang/ilang_frontend.cc +++ b/frontends/ilang/ilang_frontend.cc @@ -35,7 +35,7 @@ YOSYS_NAMESPACE_BEGIN struct IlangFrontend : public Frontend { IlangFrontend() : Frontend("ilang", "read modules from ilang file") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -44,11 +44,47 @@ struct IlangFrontend : public Frontend { log("Load modules from an ilang file to the current design. (ilang is a text\n"); log("representation of a design in yosys's internal format.)\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 blackbox\n"); + log(" module, and overwrite the existing module if it is a blackbox module.)\n"); + log("\n"); + log(" -overwrite\n"); + log(" overwrite existing modules with the same name\n"); + log("\n"); + log(" -lib\n"); + log(" only create empty blackbox modules\n"); + log("\n"); } - virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) + void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { + ILANG_FRONTEND::flag_nooverwrite = false; + ILANG_FRONTEND::flag_overwrite = false; + ILANG_FRONTEND::flag_lib = false; + log_header(design, "Executing ILANG frontend.\n"); - extra_args(f, filename, args, 1); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + std::string arg = args[argidx]; + if (arg == "-nooverwrite") { + ILANG_FRONTEND::flag_nooverwrite = true; + ILANG_FRONTEND::flag_overwrite = false; + continue; + } + if (arg == "-overwrite") { + ILANG_FRONTEND::flag_nooverwrite = false; + ILANG_FRONTEND::flag_overwrite = true; + continue; + } + if (arg == "-lib") { + ILANG_FRONTEND::flag_lib = true; + continue; + } + break; + } + extra_args(f, filename, args, argidx); + log("Input filename: %s\n", filename.c_str()); ILANG_FRONTEND::lexin = f; diff --git a/frontends/ilang/ilang_frontend.h b/frontends/ilang/ilang_frontend.h index ad3ffec90..f8a152841 100644 --- a/frontends/ilang/ilang_frontend.h +++ b/frontends/ilang/ilang_frontend.h @@ -32,6 +32,9 @@ YOSYS_NAMESPACE_BEGIN namespace ILANG_FRONTEND { extern std::istream *lexin; extern RTLIL::Design *current_design; + extern bool flag_nooverwrite; + extern bool flag_overwrite; + extern bool flag_lib; } YOSYS_NAMESPACE_END diff --git a/frontends/ilang/ilang_lexer.l b/frontends/ilang/ilang_lexer.l index 842388548..4fd0ae855 100644 --- a/frontends/ilang/ilang_lexer.l +++ b/frontends/ilang/ilang_lexer.l @@ -30,7 +30,7 @@ #endif #include "frontends/ilang/ilang_frontend.h" -#include "ilang_parser.tab.h" +#include "ilang_parser.tab.hh" USING_YOSYS_NAMESPACE @@ -53,6 +53,7 @@ USING_YOSYS_NAMESPACE "attribute" { return TOK_ATTRIBUTE; } "parameter" { return TOK_PARAMETER; } "signed" { return TOK_SIGNED; } +"real" { return TOK_REAL; } "wire" { return TOK_WIRE; } "memory" { return TOK_MEMORY; } "width" { return TOK_WIDTH; } diff --git a/frontends/ilang/ilang_parser.y b/frontends/ilang/ilang_parser.y index bfc062fec..b4b9693da 100644 --- a/frontends/ilang/ilang_parser.y +++ b/frontends/ilang/ilang_parser.y @@ -37,13 +37,24 @@ namespace ILANG_FRONTEND { std::vector<std::vector<RTLIL::SwitchRule*>*> switch_stack; std::vector<RTLIL::CaseRule*> case_stack; dict<RTLIL::IdString, RTLIL::Const> attrbuf; + bool flag_nooverwrite, flag_overwrite, flag_lib; + bool delete_current_module; } using namespace ILANG_FRONTEND; YOSYS_NAMESPACE_END USING_YOSYS_NAMESPACE %} -%name-prefix "rtlil_frontend_ilang_yy" +%define api.prefix {rtlil_frontend_ilang_yy} + +/* The union is defined in the header, so we need to provide all the + * includes it requires + */ +%code requires { +#include <string> +#include <vector> +#include "frontends/ilang/ilang_frontend.h" +} %union { char *string; @@ -59,7 +70,7 @@ USING_YOSYS_NAMESPACE %token TOK_CELL TOK_CONNECT TOK_SWITCH TOK_CASE TOK_ASSIGN TOK_SYNC %token TOK_LOW TOK_HIGH TOK_POSEDGE TOK_NEGEDGE TOK_EDGE TOK_ALWAYS TOK_GLOBAL TOK_INIT %token TOK_UPDATE TOK_PROCESS TOK_END TOK_INVALID TOK_EOL TOK_OFFSET -%token TOK_PARAMETER TOK_ATTRIBUTE TOK_MEMORY TOK_SIZE TOK_SIGNED TOK_UPTO +%token TOK_PARAMETER TOK_ATTRIBUTE TOK_MEMORY TOK_SIZE TOK_SIGNED TOK_REAL TOK_UPTO %type <rsigspec> sigspec_list_reversed %type <sigspec> sigspec sigspec_list @@ -93,18 +104,38 @@ design: module: TOK_MODULE TOK_ID EOL { - if (current_design->has($2)) - rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of module %s.", $2).c_str()); + delete_current_module = false; + if (current_design->has($2)) { + RTLIL::Module *existing_mod = current_design->module($2); + if (!flag_overwrite && (flag_lib || (attrbuf.count("\\blackbox") && attrbuf.at("\\blackbox").as_bool()))) { + log("Ignoring blackbox re-definition of module %s.\n", $2); + delete_current_module = true; + } else if (!flag_nooverwrite && !flag_overwrite && !existing_mod->get_bool_attribute("\\blackbox")) { + rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of module %s.", $2).c_str()); + } else if (flag_nooverwrite) { + log("Ignoring re-definition of module %s.\n", $2); + delete_current_module = true; + } else { + log("Replacing existing%s module %s.\n", existing_mod->get_bool_attribute("\\blackbox") ? " blackbox" : "", $2); + current_design->remove(existing_mod); + } + } current_module = new RTLIL::Module; current_module->name = $2; current_module->attributes = attrbuf; - current_design->add(current_module); + if (!delete_current_module) + current_design->add(current_module); attrbuf.clear(); free($2); } module_body TOK_END { if (attrbuf.size() != 0) rtlil_frontend_ilang_yyerror("dangling attribute"); current_module->fixup_ports(); + if (delete_current_module) + delete current_module; + else if (flag_lib) + current_module->makeblackbox(); + current_module = nullptr; } EOL; module_body: @@ -219,6 +250,12 @@ cell_body: free($4); delete $5; } | + cell_body TOK_PARAMETER TOK_REAL TOK_ID constant EOL { + current_cell->parameters[$4] = *$5; + current_cell->parameters[$4].flags |= RTLIL::CONST_FLAG_REAL; + free($4); + delete $5; + } | cell_body TOK_CONNECT TOK_ID sigspec EOL { if (current_cell->hasPort($3)) rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of cell port %s.", $3).c_str()); @@ -245,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 */ | @@ -261,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(); @@ -282,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; @@ -387,17 +429,13 @@ sigspec: $$ = new RTLIL::SigSpec(current_module->wires_[$1]); free($1); } | - TOK_ID '[' TOK_INT ']' { - if (current_module->wires_.count($1) == 0) - rtlil_frontend_ilang_yyerror(stringf("ilang error: wire %s not found", $1).c_str()); - $$ = new RTLIL::SigSpec(current_module->wires_[$1], $3); - free($1); + sigspec '[' TOK_INT ']' { + $$ = new RTLIL::SigSpec($1->extract($3)); + delete $1; } | - TOK_ID '[' TOK_INT ':' TOK_INT ']' { - if (current_module->wires_.count($1) == 0) - rtlil_frontend_ilang_yyerror(stringf("ilang error: wire %s not found", $1).c_str()); - $$ = new RTLIL::SigSpec(current_module->wires_[$1], $5, $3 - $5 + 1); - free($1); + sigspec '[' TOK_INT ':' TOK_INT ']' { + $$ = new RTLIL::SigSpec($1->extract($5, $3 - $5 + 1)); + delete $1; } | '{' sigspec_list '}' { $$ = $2; @@ -427,4 +465,3 @@ conn_stmt: delete $2; delete $3; }; - diff --git a/frontends/json/jsonparse.cc b/frontends/json/jsonparse.cc index 629578c61..7aceffbfc 100644 --- a/frontends/json/jsonparse.cc +++ b/frontends/json/jsonparse.cc @@ -25,7 +25,7 @@ struct JsonNode { char type; // S=String, N=Number, A=Array, D=Dict string data_string; - int data_number; + int64_t data_number; vector<JsonNode*> data_array; dict<string, JsonNode*> data_dict; vector<string> data_dict_keys; @@ -206,6 +206,38 @@ struct JsonNode } }; +Const json_parse_attr_param_value(JsonNode *node) +{ + Const value; + + if (node->type == 'S') { + string &s = node->data_string; + size_t cursor = s.find_first_not_of("01xz"); + if (cursor == string::npos) { + value = Const::from_string(s); + } else if (s.find_first_not_of(' ', cursor) == string::npos) { + value = Const(s.substr(0, GetSize(s)-1)); + } else { + value = Const(s); + } + } else + if (node->type == 'N') { + value = Const(node->data_number, 32); + if (node->data_number < 0) + value.flags |= RTLIL::CONST_FLAG_SIGNED; + } else + if (node->type == 'A') { + log_error("JSON attribute or parameter value is an array.\n"); + } else + if (node->type == 'D') { + log_error("JSON attribute or parameter value is a dict.\n"); + } else { + log_abort(); + } + + return value; +} + void json_parse_attr_param(dict<IdString, Const> &results, JsonNode *node) { if (node->type != 'D') @@ -214,28 +246,7 @@ void json_parse_attr_param(dict<IdString, Const> &results, JsonNode *node) for (auto it : node->data_dict) { IdString key = RTLIL::escape_id(it.first.c_str()); - JsonNode *value_node = it.second; - Const value; - - if (value_node->type == 'S') { - string &s = value_node->data_string; - if (s.find_first_not_of("01xz") == string::npos) - value = Const::from_string(s); - else - value = Const(s); - } else - if (value_node->type == 'N') { - value = Const(value_node->data_number, 32); - } else - if (value_node->type == 'A') { - log_error("JSON attribute or parameter value is an array.\n"); - } else - if (value_node->type == 'D') { - log_error("JSON attribute or parameter value is a dict.\n"); - } else { - log_abort(); - } - + Const value = json_parse_attr_param_value(it.second); results[key] = value; } } @@ -292,6 +303,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 +395,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); @@ -494,7 +529,7 @@ void json_import(Design *design, string &modname, JsonNode *node) struct JsonFrontend : public Frontend { JsonFrontend() : Frontend("json", "read JSON file") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -504,7 +539,7 @@ struct JsonFrontend : public Frontend { log("for a description of the file format.\n"); log("\n"); } - virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) + void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing JSON frontend.\n"); diff --git a/frontends/liberty/liberty.cc b/frontends/liberty/liberty.cc index b9e53a4be..14de95e07 100644 --- a/frontends/liberty/liberty.cc +++ b/frontends/liberty/liberty.cc @@ -36,7 +36,8 @@ static RTLIL::SigSpec parse_func_identifier(RTLIL::Module *module, const char *& int id_len = 0; while (('a' <= expr[id_len] && expr[id_len] <= 'z') || ('A' <= expr[id_len] && expr[id_len] <= 'Z') || - ('0' <= expr[id_len] && expr[id_len] <= '9') || expr[id_len] == '.' || expr[id_len] == '_') id_len++; + ('0' <= expr[id_len] && expr[id_len] <= '9') || expr[id_len] == '.' || + expr[id_len] == '_' || expr[id_len] == '[' || expr[id_len] == ']') id_len++; if (id_len == 0) log_error("Expected identifier at `%s'.\n", expr); @@ -452,7 +453,7 @@ void parse_type_map(std::map<std::string, std::tuple<int, int, bool>> &type_map, struct LibertyFrontend : public Frontend { LibertyFrontend() : Frontend("liberty", "read cells from liberty file") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -485,7 +486,7 @@ struct LibertyFrontend : public Frontend { log(" set the specified attribute (to the value 1) on all loaded modules\n"); log("\n"); } - virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) + void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { bool flag_lib = false; bool flag_nooverwrite = false; @@ -550,7 +551,7 @@ struct LibertyFrontend : public Frontend { if (design->has(cell_name)) { Module *existing_mod = design->module(cell_name); if (!flag_nooverwrite && !flag_overwrite && !existing_mod->get_bool_attribute("\\blackbox")) { - log_error("Re-definition of of cell/module %s!\n", log_id(cell_name)); + log_error("Re-definition of cell/module %s!\n", log_id(cell_name)); } else if (flag_nooverwrite) { log("Ignoring re-definition of module %s.\n", log_id(cell_name)); continue; @@ -615,7 +616,7 @@ struct LibertyFrontend : public Frontend { LibertyAst *bus_type_node = node->find("bus_type"); if (!bus_type_node || !type_map.count(bus_type_node->value)) - log_error("Unkown or unsupported type for bus interface %s on cell %s.\n", + log_error("Unknown or unsupported type for bus interface %s on cell %s.\n", node->args.at(0).c_str(), log_id(cell_name)); int bus_type_width = std::get<0>(type_map.at(bus_type_node->value)); @@ -634,9 +635,12 @@ struct LibertyFrontend : public Frontend { } } - for (auto node : cell->children) + if (!flag_lib) { - if (!flag_lib) { + // some liberty files do not put ff/latch at the beginning of a cell + // try to find "ff" or "latch" and create FF/latch _before_ processing all other nodes + for (auto node : cell->children) + { if (node->id == "ff" && node->args.size() == 2) create_ff(module, node); if (node->id == "latch" && node->args.size() == 2) @@ -645,7 +649,10 @@ struct LibertyFrontend : public Frontend { goto skip_cell; } } + } + for (auto node : cell->children) + { if (node->id == "pin" && node->args.size() == 1) { LibertyAst *dir = node->find("direction"); diff --git a/frontends/verific/README b/frontends/verific/README index b4c436a3a..89584f2e8 100644 --- a/frontends/verific/README +++ b/frontends/verific/README @@ -4,35 +4,6 @@ This directory contains Verific bindings for Yosys. See http://www.verific.com/ for details. -Building Yosys with the 32 bit Verific eval library on amd64: -============================================================= - -1.) Use a Makefile.conf like the following one: - ---snip-- -CONFIG := gcc -ENABLE_TCL := 0 -ENABLE_PLUGINS := 0 -ENABLE_VERIFIC := 1 -CXXFLAGS += -m32 -LDFLAGS += -m32 -VERIFIC_DIR = /usr/local/src/verific_lib_eval ---snap-- - - -2.) Install the necessary multilib packages - -Hint: On debian/ubuntu the multilib packages have names such as -libreadline-dev:i386 or lib32readline6-dev, depending on the -exact version of debian/ubuntu you are working with. - - -3.) Build and test - -make -j8 -./yosys -p 'verific -sv frontends/verific/example.sv; verific -import top' - - Verific Features that should be enabled in your Verific library =============================================================== @@ -50,7 +21,7 @@ Then run in the following command in this directory: sby -f example.sby -This will generate approximately one page of text outpout. The last lines +This will generate approximately one page of text output. The last lines should be something like this: SBY [example] summary: Elapsed clock time [H:MM:SS (secs)]: 0:00:00 (0) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 62a8028b8..c5eef4b55 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -19,6 +19,7 @@ #include "kernel/yosys.h" #include "kernel/sigtools.h" +#include "kernel/celltypes.h" #include "kernel/log.h" #include <stdlib.h> #include <stdio.h> @@ -46,7 +47,15 @@ USING_YOSYS_NAMESPACE #include "VeriModule.h" #include "VeriWrite.h" #include "VhdlUnits.h" -#include "Message.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 @@ -64,6 +73,9 @@ YOSYS_NAMESPACE_BEGIN int verific_verbose; bool verific_import_pending; string verific_error_msg; +int verific_sva_fsm_limit; + +vector<string> verific_incdirs, verific_libdirs; void msg_func(msg_type_t msg_type, const char *message_id, linefile_type linefile, const char *msg, va_list args) { @@ -100,9 +112,10 @@ string get_full_netlist_name(Netlist *nl) // ================================================================== -VerificImporter::VerificImporter(bool mode_gates, bool mode_keep, bool mode_nosva, bool mode_names, bool mode_verific, bool mode_autocover) : +VerificImporter::VerificImporter(bool mode_gates, bool mode_keep, bool mode_nosva, bool mode_names, bool mode_verific, bool mode_autocover, bool mode_fullinit) : mode_gates(mode_gates), mode_keep(mode_keep), mode_nosva(mode_nosva), - mode_names(mode_names), mode_verific(mode_verific), mode_autocover(mode_autocover) + mode_names(mode_names), mode_verific(mode_verific), mode_autocover(mode_autocover), + mode_fullinit(mode_fullinit) { } @@ -115,6 +128,27 @@ RTLIL::SigBit VerificImporter::net_map_at(Net *net) return net_map.at(net); } +bool is_blackbox(Netlist *nl) +{ + if (nl->IsBlackBox()) + return true; + + const char *attr = nl->GetAttValue("blackbox"); + if (attr != nullptr && strcmp(attr, "0")) + return true; + + return false; +} + +RTLIL::IdString VerificImporter::new_verific_id(Verific::DesignObj *obj) +{ + std::string s = stringf("$verific$%s", obj->Name()); + if (obj->Linefile()) + s += stringf("$%s:%d", Verific::LineFile::GetFileName(obj->Linefile()), Verific::LineFile::GetLineNo(obj->Linefile())); + s += stringf("$%d", autoidx++); + return s; +} + void VerificImporter::import_attributes(dict<RTLIL::IdString, RTLIL::Const> &attributes, DesignObj *obj) { MapIter mi; @@ -200,7 +234,7 @@ RTLIL::SigSpec VerificImporter::operatorOutput(Instance *inst, const pool<Net*, dummy_wire = NULL; } else { if (dummy_wire == NULL) - dummy_wire = module->addWire(NEW_ID); + dummy_wire = module->addWire(new_verific_id(inst)); else dummy_wire->width++; sig.append(RTLIL::SigSpec(dummy_wire, dummy_wire->width - 1)); @@ -216,8 +250,8 @@ bool VerificImporter::import_netlist_instance_gates(Instance *inst, RTLIL::IdStr } if (inst->Type() == PRIM_NAND) { - RTLIL::SigSpec tmp = module->addWire(NEW_ID); - module->addAndGate(NEW_ID, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), tmp); + RTLIL::SigSpec tmp = module->addWire(new_verific_id(inst)); + module->addAndGate(new_verific_id(inst), net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), tmp); module->addNotGate(inst_name, tmp, net_map_at(inst->GetOutput())); return true; } @@ -228,8 +262,8 @@ bool VerificImporter::import_netlist_instance_gates(Instance *inst, RTLIL::IdStr } if (inst->Type() == PRIM_NOR) { - RTLIL::SigSpec tmp = module->addWire(NEW_ID); - module->addOrGate(NEW_ID, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), tmp); + RTLIL::SigSpec tmp = module->addWire(new_verific_id(inst)); + module->addOrGate(new_verific_id(inst), net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), tmp); module->addNotGate(inst_name, tmp, net_map_at(inst->GetOutput())); return true; } @@ -269,16 +303,16 @@ bool VerificImporter::import_netlist_instance_gates(Instance *inst, RTLIL::IdStr if (inst->Type() == PRIM_FADD) { RTLIL::SigSpec a = net_map_at(inst->GetInput1()), b = net_map_at(inst->GetInput2()), c = net_map_at(inst->GetCin()); - RTLIL::SigSpec x = inst->GetCout() ? net_map_at(inst->GetCout()) : module->addWire(NEW_ID); - RTLIL::SigSpec y = inst->GetOutput() ? net_map_at(inst->GetOutput()) : module->addWire(NEW_ID); - RTLIL::SigSpec tmp1 = module->addWire(NEW_ID); - RTLIL::SigSpec tmp2 = module->addWire(NEW_ID); - RTLIL::SigSpec tmp3 = module->addWire(NEW_ID); - module->addXorGate(NEW_ID, a, b, tmp1); + RTLIL::SigSpec x = inst->GetCout() ? net_map_at(inst->GetCout()) : module->addWire(new_verific_id(inst)); + RTLIL::SigSpec y = inst->GetOutput() ? net_map_at(inst->GetOutput()) : module->addWire(new_verific_id(inst)); + RTLIL::SigSpec tmp1 = module->addWire(new_verific_id(inst)); + RTLIL::SigSpec tmp2 = module->addWire(new_verific_id(inst)); + RTLIL::SigSpec tmp3 = module->addWire(new_verific_id(inst)); + module->addXorGate(new_verific_id(inst), a, b, tmp1); module->addXorGate(inst_name, tmp1, c, y); - module->addAndGate(NEW_ID, tmp1, c, tmp2); - module->addAndGate(NEW_ID, a, b, tmp3); - module->addOrGate(NEW_ID, tmp2, tmp3, x); + module->addAndGate(new_verific_id(inst), tmp1, c, tmp2); + module->addAndGate(new_verific_id(inst), a, b, tmp3); + module->addOrGate(new_verific_id(inst), tmp2, tmp3, x); return true; } @@ -305,63 +339,78 @@ bool VerificImporter::import_netlist_instance_gates(Instance *inst, RTLIL::IdStr bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdString inst_name) { + RTLIL::Cell *cell = nullptr; + if (inst->Type() == PRIM_AND) { - module->addAnd(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetOutput())); + cell = module->addAnd(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetOutput())); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == PRIM_NAND) { - RTLIL::SigSpec tmp = module->addWire(NEW_ID); - module->addAnd(NEW_ID, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), tmp); - module->addNot(inst_name, tmp, net_map_at(inst->GetOutput())); + RTLIL::SigSpec tmp = module->addWire(new_verific_id(inst)); + cell = module->addAnd(new_verific_id(inst), net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), tmp); + import_attributes(cell->attributes, inst); + cell = module->addNot(inst_name, tmp, net_map_at(inst->GetOutput())); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == PRIM_OR) { - module->addOr(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetOutput())); + cell = module->addOr(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetOutput())); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == PRIM_NOR) { - RTLIL::SigSpec tmp = module->addWire(NEW_ID); - module->addOr(NEW_ID, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), tmp); - module->addNot(inst_name, tmp, net_map_at(inst->GetOutput())); + RTLIL::SigSpec tmp = module->addWire(new_verific_id(inst)); + cell = module->addOr(new_verific_id(inst), net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), tmp); + import_attributes(cell->attributes, inst); + cell = module->addNot(inst_name, tmp, net_map_at(inst->GetOutput())); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == PRIM_XOR) { - module->addXor(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetOutput())); + cell = module->addXor(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetOutput())); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == PRIM_XNOR) { - module->addXnor(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetOutput())); + cell = module->addXnor(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetOutput())); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == PRIM_INV) { - module->addNot(inst_name, net_map_at(inst->GetInput()), net_map_at(inst->GetOutput())); + cell = module->addNot(inst_name, net_map_at(inst->GetInput()), net_map_at(inst->GetOutput())); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == PRIM_MUX) { - module->addMux(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetControl()), net_map_at(inst->GetOutput())); + cell = module->addMux(inst_name, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), net_map_at(inst->GetControl()), net_map_at(inst->GetOutput())); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == PRIM_TRI) { - module->addMux(inst_name, RTLIL::State::Sz, net_map_at(inst->GetInput()), net_map_at(inst->GetControl()), net_map_at(inst->GetOutput())); + cell = module->addMux(inst_name, RTLIL::State::Sz, net_map_at(inst->GetInput()), net_map_at(inst->GetControl()), net_map_at(inst->GetOutput())); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == PRIM_FADD) { - RTLIL::SigSpec a_plus_b = module->addWire(NEW_ID, 2); - RTLIL::SigSpec y = inst->GetOutput() ? net_map_at(inst->GetOutput()) : module->addWire(NEW_ID); + RTLIL::SigSpec a_plus_b = module->addWire(new_verific_id(inst), 2); + RTLIL::SigSpec y = inst->GetOutput() ? net_map_at(inst->GetOutput()) : module->addWire(new_verific_id(inst)); if (inst->GetCout()) y.append(net_map_at(inst->GetCout())); - module->addAdd(NEW_ID, net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), a_plus_b); - module->addAdd(inst_name, a_plus_b, net_map_at(inst->GetCin()), y); + cell = module->addAdd(new_verific_id(inst), net_map_at(inst->GetInput1()), net_map_at(inst->GetInput2()), a_plus_b); + import_attributes(cell->attributes, inst); + cell = module->addAdd(inst_name, a_plus_b, net_map_at(inst->GetCin()), y); + import_attributes(cell->attributes, inst); return true; } @@ -372,24 +421,26 @@ bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdStr log_assert(clocking.body_net == nullptr); if (inst->GetSet()->IsGnd() && inst->GetReset()->IsGnd()) - clocking.addDff(inst_name, net_map_at(inst->GetInput()), net_map_at(inst->GetOutput())); + cell = clocking.addDff(inst_name, net_map_at(inst->GetInput()), net_map_at(inst->GetOutput())); else if (inst->GetSet()->IsGnd()) - clocking.addAdff(inst_name, net_map_at(inst->GetReset()), net_map_at(inst->GetInput()), net_map_at(inst->GetOutput()), RTLIL::State::S0); + cell = clocking.addAdff(inst_name, net_map_at(inst->GetReset()), net_map_at(inst->GetInput()), net_map_at(inst->GetOutput()), RTLIL::State::S0); else if (inst->GetReset()->IsGnd()) - clocking.addAdff(inst_name, net_map_at(inst->GetSet()), net_map_at(inst->GetInput()), net_map_at(inst->GetOutput()), RTLIL::State::S1); + cell = clocking.addAdff(inst_name, net_map_at(inst->GetSet()), net_map_at(inst->GetInput()), net_map_at(inst->GetOutput()), RTLIL::State::S1); else - clocking.addDffsr(inst_name, net_map_at(inst->GetSet()), net_map_at(inst->GetReset()), + cell = clocking.addDffsr(inst_name, net_map_at(inst->GetSet()), net_map_at(inst->GetReset()), net_map_at(inst->GetInput()), net_map_at(inst->GetOutput())); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == PRIM_DLATCHRS) { if (inst->GetSet()->IsGnd() && inst->GetReset()->IsGnd()) - module->addDlatch(inst_name, net_map_at(inst->GetControl()), net_map_at(inst->GetInput()), net_map_at(inst->GetOutput())); + cell = module->addDlatch(inst_name, net_map_at(inst->GetControl()), net_map_at(inst->GetInput()), net_map_at(inst->GetOutput())); else - module->addDlatchsr(inst_name, net_map_at(inst->GetControl()), net_map_at(inst->GetSet()), net_map_at(inst->GetReset()), + cell = module->addDlatchsr(inst_name, net_map_at(inst->GetControl()), net_map_at(inst->GetSet()), net_map_at(inst->GetReset()), net_map_at(inst->GetInput()), net_map_at(inst->GetOutput())); + import_attributes(cell->attributes, inst); return true; } @@ -405,37 +456,45 @@ bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdStr if (inst->GetCout() != NULL) out.append(net_map_at(inst->GetCout())); if (inst->GetCin()->IsGnd()) { - module->addAdd(inst_name, IN1, IN2, out, SIGNED); + cell = module->addAdd(inst_name, IN1, IN2, out, SIGNED); + import_attributes(cell->attributes, inst); } else { - RTLIL::SigSpec tmp = module->addWire(NEW_ID, GetSize(out)); - module->addAdd(NEW_ID, IN1, IN2, tmp, SIGNED); - module->addAdd(inst_name, tmp, net_map_at(inst->GetCin()), out, false); + RTLIL::SigSpec tmp = module->addWire(new_verific_id(inst), GetSize(out)); + cell = module->addAdd(new_verific_id(inst), IN1, IN2, tmp, SIGNED); + import_attributes(cell->attributes, inst); + cell = module->addAdd(inst_name, tmp, net_map_at(inst->GetCin()), out, false); + import_attributes(cell->attributes, inst); } return true; } if (inst->Type() == OPER_MULTIPLIER) { - module->addMul(inst_name, IN1, IN2, OUT, SIGNED); + cell = module->addMul(inst_name, IN1, IN2, OUT, SIGNED); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == OPER_DIVIDER) { - module->addDiv(inst_name, IN1, IN2, OUT, SIGNED); + cell = module->addDiv(inst_name, IN1, IN2, OUT, SIGNED); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == OPER_MODULO) { - module->addMod(inst_name, IN1, IN2, OUT, SIGNED); + cell = module->addMod(inst_name, IN1, IN2, OUT, SIGNED); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == OPER_REMAINDER) { - module->addMod(inst_name, IN1, IN2, OUT, SIGNED); + cell = module->addMod(inst_name, IN1, IN2, OUT, SIGNED); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == OPER_SHIFT_LEFT) { - module->addShl(inst_name, IN1, IN2, OUT, false); + cell = module->addShl(inst_name, IN1, IN2, OUT, false); + import_attributes(cell->attributes, inst); return true; } @@ -445,7 +504,8 @@ bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdStr for (unsigned i = 1; i < inst->OutputSize(); i++) { vec.append(RTLIL::State::S0); } - module->addShl(inst_name, vec, IN, OUT, false); + cell = module->addShl(inst_name, vec, IN, OUT, false); + import_attributes(cell->attributes, inst); return true; } @@ -455,7 +515,8 @@ bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdStr for (unsigned i = 1; i < inst->OutputSize(); i++) { vec.append(RTLIL::State::S0); } - module->addShl(inst_name, vec, IN, OUT, false); + cell = module->addShl(inst_name, vec, IN, OUT, false); + import_attributes(cell->attributes, inst); return true; } @@ -463,108 +524,127 @@ bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdStr Net *net_cin = inst->GetCin(); Net *net_a_msb = inst->GetInput1Bit(0); if (net_cin->IsGnd()) - module->addShr(inst_name, IN1, IN2, OUT, false); + cell = module->addShr(inst_name, IN1, IN2, OUT, false); else if (net_cin == net_a_msb) - module->addSshr(inst_name, IN1, IN2, OUT, true); + cell = module->addSshr(inst_name, IN1, IN2, OUT, true); else log_error("Can't import Verific OPER_SHIFT_RIGHT instance %s: carry_in is neither 0 nor msb of left input\n", inst->Name()); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == OPER_REDUCE_AND) { - module->addReduceAnd(inst_name, IN, net_map_at(inst->GetOutput()), SIGNED); + cell = module->addReduceAnd(inst_name, IN, net_map_at(inst->GetOutput()), SIGNED); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == OPER_REDUCE_OR) { - module->addReduceOr(inst_name, IN, net_map_at(inst->GetOutput()), SIGNED); + cell = module->addReduceOr(inst_name, IN, net_map_at(inst->GetOutput()), SIGNED); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == OPER_REDUCE_XOR) { - module->addReduceXor(inst_name, IN, net_map_at(inst->GetOutput()), SIGNED); + cell = module->addReduceXor(inst_name, IN, net_map_at(inst->GetOutput()), SIGNED); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == OPER_REDUCE_XNOR) { - module->addReduceXnor(inst_name, IN, net_map_at(inst->GetOutput()), SIGNED); + cell = module->addReduceXnor(inst_name, IN, net_map_at(inst->GetOutput()), SIGNED); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == OPER_REDUCE_NOR) { - SigSpec t = module->ReduceOr(NEW_ID, IN, SIGNED); - module->addNot(inst_name, t, net_map_at(inst->GetOutput())); + SigSpec t = module->ReduceOr(new_verific_id(inst), IN, SIGNED); + cell = module->addNot(inst_name, t, net_map_at(inst->GetOutput())); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == OPER_LESSTHAN) { Net *net_cin = inst->GetCin(); if (net_cin->IsGnd()) - module->addLt(inst_name, IN1, IN2, net_map_at(inst->GetOutput()), SIGNED); + cell = module->addLt(inst_name, IN1, IN2, net_map_at(inst->GetOutput()), SIGNED); else if (net_cin->IsPwr()) - module->addLe(inst_name, IN1, IN2, net_map_at(inst->GetOutput()), SIGNED); + cell = module->addLe(inst_name, IN1, IN2, net_map_at(inst->GetOutput()), SIGNED); else log_error("Can't import Verific OPER_LESSTHAN instance %s: carry_in is neither 0 nor 1\n", inst->Name()); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == OPER_WIDE_AND) { - module->addAnd(inst_name, IN1, IN2, OUT, SIGNED); + cell = module->addAnd(inst_name, IN1, IN2, OUT, SIGNED); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == OPER_WIDE_OR) { - module->addOr(inst_name, IN1, IN2, OUT, SIGNED); + cell = module->addOr(inst_name, IN1, IN2, OUT, SIGNED); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == OPER_WIDE_XOR) { - module->addXor(inst_name, IN1, IN2, OUT, SIGNED); + cell = module->addXor(inst_name, IN1, IN2, OUT, SIGNED); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == OPER_WIDE_XNOR) { - module->addXnor(inst_name, IN1, IN2, OUT, SIGNED); + cell = module->addXnor(inst_name, IN1, IN2, OUT, SIGNED); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == OPER_WIDE_BUF) { - module->addPos(inst_name, IN, FILTERED_OUT, SIGNED); + cell = module->addPos(inst_name, IN, FILTERED_OUT, SIGNED); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == OPER_WIDE_INV) { - module->addNot(inst_name, IN, OUT, SIGNED); + cell = module->addNot(inst_name, IN, OUT, SIGNED); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == OPER_MINUS) { - module->addSub(inst_name, IN1, IN2, OUT, SIGNED); + cell = module->addSub(inst_name, IN1, IN2, OUT, SIGNED); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == OPER_UMINUS) { - module->addNeg(inst_name, IN, OUT, SIGNED); + cell = module->addNeg(inst_name, IN, OUT, SIGNED); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == OPER_EQUAL) { - module->addEq(inst_name, IN1, IN2, net_map_at(inst->GetOutput()), SIGNED); + cell = module->addEq(inst_name, IN1, IN2, net_map_at(inst->GetOutput()), SIGNED); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == OPER_NEQUAL) { - module->addNe(inst_name, IN1, IN2, net_map_at(inst->GetOutput()), SIGNED); + cell = module->addNe(inst_name, IN1, IN2, net_map_at(inst->GetOutput()), SIGNED); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == OPER_WIDE_MUX) { - module->addMux(inst_name, IN1, IN2, net_map_at(inst->GetControl()), OUT); + cell = module->addMux(inst_name, IN1, IN2, net_map_at(inst->GetControl()), OUT); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == OPER_NTO1MUX) { - module->addShr(inst_name, IN2, IN1, net_map_at(inst->GetOutput())); + cell = module->addShr(inst_name, IN2, IN1, net_map_at(inst->GetOutput())); + import_attributes(cell->attributes, inst); return true; } @@ -584,25 +664,29 @@ bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdStr padded_data.append(d); } - module->addShr(inst_name, padded_data, sel, out); + cell = module->addShr(inst_name, padded_data, sel, out); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == OPER_SELECTOR) { - module->addPmux(inst_name, State::S0, IN2, IN1, net_map_at(inst->GetOutput())); + cell = module->addPmux(inst_name, State::S0, IN2, IN1, net_map_at(inst->GetOutput())); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == OPER_WIDE_SELECTOR) { SigSpec out = OUT; - module->addPmux(inst_name, SigSpec(State::S0, GetSize(out)), IN2, IN1, out); + cell = module->addPmux(inst_name, SigSpec(State::S0, GetSize(out)), IN2, IN1, out); + import_attributes(cell->attributes, inst); return true; } if (inst->Type() == OPER_WIDE_TRI) { - module->addMux(inst_name, RTLIL::SigSpec(RTLIL::State::Sz, inst->OutputSize()), IN, net_map_at(inst->GetControl()), OUT); + cell = module->addMux(inst_name, RTLIL::SigSpec(RTLIL::State::Sz, inst->OutputSize()), IN, net_map_at(inst->GetControl()), OUT); + import_attributes(cell->attributes, inst); return true; } @@ -616,9 +700,10 @@ bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdStr RTLIL::SigSpec sig_reset = operatorInport(inst, "reset"); if (sig_set.is_fully_const() && !sig_set.as_bool() && sig_reset.is_fully_const() && !sig_reset.as_bool()) - clocking.addDff(inst_name, IN, OUT); + cell = clocking.addDff(inst_name, IN, OUT); else - clocking.addDffsr(inst_name, sig_set, sig_reset, IN, OUT); + cell = clocking.addDffsr(inst_name, sig_set, sig_reset, IN, OUT); + import_attributes(cell->attributes, inst); return true; } @@ -701,13 +786,14 @@ void VerificImporter::merge_past_ffs(pool<RTLIL::Cell*> &candidates) void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*> &nl_todo) { - std::string module_name = nl->IsOperator() ? std::string("$verific$") + nl->Owner()->Name() : RTLIL::escape_id(nl->Owner()->Name()); + std::string netlist_name = nl->GetAtt(" \\top") ? nl->CellBaseName() : nl->Owner()->Name(); + std::string module_name = nl->IsOperator() ? "$verific$" + netlist_name : RTLIL::escape_id(netlist_name); netlist = nl; if (design->has(module_name)) { - if (!nl->IsOperator()) - log_cmd_error("Re-definition of module `%s'.\n", nl->Owner()->Name()); + if (!nl->IsOperator() && !is_blackbox(nl)) + log_cmd_error("Re-definition of module `%s'.\n", netlist_name.c_str()); return; } @@ -715,7 +801,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se module->name = module_name; design->add(module); - if (nl->IsBlackBox()) { + if (is_blackbox(nl)) { log("Importing blackbox module %s.\n", RTLIL::id2cstr(module->name)); module->set_bool_attribute("\\blackbox"); } else { @@ -847,7 +933,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se ascii_initdata++; } if (initval_valid) { - RTLIL::Cell *cell = module->addCell(NEW_ID, "$meminit"); + RTLIL::Cell *cell = module->addCell(new_verific_id(net), "$meminit"); cell->parameters["\\WORDS"] = 1; if (net->GetOrigTypeRange()->LeftRangeBound() < net->GetOrigTypeRange()->RightRangeBound()) cell->setPort("\\ADDR", word_idx); @@ -910,7 +996,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se if (net->Bus()) continue; - RTLIL::IdString wire_name = module->uniquify(mode_names || net->IsUserDeclared() ? RTLIL::escape_id(net->Name()) : NEW_ID); + RTLIL::IdString wire_name = module->uniquify(mode_names || net->IsUserDeclared() ? RTLIL::escape_id(net->Name()) : new_verific_id(net)); if (verific_verbose) log(" importing net %s as %s.\n", net->Name(), log_id(wire_name)); @@ -934,7 +1020,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se if (found_new_net) { - RTLIL::IdString wire_name = module->uniquify(mode_names || netbus->IsUserDeclared() ? RTLIL::escape_id(netbus->Name()) : NEW_ID); + RTLIL::IdString wire_name = module->uniquify(mode_names || netbus->IsUserDeclared() ? RTLIL::escape_id(netbus->Name()) : new_verific_id(netbus)); if (verific_verbose) log(" importing netbus %s as %s.\n", netbus->Name(), log_id(wire_name)); @@ -1010,16 +1096,16 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se } if (GetSize(anyconst_sig)) - module->connect(anyconst_sig, module->Anyconst(NEW_ID, GetSize(anyconst_sig))); + module->connect(anyconst_sig, module->Anyconst(new_verific_id(netbus), GetSize(anyconst_sig))); if (GetSize(anyseq_sig)) - module->connect(anyseq_sig, module->Anyseq(NEW_ID, GetSize(anyseq_sig))); + module->connect(anyseq_sig, module->Anyseq(new_verific_id(netbus), GetSize(anyseq_sig))); if (GetSize(allconst_sig)) - module->connect(allconst_sig, module->Allconst(NEW_ID, GetSize(allconst_sig))); + module->connect(allconst_sig, module->Allconst(new_verific_id(netbus), GetSize(allconst_sig))); if (GetSize(allseq_sig)) - module->connect(allseq_sig, module->Allseq(NEW_ID, GetSize(allseq_sig))); + module->connect(allseq_sig, module->Allseq(new_verific_id(netbus), GetSize(allseq_sig))); } for (auto it : init_nets) @@ -1043,10 +1129,10 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se } for (auto net : anyconst_nets) - module->connect(net_map_at(net), module->Anyconst(NEW_ID)); + module->connect(net_map_at(net), module->Anyconst(new_verific_id(net))); for (auto net : anyseq_nets) - module->connect(net_map_at(net), module->Anyseq(NEW_ID)); + module->connect(net_map_at(net), module->Anyseq(new_verific_id(net))); pool<Instance*, hash_ptr_ops> sva_asserts; pool<Instance*, hash_ptr_ops> sva_assumes; @@ -1057,7 +1143,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se FOREACH_INSTANCE_OF_NETLIST(nl, mi, inst) { - RTLIL::IdString inst_name = module->uniquify(mode_names || inst->IsUserDeclared() ? RTLIL::escape_id(inst->Name()) : NEW_ID); + RTLIL::IdString inst_name = module->uniquify(mode_names || inst->IsUserDeclared() ? RTLIL::escape_id(inst->Name()) : new_verific_id(inst)); if (verific_verbose) log(" importing cell %s (%s) as %s.\n", inst->Name(), inst->View()->Owner()->Name(), log_id(inst_name)); @@ -1125,27 +1211,34 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se if (inst->Type() == OPER_WRITE_PORT || inst->Type() == OPER_CLOCKED_WRITE_PORT) { RTLIL::Memory *memory = module->memories.at(RTLIL::escape_id(inst->GetOutput()->Name())); - if (memory->width != int(inst->Input2Size())) - log_error("Import of asymmetric memories of this type is not supported yet: %s %s\n", inst->Name(), inst->GetInput()->Name()); + int numchunks = int(inst->Input2Size()) / memory->width; + int chunksbits = ceil_log2(numchunks); + + if ((numchunks * memory->width) != int(inst->Input2Size()) || (numchunks & (numchunks - 1)) != 0) + log_error("Import of asymmetric memories of this type is not supported yet: %s %s\n", inst->Name(), inst->GetOutput()->Name()); - RTLIL::SigSpec addr = operatorInput1(inst); - RTLIL::SigSpec data = operatorInput2(inst); - - RTLIL::Cell *cell = module->addCell(inst_name, "$memwr"); - cell->parameters["\\MEMID"] = memory->name.str(); - cell->parameters["\\CLK_ENABLE"] = false; - cell->parameters["\\CLK_POLARITY"] = true; - cell->parameters["\\PRIORITY"] = 0; - cell->parameters["\\ABITS"] = GetSize(addr); - cell->parameters["\\WIDTH"] = GetSize(data); - cell->setPort("\\EN", RTLIL::SigSpec(net_map_at(inst->GetControl())).repeat(GetSize(data))); - cell->setPort("\\CLK", RTLIL::State::S0); - cell->setPort("\\ADDR", addr); - cell->setPort("\\DATA", data); - - if (inst->Type() == OPER_CLOCKED_WRITE_PORT) { - cell->parameters["\\CLK_ENABLE"] = true; - cell->setPort("\\CLK", net_map_at(inst->GetClock())); + for (int i = 0; i < numchunks; i++) + { + RTLIL::SigSpec addr = {operatorInput1(inst), RTLIL::Const(i, chunksbits)}; + RTLIL::SigSpec data = operatorInput2(inst).extract(i * memory->width, memory->width); + + RTLIL::Cell *cell = module->addCell(numchunks == 1 ? inst_name : + RTLIL::IdString(stringf("%s_%d", inst_name.c_str(), i)), "$memwr"); + cell->parameters["\\MEMID"] = memory->name.str(); + cell->parameters["\\CLK_ENABLE"] = false; + cell->parameters["\\CLK_POLARITY"] = true; + cell->parameters["\\PRIORITY"] = 0; + cell->parameters["\\ABITS"] = GetSize(addr); + cell->parameters["\\WIDTH"] = GetSize(data); + cell->setPort("\\EN", RTLIL::SigSpec(net_map_at(inst->GetControl())).repeat(GetSize(data))); + cell->setPort("\\CLK", RTLIL::State::S0); + cell->setPort("\\ADDR", addr); + cell->setPort("\\DATA", data); + + if (inst->Type() == OPER_CLOCKED_WRITE_PORT) { + cell->parameters["\\CLK_ENABLE"] = true; + cell->setPort("\\CLK", net_map_at(inst->GetClock())); + } } continue; } @@ -1181,7 +1274,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se log_assert(inst->Input1Size() == inst->OutputSize()); SigSpec sig_d, sig_q, sig_o; - sig_q = module->addWire(NEW_ID, inst->Input1Size()); + sig_q = module->addWire(new_verific_id(inst), inst->Input1Size()); for (int i = int(inst->Input1Size())-1; i >= 0; i--){ sig_d.append(net_map_at(inst->GetInput1Bit(i))); @@ -1195,8 +1288,8 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se log_signal(sig_d), log_signal(sig_q), log_signal(sig_o)); } - clocking.addDff(NEW_ID, sig_d, sig_q); - module->addXnor(NEW_ID, sig_d, sig_q, sig_o); + clocking.addDff(new_verific_id(inst), sig_d, sig_q); + module->addXnor(new_verific_id(inst), sig_d, sig_q, sig_o); if (!mode_keep) continue; @@ -1210,7 +1303,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se SigSpec sig_d = net_map_at(inst->GetInput1()); SigSpec sig_o = net_map_at(inst->GetOutput()); - SigSpec sig_q = module->addWire(NEW_ID); + SigSpec sig_q = module->addWire(new_verific_id(inst)); if (verific_verbose) { log(" %sedge FF with D=%s, Q=%s, C=%s.\n", clocking.posedge ? "pos" : "neg", @@ -1219,8 +1312,8 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se log_signal(sig_d), log_signal(sig_q), log_signal(sig_o)); } - clocking.addDff(NEW_ID, sig_d, sig_q); - module->addXnor(NEW_ID, sig_d, sig_q, sig_o); + clocking.addDff(new_verific_id(inst), sig_d, sig_q); + module->addXnor(new_verific_id(inst), sig_d, sig_q, sig_o); if (!mode_keep) continue; @@ -1239,7 +1332,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se log(" %sedge FF with D=%s, Q=%s, C=%s.\n", clocking.posedge ? "pos" : "neg", log_signal(sig_d), log_signal(sig_q), log_signal(clocking.clock_sig)); - past_ffs.insert(clocking.addDff(NEW_ID, sig_d, sig_q)); + past_ffs.insert(clocking.addDff(new_verific_id(inst), sig_d, sig_q)); if (!mode_keep) continue; @@ -1253,14 +1346,14 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se SigBit sig_d = net_map_at(inst->GetInput1()); SigBit sig_o = net_map_at(inst->GetOutput()); - SigBit sig_q = module->addWire(NEW_ID); + SigBit sig_q = module->addWire(new_verific_id(inst)); if (verific_verbose) log(" %sedge FF with D=%s, Q=%s, C=%s.\n", clocking.posedge ? "pos" : "neg", log_signal(sig_d), log_signal(sig_q), log_signal(clocking.clock_sig)); - clocking.addDff(NEW_ID, sig_d, sig_q); - module->addEq(NEW_ID, {sig_q, sig_d}, Const(inst->Type() == PRIM_SVA_ROSE ? 1 : 2, 2), sig_o); + clocking.addDff(new_verific_id(inst), sig_d, sig_q); + module->addEq(new_verific_id(inst), {sig_q, sig_d}, Const(inst->Type() == PRIM_SVA_ROSE ? 1 : 2, 2), sig_o); if (!mode_keep) continue; @@ -1283,9 +1376,9 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se Cell *cell = nullptr; if (assume_attr != nullptr && !strcmp(assume_attr, "1")) - cell = module->addAssume(NEW_ID, cond, State::S1); + cell = module->addAssume(new_verific_id(inst), cond, State::S1); else - cell = module->addAssert(NEW_ID, cond, State::S1); + cell = module->addAssert(new_verific_id(inst), cond, State::S1); import_attributes(cell->attributes, inst); continue; @@ -1327,7 +1420,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se IdString port_name_id = RTLIL::escape_id(port_name); auto &sigvec = cell_port_conns[port_name_id]; if (GetSize(sigvec) <= port_offset) { - SigSpec zwires = module->addWire(NEW_ID, port_offset+1-GetSize(sigvec)); + SigSpec zwires = module->addWire(new_verific_id(inst), port_offset+1-GetSize(sigvec)); for (auto bit : zwires) sigvec.push_back(bit); } @@ -1363,6 +1456,50 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se merge_past_ffs(past_ffs); } + + if (!mode_fullinit) + { + pool<SigBit> non_ff_bits; + CellTypes ff_types; + + ff_types.setup_internals_ff(); + ff_types.setup_stdcells_mem(); + + for (auto cell : module->cells()) + { + if (ff_types.cell_known(cell->type)) + continue; + + for (auto conn : cell->connections()) + { + if (!cell->output(conn.first)) + continue; + + for (auto bit : conn.second) + if (bit.wire != nullptr) + non_ff_bits.insert(bit); + } + } + + for (auto wire : module->wires()) + { + if (!wire->attributes.count("\\init")) + continue; + + Const &initval = wire->attributes.at("\\init"); + for (int i = 0; i < GetSize(initval); i++) + { + if (initval[i] != State::S0 && initval[i] != State::S1) + continue; + + if (non_ff_bits.count(SigBit(wire, i))) + initval[i] = State::Sx; + } + + if (initval.is_fully_undef()) + wire->attributes.erase("\\init"); + } + } } // ================================================================== @@ -1537,30 +1674,35 @@ struct VerificExtNets int portname_cnt = 0; // a map from Net to the same Net one level up in the design hierarchy - std::map<Net*, Net*> net_level_up; + std::map<Net*, Net*> net_level_up_drive_up; + std::map<Net*, Net*> net_level_up_drive_down; - Net *get_net_level_up(Net *net) + Net *route_up(Net *net, bool drive_up, Net *final_net = nullptr) { + auto &net_level_up = drive_up ? net_level_up_drive_up : net_level_up_drive_down; + if (net_level_up.count(net) == 0) { Netlist *nl = net->Owner(); // Simply return if Netlist is not unique - if (nl->NumOfRefs() != 1) - return net; + log_assert(nl->NumOfRefs() == 1); Instance *up_inst = (Instance*)nl->GetReferences()->GetLast(); Netlist *up_nl = up_inst->Owner(); // create new Port string name = stringf("___extnets_%d", portname_cnt++); - Port *new_port = new Port(name.c_str(), DIR_OUT); + Port *new_port = new Port(name.c_str(), drive_up ? DIR_OUT : DIR_IN); nl->Add(new_port); net->Connect(new_port); // create new Net in up Netlist - Net *new_net = new Net(name.c_str()); - up_nl->Add(new_net); + Net *new_net = final_net; + if (new_net == nullptr || new_net->Owner() != up_nl) { + new_net = new Net(name.c_str()); + up_nl->Add(new_net); + } up_inst->Connect(new_port, new_net); net_level_up[net] = new_net; @@ -1569,6 +1711,39 @@ struct VerificExtNets return net_level_up.at(net); } + Net *route_up(Net *net, bool drive_up, Netlist *dest, Net *final_net = nullptr) + { + while (net->Owner() != dest) + net = route_up(net, drive_up, final_net); + if (final_net != nullptr) + log_assert(net == final_net); + return net; + } + + Netlist *find_common_ancestor(Netlist *A, Netlist *B) + { + std::set<Netlist*> ancestors_of_A; + + Netlist *cursor = A; + while (1) { + ancestors_of_A.insert(cursor); + if (cursor->NumOfRefs() != 1) + break; + cursor = ((Instance*)cursor->GetReferences()->GetLast())->Owner(); + } + + cursor = B; + while (1) { + if (ancestors_of_A.count(cursor)) + return cursor; + if (cursor->NumOfRefs() != 1) + break; + cursor = ((Instance*)cursor->GetReferences()->GetLast())->Owner(); + } + + log_error("No common ancestor found between %s and %s.\n", get_full_netlist_name(A).c_str(), get_full_netlist_name(B).c_str()); + } + void run(Netlist *nl) { MapIter mi, mi2; @@ -1592,19 +1767,37 @@ struct VerificExtNets if (verific_verbose) log("Fixing external net reference on port %s.%s.%s:\n", get_full_netlist_name(nl).c_str(), inst->Name(), port->Name()); - while (net->IsExternalTo(nl)) - { - Net *newnet = get_net_level_up(net); - if (newnet == net) break; + Netlist *ext_nl = net->Owner(); + if (verific_verbose) + log(" external net owner: %s\n", get_full_netlist_name(ext_nl).c_str()); + + Netlist *ca_nl = find_common_ancestor(nl, ext_nl); + + if (verific_verbose) + log(" common ancestor: %s\n", get_full_netlist_name(ca_nl).c_str()); + + Net *ca_net = route_up(net, !port->IsOutput(), ca_nl); + Net *new_net = ca_net; + + if (ca_nl != nl) + { if (verific_verbose) - log(" external net: %s.%s\n", get_full_netlist_name(net->Owner()).c_str(), net->Name()); - net = newnet; + log(" net in common ancestor: %s\n", ca_net->Name()); + + string name = stringf("___extnets_%d", portname_cnt++); + new_net = new Net(name.c_str()); + nl->Add(new_net); + + Net *n YS_ATTRIBUTE(unused) = route_up(new_net, port->IsOutput(), ca_nl, ca_net); + log_assert(n == ca_net); } if (verific_verbose) - log(" final net: %s.%s%s\n", get_full_netlist_name(net->Owner()).c_str(), net->Name(), net->IsExternalTo(nl) ? " (external)" : ""); - todo_connect.push_back(tuple<Instance*, Port*, Net*>(inst, port, net)); + log(" new local net: %s\n", new_net->Name()); + + log_assert(!new_net->IsExternalTo(nl)); + todo_connect.push_back(tuple<Instance*, Port*, Net*>(inst, port, new_net)); } for (auto it : todo_connect) { @@ -1614,30 +1807,64 @@ struct VerificExtNets } }; -void verific_import(Design *design, std::string top) +void verific_import(Design *design, const std::map<std::string,std::string> ¶meters, std::string top) { + verific_sva_fsm_limit = 16; + std::set<Netlist*> nl_todo, nl_done; - { - VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary("work", 1); - VeriLibrary *veri_lib = veri_file::GetLibrary("work", 1); + VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary("work", 1); + VeriLibrary *veri_lib = veri_file::GetLibrary("work", 1); + Array *netlists = NULL; + Array veri_libs, vhdl_libs; + if (vhdl_lib) vhdl_libs.InsertLast(vhdl_lib); + if (veri_lib) veri_libs.InsertLast(veri_lib); + + Map verific_params(STRING_HASH); + for (const auto &i : parameters) + verific_params.Insert(i.first.c_str(), i.second.c_str()); - Array veri_libs, vhdl_libs; - if (vhdl_lib) vhdl_libs.InsertLast(vhdl_lib); - if (veri_lib) veri_libs.InsertLast(veri_lib); + if (top.empty()) { + netlists = hier_tree::ElaborateAll(&veri_libs, &vhdl_libs, &verific_params); + } + else { + Array veri_modules, vhdl_units; + + if (veri_lib) { + VeriModule *veri_module = veri_lib->GetModule(top.c_str(), 1); + if (veri_module) { + veri_modules.InsertLast(veri_module); + } - Array *netlists = hier_tree::ElaborateAll(&veri_libs, &vhdl_libs); - Netlist *nl; - int i; + // Also elaborate all root modules since they may contain bind statements + MapIter mi; + FOREACH_VERILOG_MODULE_IN_LIBRARY(veri_lib, mi, veri_module) { + if (!veri_module->IsRootModule()) continue; + veri_modules.InsertLast(veri_module); + } + } - FOREACH_ARRAY_ITEM(netlists, i, nl) { - if (top.empty() || nl->Owner()->Name() == top) - nl_todo.insert(nl); + if (vhdl_lib) { + VhdlDesignUnit *vhdl_unit = vhdl_lib->GetPrimUnit(top.c_str()); + if (vhdl_unit) + vhdl_units.InsertLast(vhdl_unit); } - delete netlists; + netlists = hier_tree::Elaborate(&veri_modules, &vhdl_units, &verific_params); + } + + Netlist *nl; + int i; + + FOREACH_ARRAY_ITEM(netlists, i, nl) { + if (top.empty() && nl->CellBaseName() != top) + continue; + nl->AddAtt(new Att(" \\top", NULL)); + nl_todo.insert(nl); } + delete netlists; + if (!verific_error_msg.empty()) log_error("%s\n", verific_error_msg.c_str()); @@ -1648,7 +1875,7 @@ void verific_import(Design *design, std::string top) while (!nl_todo.empty()) { Netlist *nl = *nl_todo.begin(); if (nl_done.count(nl) == 0) { - VerificImporter importer(false, false, false, false, false, false); + VerificImporter importer(false, false, false, false, false, false, false); importer.import_netlist(design, nl, nl_todo); } nl_todo.erase(nl); @@ -1658,6 +1885,8 @@ void verific_import(Design *design, std::string top) veri_file::Reset(); vhdl_file::Reset(); Libset::Reset(); + verific_incdirs.clear(); + verific_libdirs.clear(); verific_import_pending = false; if (!verific_error_msg.empty()) @@ -1669,6 +1898,7 @@ YOSYS_NAMESPACE_END PRIVATE_NAMESPACE_BEGIN +#ifdef YOSYS_ENABLE_VERIFIC bool check_noverific_env() { const char *e = getenv("YOSYS_NOVERIFIC"); @@ -1678,10 +1908,11 @@ bool check_noverific_env() return false; return true; } +#endif struct VerificPass : public Pass { VerificPass() : Pass("verific", "load Verilog and VHDL designs using Verific") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -1702,11 +1933,18 @@ struct VerificPass : public Pass { log("\n"); log("Like -sv, but define FORMAL instead of SYNTHESIS.\n"); log("\n"); + log("\n"); log(" verific {-vhdl87|-vhdl93|-vhdl2k|-vhdl2008|-vhdl} <vhdl-file>..\n"); log("\n"); log("Load the specified VHDL files into Verific.\n"); log("\n"); log("\n"); + log(" verific -work <libname> {-sv|-vhdl|...} <hdl-file>\n"); + log("\n"); + log("Load the specified Verilog/SystemVerilog/VHDL file into the specified library.\n"); + log("(default library when -work is not present: \"work\")\n"); + log("\n"); + log("\n"); log(" verific -vlog-incdir <directory>..\n"); log("\n"); log("Add Verilog include directories.\n"); @@ -1728,6 +1966,15 @@ struct VerificPass : public Pass { log("Remove Verilog defines previously set with -vlog-define.\n"); log("\n"); log("\n"); + log(" verific -set-error <msg_id>..\n"); + log(" verific -set-warning <msg_id>..\n"); + log(" verific -set-info <msg_id>..\n"); + log(" verific -set-ignore <msg_id>..\n"); + log("\n"); + log("Set message severity. <msg_id> is the string in square brackets when a message\n"); + log("is printed, such as VERI-1209.\n"); + log("\n"); + log("\n"); log(" verific -import [options] <top-module>..\n"); log("\n"); log("Elaborate the design for the specified top modules, import to Yosys and\n"); @@ -1751,6 +1998,16 @@ struct VerificPass : public Pass { log(" -autocover\n"); log(" Generate automatic cover statements for all asserts\n"); log("\n"); + log(" -fullinit\n"); + log(" Keep all register initializations, even those for non-FF registers.\n"); + log("\n"); + log(" -chparam name value \n"); + log(" Elaborate the specified top modules (all modules when -all given) using\n"); + log(" this parameter value. Modules on which this parameter does not exist will\n"); + log(" cause Verific to produce a VERI-1928 or VHDL-1676 message. This option\n"); + log(" can be specified multiple times to override multiple parameters.\n"); + log(" String values must be passed in double quotes (\").\n"); + log("\n"); log(" -v, -vv\n"); log(" Verbose log messages. (-vv is even more verbose than -v.)\n"); log("\n"); @@ -1769,6 +2026,9 @@ struct VerificPass : public Pass { log(" -nosva\n"); log(" Ignore SVA properties, do not infer checker logic.\n"); log("\n"); + log(" -L <int>\n"); + log(" Maximum number of ctrl bits for SVA checker FSMs (default=16).\n"); + log("\n"); log(" -n\n"); log(" Keep all Verific names on instances and nets. By default only\n"); log(" user-declared names are preserved.\n"); @@ -1780,23 +2040,51 @@ struct VerificPass : public Pass { log("\n"); } #ifdef YOSYS_ENABLE_VERIFIC - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { + static bool set_verific_global_flags = true; + if (check_noverific_env()) log_cmd_error("This version of Yosys is built without Verific support.\n"); log_header(design, "Executing VERIFIC (loading SystemVerilog and VHDL designs using Verific).\n"); - Message::SetConsoleOutput(0); - Message::RegisterCallBackMsg(msg_func); - RuntimeFlags::SetVar("db_preserve_user_nets", 1); - RuntimeFlags::SetVar("db_allow_external_nets", 1); - RuntimeFlags::SetVar("vhdl_ignore_assertion_statements", 0); - RuntimeFlags::SetVar("veri_extract_dualport_rams", 0); - RuntimeFlags::SetVar("veri_extract_multiport_rams", 1); - RuntimeFlags::SetVar("db_infer_wide_operators", 1); + if (set_verific_global_flags) + { + Message::SetConsoleOutput(0); + Message::RegisterCallBackMsg(msg_func); + + RuntimeFlags::SetVar("db_preserve_user_nets", 1); + RuntimeFlags::SetVar("db_allow_external_nets", 1); + RuntimeFlags::SetVar("db_infer_wide_operators", 1); + + RuntimeFlags::SetVar("veri_extract_dualport_rams", 0); + RuntimeFlags::SetVar("veri_extract_multiport_rams", 1); + + RuntimeFlags::SetVar("vhdl_extract_dualport_rams", 0); + RuntimeFlags::SetVar("vhdl_extract_multiport_rams", 1); + + RuntimeFlags::SetVar("vhdl_support_variable_slice", 1); + RuntimeFlags::SetVar("vhdl_ignore_assertion_statements", 0); + + // Workaround for VIPER #13851 + RuntimeFlags::SetVar("veri_create_name_for_unnamed_gen_block", 1); + + // 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 + + set_verific_global_flags = false; + } verific_verbose = 0; + verific_sva_fsm_limit = 16; const char *release_str = Message::ReleaseString(); time_t release_time = Message::ReleaseDate(); @@ -1811,16 +2099,39 @@ struct VerificPass : public Pass { log("Built with Verific %s, released at %s.\n", release_str, release_tmstr); int argidx = 1; + std::string work = "work"; + + if (GetSize(args) > argidx && (args[argidx] == "-set-error" || args[argidx] == "-set-warning" || + args[argidx] == "-set-info" || args[argidx] == "-set-ignore")) + { + msg_type_t new_type; + + if (args[argidx] == "-set-error") + new_type = VERIFIC_ERROR; + else if (args[argidx] == "-set-warning") + new_type = VERIFIC_WARNING; + else if (args[argidx] == "-set-info") + new_type = VERIFIC_INFO; + else if (args[argidx] == "-set-ignore") + new_type = VERIFIC_IGNORE; + else + log_abort(); + + for (argidx++; argidx < GetSize(args); argidx++) + Message::SetMessageType(args[argidx].c_str(), new_type); + + goto check_error; + } if (GetSize(args) > argidx && args[argidx] == "-vlog-incdir") { for (argidx++; argidx < GetSize(args); argidx++) - veri_file::AddIncludeDir(args[argidx].c_str()); + verific_incdirs.push_back(args[argidx]); goto check_error; } if (GetSize(args) > argidx && args[argidx] == "-vlog-libdir") { for (argidx++; argidx < GetSize(args); argidx++) - veri_file::AddYDir(args[argidx].c_str()); + verific_libdirs.push_back(args[argidx]); goto check_error; } @@ -1847,6 +2158,15 @@ struct VerificPass : public Pass { goto check_error; } + for (; argidx < GetSize(args); argidx++) + { + if (args[argidx] == "-work" && argidx+1 < GetSize(args)) { + work = args[++argidx]; + continue; + } + break; + } + if (GetSize(args) > argidx && (args[argidx] == "-vlog95" || args[argidx] == "-vlog2k" || args[argidx] == "-sv2005" || args[argidx] == "-sv2009" || args[argidx] == "-sv2012" || args[argidx] == "-sv" || args[argidx] == "-formal")) { @@ -1869,7 +2189,7 @@ struct VerificPass : public Pass { veri_file::DefineMacro("VERIFIC"); veri_file::DefineMacro(args[argidx] == "-formal" ? "FORMAL" : "SYNTHESIS"); - for (argidx++; argidx < GetSize(args) && GetSize(args[argidx]) >= 2 && args[argidx].substr(0, 2) == "-D"; argidx++) { + for (argidx++; argidx < GetSize(args) && GetSize(args[argidx]) >= 2 && args[argidx].compare(0, 2, "-D") == 0; argidx++) { std::string name = args[argidx].substr(2); if (args[argidx] == "-D") { if (++argidx >= GetSize(args)) @@ -1886,10 +2206,15 @@ struct VerificPass : public Pass { } } + for (auto &dir : verific_incdirs) + veri_file::AddIncludeDir(dir.c_str()); + for (auto &dir : verific_libdirs) + veri_file::AddYDir(dir.c_str()); + while (argidx < GetSize(args)) file_names.Insert(args[argidx++].c_str()); - if (!veri_file::AnalyzeMultipleFiles(&file_names, verilog_mode, "work", veri_file::MFCU)) + if (!veri_file::AnalyzeMultipleFiles(&file_names, verilog_mode, work.c_str(), veri_file::MFCU)) log_cmd_error("Reading Verilog/SystemVerilog sources failed.\n"); verific_import_pending = true; @@ -1899,7 +2224,7 @@ struct VerificPass : public Pass { if (GetSize(args) > argidx && args[argidx] == "-vhdl87") { vhdl_file::SetDefaultLibraryPath((proc_share_dirname() + "verific/vhdl_vdbs_1987").c_str()); for (argidx++; argidx < GetSize(args); argidx++) - if (!vhdl_file::Analyze(args[argidx].c_str(), "work", vhdl_file::VHDL_87)) + if (!vhdl_file::Analyze(args[argidx].c_str(), work.c_str(), vhdl_file::VHDL_87)) log_cmd_error("Reading `%s' in VHDL_87 mode failed.\n", args[argidx].c_str()); verific_import_pending = true; goto check_error; @@ -1908,7 +2233,7 @@ struct VerificPass : public Pass { if (GetSize(args) > argidx && args[argidx] == "-vhdl93") { vhdl_file::SetDefaultLibraryPath((proc_share_dirname() + "verific/vhdl_vdbs_1993").c_str()); for (argidx++; argidx < GetSize(args); argidx++) - if (!vhdl_file::Analyze(args[argidx].c_str(), "work", vhdl_file::VHDL_93)) + if (!vhdl_file::Analyze(args[argidx].c_str(), work.c_str(), vhdl_file::VHDL_93)) log_cmd_error("Reading `%s' in VHDL_93 mode failed.\n", args[argidx].c_str()); verific_import_pending = true; goto check_error; @@ -1917,7 +2242,7 @@ struct VerificPass : public Pass { if (GetSize(args) > argidx && args[argidx] == "-vhdl2k") { vhdl_file::SetDefaultLibraryPath((proc_share_dirname() + "verific/vhdl_vdbs_1993").c_str()); for (argidx++; argidx < GetSize(args); argidx++) - if (!vhdl_file::Analyze(args[argidx].c_str(), "work", vhdl_file::VHDL_2K)) + if (!vhdl_file::Analyze(args[argidx].c_str(), work.c_str(), vhdl_file::VHDL_2K)) log_cmd_error("Reading `%s' in VHDL_2K mode failed.\n", args[argidx].c_str()); verific_import_pending = true; goto check_error; @@ -1926,7 +2251,7 @@ struct VerificPass : public Pass { if (GetSize(args) > argidx && (args[argidx] == "-vhdl2008" || args[argidx] == "-vhdl")) { vhdl_file::SetDefaultLibraryPath((proc_share_dirname() + "verific/vhdl_vdbs_2008").c_str()); for (argidx++; argidx < GetSize(args); argidx++) - if (!vhdl_file::Analyze(args[argidx].c_str(), "work", vhdl_file::VHDL_2008)) + if (!vhdl_file::Analyze(args[argidx].c_str(), work.c_str(), vhdl_file::VHDL_2008)) log_cmd_error("Reading `%s' in VHDL_2008 mode failed.\n", args[argidx].c_str()); verific_import_pending = true; goto check_error; @@ -1937,9 +2262,10 @@ struct VerificPass : public Pass { std::set<Netlist*> nl_todo, nl_done; bool mode_all = false, mode_gates = false, mode_keep = false; bool mode_nosva = false, mode_names = false, mode_verific = false; - bool mode_autocover = false; + bool mode_autocover = false, mode_fullinit = false; bool flatten = false, extnets = false; string dumpfile; + Map parameters(STRING_HASH); for (argidx++; argidx < GetSize(args); argidx++) { if (args[argidx] == "-all") { @@ -1966,6 +2292,10 @@ struct VerificPass : public Pass { mode_nosva = true; continue; } + if (args[argidx] == "-L" && argidx+1 < GetSize(args)) { + verific_sva_fsm_limit = atoi(args[++argidx].c_str()); + continue; + } if (args[argidx] == "-n") { mode_names = true; continue; @@ -1974,6 +2304,19 @@ struct VerificPass : public Pass { mode_autocover = true; continue; } + if (args[argidx] == "-fullinit") { + mode_fullinit = true; + continue; + } + if (args[argidx] == "-chparam" && argidx+2 < GetSize(args)) { + const std::string &key = args[++argidx]; + const std::string &value = args[++argidx]; + unsigned new_insertion = parameters.Insert(key.c_str(), value.c_str(), + 1 /* force_overwrite */); + if (!new_insertion) + log_warning_noprefix("-chparam %s already specified: overwriting.\n", key.c_str()); + continue; + } if (args[argidx] == "-V") { mode_verific = true; continue; @@ -1993,98 +2336,56 @@ struct VerificPass : public Pass { break; } - if (argidx > GetSize(args) && args[argidx].substr(0, 1) == "-") + if (argidx > GetSize(args) && args[argidx].compare(0, 1, "-") == 0) cmd_error(args, argidx, "unknown option"); if (mode_all) { -#if 0 - log("Running veri_file::ElaborateAll().\n"); - if (!veri_file::ElaborateAll()) - log_cmd_error("Elaboration of Verilog modules failed.\n"); - - log("Running vhdl_file::ElaborateAll().\n"); - if (!vhdl_file::ElaborateAll()) - log_cmd_error("Elaboration of VHDL modules failed.\n"); - - Library *lib = Netlist::PresentDesign()->Owner()->Owner(); - - if (argidx == GetSize(args)) - { - MapIter iter; - char *iter_name; - Verific::Cell *iter_cell; - - FOREACH_MAP_ITEM(lib->GetCells(), iter, &iter_name, &iter_cell) { - if (*iter_name != '$') - nl_todo.insert(iter_cell->GetFirstNetlist()); - } - } - else - { - for (; argidx < GetSize(args); argidx++) - { - Verific::Cell *cell = lib->GetCell(args[argidx].c_str()); - - if (cell == nullptr) - log_cmd_error("Module not found: %s\n", args[argidx].c_str()); - - nl_todo.insert(cell->GetFirstNetlist()); - cell->GetFirstNetlist()->SetPresentDesign(); - } - } -#else log("Running hier_tree::ElaborateAll().\n"); - VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary("work", 1); - VeriLibrary *veri_lib = veri_file::GetLibrary("work", 1); + VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary(work.c_str(), 1); + VeriLibrary *veri_lib = veri_file::GetLibrary(work.c_str(), 1); Array veri_libs, vhdl_libs; if (vhdl_lib) vhdl_libs.InsertLast(vhdl_lib); if (veri_lib) veri_libs.InsertLast(veri_lib); - Array *netlists = hier_tree::ElaborateAll(&veri_libs, &vhdl_libs); + Array *netlists = hier_tree::ElaborateAll(&veri_libs, &vhdl_libs, ¶meters); Netlist *nl; int i; FOREACH_ARRAY_ITEM(netlists, i, nl) nl_todo.insert(nl); delete netlists; -#endif } else { if (argidx == GetSize(args)) log_cmd_error("No top module specified.\n"); -#if 0 - for (; argidx < GetSize(args); argidx++) { - if (veri_file::GetModule(args[argidx].c_str())) { - log("Running veri_file::Elaborate(\"%s\").\n", args[argidx].c_str()); - if (!veri_file::Elaborate(args[argidx].c_str())) - log_cmd_error("Elaboration of top module `%s' failed.\n", args[argidx].c_str()); - nl_todo.insert(Netlist::PresentDesign()); - } else { - log("Running vhdl_file::Elaborate(\"%s\").\n", args[argidx].c_str()); - if (!vhdl_file::Elaborate(args[argidx].c_str())) - log_cmd_error("Elaboration of top module `%s' failed.\n", args[argidx].c_str()); - nl_todo.insert(Netlist::PresentDesign()); - } - } -#else Array veri_modules, vhdl_units; for (; argidx < GetSize(args); argidx++) { const char *name = args[argidx].c_str(); + VeriLibrary* veri_lib = veri_file::GetLibrary(work.c_str(), 1); + + if (veri_lib) { + VeriModule *veri_module = veri_lib->GetModule(name, 1); + if (veri_module) { + log("Adding Verilog module '%s' to elaboration queue.\n", name); + veri_modules.InsertLast(veri_module); + continue; + } - VeriModule *veri_module = veri_file::GetModule(name); - if (veri_module) { - log("Adding Verilog module '%s' to elaboration queue.\n", name); - veri_modules.InsertLast(veri_module); - continue; + // Also elaborate all root modules since they may contain bind statements + MapIter mi; + FOREACH_VERILOG_MODULE_IN_LIBRARY(veri_lib, mi, veri_module) { + if (!veri_module->IsRootModule()) continue; + veri_modules.InsertLast(veri_module); + } } - VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary("work", 1); + VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary(work.c_str(), 1); VhdlDesignUnit *vhdl_unit = vhdl_lib->GetPrimUnit(name); if (vhdl_unit) { log("Adding VHDL unit '%s' to elaboration queue.\n", name); @@ -2096,14 +2397,15 @@ struct VerificPass : public Pass { } log("Running hier_tree::Elaborate().\n"); - Array *netlists = hier_tree::Elaborate(&veri_modules, &vhdl_units); + Array *netlists = hier_tree::Elaborate(&veri_modules, &vhdl_units, ¶meters); Netlist *nl; int i; - FOREACH_ARRAY_ITEM(netlists, i, nl) + FOREACH_ARRAY_ITEM(netlists, i, nl) { + nl->AddAtt(new Att(" \\top", NULL)); nl_todo.insert(nl); + } delete netlists; -#endif } if (!verific_error_msg.empty()) @@ -2129,7 +2431,7 @@ struct VerificPass : public Pass { Netlist *nl = *nl_todo.begin(); if (nl_done.count(nl) == 0) { VerificImporter importer(mode_gates, mode_keep, mode_nosva, - mode_names, mode_verific, mode_autocover); + mode_names, mode_verific, mode_autocover, mode_fullinit); importer.import_netlist(design, nl, nl_todo); } nl_todo.erase(nl); @@ -2139,6 +2441,8 @@ struct VerificPass : public Pass { veri_file::Reset(); vhdl_file::Reset(); Libset::Reset(); + verific_incdirs.clear(); + verific_libdirs.clear(); verific_import_pending = false; goto check_error; } @@ -2151,7 +2455,7 @@ struct VerificPass : public Pass { } #else /* YOSYS_ENABLE_VERIFIC */ - virtual void execute(std::vector<std::string>, RTLIL::Design *) { + void execute(std::vector<std::string>, RTLIL::Design *) YS_OVERRIDE { log_cmd_error("This version of Yosys is built without Verific support.\n"); } #endif @@ -2159,7 +2463,7 @@ struct VerificPass : public Pass { struct ReadPass : public Pass { ReadPass() : Pass("read", "load HDL designs") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -2186,27 +2490,54 @@ struct ReadPass : public Pass { log("\n"); log("Unset global Verilog/SystemVerilog defines.\n"); log("\n"); + log("\n"); + log(" read -incdir <directory>\n"); + log("\n"); + log("Add directory to global Verilog/SystemVerilog include directories.\n"); + log("\n"); + log("\n"); + log(" read -verific\n"); + log(" read -noverific\n"); + log("\n"); + log("Subsequent calls to 'read' will either use or not use Verific. Calling 'read'\n"); + log("with -verific will result in an error on Yosys binaries that are built without\n"); + log("Verific support. The default is to use Verific if it is available.\n"); + log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { - if (args.size() < 2) +#ifdef YOSYS_ENABLE_VERIFIC + static bool verific_available = !check_noverific_env(); +#else + static bool verific_available = false; +#endif + static bool use_verific = verific_available; + + if (args.size() < 2 || args[1][0] != '-') log_cmd_error("Missing mode parameter.\n"); + if (args[1] == "-verific" || args[1] == "-noverific") { + if (args.size() != 2) + log_cmd_error("Additional arguments to -verific/-noverific.\n"); + if (args[1] == "-verific") { + if (!verific_available) + log_cmd_error("This version of Yosys is built without Verific support.\n"); + use_verific = true; + } else { + use_verific = false; + } + return; + } + if (args.size() < 3) log_cmd_error("Missing file name parameter.\n"); -#ifdef YOSYS_ENABLE_VERIFIC - bool use_verific = !check_noverific_env(); -#else - bool use_verific = false; -#endif - if (args[1] == "-vlog95" || args[1] == "-vlog2k") { if (use_verific) { args[0] = "verific"; } else { args[0] = "read_verilog"; - args.erase(args.begin()+1, args.begin()+2); + args[1] = "-defer"; } Pass::call(design, args); return; @@ -2220,6 +2551,7 @@ struct ReadPass : public Pass { if (args[1] == "-formal") args.insert(args.begin()+1, std::string()); args[1] = "-sv"; + args.insert(args.begin()+1, "-defer"); } Pass::call(design, args); return; @@ -2263,6 +2595,20 @@ struct ReadPass : public Pass { return; } + if (args[1] == "-incdir") { + if (use_verific) { + args[0] = "verific"; + args[1] = "-vlog-incdir"; + Pass::call(design, args); + } + args[0] = "verilog_defaults"; + args[1] = "-add"; + for (int i = 2; i < GetSize(args); i++) + args[i] = "-I" + args[i]; + Pass::call(design, args); + return; + } + log_cmd_error("Missing or unsupported mode parameter.\n"); } } ReadPass; diff --git a/frontends/verific/verific.h b/frontends/verific/verific.h index cbd9314db..5cbd78f7b 100644 --- a/frontends/verific/verific.h +++ b/frontends/verific/verific.h @@ -26,7 +26,7 @@ YOSYS_NAMESPACE_BEGIN extern int verific_verbose; extern bool verific_import_pending; -extern void verific_import(Design *design, std::string top = std::string()); +extern void verific_import(Design *design, const std::map<std::string,std::string> ¶meters, std::string top = std::string()); extern pool<int> verific_sva_prims; @@ -72,12 +72,13 @@ struct VerificImporter pool<Verific::Net*, hash_ptr_ops> any_all_nets; bool mode_gates, mode_keep, mode_nosva, mode_names, mode_verific; - bool mode_autocover; + bool mode_autocover, mode_fullinit; - VerificImporter(bool mode_gates, bool mode_keep, bool mode_nosva, bool mode_names, bool mode_verific, bool mode_autocover); + VerificImporter(bool mode_gates, bool mode_keep, bool mode_nosva, bool mode_names, bool mode_verific, bool mode_autocover, bool mode_fullinit); RTLIL::SigBit net_map_at(Verific::Net *net); + RTLIL::IdString new_verific_id(Verific::DesignObj *obj); void import_attributes(dict<RTLIL::IdString, RTLIL::Const> &attributes, Verific::DesignObj *obj); RTLIL::SigSpec operatorInput(Verific::Instance *inst); @@ -101,6 +102,8 @@ void verific_import_sva_cover(VerificImporter *importer, Verific::Instance *inst void verific_import_sva_trigger(VerificImporter *importer, Verific::Instance *inst); bool verific_is_sva_net(VerificImporter *importer, Verific::Net *net); +extern int verific_sva_fsm_limit; + YOSYS_NAMESPACE_END #endif diff --git a/frontends/verific/verificsva.cc b/frontends/verific/verificsva.cc index 8e985c3a6..909e9b4f1 100644 --- a/frontends/verific/verificsva.cc +++ b/frontends/verific/verificsva.cc @@ -357,7 +357,7 @@ struct SvaFsm for (int i = 0; i < GetSize(nodes); i++) { if (next_state_sig[i] != State::S0) { - clocking.addDff(NEW_ID, next_state_sig[i], state_wire[i], Const(0, 1)); + clocking.addDff(NEW_ID, next_state_sig[i], state_wire[i], State::S0); } else { module->connect(state_wire[i], State::S0); } @@ -466,13 +466,14 @@ struct SvaFsm dnode.ctrl.sort_and_unify(); - if (GetSize(dnode.ctrl) > 16) { + if (GetSize(dnode.ctrl) > verific_sva_fsm_limit) { if (verific_verbose >= 2) { log(" detected state explosion in DFSM generation:\n"); dump(); log(" ctrl signal: %s\n", log_signal(dnode.ctrl)); } - log_error("SVA DFSM state ctrl signal has %d (>16) bits. Stopping to prevent exponential design size explosion.\n", GetSize(dnode.ctrl)); + log_error("SVA DFSM state ctrl signal has %d (>%d) bits. Stopping to prevent exponential design size explosion.\n", + GetSize(dnode.ctrl), verific_sva_fsm_limit); } for (int i = 0; i < (1 << GetSize(dnode.ctrl)); i++) @@ -826,9 +827,9 @@ struct SvaFsm for (auto &it : nodes[i].edges) { if (it.second != State::S1) - log(" egde %s -> %d\n", log_signal(it.second), it.first); + log(" edge %s -> %d\n", log_signal(it.second), it.first); else - log(" egde -> %d\n", it.first); + log(" edge -> %d\n", it.first); } for (auto &it : nodes[i].links) { @@ -855,9 +856,9 @@ struct SvaFsm for (auto &it : unodes[i].edges) { if (!it.second.empty()) - log(" egde %s -> %d\n", log_signal(it.second), it.first); + log(" edge %s -> %d\n", log_signal(it.second), it.first); else - log(" egde -> %d\n", it.first); + log(" edge -> %d\n", it.first); } for (auto &ctrl : unodes[i].accept) { @@ -1517,9 +1518,11 @@ struct VerificSvaImporter Instance *consequent_inst = net_to_ast_driver(consequent_net); - if (consequent_inst->Type() != PRIM_SVA_S_EVENTUALLY && consequent_inst->Type() != PRIM_SVA_EVENTUALLY) { + if (consequent_inst == nullptr) + return false; + + if (consequent_inst->Type() != PRIM_SVA_S_EVENTUALLY && consequent_inst->Type() != PRIM_SVA_EVENTUALLY) return false; - } if (mode_cover || mode_trigger) parser_error(consequent_inst); @@ -1663,7 +1666,20 @@ struct VerificSvaImporter log(" importing SVA property at root cell %s (%s) at %s:%d.\n", root->Name(), root->View()->Owner()->Name(), LineFile::GetFileName(root->Linefile()), LineFile::GetLineNo(root->Linefile())); - RTLIL::IdString root_name = module->uniquify(importer->mode_names || root->IsUserDeclared() ? RTLIL::escape_id(root->Name()) : NEW_ID); + bool is_user_declared = root->IsUserDeclared(); + + // FIXME + if (!is_user_declared) { + const char *name = root->Name(); + for (int i = 0; name[i]; i++) { + if (i ? (name[i] < '0' || name[i] > '9') : (name[i] != 'i')) { + is_user_declared = true; + break; + } + } + } + + RTLIL::IdString root_name = module->uniquify(importer->mode_names || is_user_declared ? RTLIL::escape_id(root->Name()) : NEW_ID); // parse SVA sequence into trigger signal diff --git a/frontends/verilog/.gitignore b/frontends/verilog/.gitignore index 1d4ae9e5c..aadbcdcdd 100644 --- a/frontends/verilog/.gitignore +++ b/frontends/verilog/.gitignore @@ -1,4 +1,4 @@ verilog_lexer.cc verilog_parser.output verilog_parser.tab.cc -verilog_parser.tab.h +verilog_parser.tab.hh diff --git a/frontends/verilog/Makefile.inc b/frontends/verilog/Makefile.inc index a06c1d5ab..6a8462b41 100644 --- a/frontends/verilog/Makefile.inc +++ b/frontends/verilog/Makefile.inc @@ -1,20 +1,21 @@ GENFILES += frontends/verilog/verilog_parser.tab.cc -GENFILES += frontends/verilog/verilog_parser.tab.h +GENFILES += frontends/verilog/verilog_parser.tab.hh GENFILES += frontends/verilog/verilog_parser.output GENFILES += frontends/verilog/verilog_lexer.cc frontends/verilog/verilog_parser.tab.cc: frontends/verilog/verilog_parser.y $(Q) mkdir -p $(dir $@) - $(P) $(BISON) -d -r all -b frontends/verilog/verilog_parser $< - $(Q) mv frontends/verilog/verilog_parser.tab.c frontends/verilog/verilog_parser.tab.cc + $(P) $(BISON) -o $@ -d -r all -b frontends/verilog/verilog_parser $< -frontends/verilog/verilog_parser.tab.h: frontends/verilog/verilog_parser.tab.cc +frontends/verilog/verilog_parser.tab.hh: frontends/verilog/verilog_parser.tab.cc frontends/verilog/verilog_lexer.cc: frontends/verilog/verilog_lexer.l $(Q) mkdir -p $(dir $@) $(P) flex -o frontends/verilog/verilog_lexer.cc $< +frontends/verilog/verilog_parser.tab.o: CXXFLAGS += -DYYMAXDEPTH=10000000 + OBJS += frontends/verilog/verilog_parser.tab.o OBJS += frontends/verilog/verilog_lexer.o OBJS += frontends/verilog/preproc.o diff --git a/frontends/verilog/const2ast.cc b/frontends/verilog/const2ast.cc index 4a58357bf..49281f7e7 100644 --- a/frontends/verilog/const2ast.cc +++ b/frontends/verilog/const2ast.cc @@ -49,8 +49,7 @@ static int my_decimal_div_by_two(std::vector<uint8_t> &digits) int carry = 0; for (size_t i = 0; i < digits.size(); i++) { if (digits[i] >= 10) - log_error("Invalid use of [a-fxz?] in decimal constant at %s:%d.\n", - current_filename.c_str(), get_line_num()); + log_file_error(current_filename, get_line_num(), "Invalid use of [a-fxz?] in decimal constant.\n"); digits[i] += carry * 10; carry = digits[i] % 2; digits[i] /= 2; @@ -72,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<RTLIL::State> &data, const char *str, int len_in_bits, int base, char case_type) +static void my_strtobin(std::vector<RTLIL::State> &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<uint8_t> digits; @@ -86,10 +85,8 @@ static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int le digits.push_back(10 + *str - 'A'); else if (*str == 'x' || *str == 'X') digits.push_back(0xf0); - else if (*str == 'z' || *str == 'Z') + else if (*str == 'z' || *str == 'Z' || *str == '?') digits.push_back(0xf1); - else if (*str == '?') - digits.push_back(0xf2); str++; } @@ -100,42 +97,43 @@ static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int le if (base == 10) { while (!digits.empty()) - data.push_back(my_decimal_div_by_two(digits) ? RTLIL::S1 : RTLIL::S0); + data.push_back(my_decimal_div_by_two(digits) ? State::S1 : State::S0); } else { int bits_per_digit = my_ilog2(base-1); for (auto it = digits.rbegin(), e = digits.rend(); it != e; it++) { if (*it > (base-1) && *it < 0xf0) - log_error("Digit larger than %d used in in base-%d constant at %s:%d.\n", - base-1, base, current_filename.c_str(), get_line_num()); + log_file_error(current_filename, get_line_num(), "Digit larger than %d used in in base-%d constant.\n", + base-1, base); for (int i = 0; i < bits_per_digit; i++) { int bitmask = 1 << i; if (*it == 0xf0) data.push_back(case_type == 'x' ? RTLIL::Sa : RTLIL::Sx); else if (*it == 0xf1) data.push_back(case_type == 'x' || case_type == 'z' ? RTLIL::Sa : RTLIL::Sz); - else if (*it == 0xf2) - data.push_back(RTLIL::Sa); else - data.push_back((*it & bitmask) ? RTLIL::S1 : RTLIL::S0); + data.push_back((*it & bitmask) ? State::S1 : State::S0); } } } int len = GetSize(data); - RTLIL::State msb = data.empty() ? RTLIL::S0 : data.back(); + RTLIL::State msb = data.empty() ? State::S0 : data.back(); if (len_in_bits < 0) { if (len < 32) - data.resize(32, msb == RTLIL::S0 || msb == RTLIL::S1 ? RTLIL::S0 : msb); + data.resize(32, msb == State::S0 || msb == State::S1 ? RTLIL::S0 : msb); 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) + if (data[len] == State::S1) break; - if (msb == RTLIL::S0 || msb == RTLIL::S1) { + if (msb == State::S0 || msb == State::S1) { len += 1; - data.resize(len_in_bits, RTLIL::S0); + data.resize(len_in_bits, State::S0); } else { len += 2; data.resize(len_in_bits, msb); @@ -151,7 +149,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; @@ -167,7 +165,7 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn for (int i = 0; i < len; i++) { unsigned char ch = str[len - i]; for (int j = 0; j < 8; j++) { - data.push_back((ch & 1) ? RTLIL::S1 : RTLIL::S0); + data.push_back((ch & 1) ? State::S1 : State::S0); ch = ch >> 1; } } @@ -187,9 +185,9 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn // Simple base-10 integer if (*endptr == 0) { std::vector<RTLIL::State> data; - my_strtobin(data, str, -1, 10, case_type); - if (data.back() == RTLIL::S1) - data.push_back(RTLIL::S0); + my_strtobin(data, str, -1, 10, case_type, false); + if (data.back() == State::S1) + data.push_back(State::S0); return AstNode::mkconst_bits(data, true); } @@ -197,12 +195,13 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn if (str == endptr) len_in_bits = -1; - // The "<bits>'s?[bodhBODH]<digits>" syntax + // The "<bits>'[sS]?[bodhBODH]<digits>" syntax if (*endptr == '\'') { std::vector<RTLIL::State> data; bool is_signed = false; - if (*(endptr+1) == 's') { + bool is_unsized = len_in_bits < 0; + if (*(endptr+1) == 's' || *(endptr+1) == 'S') { is_signed = true; endptr++; } @@ -210,32 +209,37 @@ 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); + if (is_signed && data.back() == State::S1) + data.push_back(State::S0); } - return AstNode::mkconst_bits(data, is_signed); + return AstNode::mkconst_bits(data, is_signed, is_unsized); } return NULL; } YOSYS_NAMESPACE_END - diff --git a/frontends/verilog/verilog_frontend.cc b/frontends/verilog/verilog_frontend.cc index 505c94619..0e2bead6f 100644 --- a/frontends/verilog/verilog_frontend.cc +++ b/frontends/verilog/verilog_frontend.cc @@ -42,14 +42,14 @@ static std::list<std::vector<std::string>> verilog_defaults_stack; static void error_on_dpi_function(AST::AstNode *node) { if (node->type == AST::AST_DPI_FUNCTION) - log_error("Found DPI function %s at %s:%d.\n", node->str.c_str(), node->filename.c_str(), node->linenum); + log_file_error(node->filename, node->linenum, "Found DPI function %s.\n", node->str.c_str()); for (auto child : node->children) error_on_dpi_function(child); } struct VerilogFrontend : public Frontend { VerilogFrontend() : Frontend("verilog", "read modules from Verilog file") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -66,19 +66,37 @@ struct VerilogFrontend : public Frontend { log(" enable support for SystemVerilog assertions and some Yosys extensions\n"); log(" replace the implicit -D SYNTHESIS with -D FORMAL\n"); log("\n"); + log(" -noassert\n"); + log(" ignore assert() statements\n"); + log("\n"); + log(" -noassume\n"); + log(" ignore assume() statements\n"); + log("\n"); log(" -norestrict\n"); - log(" ignore restrict() assertions\n"); + log(" ignore restrict() statements\n"); log("\n"); log(" -assume-asserts\n"); log(" treat all assert() statements like assume() statements\n"); log("\n"); + log(" -assert-assumes\n"); + log(" treat all assume() statements like assert() statements\n"); + log("\n"); + log(" -debug\n"); + log(" alias for -dump_ast1 -dump_ast2 -dump_vlog1 -dump_vlog2 -yydebug\n"); + log("\n"); log(" -dump_ast1\n"); log(" dump abstract syntax tree (before simplification)\n"); log("\n"); log(" -dump_ast2\n"); log(" dump abstract syntax tree (after simplification)\n"); log("\n"); - log(" -dump_vlog\n"); + log(" -no_dump_ptr\n"); + log(" do not include hex memory addresses in dump (easier to diff dumps)\n"); + log("\n"); + log(" -dump_vlog1\n"); + log(" dump ast as Verilog code (before simplification)\n"); + log("\n"); + log(" -dump_vlog2\n"); log(" dump ast as Verilog code (after simplification)\n"); log("\n"); log(" -dump_rtlil\n"); @@ -127,8 +145,21 @@ struct VerilogFrontend : public Frontend { log(" -nodpi\n"); log(" disable DPI-C support\n"); log("\n"); + log(" -noblackbox\n"); + log(" do not automatically add a (* blackbox *) attribute to an\n"); + log(" empty module.\n"); + log("\n"); log(" -lib\n"); log(" only create empty blackbox modules. This implies -DBLACKBOX.\n"); + log(" modules with the (* whitebox *) attribute will be preserved.\n"); + log(" (* lib_whitebox *) will be treated like (* whitebox *).\n"); + log("\n"); + log(" -nowb\n"); + log(" delete (* whitebox *) and (* lib_whitebox *) attributes from\n"); + log(" all modules.\n"); + log("\n"); + log(" -specify\n"); + log(" parse and import specify blocks\n"); log("\n"); log(" -noopt\n"); log(" don't perform basic optimizations (such as const folding) in the\n"); @@ -137,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"); @@ -180,11 +214,13 @@ struct VerilogFrontend : public Frontend { log("supported by the Yosys Verilog front-end.\n"); log("\n"); } - virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) + void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { bool flag_dump_ast1 = false; bool flag_dump_ast2 = false; - bool flag_dump_vlog = false; + bool flag_no_dump_ptr = false; + bool flag_dump_vlog1 = false; + bool flag_dump_vlog2 = false; bool flag_dump_rtlil = false; bool flag_nolatches = false; bool flag_nomeminit = false; @@ -195,9 +231,12 @@ 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; + bool flag_noblackbox = false; + bool flag_nowb = false; std::map<std::string, std::string> defines_map; std::list<std::string> include_dirs; std::list<std::string> attributes; @@ -208,10 +247,9 @@ struct VerilogFrontend : public Frontend { norestrict_mode = false; assume_asserts_mode = false; lib_mode = false; + specify_mode = false; default_nettype_wire = true; - log_header(design, "Executing Verilog-2005 frontend.\n"); - args.insert(args.begin()+1, verilog_defaults.begin(), verilog_defaults.end()); size_t argidx; @@ -225,6 +263,14 @@ struct VerilogFrontend : public Frontend { formal_mode = true; continue; } + if (arg == "-noassert") { + noassert_mode = true; + continue; + } + if (arg == "-noassume") { + noassume_mode = true; + continue; + } if (arg == "-norestrict") { norestrict_mode = true; continue; @@ -233,6 +279,18 @@ struct VerilogFrontend : public Frontend { assume_asserts_mode = true; continue; } + if (arg == "-assert-assumes") { + assert_assumes_mode = true; + continue; + } + if (arg == "-debug") { + flag_dump_ast1 = true; + flag_dump_ast2 = true; + flag_dump_vlog1 = true; + flag_dump_vlog2 = true; + frontend_verilog_yydebug = true; + continue; + } if (arg == "-dump_ast1") { flag_dump_ast1 = true; continue; @@ -241,8 +299,16 @@ struct VerilogFrontend : public Frontend { flag_dump_ast2 = true; continue; } - if (arg == "-dump_vlog") { - flag_dump_vlog = true; + if (arg == "-no_dump_ptr") { + flag_no_dump_ptr = true; + continue; + } + if (arg == "-dump_vlog1") { + flag_dump_vlog1 = true; + continue; + } + if (arg == "-dump_vlog2") { + flag_dump_vlog2 = true; continue; } if (arg == "-dump_rtlil") { @@ -281,11 +347,23 @@ struct VerilogFrontend : public Frontend { flag_nodpi = true; continue; } + if (arg == "-noblackbox") { + flag_noblackbox = true; + continue; + } if (arg == "-lib") { lib_mode = true; defines_map["BLACKBOX"] = string(); continue; } + if (arg == "-nowb") { + flag_nowb = true; + continue; + } + if (arg == "-specify") { + specify_mode = true; + continue; + } if (arg == "-noopt") { flag_noopt = true; continue; @@ -294,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; @@ -347,6 +429,8 @@ struct VerilogFrontend : public Frontend { } extra_args(f, filename, args, argidx); + log_header(design, "Executing Verilog-2005 frontend: %s\n", filename.c_str()); + log("Parsing %s%s input from `%s' to AST representation.\n", formal_mode ? "formal " : "", sv_mode ? "SystemVerilog" : "Verilog", filename.c_str()); @@ -381,7 +465,8 @@ struct VerilogFrontend : public Frontend { if (flag_nodpi) error_on_dpi_function(current_ast); - AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, flag_dump_rtlil, flag_nolatches, flag_nomeminit, flag_nomem2reg, flag_mem2reg, lib_mode, flag_noopt, flag_icells, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire); + 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_pwires, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire); if (!flag_nopp) delete lexin; @@ -395,7 +480,7 @@ struct VerilogFrontend : public Frontend { struct VerilogDefaults : public Pass { VerilogDefaults() : Pass("verilog_defaults", "set default options for read_verilog") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -416,7 +501,7 @@ struct VerilogDefaults : public Pass { log("not imply -clear.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design*) + void execute(std::vector<std::string> args, RTLIL::Design*) YS_OVERRIDE { if (args.size() < 2) cmd_error(args, 1, "Missing argument."); @@ -453,7 +538,7 @@ struct VerilogDefaults : public Pass { struct VerilogDefines : public Pass { VerilogDefines() : Pass("verilog_defines", "define and undefine verilog defines") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -469,7 +554,7 @@ struct VerilogDefines : public Pass { log(" undefine the preprocessor symbol 'name'\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { @@ -519,13 +604,11 @@ void frontend_verilog_yyerror(char const *fmt, ...) va_list ap; char buffer[1024]; char *p = buffer; - p += snprintf(p, buffer + sizeof(buffer) - p, "Parser error in line %s:%d: ", - YOSYS_NAMESPACE_PREFIX AST::current_filename.c_str(), frontend_verilog_yyget_lineno()); va_start(ap, fmt); p += vsnprintf(p, buffer + sizeof(buffer) - p, fmt, ap); va_end(ap); p += snprintf(p, buffer + sizeof(buffer) - p, "\n"); - YOSYS_NAMESPACE_PREFIX log_error("%s", buffer); + YOSYS_NAMESPACE_PREFIX log_file_error(YOSYS_NAMESPACE_PREFIX AST::current_filename, frontend_verilog_yyget_lineno(), + "%s", buffer); exit(1); } - diff --git a/frontends/verilog/verilog_frontend.h b/frontends/verilog/verilog_frontend.h index 16edc7985..a7c9b2fe6 100644 --- a/frontends/verilog/verilog_frontend.h +++ b/frontends/verilog/verilog_frontend.h @@ -54,15 +54,27 @@ namespace VERILOG_FRONTEND // running in -formal mode extern bool formal_mode; + // running in -noassert mode + extern bool noassert_mode; + + // running in -noassume mode + extern bool noassume_mode; + // running in -norestrict mode extern bool norestrict_mode; // running in -assume-asserts mode extern bool assume_asserts_mode; + // running in -assert-assumes mode + extern bool assert_assumes_mode; + // running in -lib mode extern bool lib_mode; + // running in -specify mode + extern bool specify_mode; + // lexer input stream extern std::istream *lexin; } diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index d12c9ee4e..4acfb414d 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -42,7 +42,7 @@ #include "kernel/log.h" #include "frontends/verilog/verilog_frontend.h" #include "frontends/ast/ast.h" -#include "verilog_parser.tab.h" +#include "verilog_parser.tab.hh" USING_YOSYS_NAMESPACE using namespace AST; @@ -70,6 +70,9 @@ YOSYS_NAMESPACE_END #define YY_INPUT(buf,result,max_size) \ result = readsome(*VERILOG_FRONTEND::lexin, buf, max_size) +#undef YY_BUF_SIZE +#define YY_BUF_SIZE 65536 + %} %option yylineno @@ -135,6 +138,9 @@ YOSYS_NAMESPACE_END frontend_verilog_yyerror("Unsupported default nettype: %s", p); } +"`protect"[^\n]* /* ignore `protect*/ +"`endprotect"[^\n]* /* ignore `endprotect*/ + "`"[a-zA-Z_$][a-zA-Z0-9_$]* { frontend_verilog_yyerror("Unimplemented compiler directive or undefined macro %s.", yytext); } @@ -145,11 +151,14 @@ YOSYS_NAMESPACE_END "endfunction" { return TOK_ENDFUNCTION; } "task" { return TOK_TASK; } "endtask" { return TOK_ENDTASK; } -"specify" { return TOK_SPECIFY; } +"specify" { return specify_mode ? TOK_SPECIFY : TOK_IGNORED_SPECIFY; } "endspecify" { return TOK_ENDSPECIFY; } "specparam" { return TOK_SPECPARAM; } "package" { SV_KEYWORD(TOK_PACKAGE); } "endpackage" { SV_KEYWORD(TOK_ENDPACKAGE); } +"interface" { SV_KEYWORD(TOK_INTERFACE); } +"endinterface" { SV_KEYWORD(TOK_ENDINTERFACE); } +"modport" { SV_KEYWORD(TOK_MODPORT); } "parameter" { return TOK_PARAMETER; } "localparam" { return TOK_LOCALPARAM; } "defparam" { return TOK_DEFPARAM; } @@ -183,6 +192,16 @@ YOSYS_NAMESPACE_END "always_ff" { SV_KEYWORD(TOK_ALWAYS); } "always_latch" { SV_KEYWORD(TOK_ALWAYS); } + /* use special token for labels on assert, assume, cover, and restrict because it's insanley complex + 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; +} + "assert" { if (formal_mode) return TOK_ASSERT; SV_KEYWORD(TOK_ASSERT); } "assume" { if (formal_mode) return TOK_ASSUME; SV_KEYWORD(TOK_ASSUME); } "cover" { if (formal_mode) return TOK_COVER; SV_KEYWORD(TOK_COVER); } @@ -192,7 +211,9 @@ YOSYS_NAMESPACE_END "const" { if (formal_mode) return TOK_CONST; SV_KEYWORD(TOK_CONST); } "checker" { if (formal_mode) return TOK_CHECKER; SV_KEYWORD(TOK_CHECKER); } "endchecker" { if (formal_mode) return TOK_ENDCHECKER; SV_KEYWORD(TOK_ENDCHECKER); } -"logic" { SV_KEYWORD(TOK_REG); } +"final" { SV_KEYWORD(TOK_FINAL); } +"logic" { SV_KEYWORD(TOK_LOGIC); } +"var" { SV_KEYWORD(TOK_VAR); } "bit" { SV_KEYWORD(TOK_REG); } "eventually" { if (formal_mode) return TOK_EVENTUALLY; SV_KEYWORD(TOK_EVENTUALLY); } @@ -202,6 +223,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; } @@ -216,7 +239,7 @@ YOSYS_NAMESPACE_END return TOK_CONSTVAL; } -[0-9]*[ \t]*\'s?[bodhBODH][ \t\r\n]*[0-9a-fA-FzxZX?_]+ { +[0-9]*[ \t]*\'[sS]?[bodhBODH]?[ \t\r\n]*[0-9a-fA-FzxZX?_]+ { frontend_verilog_yylval.string = new std::string(yytext); return TOK_CONSTVAL; } @@ -268,7 +291,7 @@ YOSYS_NAMESPACE_END yystr[j++] = yystr[i++]; } yystr[j] = 0; - frontend_verilog_yylval.string = new std::string(yystr); + frontend_verilog_yylval.string = new std::string(yystr, j); free(yystr); return TOK_STRING; } @@ -287,6 +310,17 @@ supply1 { return TOK_SUPPLY1; } return TOK_ID; } +"$"(setup|hold|setuphold|removal|recovery|recrem|skew|timeskew|fullskew|nochange) { + if (!specify_mode) REJECT; + frontend_verilog_yylval.string = new std::string(yytext); + 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; } @@ -295,6 +329,11 @@ supply1 { return TOK_SUPPLY1; } return TOK_ID; } +[a-zA-Z_$][a-zA-Z0-9_$\.]* { + frontend_verilog_yylval.string = new std::string(std::string("\\") + yytext); + return TOK_ID; +} + "/*"[ \t]*(synopsys|synthesis)[ \t]*translate_off[ \t]*"*/" { static bool printed_warning = false; if (!printed_warning) { @@ -392,6 +431,17 @@ import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ { "+:" { return TOK_POS_INDEXED; } "-:" { return TOK_NEG_INDEXED; } +[-+]?[=*]> { + if (!specify_mode) REJECT; + frontend_verilog_yylval.string = new std::string(yytext); + return TOK_SPECIFY_OPER; +} + +"&&&" { + if (!specify_mode) REJECT; + return TOK_SPECIFY_AND; +} + "/*" { BEGIN(COMMENT); } <COMMENT>. /* ignore comment body */ <COMMENT>\n /* ignore comment body */ diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index e803d8072..4afd72b73 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -35,6 +35,7 @@ %{ #include <list> +#include <stack> #include <string.h> #include "frontends/verilog/verilog_frontend.h" #include "kernel/log.h" @@ -47,7 +48,8 @@ YOSYS_NAMESPACE_BEGIN namespace VERILOG_FRONTEND { int port_counter; std::map<std::string, int> port_stubs; - std::map<std::string, AstNode*> attr_list, default_attr_list; + std::map<std::string, AstNode*> *attr_list, default_attr_list; + std::stack<std::map<std::string, AstNode*> *> attr_list_stack; std::map<std::string, AstNode*> *albuf; std::vector<AstNode*> ast_stack; struct AstNode *astbuf1, *astbuf2, *astbuf3; @@ -57,9 +59,11 @@ namespace VERILOG_FRONTEND { std::vector<char> case_type_stack; bool do_not_require_port_stubs; bool default_nettype_wire; - bool sv_mode, formal_mode, lib_mode; - bool norestrict_mode, assume_asserts_mode; + bool sv_mode, formal_mode, lib_mode, specify_mode; + bool noassert_mode, noassume_mode, norestrict_mode; + bool assume_asserts_mode, assert_assumes_mode; bool current_wire_rand, current_wire_const; + bool current_modport_input, current_modport_output; std::istream *lexin; } YOSYS_NAMESPACE_END @@ -90,41 +94,77 @@ static void free_attr(std::map<std::string, AstNode*> *al) delete al; } +struct specify_target { + char polarity_op; + AstNode *dst, *dat; +}; + +struct specify_triple { + AstNode *t_min, *t_avg, *t_max; +}; + +struct specify_rise_fall { + specify_triple rise; + specify_triple fall; +}; + %} -%name-prefix "frontend_verilog_yy" +%define api.prefix {frontend_verilog_yy} + +/* The union is defined in the header, so we need to provide all the + * includes it requires + */ +%code requires { +#include <map> +#include <string> +#include "frontends/verilog/verilog_frontend.h" +} %union { std::string *string; struct YOSYS_NAMESPACE_PREFIX AST::AstNode *ast; std::map<std::string, YOSYS_NAMESPACE_PREFIX AST::AstNode*> *al; + struct specify_target *specify_target_ptr; + struct specify_triple *specify_triple_ptr; + struct specify_rise_fall *specify_rise_fall_ptr; bool boolean; + char ch; } %token <string> TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE +%token <string> 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_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_REG +%token TOK_INTERFACE TOK_ENDINTERFACE TOK_MODPORT TOK_VAR +%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 %token TOK_CASE TOK_CASEX TOK_CASEZ TOK_ENDCASE TOK_DEFAULT -%token TOK_FUNCTION TOK_ENDFUNCTION TOK_TASK TOK_ENDTASK TOK_SPECIFY TOK_ENDSPECIFY TOK_SPECPARAM +%token TOK_FUNCTION TOK_ENDFUNCTION TOK_TASK TOK_ENDTASK TOK_SPECIFY +%token TOK_IGNORED_SPECIFY TOK_ENDSPECIFY TOK_SPECPARAM TOK_SPECIFY_AND %token TOK_GENERATE TOK_ENDGENERATE TOK_GENVAR TOK_REAL %token TOK_SYNOPSYS_FULL_CASE TOK_SYNOPSYS_PARALLEL_CASE %token TOK_SUPPLY0 TOK_SUPPLY1 TOK_TO_SIGNED TOK_TO_UNSIGNED -%token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_ASSERT TOK_ASSUME -%token TOK_RESTRICT TOK_COVER TOK_PROPERTY TOK_ENUM TOK_TYPEDEF +%token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_PROPERTY TOK_ENUM TOK_TYPEDEF %token TOK_RAND TOK_CONST TOK_CHECKER TOK_ENDCHECKER TOK_EVENTUALLY %token TOK_INCREMENT TOK_DECREMENT TOK_UNIQUE TOK_PRIORITY %type <ast> range range_or_multirange non_opt_range non_opt_multirange range_or_signed_int %type <ast> wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list -%type <string> opt_label tok_prim_wrapper hierarchical_id -%type <boolean> opt_signed unique_case_attr +%type <string> opt_label opt_sva_label tok_prim_wrapper hierarchical_id +%type <boolean> opt_signed opt_property unique_case_attr %type <al> attr case_attr +%type <specify_target_ptr> specify_target +%type <specify_triple_ptr> specify_triple +%type <specify_rise_fall_ptr> specify_rise_fall +%type <ast> specify_if specify_condition specify_opt_arg +%type <ch> specify_edge + // operator precedence from low to high %left OP_LOR %left OP_LAND @@ -167,19 +207,23 @@ design: param_decl design | localparam_decl design | package design | + interface design | /* empty */; attr: { - for (auto &it : attr_list) - delete it.second; - attr_list.clear(); + if (attr_list != nullptr) + attr_list_stack.push(attr_list); + attr_list = new std::map<std::string, AstNode*>; for (auto &it : default_attr_list) - attr_list[it.first] = it.second->clone(); + (*attr_list)[it.first] = it.second->clone(); } attr_opt { - std::map<std::string, AstNode*> *al = new std::map<std::string, AstNode*>; - al->swap(attr_list); - $$ = al; + $$ = attr_list; + if (!attr_list_stack.empty()) { + attr_list = attr_list_stack.top(); + attr_list_stack.pop(); + } else + attr_list = nullptr; }; attr_opt: @@ -188,15 +232,20 @@ attr_opt: defattr: DEFATTR_BEGIN { + if (attr_list != nullptr) + attr_list_stack.push(attr_list); + attr_list = new std::map<std::string, AstNode*>; for (auto &it : default_attr_list) delete it.second; default_attr_list.clear(); - for (auto &it : attr_list) - delete it.second; - attr_list.clear(); } opt_attr_list { - default_attr_list = attr_list; - attr_list.clear(); + attr_list->swap(default_attr_list); + delete attr_list; + if (!attr_list_stack.empty()) { + attr_list = attr_list_stack.top(); + attr_list_stack.pop(); + } else + attr_list = nullptr; } DEFATTR_END; opt_attr_list: @@ -208,15 +257,15 @@ attr_list: attr_assign: hierarchical_id { - if (attr_list.count(*$1) != 0) - delete attr_list[*$1]; - attr_list[*$1] = AstNode::mkconst_int(1, false); + if (attr_list->count(*$1) != 0) + delete (*attr_list)[*$1]; + (*attr_list)[*$1] = AstNode::mkconst_int(1, false); delete $1; } | hierarchical_id '=' expr { - if (attr_list.count(*$1) != 0) - delete attr_list[*$1]; - attr_list[*$1] = $3; + if (attr_list->count(*$1) != 0) + delete (*attr_list)[*$1]; + (*attr_list)[*$1] = $3; delete $1; }; @@ -225,7 +274,7 @@ hierarchical_id: $$ = $1; } | hierarchical_id TOK_PACKAGESEP TOK_ID { - if ($3->substr(0, 1) == "\\") + if ($3->compare(0, 1, "\\") == 0) *$1 += "::" + $3->substr(1); else *$1 += "::" + *$3; @@ -233,7 +282,7 @@ hierarchical_id: $$ = $1; } | hierarchical_id '.' TOK_ID { - if ($3->substr(0, 1) == "\\") + if ($3->compare(0, 1, "\\") == 0) *$1 += "." + $3->substr(1); else *$1 += "." + *$3; @@ -270,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; @@ -296,12 +347,18 @@ 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)); } else - frontend_verilog_yyerror("Syntax error."); + frontend_verilog_yyerror("SystemVerilog interface in module port list cannot have a default value."); } | /* empty */; @@ -319,6 +376,21 @@ module_arg: } delete $1; } module_arg_opt_assignment | + TOK_ID { + astbuf1 = new AstNode(AST_INTERFACEPORT); + astbuf1->children.push_back(new AstNode(AST_INTERFACEPORTTYPE)); + astbuf1->children[0]->str = *$1; + delete $1; + } TOK_ID { /* SV interfaces */ + if (!sv_mode) + frontend_verilog_yyerror("Interface found in port list (%s). This is not supported unless read_verilog is called with -sv!", $3->c_str()); + astbuf2 = astbuf1->clone(); // really only needed if multiple instances of same type. + astbuf2->str = *$3; + delete $3; + astbuf2->port_id = ++port_counter; + ast_stack.back()->children.push_back(astbuf2); + delete astbuf1; // really only needed if multiple instances of same type. + } module_arg_opt_assignment | attr wire_type range TOK_ID { AstNode *node = $2; node->str = *$4; @@ -356,6 +428,33 @@ package_body: package_body_stmt: localparam_decl; +interface: + TOK_INTERFACE TOK_ID { + do_not_require_port_stubs = false; + AstNode *intf = new AstNode(AST_INTERFACE); + ast_stack.back()->children.push_back(intf); + ast_stack.push_back(intf); + current_ast_mod = intf; + port_stubs.clear(); + port_counter = 0; + intf->str = *$2; + delete $2; + } module_para_opt module_args_opt ';' interface_body TOK_ENDINTERFACE { + if (port_stubs.size() != 0) + frontend_verilog_yyerror("Missing details for module port `%s'.", + port_stubs.begin()->first.c_str()); + ast_stack.pop_back(); + log_assert(ast_stack.size() == 1); + current_ast_mod = NULL; + }; + +interface_body: + interface_body interface_body_stmt |; + +interface_body_stmt: + param_decl | localparam_decl | defparam_decl | wire_decl | always_stmt | assign_stmt | + modport_stmt; + non_opt_delay: '#' TOK_ID { delete $2; } | '#' TOK_CONSTVAL { delete $2; } | @@ -376,9 +475,10 @@ wire_type: }; wire_type_token_list: - wire_type_token | wire_type_token_list wire_type_token; + wire_type_token | wire_type_token_list wire_type_token | + wire_type_token_io ; -wire_type_token: +wire_type_token_io: TOK_INPUT { astbuf3->is_input = true; } | @@ -388,12 +488,26 @@ wire_type_token: TOK_INOUT { astbuf3->is_input = true; astbuf3->is_output = true; - } | + }; + +wire_type_token: TOK_WIRE { } | + TOK_WOR { + astbuf3->is_wor = true; + } | + TOK_WAND { + astbuf3->is_wand = true; + } | TOK_REG { astbuf3->is_reg = true; } | + TOK_LOGIC { + astbuf3->is_logic = true; + } | + TOK_VAR { + astbuf3->is_logic = true; + } | TOK_INTEGER { astbuf3->is_reg = true; astbuf3->range_left = 31; @@ -403,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; } | @@ -477,7 +592,7 @@ module_body: module_body_stmt: task_func_decl | specify_block |param_decl | localparam_decl | defparam_decl | specparam_declaration | wire_decl | assign_stmt | cell_stmt | - always_stmt | TOK_GENERATE module_gen_body TOK_ENDGENERATE | defattr | assert_property | checker_decl; + always_stmt | TOK_GENERATE module_gen_body TOK_ENDGENERATE | defattr | assert_property | checker_decl | ignored_specify_block; checker_decl: TOK_CHECKER TOK_ID ';' { @@ -545,6 +660,7 @@ task_func_decl: AstNode *outreg = new AstNode(AST_WIRE); outreg->str = *$6; outreg->is_signed = $4; + outreg->is_reg = true; if ($5 != NULL) { outreg->children.push_back($5); outreg->is_signed = $4 || $5->is_signed; @@ -619,7 +735,7 @@ task_func_port: astbuf2 = $3; if (astbuf1->range_left >= 0 && astbuf1->range_right >= 0) { if (astbuf2) { - frontend_verilog_yyerror("Syntax error."); + frontend_verilog_yyerror("integer/genvar types cannot have packed dimensions (task/function arguments)"); } else { astbuf2 = new AstNode(AST_RANGE); astbuf2->children.push_back(AstNode::mkconst_int(astbuf1->range_left, true)); @@ -627,27 +743,266 @@ task_func_port: } } if (astbuf2 && astbuf2->children.size() != 2) - frontend_verilog_yyerror("Syntax error."); + frontend_verilog_yyerror("task/function argument range must be of the form: [<expr>:<expr>], [<expr>+:<expr>], or [<expr>-:<expr>]"); } wire_name | wire_name; task_func_body: task_func_body behavioral_stmt | /* empty */; +/*************************** specify parser ***************************/ + specify_block: - TOK_SPECIFY specify_item_opt TOK_ENDSPECIFY | - TOK_SPECIFY TOK_ENDSPECIFY ; + TOK_SPECIFY specify_item_list TOK_ENDSPECIFY; -specify_item_opt: - specify_item_opt specify_item | - specify_item ; +specify_item_list: + specify_item specify_item_list | + /* empty */; specify_item: + specify_if '(' specify_edge expr TOK_SPECIFY_OPER specify_target ')' '=' specify_rise_fall ';' { + AstNode *en_expr = $1; + char specify_edge = $3; + AstNode *src_expr = $4; + string *oper = $5; + specify_target *target = $6; + specify_rise_fall *timing = $9; + + if (specify_edge != 0 && target->dat == nullptr) + frontend_verilog_yyerror("Found specify edge but no data spec.\n"); + + AstNode *cell = new AstNode(AST_CELL); + ast_stack.back()->children.push_back(cell); + cell->str = stringf("$specify$%d", autoidx++); + cell->children.push_back(new AstNode(AST_CELLTYPE)); + cell->children.back()->str = target->dat ? "$specify3" : "$specify2"; + + char oper_polarity = 0; + char oper_type = oper->at(0); + + if (oper->size() == 3) { + oper_polarity = oper->at(0); + oper_type = oper->at(1); + } + + cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(oper_type == '*', false, 1))); + cell->children.back()->str = "\\FULL"; + + cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(oper_polarity != 0, false, 1))); + cell->children.back()->str = "\\SRC_DST_PEN"; + + cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(oper_polarity == '+', false, 1))); + cell->children.back()->str = "\\SRC_DST_POL"; + + cell->children.push_back(new AstNode(AST_PARASET, timing->rise.t_min)); + cell->children.back()->str = "\\T_RISE_MIN"; + + cell->children.push_back(new AstNode(AST_PARASET, timing->rise.t_avg)); + cell->children.back()->str = "\\T_RISE_TYP"; + + cell->children.push_back(new AstNode(AST_PARASET, timing->rise.t_max)); + cell->children.back()->str = "\\T_RISE_MAX"; + + cell->children.push_back(new AstNode(AST_PARASET, timing->fall.t_min)); + cell->children.back()->str = "\\T_FALL_MIN"; + + cell->children.push_back(new AstNode(AST_PARASET, timing->fall.t_avg)); + cell->children.back()->str = "\\T_FALL_TYP"; + + cell->children.push_back(new AstNode(AST_PARASET, timing->fall.t_max)); + cell->children.back()->str = "\\T_FALL_MAX"; + + cell->children.push_back(new AstNode(AST_ARGUMENT, en_expr ? en_expr : AstNode::mkconst_int(1, false, 1))); + cell->children.back()->str = "\\EN"; + + cell->children.push_back(new AstNode(AST_ARGUMENT, src_expr)); + cell->children.back()->str = "\\SRC"; + + cell->children.push_back(new AstNode(AST_ARGUMENT, target->dst)); + cell->children.back()->str = "\\DST"; + + if (target->dat) + { + cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(specify_edge != 0, false, 1))); + cell->children.back()->str = "\\EDGE_EN"; + + cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(specify_edge == 'p', false, 1))); + cell->children.back()->str = "\\EDGE_POL"; + + cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(target->polarity_op != 0, false, 1))); + cell->children.back()->str = "\\DAT_DST_PEN"; + + cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(target->polarity_op == '+', false, 1))); + cell->children.back()->str = "\\DAT_DST_POL"; + + cell->children.push_back(new AstNode(AST_ARGUMENT, target->dat)); + cell->children.back()->str = "\\DAT"; + } + + delete oper; + delete target; + delete timing; + } | + TOK_ID '(' specify_edge expr specify_condition ',' specify_edge expr specify_condition ',' expr specify_opt_arg ')' ';' { + if (*$1 != "$setup" && *$1 != "$hold" && *$1 != "$setuphold" && *$1 != "$removal" && *$1 != "$recovery" && + *$1 != "$recrem" && *$1 != "$skew" && *$1 != "$timeskew" && *$1 != "$fullskew" && *$1 != "$nochange") + frontend_verilog_yyerror("Unsupported specify rule type: %s\n", $1->c_str()); + + AstNode *src_pen = AstNode::mkconst_int($3 != 0, false, 1); + AstNode *src_pol = AstNode::mkconst_int($3 == 'p', false, 1); + AstNode *src_expr = $4, *src_en = $5 ? $5 : AstNode::mkconst_int(1, false, 1); + + AstNode *dst_pen = AstNode::mkconst_int($7 != 0, false, 1); + AstNode *dst_pol = AstNode::mkconst_int($7 == 'p', false, 1); + AstNode *dst_expr = $8, *dst_en = $9 ? $9 : AstNode::mkconst_int(1, false, 1); + + AstNode *limit = $11; + AstNode *limit2 = $12; + + AstNode *cell = new AstNode(AST_CELL); + ast_stack.back()->children.push_back(cell); + cell->str = stringf("$specify$%d", autoidx++); + cell->children.push_back(new AstNode(AST_CELLTYPE)); + cell->children.back()->str = "$specrule"; + + cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_str(*$1))); + cell->children.back()->str = "\\TYPE"; + + cell->children.push_back(new AstNode(AST_PARASET, limit)); + cell->children.back()->str = "\\T_LIMIT"; + + cell->children.push_back(new AstNode(AST_PARASET, limit2 ? limit2 : AstNode::mkconst_int(0, true))); + cell->children.back()->str = "\\T_LIMIT2"; + + cell->children.push_back(new AstNode(AST_PARASET, src_pen)); + cell->children.back()->str = "\\SRC_PEN"; + + cell->children.push_back(new AstNode(AST_PARASET, src_pol)); + cell->children.back()->str = "\\SRC_POL"; + + cell->children.push_back(new AstNode(AST_PARASET, dst_pen)); + cell->children.back()->str = "\\DST_PEN"; + + cell->children.push_back(new AstNode(AST_PARASET, dst_pol)); + cell->children.back()->str = "\\DST_POL"; + + cell->children.push_back(new AstNode(AST_ARGUMENT, src_en)); + cell->children.back()->str = "\\SRC_EN"; + + cell->children.push_back(new AstNode(AST_ARGUMENT, src_expr)); + cell->children.back()->str = "\\SRC"; + + cell->children.push_back(new AstNode(AST_ARGUMENT, dst_en)); + cell->children.back()->str = "\\DST_EN"; + + cell->children.push_back(new AstNode(AST_ARGUMENT, dst_expr)); + cell->children.back()->str = "\\DST"; + + delete $1; + }; + +specify_opt_arg: + ',' expr { + $$ = $2; + } | + /* empty */ { + $$ = nullptr; + }; + +specify_if: + TOK_IF '(' expr ')' { + $$ = $3; + } | + /* empty */ { + $$ = nullptr; + }; + +specify_condition: + TOK_SPECIFY_AND expr { + $$ = $2; + } | + /* empty */ { + $$ = nullptr; + }; + +specify_target: + expr { + $$ = new specify_target; + $$->polarity_op = 0; + $$->dst = $1; + $$->dat = nullptr; + } | + '(' expr ':' expr ')'{ + $$ = new specify_target; + $$->polarity_op = 0; + $$->dst = $2; + $$->dat = $4; + } | + '(' expr TOK_NEG_INDEXED expr ')'{ + $$ = new specify_target; + $$->polarity_op = '-'; + $$->dst = $2; + $$->dat = $4; + } | + '(' expr TOK_POS_INDEXED expr ')'{ + $$ = new specify_target; + $$->polarity_op = '+'; + $$->dst = $2; + $$->dat = $4; + }; + +specify_edge: + TOK_POSEDGE { $$ = 'p'; } | + TOK_NEGEDGE { $$ = 'n'; } | + { $$ = 0; }; + +specify_rise_fall: + specify_triple { + $$ = new specify_rise_fall; + $$->rise = *$1; + $$->fall.t_min = $1->t_min->clone(); + $$->fall.t_avg = $1->t_avg->clone(); + $$->fall.t_max = $1->t_max->clone(); + delete $1; + } | + '(' specify_triple ',' specify_triple ')' { + $$ = new specify_rise_fall; + $$->rise = *$2; + $$->fall = *$4; + delete $2; + delete $4; + }; + +specify_triple: + expr { + $$ = new specify_triple; + $$->t_min = $1; + $$->t_avg = $1->clone(); + $$->t_max = $1->clone(); + } | + expr ':' expr ':' expr { + $$ = new specify_triple; + $$->t_min = $1; + $$->t_avg = $3; + $$->t_max = $5; + }; + +/******************** ignored specify parser **************************/ + +ignored_specify_block: + TOK_IGNORED_SPECIFY ignored_specify_item_opt TOK_ENDSPECIFY | + TOK_IGNORED_SPECIFY TOK_ENDSPECIFY ; + +ignored_specify_item_opt: + ignored_specify_item_opt ignored_specify_item | + ignored_specify_item ; + +ignored_specify_item: specparam_declaration // | pulsestyle_declaration // | showcancelled_declaration | path_declaration - // | system_timing_declaration + | system_timing_declaration ; specparam_declaration: @@ -658,63 +1013,62 @@ specparam_declaration: // and the 'non_opt_range' rule allows index ranges not allowed by 1364-2005 // exxxxtending this for SV specparam would change this anyhow specparam_range: - '[' constant_expression ':' constant_expression ']' ; + '[' ignspec_constant_expression ':' ignspec_constant_expression ']' ; list_of_specparam_assignments: specparam_assignment | list_of_specparam_assignments ',' specparam_assignment; specparam_assignment: - TOK_ID '=' constant_mintypmax_expression ; + ignspec_id '=' constant_mintypmax_expression ; -/* -pulsestyle_declaration : - ; - -showcancelled_declaration : - ; -*/ +ignspec_opt_cond: + TOK_IF '(' ignspec_expr ')' | /* empty */; path_declaration : - simple_path_declaration + simple_path_declaration ';' // | edge_sensitive_path_declaration // | state_dependent_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 : - //list_of_path_delay_expressions - '(' list_of_path_delay_expressions ')' + '(' path_delay_expression list_of_path_delay_extra_expressions ')' + | path_delay_expression + | path_delay_expression list_of_path_delay_extra_expressions ; -list_of_path_delay_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 ',' - path_delay_expression ',' path_delay_expression ',' path_delay_expression - ; +list_of_path_delay_extra_expressions : + ',' 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 ')' | + '(' 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 : + specify_input_terminal_descriptor opt_polarity_operator | + specify_input_terminal_descriptor more_path_inputs opt_polarity_operator ; + +more_path_inputs : + ',' specify_input_terminal_descriptor | + more_path_inputs ',' specify_input_terminal_descriptor ; + +list_of_path_outputs : + specify_output_terminal_descriptor | + list_of_path_outputs ',' specify_output_terminal_descriptor ; opt_polarity_operator : '+' @@ -723,81 +1077,46 @@ opt_polarity_operator : // Good enough for the time being specify_input_terminal_descriptor : - TOK_ID ; + ignspec_id ; // Good enough for the time being specify_output_terminal_descriptor : - TOK_ID ; + ignspec_id ; -/* system_timing_declaration : - ; -*/ - -/* -t_path_delay_expression : - path_delay_expression; - -trise_path_delay_expression : - path_delay_expression; + ignspec_id '(' system_timing_args ')' ';' ; -tfall_path_delay_expression : - path_delay_expression; +system_timing_arg : + TOK_POSEDGE ignspec_id | + TOK_NEGEDGE ignspec_id | + ignspec_expr ; -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; -*/ +system_timing_args : + system_timing_arg | + system_timing_args ',' system_timing_arg ; path_delay_expression : - constant_mintypmax_expression; + ignspec_constant_expression; constant_mintypmax_expression : - constant_expression - | constant_expression ':' constant_expression ':' constant_expression + ignspec_constant_expression + | ignspec_constant_expression ':' ignspec_constant_expression ':' ignspec_constant_expression ; // for the time being this is OK, but we may write our own expr here. // as I'm not sure it is legal to use a full expr here (probably not) // On the other hand, other rules requiring constant expressions also use 'expr' -// (such as param assignment), so we may leave this as-is, perhaps assing runtime checks for constant-ness -constant_expression: - expr ; +// (such as param assignment), so we may leave this as-is, perhaps adding runtime checks for constant-ness +ignspec_constant_expression: + expr { delete $1; }; + +ignspec_expr: + expr { delete $1; }; + +ignspec_id: + TOK_ID { delete $1; }; + +/**********************************************************************/ param_signed: TOK_SIGNED { @@ -807,7 +1126,7 @@ param_signed: param_integer: TOK_INTEGER { if (astbuf1->children.size() != 1) - frontend_verilog_yyerror("Syntax error."); + frontend_verilog_yyerror("Internal error in param_integer - should not happen?"); astbuf1->children.push_back(new AstNode(AST_RANGE)); astbuf1->children.back()->children.push_back(AstNode::mkconst_int(31, true)); astbuf1->children.back()->children.push_back(AstNode::mkconst_int(0, true)); @@ -817,7 +1136,7 @@ param_integer: param_real: TOK_REAL { if (astbuf1->children.size() != 1) - frontend_verilog_yyerror("Syntax error."); + frontend_verilog_yyerror("Parameter already declared as integer, cannot set to real."); astbuf1->children.push_back(new AstNode(AST_REALVALUE)); } | /* empty */; @@ -825,23 +1144,25 @@ param_range: range { if ($1 != NULL) { if (astbuf1->children.size() != 1) - frontend_verilog_yyerror("Syntax error."); + frontend_verilog_yyerror("integer/real parameters should not have a range."); astbuf1->children.push_back($1); } }; param_decl: - TOK_PARAMETER { + 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; }; localparam_decl: - TOK_LOCALPARAM { + 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; }; @@ -851,9 +1172,15 @@ param_decl_list: single_param_decl: TOK_ID '=' expr { - if (astbuf1 == nullptr) - frontend_verilog_yyerror("syntax error"); - AstNode *node = astbuf1->clone(); + AstNode *node; + if (astbuf1 == nullptr) { + if (!sv_mode) + frontend_verilog_yyerror("In pure Verilog (not SystemVerilog), parameter/localparam with an initializer must use the parameter/localparam keyword"); + node = new AstNode(AST_PARAMETER); + node->children.push_back(AstNode::mkconst_int(0, true)); + } else { + node = astbuf1->clone(); + } node->str = *$1; delete node->children[0]; node->children[0] = $3; @@ -884,7 +1211,7 @@ wire_decl: astbuf2 = $3; if (astbuf1->range_left >= 0 && astbuf1->range_right >= 0) { if (astbuf2) { - frontend_verilog_yyerror("Syntax error."); + frontend_verilog_yyerror("integer/genvar types cannot have packed dimensions."); } else { astbuf2 = new AstNode(AST_RANGE); astbuf2->children.push_back(AstNode::mkconst_int(astbuf1->range_left, true)); @@ -892,7 +1219,7 @@ wire_decl: } } if (astbuf2 && astbuf2->children.size() != 2) - frontend_verilog_yyerror("Syntax error."); + frontend_verilog_yyerror("wire/reg/logic packed dimension must be of the form: [<expr>:<expr>], [<expr>+:<expr>], or [<expr>-:<expr>]"); } wire_name_list { delete astbuf1; if (astbuf2 != NULL) @@ -977,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)); @@ -986,7 +1318,7 @@ wire_name_and_opt_assign: wire_name: TOK_ID range_or_multirange { if (astbuf1 == nullptr) - frontend_verilog_yyerror("Syntax error."); + frontend_verilog_yyerror("Internal error - should not happen - no AST_WIRE node."); AstNode *node = astbuf1->clone(); node->str = *$1; append_attr_clone(node, albuf); @@ -994,7 +1326,7 @@ wire_name: node->children.push_back(astbuf2->clone()); if ($2 != NULL) { if (node->is_input || node->is_output) - frontend_verilog_yyerror("Syntax error."); + frontend_verilog_yyerror("input/output/inout ports cannot have unpacked dimensions."); if (!astbuf2) { AstNode *rng = new AstNode(AST_RANGE); rng->children.push_back(AstNode::mkconst_int(0, true)); @@ -1002,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) { @@ -1024,6 +1362,7 @@ wire_name: node->port_id = current_function_or_task_port_id++; } ast_stack.back()->children.push_back(node); + delete $1; }; @@ -1148,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: @@ -1236,74 +1588,219 @@ opt_label: $$ = NULL; }; +opt_sva_label: + TOK_SVA_LABEL ':' { + $$ = $1; + } | + /* empty */ { + $$ = NULL; + }; + opt_property: - TOK_PROPERTY | /* empty */; + TOK_PROPERTY { + $$ = true; + } | + TOK_FINAL { + $$ = false; + } | + /* empty */ { + $$ = false; + }; -opt_stmt_label: - TOK_ID ':' | /* empty */; +modport_stmt: + TOK_MODPORT TOK_ID { + AstNode *modport = new AstNode(AST_MODPORT); + ast_stack.back()->children.push_back(modport); + ast_stack.push_back(modport); + modport->str = *$2; + delete $2; + } modport_args_opt { + ast_stack.pop_back(); + log_assert(ast_stack.size() == 2); + } ';' + +modport_args_opt: + '(' ')' | '(' modport_args optional_comma ')'; + +modport_args: + modport_arg | modport_args ',' modport_arg; + +modport_arg: + modport_type_token modport_member | + modport_member + +modport_member: + TOK_ID { + AstNode *modport_member = new AstNode(AST_MODPORTMEMBER); + ast_stack.back()->children.push_back(modport_member); + modport_member->str = *$1; + modport_member->is_input = current_modport_input; + modport_member->is_output = current_modport_output; + delete $1; + } + +modport_type_token: + TOK_INPUT {current_modport_input = 1; current_modport_output = 0;} | TOK_OUTPUT {current_modport_input = 0; current_modport_output = 1;} assert: - opt_stmt_label TOK_ASSERT opt_property '(' expr ')' ';' { - ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $5)); + opt_sva_label TOK_ASSERT opt_property '(' expr ')' ';' { + if (noassert_mode) { + delete $5; + } else { + AstNode *node = new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $5); + if ($1 != nullptr) + node->str = *$1; + ast_stack.back()->children.push_back(node); + } + if ($1 != nullptr) + delete $1; } | - opt_stmt_label TOK_ASSUME opt_property '(' expr ')' ';' { - ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $5)); + opt_sva_label TOK_ASSUME opt_property '(' expr ')' ';' { + if (noassume_mode) { + delete $5; + } else { + AstNode *node = new AstNode(assert_assumes_mode ? AST_ASSERT : AST_ASSUME, $5); + if ($1 != nullptr) + node->str = *$1; + ast_stack.back()->children.push_back(node); + } + if ($1 != nullptr) + delete $1; } | - opt_stmt_label TOK_ASSERT opt_property '(' TOK_EVENTUALLY expr ')' ';' { - ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $6)); + opt_sva_label TOK_ASSERT opt_property '(' TOK_EVENTUALLY expr ')' ';' { + if (noassert_mode) { + delete $6; + } else { + AstNode *node = new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $6); + if ($1 != nullptr) + node->str = *$1; + ast_stack.back()->children.push_back(node); + } + if ($1 != nullptr) + delete $1; } | - opt_stmt_label TOK_ASSUME opt_property '(' TOK_EVENTUALLY expr ')' ';' { - ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $6)); + opt_sva_label TOK_ASSUME opt_property '(' TOK_EVENTUALLY expr ')' ';' { + if (noassume_mode) { + delete $6; + } else { + AstNode *node = new AstNode(assert_assumes_mode ? AST_LIVE : AST_FAIR, $6); + if ($1 != nullptr) + node->str = *$1; + ast_stack.back()->children.push_back(node); + } + if ($1 != nullptr) + delete $1; } | - opt_stmt_label TOK_COVER opt_property '(' expr ')' ';' { - ast_stack.back()->children.push_back(new AstNode(AST_COVER, $5)); + opt_sva_label TOK_COVER opt_property '(' expr ')' ';' { + AstNode *node = new AstNode(AST_COVER, $5); + if ($1 != nullptr) { + node->str = *$1; + delete $1; + } + ast_stack.back()->children.push_back(node); } | - opt_stmt_label TOK_COVER opt_property '(' ')' ';' { - ast_stack.back()->children.push_back(new AstNode(AST_COVER, AstNode::mkconst_int(1, false))); + opt_sva_label TOK_COVER opt_property '(' ')' ';' { + AstNode *node = new AstNode(AST_COVER, AstNode::mkconst_int(1, false)); + if ($1 != nullptr) { + node->str = *$1; + delete $1; + } + ast_stack.back()->children.push_back(node); } | - opt_stmt_label TOK_COVER ';' { - ast_stack.back()->children.push_back(new AstNode(AST_COVER, AstNode::mkconst_int(1, false))); + opt_sva_label TOK_COVER ';' { + AstNode *node = new AstNode(AST_COVER, AstNode::mkconst_int(1, false)); + if ($1 != nullptr) { + node->str = *$1; + delete $1; + } + ast_stack.back()->children.push_back(node); } | - opt_stmt_label TOK_RESTRICT opt_property '(' expr ')' ';' { - if (norestrict_mode) + opt_sva_label TOK_RESTRICT opt_property '(' expr ')' ';' { + if (norestrict_mode) { delete $5; - else - ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $5)); + } else { + AstNode *node = new AstNode(AST_ASSUME, $5); + if ($1 != nullptr) + node->str = *$1; + ast_stack.back()->children.push_back(node); + } + if (!$3) + log_file_warning(current_filename, get_line_num(), "SystemVerilog does not allow \"restrict\" without \"property\".\n"); + if ($1 != nullptr) + delete $1; } | - opt_stmt_label TOK_RESTRICT opt_property '(' TOK_EVENTUALLY expr ')' ';' { - if (norestrict_mode) + opt_sva_label TOK_RESTRICT opt_property '(' TOK_EVENTUALLY expr ')' ';' { + if (norestrict_mode) { delete $6; - else - ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $6)); + } else { + AstNode *node = new AstNode(AST_FAIR, $6); + if ($1 != nullptr) + node->str = *$1; + ast_stack.back()->children.push_back(node); + } + if (!$3) + log_file_warning(current_filename, get_line_num(), "SystemVerilog does not allow \"restrict\" without \"property\".\n"); + if ($1 != nullptr) + delete $1; }; assert_property: - TOK_ASSERT TOK_PROPERTY '(' expr ')' ';' { - ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $4)); - } | - TOK_ASSUME TOK_PROPERTY '(' expr ')' ';' { - ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $4)); + opt_sva_label TOK_ASSERT TOK_PROPERTY '(' expr ')' ';' { + ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $5)); + if ($1 != nullptr) { + ast_stack.back()->children.back()->str = *$1; + delete $1; + } } | - TOK_ASSERT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' { - ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $5)); + opt_sva_label TOK_ASSUME TOK_PROPERTY '(' expr ')' ';' { + ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $5)); + if ($1 != nullptr) { + ast_stack.back()->children.back()->str = *$1; + delete $1; + } } | - TOK_ASSUME TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' { - ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $5)); + opt_sva_label TOK_ASSERT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' { + ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $6)); + if ($1 != nullptr) { + ast_stack.back()->children.back()->str = *$1; + delete $1; + } } | - TOK_COVER TOK_PROPERTY '(' expr ')' ';' { - ast_stack.back()->children.push_back(new AstNode(AST_COVER, $4)); + opt_sva_label TOK_ASSUME TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' { + ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $6)); + if ($1 != nullptr) { + ast_stack.back()->children.back()->str = *$1; + delete $1; + } } | - TOK_RESTRICT TOK_PROPERTY '(' expr ')' ';' { - if (norestrict_mode) - delete $4; - else - ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $4)); + opt_sva_label TOK_COVER TOK_PROPERTY '(' expr ')' ';' { + ast_stack.back()->children.push_back(new AstNode(AST_COVER, $5)); + if ($1 != nullptr) { + ast_stack.back()->children.back()->str = *$1; + delete $1; + } } | - TOK_RESTRICT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' { - if (norestrict_mode) + opt_sva_label TOK_RESTRICT TOK_PROPERTY '(' expr ')' ';' { + if (norestrict_mode) { delete $5; - else - ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $5)); + } else { + ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $5)); + if ($1 != nullptr) { + ast_stack.back()->children.back()->str = *$1; + delete $1; + } + } + } | + opt_sva_label TOK_RESTRICT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' { + if (norestrict_mode) { + delete $6; + } else { + ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $6)); + if ($1 != nullptr) { + ast_stack.back()->children.back()->str = *$1; + delete $1; + } + } }; simple_behavioral_stmt: @@ -1339,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); @@ -1348,7 +1855,7 @@ behavioral_stmt: node->str = *$3; } behavioral_stmt_list TOK_END opt_label { if ($3 != NULL && $7 != NULL && *$3 != *$7) - frontend_verilog_yyerror("Syntax error."); + frontend_verilog_yyerror("Begin label (%s) and end label (%s) don't match.", $3->c_str()+1, $7->c_str()+1); if ($3 != NULL) delete $3; if ($7 != NULL) @@ -1521,6 +2028,11 @@ case_expr_list: TOK_DEFAULT { ast_stack.back()->children.push_back(new AstNode(AST_DEFAULT)); } | + TOK_SVA_LABEL { + ast_stack.back()->children.push_back(new AstNode(AST_IDENTIFIER)); + ast_stack.back()->children.back()->str = *$1; + delete $1; + } | expr { ast_stack.back()->children.push_back($1); } | @@ -1629,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: @@ -1663,8 +2184,8 @@ basic_expr: $$ = $1; } | '(' expr ')' TOK_CONSTVAL { - if ($4->substr(0, 1) != "'") - frontend_verilog_yyerror("Syntax error."); + if ($4->compare(0, 1, "'") != 0) + frontend_verilog_yyerror("Cast operation must be applied on sized constants e.g. (<expr>)<constval> , while %s is not a sized constant.", $4->c_str()); AstNode *bits = $2; AstNode *val = const2ast(*$4, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode); if (val == NULL) @@ -1673,8 +2194,8 @@ basic_expr: delete $4; } | hierarchical_id TOK_CONSTVAL { - if ($2->substr(0, 1) != "'") - frontend_verilog_yyerror("Syntax error."); + if ($2->compare(0, 1, "'") != 0) + frontend_verilog_yyerror("Cast operation must be applied on sized constants, e.g. <ID>\'d0, while %s is not a sized constant.", $2->c_str()); AstNode *bits = new AstNode(AST_IDENTIFIER); bits->str = *$1; AstNode *val = const2ast(*$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode); @@ -1899,4 +2420,3 @@ concat_list: $$ = $3; $$->children.push_back($1); }; - diff --git a/kernel/cellaigs.cc b/kernel/cellaigs.cc index 5fd76afe5..02854edb2 100644 --- a/kernel/cellaigs.cc +++ b/kernel/cellaigs.cc @@ -268,9 +268,9 @@ Aig::Aig(Cell *cell) cell->parameters.sort(); for (auto p : cell->parameters) { - if (p.first == "\\A_WIDTH" && mkname_a_signed) { + if (p.first == ID(A_WIDTH) && mkname_a_signed) { name = mkname_last + stringf(":%d%c", p.second.as_int(), mkname_is_signed ? 'S' : 'U'); - } else if (p.first == "\\B_WIDTH" && mkname_b_signed) { + } else if (p.first == ID(B_WIDTH) && mkname_b_signed) { name = mkname_last + stringf(":%d%c", p.second.as_int(), mkname_is_signed ? 'S' : 'U'); } else { mkname_last = name; @@ -280,181 +280,183 @@ Aig::Aig(Cell *cell) mkname_a_signed = false; mkname_b_signed = false; mkname_is_signed = false; - if (p.first == "\\A_SIGNED") { + if (p.first == ID(A_SIGNED)) { mkname_a_signed = true; mkname_is_signed = p.second.as_bool(); } - if (p.first == "\\B_SIGNED") { + if (p.first == ID(B_SIGNED)) { mkname_b_signed = true; mkname_is_signed = p.second.as_bool(); } } - if (cell->type.in("$not", "$_NOT_", "$pos", "$_BUF_")) + if (cell->type.in(ID($not), ID($_NOT_), ID($pos), ID($_BUF_))) { - for (int i = 0; i < GetSize(cell->getPort("\\Y")); i++) { - int A = mk.inport("\\A", i); - int Y = cell->type.in("$not", "$_NOT_") ? mk.not_gate(A) : A; - mk.outport(Y, "\\Y", i); + for (int i = 0; i < GetSize(cell->getPort(ID::Y)); i++) { + int A = mk.inport(ID::A, i); + int Y = cell->type.in(ID($not), ID($_NOT_)) ? mk.not_gate(A) : A; + mk.outport(Y, ID::Y, i); } goto optimize; } - if (cell->type.in("$and", "$_AND_", "$_NAND_", "$or", "$_OR_", "$_NOR_", "$xor", "$xnor", "$_XOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_")) - { - for (int i = 0; i < GetSize(cell->getPort("\\Y")); i++) { - int A = mk.inport("\\A", i); - int B = mk.inport("\\B", i); - int Y = cell->type.in("$and", "$_AND_") ? mk.and_gate(A, B) : - cell->type.in("$_NAND_") ? mk.nand_gate(A, B) : - cell->type.in("$or", "$_OR_") ? mk.or_gate(A, B) : - cell->type.in("$_NOR_") ? mk.nor_gate(A, B) : - cell->type.in("$xor", "$_XOR_") ? mk.xor_gate(A, B) : - cell->type.in("$xnor", "$_XNOR_") ? mk.xnor_gate(A, B) : - cell->type.in("$_ANDNOT_") ? mk.andnot_gate(A, B) : - cell->type.in("$_ORNOT_") ? mk.ornot_gate(A, B) : -1; - mk.outport(Y, "\\Y", i); + if (cell->type.in(ID($and), ID($_AND_), ID($_NAND_), ID($or), ID($_OR_), ID($_NOR_), ID($xor), ID($xnor), ID($_XOR_), ID($_XNOR_), ID($_ANDNOT_), ID($_ORNOT_))) + { + for (int i = 0; i < GetSize(cell->getPort(ID::Y)); i++) { + int A = mk.inport(ID::A, i); + int B = mk.inport(ID::B, i); + int Y = cell->type.in(ID($and), ID($_AND_)) ? mk.and_gate(A, B) : + cell->type.in(ID($_NAND_)) ? mk.nand_gate(A, B) : + cell->type.in(ID($or), ID($_OR_)) ? mk.or_gate(A, B) : + cell->type.in(ID($_NOR_)) ? mk.nor_gate(A, B) : + cell->type.in(ID($xor), ID($_XOR_)) ? mk.xor_gate(A, B) : + cell->type.in(ID($xnor), ID($_XNOR_)) ? mk.xnor_gate(A, B) : + cell->type.in(ID($_ANDNOT_)) ? mk.andnot_gate(A, B) : + cell->type.in(ID($_ORNOT_)) ? mk.ornot_gate(A, B) : -1; + mk.outport(Y, ID::Y, i); } goto optimize; } - if (cell->type.in("$mux", "$_MUX_")) + if (cell->type.in(ID($mux), ID($_MUX_))) { - int S = mk.inport("\\S"); - for (int i = 0; i < GetSize(cell->getPort("\\Y")); i++) { - int A = mk.inport("\\A", i); - int B = mk.inport("\\B", i); + int S = mk.inport(ID(S)); + for (int i = 0; i < GetSize(cell->getPort(ID::Y)); i++) { + int A = mk.inport(ID::A, i); + int B = mk.inport(ID::B, i); int Y = mk.mux_gate(A, B, S); - mk.outport(Y, "\\Y", i); + if (cell->type == ID($_NMUX_)) + Y = mk.not_gate(Y); + mk.outport(Y, ID::Y, i); } goto optimize; } - if (cell->type.in("$reduce_and", "$reduce_or", "$reduce_xor", "$reduce_xnor", "$reduce_bool")) + if (cell->type.in(ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_xnor), ID($reduce_bool))) { - int Y = mk.inport("\\A", 0); - for (int i = 1; i < GetSize(cell->getPort("\\A")); i++) { - int A = mk.inport("\\A", i); - if (cell->type == "$reduce_and") Y = mk.and_gate(A, Y); - if (cell->type == "$reduce_or") Y = mk.or_gate(A, Y); - if (cell->type == "$reduce_bool") Y = mk.or_gate(A, Y); - if (cell->type == "$reduce_xor") Y = mk.xor_gate(A, Y); - if (cell->type == "$reduce_xnor") Y = mk.xor_gate(A, Y); + int Y = mk.inport(ID::A, 0); + for (int i = 1; i < GetSize(cell->getPort(ID::A)); i++) { + int A = mk.inport(ID::A, i); + if (cell->type == ID($reduce_and)) Y = mk.and_gate(A, Y); + if (cell->type == ID($reduce_or)) Y = mk.or_gate(A, Y); + if (cell->type == ID($reduce_bool)) Y = mk.or_gate(A, Y); + if (cell->type == ID($reduce_xor)) Y = mk.xor_gate(A, Y); + if (cell->type == ID($reduce_xnor)) Y = mk.xor_gate(A, Y); } - if (cell->type == "$reduce_xnor") + if (cell->type == ID($reduce_xnor)) Y = mk.not_gate(Y); - mk.outport(Y, "\\Y", 0); - for (int i = 1; i < GetSize(cell->getPort("\\Y")); i++) - mk.outport(mk.bool_node(false), "\\Y", i); + mk.outport(Y, ID::Y, 0); + for (int i = 1; i < GetSize(cell->getPort(ID::Y)); i++) + mk.outport(mk.bool_node(false), ID::Y, i); goto optimize; } - if (cell->type.in("$logic_not", "$logic_and", "$logic_or")) + if (cell->type.in(ID($logic_not), ID($logic_and), ID($logic_or))) { - int A = mk.inport("\\A", 0), Y = -1; - for (int i = 1; i < GetSize(cell->getPort("\\A")); i++) - A = mk.or_gate(mk.inport("\\A", i), A); - if (cell->type.in("$logic_and", "$logic_or")) { - int B = mk.inport("\\B", 0); - for (int i = 1; i < GetSize(cell->getPort("\\B")); i++) - B = mk.or_gate(mk.inport("\\B", i), B); - if (cell->type == "$logic_and") Y = mk.and_gate(A, B); - if (cell->type == "$logic_or") Y = mk.or_gate(A, B); + int A = mk.inport(ID::A, 0), Y = -1; + for (int i = 1; i < GetSize(cell->getPort(ID::A)); i++) + A = mk.or_gate(mk.inport(ID::A, i), A); + if (cell->type.in(ID($logic_and), ID($logic_or))) { + int B = mk.inport(ID::B, 0); + for (int i = 1; i < GetSize(cell->getPort(ID::B)); i++) + B = mk.or_gate(mk.inport(ID::B, i), B); + if (cell->type == ID($logic_and)) Y = mk.and_gate(A, B); + if (cell->type == ID($logic_or)) Y = mk.or_gate(A, B); } else { - if (cell->type == "$logic_not") Y = mk.not_gate(A); + if (cell->type == ID($logic_not)) Y = mk.not_gate(A); } - mk.outport_bool(Y, "\\Y"); + mk.outport_bool(Y, ID::Y); goto optimize; } - if (cell->type.in("$add", "$sub")) + if (cell->type.in(ID($add), ID($sub))) { - int width = GetSize(cell->getPort("\\Y")); - vector<int> A = mk.inport_vec("\\A", width); - vector<int> B = mk.inport_vec("\\B", width); + int width = GetSize(cell->getPort(ID::Y)); + vector<int> A = mk.inport_vec(ID::A, width); + vector<int> B = mk.inport_vec(ID::B, width); int carry = mk.bool_node(false); - if (cell->type == "$sub") { + if (cell->type == ID($sub)) { for (auto &n : B) n = mk.not_gate(n); carry = mk.not_gate(carry); } vector<int> Y = mk.adder(A, B, carry); - mk.outport_vec(Y, "\\Y"); + mk.outport_vec(Y, ID::Y); goto optimize; } - if (cell->type == "$alu") + if (cell->type == ID($alu)) { - int width = GetSize(cell->getPort("\\Y")); - vector<int> A = mk.inport_vec("\\A", width); - vector<int> B = mk.inport_vec("\\B", width); - int carry = mk.inport("\\CI"); - int binv = mk.inport("\\BI"); + int width = GetSize(cell->getPort(ID::Y)); + vector<int> A = mk.inport_vec(ID::A, width); + vector<int> B = mk.inport_vec(ID::B, width); + int carry = mk.inport(ID(CI)); + int binv = mk.inport(ID(BI)); for (auto &n : B) n = mk.xor_gate(n, binv); vector<int> X(width), CO(width); vector<int> Y = mk.adder(A, B, carry, &X, &CO); for (int i = 0; i < width; i++) X[i] = mk.xor_gate(A[i], B[i]); - mk.outport_vec(Y, "\\Y"); - mk.outport_vec(X, "\\X"); - mk.outport_vec(CO, "\\CO"); + mk.outport_vec(Y, ID::Y); + mk.outport_vec(X, ID(X)); + mk.outport_vec(CO, ID(CO)); goto optimize; } - if (cell->type.in("$eq", "$ne")) + if (cell->type.in(ID($eq), ID($ne))) { - int width = max(GetSize(cell->getPort("\\A")), GetSize(cell->getPort("\\B"))); - vector<int> A = mk.inport_vec("\\A", width); - vector<int> B = mk.inport_vec("\\B", width); + int width = max(GetSize(cell->getPort(ID::A)), GetSize(cell->getPort(ID::B))); + vector<int> A = mk.inport_vec(ID::A, width); + vector<int> B = mk.inport_vec(ID::B, width); int Y = mk.bool_node(false); for (int i = 0; i < width; i++) Y = mk.or_gate(Y, mk.xor_gate(A[i], B[i])); - if (cell->type == "$eq") + if (cell->type == ID($eq)) Y = mk.not_gate(Y); - mk.outport_bool(Y, "\\Y"); + mk.outport_bool(Y, ID::Y); goto optimize; } - if (cell->type == "$_AOI3_") + if (cell->type == ID($_AOI3_)) { - int A = mk.inport("\\A"); - int B = mk.inport("\\B"); - int C = mk.inport("\\C"); + int A = mk.inport(ID::A); + int B = mk.inport(ID::B); + int C = mk.inport(ID(C)); int Y = mk.nor_gate(mk.and_gate(A, B), C); - mk.outport(Y, "\\Y"); + mk.outport(Y, ID::Y); goto optimize; } - if (cell->type == "$_OAI3_") + if (cell->type == ID($_OAI3_)) { - int A = mk.inport("\\A"); - int B = mk.inport("\\B"); - int C = mk.inport("\\C"); + int A = mk.inport(ID::A); + int B = mk.inport(ID::B); + int C = mk.inport(ID(C)); int Y = mk.nand_gate(mk.or_gate(A, B), C); - mk.outport(Y, "\\Y"); + mk.outport(Y, ID::Y); goto optimize; } - if (cell->type == "$_AOI4_") + if (cell->type == ID($_AOI4_)) { - int A = mk.inport("\\A"); - int B = mk.inport("\\B"); - int C = mk.inport("\\C"); - int D = mk.inport("\\D"); + int A = mk.inport(ID::A); + int B = mk.inport(ID::B); + int C = mk.inport(ID(C)); + int D = mk.inport(ID(D)); int Y = mk.nor_gate(mk.and_gate(A, B), mk.and_gate(C, D)); - mk.outport(Y, "\\Y"); + mk.outport(Y, ID::Y); goto optimize; } - if (cell->type == "$_OAI4_") + if (cell->type == ID($_OAI4_)) { - int A = mk.inport("\\A"); - int B = mk.inport("\\B"); - int C = mk.inport("\\C"); - int D = mk.inport("\\D"); - int Y = mk.nand_gate(mk.nor_gate(A, B), mk.nor_gate(C, D)); - mk.outport(Y, "\\Y"); + int A = mk.inport(ID::A); + int B = mk.inport(ID::B); + int C = mk.inport(ID(C)); + int D = mk.inport(ID(D)); + int Y = mk.nand_gate(mk.or_gate(A, B), mk.or_gate(C, D)); + mk.outport(Y, ID::Y); goto optimize; } diff --git a/kernel/celledges.cc b/kernel/celledges.cc index 556e8b826..d0bb99e83 100644 --- a/kernel/celledges.cc +++ b/kernel/celledges.cc @@ -24,9 +24,9 @@ PRIVATE_NAMESPACE_BEGIN void bitwise_unary_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) { - IdString A = "\\A", Y = "\\Y"; + IdString A = ID::A, Y = ID::Y; - bool is_signed = cell->getParam("\\A_SIGNED").as_bool(); + bool is_signed = cell->getParam(ID(A_SIGNED)).as_bool(); int a_width = GetSize(cell->getPort(A)); int y_width = GetSize(cell->getPort(Y)); @@ -41,14 +41,14 @@ void bitwise_unary_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) void bitwise_binary_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) { - IdString A = "\\A", B = "\\B", Y = "\\Y"; + IdString A = ID::A, B = ID::B, Y = ID::Y; - bool is_signed = cell->getParam("\\A_SIGNED").as_bool(); + bool is_signed = cell->getParam(ID(A_SIGNED)).as_bool(); int a_width = GetSize(cell->getPort(A)); int b_width = GetSize(cell->getPort(B)); int y_width = GetSize(cell->getPort(Y)); - if (cell->type == "$and" && !is_signed) { + if (cell->type == ID($and) && !is_signed) { if (a_width > b_width) a_width = b_width; else @@ -71,9 +71,9 @@ void bitwise_binary_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) void arith_neg_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) { - IdString A = "\\A", Y = "\\Y"; + IdString A = ID::A, Y = ID::Y; - bool is_signed = cell->getParam("\\A_SIGNED").as_bool(); + bool is_signed = cell->getParam(ID(A_SIGNED)).as_bool(); int a_width = GetSize(cell->getPort(A)); int y_width = GetSize(cell->getPort(Y)); @@ -87,14 +87,14 @@ void arith_neg_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) void arith_binary_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) { - IdString A = "\\A", B = "\\B", Y = "\\Y"; + IdString A = ID::A, B = ID::B, Y = ID::Y; - bool is_signed = cell->getParam("\\A_SIGNED").as_bool(); + bool is_signed = cell->getParam(ID(A_SIGNED)).as_bool(); int a_width = GetSize(cell->getPort(A)); int b_width = GetSize(cell->getPort(B)); int y_width = GetSize(cell->getPort(Y)); - if (!is_signed && cell->type != "$sub") { + if (!is_signed && cell->type != ID($sub)) { int ab_width = std::max(a_width, b_width); y_width = std::min(y_width, ab_width+1); } @@ -114,7 +114,7 @@ void arith_binary_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) void reduce_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) { - IdString A = "\\A", Y = "\\Y"; + IdString A = ID::A, Y = ID::Y; int a_width = GetSize(cell->getPort(A)); @@ -124,7 +124,7 @@ void reduce_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) void compare_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) { - IdString A = "\\A", B = "\\B", Y = "\\Y"; + IdString A = ID::A, B = ID::B, Y = ID::Y; int a_width = GetSize(cell->getPort(A)); int b_width = GetSize(cell->getPort(B)); @@ -138,7 +138,7 @@ void compare_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) void mux_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) { - IdString A = "\\A", B = "\\B", S = "\\S", Y = "\\Y"; + IdString A = ID::A, B = ID::B, S = ID(S), Y = ID::Y; int a_width = GetSize(cell->getPort(A)); int b_width = GetSize(cell->getPort(B)); @@ -160,43 +160,43 @@ PRIVATE_NAMESPACE_END bool YOSYS_NAMESPACE_PREFIX AbstractCellEdgesDatabase::add_edges_from_cell(RTLIL::Cell *cell) { - if (cell->type.in("$not", "$pos")) { + if (cell->type.in(ID($not), ID($pos))) { bitwise_unary_op(this, cell); return true; } - if (cell->type.in("$and", "$or", "$xor", "$xnor")) { + if (cell->type.in(ID($and), ID($or), ID($xor), ID($xnor))) { bitwise_binary_op(this, cell); return true; } - if (cell->type == "$neg") { + if (cell->type == ID($neg)) { arith_neg_op(this, cell); return true; } - if (cell->type.in("$add", "$sub")) { + if (cell->type.in(ID($add), ID($sub))) { arith_binary_op(this, cell); return true; } - if (cell->type.in("$reduce_and", "$reduce_or", "$reduce_xor", "$reduce_xnor", "$reduce_bool", "$logic_not")) { + if (cell->type.in(ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_xnor), ID($reduce_bool), ID($logic_not))) { reduce_op(this, cell); return true; } // FIXME: - // if (cell->type.in("$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx")) { + // if (cell->type.in(ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx))) { // shift_op(this, cell); // return true; // } - if (cell->type.in("$lt", "$le", "$eq", "$ne", "$eqx", "$nex", "$ge", "$gt")) { + if (cell->type.in(ID($lt), ID($le), ID($eq), ID($ne), ID($eqx), ID($nex), ID($ge), ID($gt))) { compare_op(this, cell); return true; } - if (cell->type.in("$mux", "$pmux")) { + if (cell->type.in(ID($mux), ID($pmux))) { mux_op(this, cell); return true; } diff --git a/kernel/celledges.h b/kernel/celledges.h index 6aab9ed43..2cc297cb2 100644 --- a/kernel/celledges.h +++ b/kernel/celledges.h @@ -1,4 +1,4 @@ -/* +/* -*- c++ -*- * yosys -- Yosys Open SYnthesis Suite * * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> @@ -38,7 +38,7 @@ struct FwdCellEdgesDatabase : AbstractCellEdgesDatabase dict<SigBit, pool<SigBit>> db; FwdCellEdgesDatabase(SigMap &sigmap) : sigmap(sigmap) { } - virtual void add_edge(RTLIL::Cell *cell, RTLIL::IdString from_port, int from_bit, RTLIL::IdString to_port, int to_bit, int) override { + void add_edge(RTLIL::Cell *cell, RTLIL::IdString from_port, int from_bit, RTLIL::IdString to_port, int to_bit, int) YS_OVERRIDE { SigBit from_sigbit = sigmap(cell->getPort(from_port)[from_bit]); SigBit to_sigbit = sigmap(cell->getPort(to_port)[to_bit]); db[from_sigbit].insert(to_sigbit); @@ -51,7 +51,7 @@ struct RevCellEdgesDatabase : AbstractCellEdgesDatabase dict<SigBit, pool<SigBit>> db; RevCellEdgesDatabase(SigMap &sigmap) : sigmap(sigmap) { } - virtual void add_edge(RTLIL::Cell *cell, RTLIL::IdString from_port, int from_bit, RTLIL::IdString to_port, int to_bit, int) override { + void add_edge(RTLIL::Cell *cell, RTLIL::IdString from_port, int from_bit, RTLIL::IdString to_port, int to_bit, int) YS_OVERRIDE { SigBit from_sigbit = sigmap(cell->getPort(from_port)[from_bit]); SigBit to_sigbit = sigmap(cell->getPort(to_port)[to_bit]); db[to_sigbit].insert(from_sigbit); diff --git a/kernel/celltypes.h b/kernel/celltypes.h index fcc4fcc4b..bc96fd602 100644 --- a/kernel/celltypes.h +++ b/kernel/celltypes.h @@ -82,22 +82,48 @@ struct CellTypes void setup_internals() { + setup_internals_eval(); + + IdString A = ID::A, B = ID::B, EN = ID(EN), Y = ID::Y; + IdString SRC = ID(SRC), DST = ID(DST), DAT = ID(DAT); + IdString EN_SRC = ID(EN_SRC), EN_DST = ID(EN_DST); + + setup_type(ID($tribuf), {A, EN}, {Y}, true); + + setup_type(ID($assert), {A, EN}, pool<RTLIL::IdString>(), true); + setup_type(ID($assume), {A, EN}, pool<RTLIL::IdString>(), true); + setup_type(ID($live), {A, EN}, pool<RTLIL::IdString>(), true); + setup_type(ID($fair), {A, EN}, pool<RTLIL::IdString>(), true); + setup_type(ID($cover), {A, EN}, pool<RTLIL::IdString>(), true); + setup_type(ID($initstate), pool<RTLIL::IdString>(), {Y}, true); + setup_type(ID($anyconst), pool<RTLIL::IdString>(), {Y}, true); + setup_type(ID($anyseq), pool<RTLIL::IdString>(), {Y}, true); + setup_type(ID($allconst), pool<RTLIL::IdString>(), {Y}, true); + setup_type(ID($allseq), pool<RTLIL::IdString>(), {Y}, true); + setup_type(ID($equiv), {A, B}, {Y}, true); + setup_type(ID($specify2), {EN, SRC, DST}, pool<RTLIL::IdString>(), true); + setup_type(ID($specify3), {EN, SRC, DST, DAT}, pool<RTLIL::IdString>(), true); + setup_type(ID($specrule), {EN_SRC, EN_DST, SRC, DST}, pool<RTLIL::IdString>(), true); + } + + void setup_internals_eval() + { std::vector<RTLIL::IdString> unary_ops = { - "$not", "$pos", "$neg", - "$reduce_and", "$reduce_or", "$reduce_xor", "$reduce_xnor", "$reduce_bool", - "$logic_not", "$slice", "$lut", "$sop" + ID($not), ID($pos), ID($neg), + ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_xnor), ID($reduce_bool), + ID($logic_not), ID($slice), ID($lut), ID($sop) }; std::vector<RTLIL::IdString> binary_ops = { - "$and", "$or", "$xor", "$xnor", - "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", - "$lt", "$le", "$eq", "$ne", "$eqx", "$nex", "$ge", "$gt", - "$add", "$sub", "$mul", "$div", "$mod", "$pow", - "$logic_and", "$logic_or", "$concat", "$macc" + ID($and), ID($or), ID($xor), ID($xnor), + ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx), + ID($lt), ID($le), ID($eq), ID($ne), ID($eqx), ID($nex), ID($ge), ID($gt), + ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($pow), + ID($logic_and), ID($logic_or), ID($concat), ID($macc) }; - IdString A = "\\A", B = "\\B", S = "\\S", Y = "\\Y"; - IdString P = "\\P", G = "\\G", C = "\\C", X = "\\X"; - IdString BI = "\\BI", CI = "\\CI", CO = "\\CO", EN = "\\EN"; + IdString A = ID::A, B = ID::B, S = ID(S), Y = ID::Y; + IdString P = ID(P), G = ID(G), C = ID(C), X = ID(X); + IdString BI = ID(BI), CI = ID(CI), CO = ID(CO), EN = ID(EN); for (auto type : unary_ops) setup_type(type, {A}, {Y}, true); @@ -105,87 +131,91 @@ struct CellTypes for (auto type : binary_ops) setup_type(type, {A, B}, {Y}, true); - for (auto type : std::vector<RTLIL::IdString>({"$mux", "$pmux"})) + for (auto type : std::vector<RTLIL::IdString>({ID($mux), ID($pmux)})) setup_type(type, {A, B, S}, {Y}, true); - setup_type("$lcu", {P, G, CI}, {CO}, true); - setup_type("$alu", {A, B, CI, BI}, {X, Y, CO}, true); - setup_type("$fa", {A, B, C}, {X, Y}, true); - - setup_type("$tribuf", {A, EN}, {Y}, true); - - setup_type("$assert", {A, EN}, pool<RTLIL::IdString>(), true); - setup_type("$assume", {A, EN}, pool<RTLIL::IdString>(), true); - setup_type("$live", {A, EN}, pool<RTLIL::IdString>(), true); - setup_type("$fair", {A, EN}, pool<RTLIL::IdString>(), true); - setup_type("$cover", {A, EN}, pool<RTLIL::IdString>(), true); - setup_type("$initstate", pool<RTLIL::IdString>(), {Y}, true); - setup_type("$anyconst", pool<RTLIL::IdString>(), {Y}, true); - setup_type("$anyseq", pool<RTLIL::IdString>(), {Y}, true); - setup_type("$allconst", pool<RTLIL::IdString>(), {Y}, true); - setup_type("$allseq", pool<RTLIL::IdString>(), {Y}, true); - setup_type("$equiv", {A, B}, {Y}, true); + setup_type(ID($lcu), {P, G, CI}, {CO}, true); + setup_type(ID($alu), {A, B, CI, BI}, {X, Y, CO}, true); + setup_type(ID($fa), {A, B, C}, {X, Y}, true); + } + + void setup_internals_ff() + { + IdString SET = ID(SET), CLR = ID(CLR), CLK = ID(CLK), ARST = ID(ARST), EN = ID(EN); + IdString Q = ID(Q), D = ID(D); + + setup_type(ID($sr), {SET, CLR}, {Q}); + setup_type(ID($ff), {D}, {Q}); + setup_type(ID($dff), {CLK, D}, {Q}); + setup_type(ID($dffe), {CLK, EN, D}, {Q}); + setup_type(ID($dffsr), {CLK, SET, CLR, D}, {Q}); + setup_type(ID($adff), {CLK, ARST, D}, {Q}); + setup_type(ID($dlatch), {EN, D}, {Q}); + setup_type(ID($dlatchsr), {EN, SET, CLR, D}, {Q}); + } void setup_internals_mem() { - IdString SET = "\\SET", CLR = "\\CLR", CLK = "\\CLK", ARST = "\\ARST", EN = "\\EN"; - IdString Q = "\\Q", D = "\\D", ADDR = "\\ADDR", DATA = "\\DATA", RD_EN = "\\RD_EN"; - IdString RD_CLK = "\\RD_CLK", RD_ADDR = "\\RD_ADDR", WR_CLK = "\\WR_CLK", WR_EN = "\\WR_EN"; - IdString WR_ADDR = "\\WR_ADDR", WR_DATA = "\\WR_DATA", RD_DATA = "\\RD_DATA"; - IdString CTRL_IN = "\\CTRL_IN", CTRL_OUT = "\\CTRL_OUT"; - - setup_type("$sr", {SET, CLR}, {Q}); - setup_type("$ff", {D}, {Q}); - setup_type("$dff", {CLK, D}, {Q}); - setup_type("$dffe", {CLK, EN, D}, {Q}); - setup_type("$dffsr", {CLK, SET, CLR, D}, {Q}); - setup_type("$adff", {CLK, ARST, D}, {Q}); - setup_type("$dlatch", {EN, D}, {Q}); - setup_type("$dlatchsr", {EN, SET, CLR, D}, {Q}); - - setup_type("$memrd", {CLK, EN, ADDR}, {DATA}); - setup_type("$memwr", {CLK, EN, ADDR, DATA}, pool<RTLIL::IdString>()); - setup_type("$meminit", {ADDR, DATA}, pool<RTLIL::IdString>()); - setup_type("$mem", {RD_CLK, RD_EN, RD_ADDR, WR_CLK, WR_EN, WR_ADDR, WR_DATA}, {RD_DATA}); - - setup_type("$fsm", {CLK, ARST, CTRL_IN}, {CTRL_OUT}); + setup_internals_ff(); + + IdString CLK = ID(CLK), ARST = ID(ARST), EN = ID(EN); + IdString ADDR = ID(ADDR), DATA = ID(DATA), RD_EN = ID(RD_EN); + IdString RD_CLK = ID(RD_CLK), RD_ADDR = ID(RD_ADDR), WR_CLK = ID(WR_CLK), WR_EN = ID(WR_EN); + IdString WR_ADDR = ID(WR_ADDR), WR_DATA = ID(WR_DATA), RD_DATA = ID(RD_DATA); + IdString CTRL_IN = ID(CTRL_IN), CTRL_OUT = ID(CTRL_OUT); + + setup_type(ID($memrd), {CLK, EN, ADDR}, {DATA}); + setup_type(ID($memwr), {CLK, EN, ADDR, DATA}, pool<RTLIL::IdString>()); + setup_type(ID($meminit), {ADDR, DATA}, pool<RTLIL::IdString>()); + setup_type(ID($mem), {RD_CLK, RD_EN, RD_ADDR, WR_CLK, WR_EN, WR_ADDR, WR_DATA}, {RD_DATA}); + + setup_type(ID($fsm), {CLK, ARST, CTRL_IN}, {CTRL_OUT}); } void setup_stdcells() { - IdString A = "\\A", B = "\\B", C = "\\C", D = "\\D"; - IdString E = "\\E", F = "\\F", G = "\\G", H = "\\H"; - IdString I = "\\I", J = "\\J", K = "\\K", L = "\\L"; - IdString M = "\\I", N = "\\N", O = "\\O", P = "\\P"; - IdString S = "\\S", T = "\\T", U = "\\U", V = "\\V"; - IdString Y = "\\Y"; - - setup_type("$_BUF_", {A}, {Y}, true); - setup_type("$_NOT_", {A}, {Y}, true); - setup_type("$_AND_", {A, B}, {Y}, true); - setup_type("$_NAND_", {A, B}, {Y}, true); - setup_type("$_OR_", {A, B}, {Y}, true); - setup_type("$_NOR_", {A, B}, {Y}, true); - setup_type("$_XOR_", {A, B}, {Y}, true); - setup_type("$_XNOR_", {A, B}, {Y}, true); - setup_type("$_ANDNOT_", {A, B}, {Y}, true); - setup_type("$_ORNOT_", {A, B}, {Y}, true); - setup_type("$_MUX_", {A, B, S}, {Y}, true); - setup_type("$_MUX4_", {A, B, C, D, S, T}, {Y}, true); - setup_type("$_MUX8_", {A, B, C, D, E, F, G, H, S, T, U}, {Y}, true); - setup_type("$_MUX16_", {A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, S, T, U, V}, {Y}, true); - setup_type("$_AOI3_", {A, B, C}, {Y}, true); - setup_type("$_OAI3_", {A, B, C}, {Y}, true); - setup_type("$_AOI4_", {A, B, C, D}, {Y}, true); - setup_type("$_OAI4_", {A, B, C, D}, {Y}, true); - setup_type("$_TBUF_", {A, E}, {Y}, true); + setup_stdcells_eval(); + + IdString A = ID::A, E = ID(E), Y = ID::Y; + + setup_type(ID($_TBUF_), {A, E}, {Y}, true); + } + + void setup_stdcells_eval() + { + IdString A = ID::A, B = ID::B, C = ID(C), D = ID(D); + IdString E = ID(E), F = ID(F), G = ID(G), H = ID(H); + IdString I = ID(I), J = ID(J), K = ID(K), L = ID(L); + IdString M = ID(M), N = ID(N), O = ID(O), P = ID(P); + IdString S = ID(S), T = ID(T), U = ID(U), V = ID(V); + IdString Y = ID::Y; + + setup_type(ID($_BUF_), {A}, {Y}, true); + setup_type(ID($_NOT_), {A}, {Y}, true); + setup_type(ID($_AND_), {A, B}, {Y}, true); + setup_type(ID($_NAND_), {A, B}, {Y}, true); + setup_type(ID($_OR_), {A, B}, {Y}, true); + setup_type(ID($_NOR_), {A, B}, {Y}, true); + setup_type(ID($_XOR_), {A, B}, {Y}, true); + setup_type(ID($_XNOR_), {A, B}, {Y}, true); + setup_type(ID($_ANDNOT_), {A, B}, {Y}, true); + setup_type(ID($_ORNOT_), {A, B}, {Y}, true); + setup_type(ID($_MUX_), {A, B, S}, {Y}, true); + setup_type(ID($_NMUX_), {A, B, S}, {Y}, true); + setup_type(ID($_MUX4_), {A, B, C, D, S, T}, {Y}, true); + setup_type(ID($_MUX8_), {A, B, C, D, E, F, G, H, S, T, U}, {Y}, true); + setup_type(ID($_MUX16_), {A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, S, T, U, V}, {Y}, true); + setup_type(ID($_AOI3_), {A, B, C}, {Y}, true); + setup_type(ID($_OAI3_), {A, B, C}, {Y}, true); + setup_type(ID($_AOI4_), {A, B, C, D}, {Y}, true); + setup_type(ID($_OAI4_), {A, B, C, D}, {Y}, true); } void setup_stdcells_mem() { - IdString S = "\\S", R = "\\R", C = "\\C"; - IdString D = "\\D", Q = "\\Q", E = "\\E"; + IdString S = ID(S), R = ID(R), C = ID(C); + IdString D = ID(D), Q = ID(Q), E = ID(E); std::vector<char> list_np = {'N', 'P'}, list_01 = {'0', '1'}; @@ -193,7 +223,7 @@ struct CellTypes for (auto c2 : list_np) setup_type(stringf("$_SR_%c%c_", c1, c2), {S, R}, {Q}); - setup_type("$_FF_", {D}, {Q}); + setup_type(ID($_FF_), {D}, {Q}); for (auto c1 : list_np) setup_type(stringf("$_DFF_%c_", c1), {C, D}, {Q}); @@ -226,24 +256,24 @@ struct CellTypes cell_types.clear(); } - bool cell_known(RTLIL::IdString type) + bool cell_known(RTLIL::IdString type) const { return cell_types.count(type) != 0; } - bool cell_output(RTLIL::IdString type, RTLIL::IdString port) + bool cell_output(RTLIL::IdString type, RTLIL::IdString port) const { auto it = cell_types.find(type); return it != cell_types.end() && it->second.outputs.count(port) != 0; } - bool cell_input(RTLIL::IdString type, RTLIL::IdString port) + bool cell_input(RTLIL::IdString type, RTLIL::IdString port) const { auto it = cell_types.find(type); return it != cell_types.end() && it->second.inputs.count(port) != 0; } - bool cell_evaluable(RTLIL::IdString type) + bool cell_evaluable(RTLIL::IdString type) const { auto it = cell_types.find(type); return it != cell_types.end() && it->second.is_evaluable; @@ -252,20 +282,20 @@ struct CellTypes static RTLIL::Const eval_not(RTLIL::Const v) { for (auto &bit : v.bits) - if (bit == RTLIL::S0) bit = RTLIL::S1; - else if (bit == RTLIL::S1) bit = RTLIL::S0; + if (bit == State::S0) bit = State::S1; + else if (bit == State::S1) bit = State::S0; return v; } - static RTLIL::Const eval(RTLIL::IdString type, const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len) + static RTLIL::Const eval(RTLIL::IdString type, const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len, bool *errp = nullptr) { - if (type == "$sshr" && !signed1) - type = "$shr"; - if (type == "$sshl" && !signed1) - type = "$shl"; + if (type == ID($sshr) && !signed1) + type = ID($shr); + if (type == ID($sshl) && !signed1) + type = ID($shl); - if (type != "$sshr" && type != "$sshl" && type != "$shr" && type != "$shl" && type != "$shift" && type != "$shiftx" && - type != "$pos" && type != "$neg" && type != "$not") { + if (type != ID($sshr) && type != ID($sshl) && type != ID($shr) && type != ID($shl) && type != ID($shift) && type != ID($shiftx) && + type != ID($pos) && type != ID($neg) && type != ID($not)) { if (!signed1 || !signed2) signed1 = false, signed2 = false; } @@ -308,61 +338,66 @@ struct CellTypes HANDLE_CELL_TYPE(neg) #undef HANDLE_CELL_TYPE - if (type == "$_BUF_") + if (type == ID($_BUF_)) return arg1; - if (type == "$_NOT_") + if (type == ID($_NOT_)) return eval_not(arg1); - if (type == "$_AND_") + if (type == ID($_AND_)) return const_and(arg1, arg2, false, false, 1); - if (type == "$_NAND_") + if (type == ID($_NAND_)) return eval_not(const_and(arg1, arg2, false, false, 1)); - if (type == "$_OR_") + if (type == ID($_OR_)) return const_or(arg1, arg2, false, false, 1); - if (type == "$_NOR_") + if (type == ID($_NOR_)) return eval_not(const_or(arg1, arg2, false, false, 1)); - if (type == "$_XOR_") + if (type == ID($_XOR_)) return const_xor(arg1, arg2, false, false, 1); - if (type == "$_XNOR_") + if (type == ID($_XNOR_)) return const_xnor(arg1, arg2, false, false, 1); - if (type == "$_ANDNOT_") + if (type == ID($_ANDNOT_)) return const_and(arg1, eval_not(arg2), false, false, 1); - if (type == "$_ORNOT_") + if (type == ID($_ORNOT_)) return const_or(arg1, eval_not(arg2), false, false, 1); + if (errp != nullptr) { + *errp = true; + return State::Sm; + } + log_abort(); } - static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2) + static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool *errp = nullptr) { - if (cell->type == "$slice") { + if (cell->type == ID($slice)) { RTLIL::Const ret; - int width = cell->parameters.at("\\Y_WIDTH").as_int(); - int offset = cell->parameters.at("\\OFFSET").as_int(); + int width = cell->parameters.at(ID(Y_WIDTH)).as_int(); + int offset = cell->parameters.at(ID(OFFSET)).as_int(); ret.bits.insert(ret.bits.end(), arg1.bits.begin()+offset, arg1.bits.begin()+offset+width); return ret; } - if (cell->type == "$concat") { + if (cell->type == ID($concat)) { RTLIL::Const ret = arg1; ret.bits.insert(ret.bits.end(), arg2.bits.begin(), arg2.bits.end()); return ret; } - if (cell->type == "$lut") + if (cell->type == ID($lut)) { - int width = cell->parameters.at("\\WIDTH").as_int(); + int width = cell->parameters.at(ID(WIDTH)).as_int(); - std::vector<RTLIL::State> t = cell->parameters.at("\\LUT").bits; + std::vector<RTLIL::State> t = cell->parameters.at(ID(LUT)).bits; while (GetSize(t) < (1 << width)) - t.push_back(RTLIL::S0); + t.push_back(State::S0); t.resize(1 << width); for (int i = width-1; i >= 0; i--) { RTLIL::State sel = arg1.bits.at(i); std::vector<RTLIL::State> new_t; - if (sel == RTLIL::S0) + if (sel == State::S0) new_t = std::vector<RTLIL::State>(t.begin(), t.begin() + GetSize(t)/2); - else if (sel == RTLIL::S1) + else if (sel == State::S1) new_t = std::vector<RTLIL::State>(t.begin() + GetSize(t)/2, t.end()); else for (int j = 0; j < GetSize(t)/2; j++) @@ -374,14 +409,14 @@ struct CellTypes return t; } - if (cell->type == "$sop") + if (cell->type == ID($sop)) { - int width = cell->parameters.at("\\WIDTH").as_int(); - int depth = cell->parameters.at("\\DEPTH").as_int(); - std::vector<RTLIL::State> t = cell->parameters.at("\\TABLE").bits; + int width = cell->parameters.at(ID(WIDTH)).as_int(); + int depth = cell->parameters.at(ID(DEPTH)).as_int(); + std::vector<RTLIL::State> t = cell->parameters.at(ID(TABLE)).bits; while (GetSize(t) < width*depth*2) - t.push_back(RTLIL::S0); + t.push_back(State::S0); RTLIL::State default_ret = State::S0; @@ -412,15 +447,15 @@ struct CellTypes return default_ret; } - bool signed_a = cell->parameters.count("\\A_SIGNED") > 0 && cell->parameters["\\A_SIGNED"].as_bool(); - bool signed_b = cell->parameters.count("\\B_SIGNED") > 0 && cell->parameters["\\B_SIGNED"].as_bool(); - int result_len = cell->parameters.count("\\Y_WIDTH") > 0 ? cell->parameters["\\Y_WIDTH"].as_int() : -1; - return eval(cell->type, arg1, arg2, signed_a, signed_b, result_len); + bool signed_a = cell->parameters.count(ID(A_SIGNED)) > 0 && cell->parameters[ID(A_SIGNED)].as_bool(); + bool signed_b = cell->parameters.count(ID(B_SIGNED)) > 0 && cell->parameters[ID(B_SIGNED)].as_bool(); + int result_len = cell->parameters.count(ID(Y_WIDTH)) > 0 ? cell->parameters[ID(Y_WIDTH)].as_int() : -1; + return eval(cell->type, arg1, arg2, signed_a, signed_b, result_len, errp); } - static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3) + static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3, bool *errp = nullptr) { - if (cell->type.in("$mux", "$pmux", "$_MUX_")) { + if (cell->type.in(ID($mux), ID($pmux), ID($_MUX_))) { RTLIL::Const ret = arg1; for (size_t i = 0; i < arg3.bits.size(); i++) if (arg3.bits[i] == RTLIL::State::S1) { @@ -430,24 +465,24 @@ struct CellTypes return ret; } - if (cell->type == "$_AOI3_") + if (cell->type == ID($_AOI3_)) return eval_not(const_or(const_and(arg1, arg2, false, false, 1), arg3, false, false, 1)); - if (cell->type == "$_OAI3_") + if (cell->type == ID($_OAI3_)) return eval_not(const_and(const_or(arg1, arg2, false, false, 1), arg3, false, false, 1)); log_assert(arg3.bits.size() == 0); - return eval(cell, arg1, arg2); + return eval(cell, arg1, arg2, errp); } - static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3, const RTLIL::Const &arg4) + static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3, const RTLIL::Const &arg4, bool *errp = nullptr) { - if (cell->type == "$_AOI4_") + if (cell->type == ID($_AOI4_)) return eval_not(const_or(const_and(arg1, arg2, false, false, 1), const_and(arg3, arg4, false, false, 1), false, false, 1)); - if (cell->type == "$_OAI4_") - return eval_not(const_and(const_or(arg1, arg2, false, false, 1), const_and(arg3, arg4, false, false, 1), false, false, 1)); + if (cell->type == ID($_OAI4_)) + return eval_not(const_and(const_or(arg1, arg2, false, false, 1), const_or(arg3, arg4, false, false, 1), false, false, 1)); log_assert(arg4.bits.size() == 0); - return eval(cell, arg1, arg2, arg3); + return eval(cell, arg1, arg2, arg3, errp); } }; @@ -457,4 +492,3 @@ extern CellTypes yosys_celltypes; YOSYS_NAMESPACE_END #endif - diff --git a/kernel/consteval.h b/kernel/consteval.h index 0229f5045..7a83d28e7 100644 --- a/kernel/consteval.h +++ b/kernel/consteval.h @@ -89,12 +89,12 @@ struct ConstEval bool eval(RTLIL::Cell *cell, RTLIL::SigSpec &undef) { - if (cell->type == "$lcu") + if (cell->type == ID($lcu)) { - RTLIL::SigSpec sig_p = cell->getPort("\\P"); - RTLIL::SigSpec sig_g = cell->getPort("\\G"); - RTLIL::SigSpec sig_ci = cell->getPort("\\CI"); - RTLIL::SigSpec sig_co = values_map(assign_map(cell->getPort("\\CO"))); + RTLIL::SigSpec sig_p = cell->getPort(ID(P)); + RTLIL::SigSpec sig_g = cell->getPort(ID(G)); + RTLIL::SigSpec sig_ci = cell->getPort(ID(CI)); + RTLIL::SigSpec sig_co = values_map(assign_map(cell->getPort(ID(CO)))); if (sig_co.is_fully_const()) return true; @@ -114,8 +114,8 @@ struct ConstEval bool carry = sig_ci.as_bool(); for (int i = 0; i < GetSize(coval); i++) { - carry = (sig_g[i] == RTLIL::S1) || (sig_p[i] == RTLIL::S1 && carry); - coval.bits[i] = carry ? RTLIL::S1 : RTLIL::S0; + carry = (sig_g[i] == State::S1) || (sig_p[i] == RTLIL::S1 && carry); + coval.bits[i] = carry ? State::S1 : State::S0; } set(sig_co, coval); @@ -128,24 +128,24 @@ struct ConstEval RTLIL::SigSpec sig_a, sig_b, sig_s, sig_y; - log_assert(cell->hasPort("\\Y")); - sig_y = values_map(assign_map(cell->getPort("\\Y"))); + log_assert(cell->hasPort(ID::Y)); + sig_y = values_map(assign_map(cell->getPort(ID::Y))); if (sig_y.is_fully_const()) return true; - if (cell->hasPort("\\S")) { - sig_s = cell->getPort("\\S"); + if (cell->hasPort(ID(S))) { + sig_s = cell->getPort(ID(S)); if (!eval(sig_s, undef, cell)) return false; } - if (cell->hasPort("\\A")) - sig_a = cell->getPort("\\A"); + if (cell->hasPort(ID::A)) + sig_a = cell->getPort(ID::A); - if (cell->hasPort("\\B")) - sig_b = cell->getPort("\\B"); + if (cell->hasPort(ID::B)) + sig_b = cell->getPort(ID::B); - if (cell->type == "$mux" || cell->type == "$pmux" || cell->type == "$_MUX_") + if (cell->type.in(ID($mux), ID($pmux), ID($_MUX_), ID($_NMUX_))) { std::vector<RTLIL::SigSpec> y_candidates; int count_maybe_set_s_bits = 0; @@ -175,7 +175,10 @@ struct ConstEval for (auto &yc : y_candidates) { if (!eval(yc, undef, cell)) return false; - y_values.push_back(yc.as_const()); + if (cell->type == ID($_NMUX_)) + y_values.push_back(RTLIL::const_not(yc.as_const(), Const(), false, false, GetSize(yc))); + else + y_values.push_back(yc.as_const()); } if (y_values.size() > 1) @@ -195,10 +198,10 @@ struct ConstEval else set(sig_y, y_values.front()); } - else if (cell->type == "$fa") + else if (cell->type == ID($fa)) { - RTLIL::SigSpec sig_c = cell->getPort("\\C"); - RTLIL::SigSpec sig_x = cell->getPort("\\X"); + RTLIL::SigSpec sig_c = cell->getPort(ID(C)); + RTLIL::SigSpec sig_x = cell->getPort(ID(X)); int width = GetSize(sig_c); if (!eval(sig_a, undef, cell)) @@ -224,13 +227,13 @@ struct ConstEval set(sig_y, val_y); set(sig_x, val_x); } - else if (cell->type == "$alu") + else if (cell->type == ID($alu)) { - bool signed_a = cell->parameters.count("\\A_SIGNED") > 0 && cell->parameters["\\A_SIGNED"].as_bool(); - bool signed_b = cell->parameters.count("\\B_SIGNED") > 0 && cell->parameters["\\B_SIGNED"].as_bool(); + bool signed_a = cell->parameters.count(ID(A_SIGNED)) > 0 && cell->parameters[ID(A_SIGNED)].as_bool(); + bool signed_b = cell->parameters.count(ID(B_SIGNED)) > 0 && cell->parameters[ID(B_SIGNED)].as_bool(); - RTLIL::SigSpec sig_ci = cell->getPort("\\CI"); - RTLIL::SigSpec sig_bi = cell->getPort("\\BI"); + RTLIL::SigSpec sig_ci = cell->getPort(ID(CI)); + RTLIL::SigSpec sig_bi = cell->getPort(ID(BI)); if (!eval(sig_a, undef, cell)) return false; @@ -244,15 +247,15 @@ struct ConstEval if (!eval(sig_bi, undef, cell)) return false; - RTLIL::SigSpec sig_x = cell->getPort("\\X"); - RTLIL::SigSpec sig_co = cell->getPort("\\CO"); + RTLIL::SigSpec sig_x = cell->getPort(ID(X)); + RTLIL::SigSpec sig_co = cell->getPort(ID(CO)); bool any_input_undef = !(sig_a.is_fully_def() && sig_b.is_fully_def() && sig_ci.is_fully_def() && sig_bi.is_fully_def()); sig_a.extend_u0(GetSize(sig_y), signed_a); sig_b.extend_u0(GetSize(sig_y), signed_b); - bool carry = sig_ci[0] == RTLIL::S1; - bool b_inv = sig_bi[0] == RTLIL::S1; + bool carry = sig_ci[0] == State::S1; + bool b_inv = sig_bi[0] == State::S1; for (int i = 0; i < GetSize(sig_y); i++) { @@ -261,26 +264,26 @@ struct ConstEval if (!x_inputs.is_fully_def()) { set(sig_x[i], RTLIL::Sx); } else { - bool bit_a = sig_a[i] == RTLIL::S1; - bool bit_b = (sig_b[i] == RTLIL::S1) != b_inv; + bool bit_a = sig_a[i] == State::S1; + bool bit_b = (sig_b[i] == State::S1) != b_inv; bool bit_x = bit_a != bit_b; - set(sig_x[i], bit_x ? RTLIL::S1 : RTLIL::S0); + set(sig_x[i], bit_x ? State::S1 : State::S0); } if (any_input_undef) { set(sig_y[i], RTLIL::Sx); set(sig_co[i], RTLIL::Sx); } else { - bool bit_a = sig_a[i] == RTLIL::S1; - bool bit_b = (sig_b[i] == RTLIL::S1) != b_inv; + bool bit_a = sig_a[i] == State::S1; + bool bit_b = (sig_b[i] == State::S1) != b_inv; bool bit_y = (bit_a != bit_b) != carry; carry = (bit_a && bit_b) || (bit_a && carry) || (bit_b && carry); - set(sig_y[i], bit_y ? RTLIL::S1 : RTLIL::S0); - set(sig_co[i], carry ? RTLIL::S1 : RTLIL::S0); + set(sig_y[i], bit_y ? State::S1 : State::S0); + set(sig_co[i], carry ? State::S1 : State::S0); } } } - else if (cell->type == "$macc") + else if (cell->type == ID($macc)) { Macc macc; macc.from_cell(cell); @@ -295,21 +298,21 @@ struct ConstEval return false; } - RTLIL::Const result(0, GetSize(cell->getPort("\\Y"))); + RTLIL::Const result(0, GetSize(cell->getPort(ID::Y))); if (!macc.eval(result)) log_abort(); - set(cell->getPort("\\Y"), result); + set(cell->getPort(ID::Y), result); } else { RTLIL::SigSpec sig_c, sig_d; - if (cell->type.in("$_AOI3_", "$_OAI3_", "$_AOI4_", "$_OAI4_")) { - if (cell->hasPort("\\C")) - sig_c = cell->getPort("\\C"); - if (cell->hasPort("\\D")) - sig_d = cell->getPort("\\D"); + if (cell->type.in(ID($_AOI3_), ID($_OAI3_), ID($_AOI4_), ID($_OAI4_))) { + if (cell->hasPort(ID(C))) + sig_c = cell->getPort(ID(C)); + if (cell->hasPort(ID(D))) + sig_d = cell->getPort(ID(D)); } if (sig_a.size() > 0 && !eval(sig_a, undef, cell)) @@ -321,8 +324,13 @@ struct ConstEval if (sig_d.size() > 0 && !eval(sig_d, undef, cell)) return false; - set(sig_y, CellTypes::eval(cell, sig_a.as_const(), sig_b.as_const(), - sig_c.as_const(), sig_d.as_const())); + bool eval_err = false; + RTLIL::Const eval_ret = CellTypes::eval(cell, sig_a.as_const(), sig_b.as_const(), sig_c.as_const(), sig_d.as_const(), &eval_err); + + if (eval_err) + return false; + + set(sig_y, eval_ret); } return true; diff --git a/kernel/cost.h b/kernel/cost.h index e795b571b..ea2a4c1f0 100644 --- a/kernel/cost.h +++ b/kernel/cost.h @@ -24,62 +24,92 @@ YOSYS_NAMESPACE_BEGIN -int get_cell_cost(RTLIL::Cell *cell, dict<RTLIL::IdString, int> *mod_cost_cache = nullptr); - -int get_cell_cost(RTLIL::IdString type, const dict<RTLIL::IdString, RTLIL::Const> ¶meters = dict<RTLIL::IdString, RTLIL::Const>(), - RTLIL::Design *design = nullptr, dict<RTLIL::IdString, int> *mod_cost_cache = nullptr) +struct CellCosts { - static dict<RTLIL::IdString, int> gate_cost = { - { "$_BUF_", 1 }, - { "$_NOT_", 2 }, - { "$_AND_", 4 }, - { "$_NAND_", 4 }, - { "$_OR_", 4 }, - { "$_NOR_", 4 }, - { "$_ANDNOT_", 4 }, - { "$_ORNOT_", 4 }, - { "$_XOR_", 8 }, - { "$_XNOR_", 8 }, - { "$_AOI3_", 6 }, - { "$_OAI3_", 6 }, - { "$_AOI4_", 8 }, - { "$_OAI4_", 8 }, - { "$_MUX_", 4 } - }; - - if (gate_cost.count(type)) - return gate_cost.at(type); - - if (parameters.empty() && design && design->module(type)) + static const dict<RTLIL::IdString, int>& default_gate_cost() { + static const dict<RTLIL::IdString, int> db = { + { ID($_BUF_), 1 }, + { ID($_NOT_), 2 }, + { ID($_AND_), 4 }, + { ID($_NAND_), 4 }, + { ID($_OR_), 4 }, + { ID($_NOR_), 4 }, + { ID($_ANDNOT_), 4 }, + { ID($_ORNOT_), 4 }, + { ID($_XOR_), 5 }, + { ID($_XNOR_), 5 }, + { ID($_AOI3_), 6 }, + { ID($_OAI3_), 6 }, + { ID($_AOI4_), 7 }, + { ID($_OAI4_), 7 }, + { ID($_MUX_), 4 }, + { ID($_NMUX_), 4 } + }; + return db; + } + + static const dict<RTLIL::IdString, int>& cmos_gate_cost() { + static const dict<RTLIL::IdString, int> db = { + { ID($_BUF_), 1 }, + { ID($_NOT_), 2 }, + { ID($_AND_), 6 }, + { ID($_NAND_), 4 }, + { ID($_OR_), 6 }, + { ID($_NOR_), 4 }, + { ID($_ANDNOT_), 6 }, + { ID($_ORNOT_), 6 }, + { ID($_XOR_), 12 }, + { ID($_XNOR_), 12 }, + { ID($_AOI3_), 6 }, + { ID($_OAI3_), 6 }, + { ID($_AOI4_), 8 }, + { ID($_OAI4_), 8 }, + { ID($_MUX_), 12 }, + { ID($_NMUX_), 10 } + }; + return db; + } + + dict<RTLIL::IdString, int> mod_cost_cache; + const dict<RTLIL::IdString, int> *gate_cost = nullptr; + Design *design = nullptr; + + int get(RTLIL::IdString type) const { - RTLIL::Module *mod = design->module(type); + if (gate_cost && gate_cost->count(type)) + return gate_cost->at(type); - if (mod->attributes.count("\\cost")) - return mod->attributes.at("\\cost").as_int(); + log_warning("Can't determine cost of %s cell.\n", log_id(type)); + return 1; + } - dict<RTLIL::IdString, int> local_mod_cost_cache; - if (mod_cost_cache == nullptr) - mod_cost_cache = &local_mod_cost_cache; + int get(RTLIL::Cell *cell) + { + if (gate_cost && gate_cost->count(cell->type)) + return gate_cost->at(cell->type); - if (mod_cost_cache->count(mod->name)) - return mod_cost_cache->at(mod->name); + if (design && design->module(cell->type) && cell->parameters.empty()) + { + RTLIL::Module *mod = design->module(cell->type); - int module_cost = 1; - for (auto c : mod->cells()) - module_cost += get_cell_cost(c, mod_cost_cache); + if (mod->attributes.count(ID(cost))) + return mod->attributes.at(ID(cost)).as_int(); - (*mod_cost_cache)[mod->name] = module_cost; - return module_cost; - } + if (mod_cost_cache.count(mod->name)) + return mod_cost_cache.at(mod->name); - log_warning("Can't determine cost of %s cell (%d parameters).\n", log_id(type), GetSize(parameters)); - return 1; -} + int module_cost = 1; + for (auto c : mod->cells()) + module_cost += get(c); -int get_cell_cost(RTLIL::Cell *cell, dict<RTLIL::IdString, int> *mod_cost_cache) -{ - return get_cell_cost(cell->type, cell->parameters, cell->module->design, mod_cost_cache); -} + mod_cost_cache[mod->name] = module_cost; + return module_cost; + } + + log_warning("Can't determine cost of %s cell (%d parameters).\n", log_id(cell->type), GetSize(cell->parameters)); + return 1; + } +}; YOSYS_NAMESPACE_END diff --git a/kernel/driver.cc b/kernel/driver.cc index 178641101..70a97c4b9 100644 --- a/kernel/driver.cc +++ b/kernel/driver.cc @@ -110,6 +110,10 @@ int main(int argc, char **argv) log_error_stderr = true; yosys_banner(); yosys_setup(); +#ifdef WITH_PYTHON + PyRun_SimpleString(("sys.path.append(\""+proc_self_dirname()+"\")").c_str()); + PyRun_SimpleString(("sys.path.append(\""+proc_share_dirname()+"plugins\")").c_str()); +#endif if (argc == 2) { @@ -179,6 +183,7 @@ int main(int argc, char **argv) { std::string frontend_command = "auto"; std::string backend_command = "auto"; + std::vector<std::string> vlog_defines; std::vector<std::string> passes_commands; std::vector<std::string> plugin_filenames; std::string output_filename = ""; @@ -268,7 +273,10 @@ int main(int argc, char **argv) printf(" -A\n"); printf(" will call abort() at the end of the script. for debugging\n"); printf("\n"); - printf(" -D <header_id>[:<filename>]\n"); + printf(" -D <macro>[=<value>]\n"); + printf(" set the specified Verilog define (via \"read -define\")\n"); + printf("\n"); + printf(" -P <header_id>[:<filename>]\n"); printf(" dump the design when printing the specified log header to a file.\n"); printf(" yosys_dump_<header_id>.il is used as filename if none is specified.\n"); printf(" Use 'ALL' as <header_id> to dump at every header.\n"); @@ -287,6 +295,9 @@ int main(int argc, char **argv) printf(" -E <depsfile>\n"); printf(" write a Makefile dependencies file with in- and output file names\n"); printf("\n"); + printf(" -g\n"); + printf(" globally enable debug log messages\n"); + printf("\n"); printf(" -V\n"); printf(" print version information and exit\n"); printf("\n"); @@ -307,7 +318,7 @@ int main(int argc, char **argv) } int opt; - while ((opt = getopt(argc, argv, "MXAQTVSm:f:Hh:b:o:p:l:L:qv:tds:c:W:w:e:D:E:")) != -1) + while ((opt = getopt(argc, argv, "MXAQTVSgm:f:Hh:b:o:p:l:L:qv:tds:c:W:w:e:D:P:E:")) != -1) { switch (opt) { @@ -332,6 +343,9 @@ int main(int argc, char **argv) case 'S': passes_commands.push_back("synth"); break; + case 'g': + log_force_debug++; + break; case 'm': plugin_filenames.push_back(optarg); break; @@ -408,6 +422,9 @@ int main(int argc, char **argv) std::regex_constants::egrep)); break; case 'D': + vlog_defines.push_back(optarg); + break; + case 'P': { auto args = split_tokens(optarg, ":"); if (!args.empty() && args[0] == "ALL") { @@ -462,6 +479,10 @@ int main(int argc, char **argv) #endif yosys_setup(); +#ifdef WITH_PYTHON + PyRun_SimpleString(("sys.path.append(\""+proc_self_dirname()+"\")").c_str()); + PyRun_SimpleString(("sys.path.append(\""+proc_share_dirname()+"plugins\")").c_str()); +#endif log_error_atexit = yosys_atexit; for (auto &fn : plugin_filenames) @@ -473,6 +494,13 @@ int main(int argc, char **argv) shell(yosys_design); } + if (!vlog_defines.empty()) { + std::string vdef_cmd = "read -define"; + for (auto vdef : vlog_defines) + vdef_cmd += " " + vdef; + run_pass(vdef_cmd); + } + while (optind < argc) run_frontend(argv[optind++], frontend_command, output_filename == "-" ? &backend_command : NULL); @@ -494,6 +522,12 @@ int main(int argc, char **argv) if (!backend_command.empty()) run_backend(output_filename, backend_command); + yosys_design->check(); + for (auto it : saved_designs) + it.second->check(); + for (auto it : pushed_designs) + it->check(); + if (!depsfile.empty()) { FILE *f = fopen(depsfile.c_str(), "wt"); @@ -501,13 +535,13 @@ int main(int argc, char **argv) log_error("Can't open dependencies file for writing: %s\n", strerror(errno)); bool first = true; for (auto fn : yosys_output_files) { - fprintf(f, "%s%s", first ? "" : " ", fn.c_str()); + fprintf(f, "%s%s", first ? "" : " ", escape_filename_spaces(fn).c_str()); first = false; } fprintf(f, ":"); for (auto fn : yosys_input_files) { if (yosys_output_files.count(fn) == 0) - fprintf(f, " %s", fn.c_str()); + fprintf(f, " %s", escape_filename_spaces(fn).c_str()); } fprintf(f, "\n"); } diff --git a/kernel/hashlib.h b/kernel/hashlib.h index df534ec1b..e7cb312ed 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -557,9 +557,11 @@ public: void clear() { hashtable.clear(); entries.clear(); } iterator begin() { return iterator(this, int(entries.size())-1); } + iterator element(int n) { return iterator(this, int(entries.size())-1-n); } iterator end() { return iterator(nullptr, -1); } const_iterator begin() const { return const_iterator(this, int(entries.size())-1); } + const_iterator element(int n) const { return const_iterator(this, int(entries.size())-1-n); } const_iterator end() const { return const_iterator(nullptr, -1); } }; @@ -881,9 +883,11 @@ public: void clear() { hashtable.clear(); entries.clear(); } iterator begin() { return iterator(this, int(entries.size())-1); } + iterator element(int n) { return iterator(this, int(entries.size())-1-n); } iterator end() { return iterator(nullptr, -1); } const_iterator begin() const { return const_iterator(this, int(entries.size())-1); } + const_iterator element(int n) const { return const_iterator(this, int(entries.size())-1-n); } const_iterator end() const { return const_iterator(nullptr, -1); } }; @@ -952,6 +956,7 @@ public: void clear() { database.clear(); } const_iterator begin() const { return database.begin(); } + const_iterator element(int n) const { return database.element(n); } const_iterator end() const { return database.end(); } }; @@ -1051,6 +1056,7 @@ public: void clear() { database.clear(); parents.clear(); } const_iterator begin() const { return database.begin(); } + const_iterator element(int n) const { return database.element(n); } const_iterator end() const { return database.end(); } }; diff --git a/kernel/log.cc b/kernel/log.cc index 6d562b9e6..e0a60ca12 100644 --- a/kernel/log.cc +++ b/kernel/log.cc @@ -56,8 +56,12 @@ int log_verbose_level; string log_last_error; void (*log_error_atexit)() = NULL; +int log_make_debug = 0; +int log_force_debug = 0; +int log_debug_suppressed = 0; + vector<int> header_count; -pool<RTLIL::IdString> log_id_cache; +vector<char*> log_id_cache; vector<shared_str> string_buf; int string_buf_index = -1; @@ -65,6 +69,13 @@ static struct timeval initial_tv = { 0, 0 }; static bool next_print_log = false; static int log_newline_count = 0; +static void log_id_cache_clear() +{ + for (auto p : log_id_cache) + free(p); + log_id_cache.clear(); +} + #if defined(_WIN32) && !defined(__MINGW32__) // this will get time information and return it in timeval, simulating gettimeofday() int gettimeofday(struct timeval *tv, struct timezone *tz) @@ -92,6 +103,9 @@ void logv(const char *format, va_list ap) format++; } + if (log_make_debug && !ys_debug(1)) + return; + std::string str = vstringf(format, ap); if (str.empty()) @@ -196,14 +210,19 @@ void logv_header(RTLIL::Design *design, const char *format, va_list ap) if (log_hdump.count(header_id) && design != nullptr) for (auto &filename : log_hdump.at(header_id)) { log("Dumping current design to '%s'.\n", filename.c_str()); + if (yosys_xtrace) + IdString::xtrace_db_dump(); Pass::call(design, {"dump", "-o", filename}); + if (yosys_xtrace) + log("#X# -- end of dump --\n"); } if (pop_errfile) log_files.pop_back(); } -void logv_warning(const char *format, va_list ap) +static void logv_warning_with_prefix(const char *prefix, + const char *format, va_list ap) { std::string message = vstringf(format, ap); bool suppressed = false; @@ -214,17 +233,20 @@ void logv_warning(const char *format, va_list ap) if (suppressed) { - log("Suppressed warning: %s", message.c_str()); + log("Suppressed %s%s", prefix, message.c_str()); } 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()); if (log_warnings.count(message)) { - log("Warning: %s", message.c_str()); + log("%s%s", prefix, message.c_str()); log_flush(); } else @@ -232,7 +254,7 @@ void logv_warning(const char *format, va_list ap) if (log_errfile != NULL && !log_quiet_warnings) log_files.push_back(log_errfile); - log("Warning: %s", message.c_str()); + log("%s%s", prefix, message.c_str()); log_flush(); if (log_errfile != NULL && !log_quiet_warnings) @@ -242,56 +264,52 @@ void logv_warning(const char *format, va_list ap) } log_warnings_count++; + log_make_debug = bak_log_make_debug; } } -void logv_warning_noprefix(const char *format, va_list ap) +void logv_warning(const char *format, va_list ap) { - std::string message = vstringf(format, ap); - bool suppressed = false; - - for (auto &re : log_nowarn_regexes) - if (std::regex_search(message, re)) - suppressed = true; - - if (suppressed) - { - log("%s", message.c_str()); - } - else - { - for (auto &re : log_werror_regexes) - if (std::regex_search(message, re)) - log_error("%s", message.c_str()); - - if (log_warnings.count(message)) - { - log("%s", message.c_str()); - log_flush(); - } - else - { - if (log_errfile != NULL && !log_quiet_warnings) - log_files.push_back(log_errfile); - - log("%s", message.c_str()); - log_flush(); + logv_warning_with_prefix("Warning: ", format, ap); +} - if (log_errfile != NULL && !log_quiet_warnings) - log_files.pop_back(); +void logv_warning_noprefix(const char *format, va_list ap) +{ + logv_warning_with_prefix("", format, ap); +} - log_warnings.insert(message); - } +void log_file_warning(const std::string &filename, int lineno, + const char *format, ...) +{ + va_list ap; + va_start(ap, format); + std::string prefix = stringf("%s:%d: Warning: ", + filename.c_str(), lineno); + logv_warning_with_prefix(prefix.c_str(), format, ap); + va_end(ap); +} - log_warnings_count++; - } +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); } -void logv_error(const char *format, va_list ap) +YS_ATTRIBUTE(noreturn) +static void logv_error_with_prefix(const char *prefix, + const char *format, va_list ap) { #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); @@ -302,9 +320,11 @@ void logv_error(const char *format, va_list ap) f = stderr; log_last_error = vstringf(format, ap); - log("ERROR: %s", log_last_error.c_str()); + 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(); @@ -318,6 +338,21 @@ void logv_error(const char *format, va_list ap) #endif } +void logv_error(const char *format, va_list ap) +{ + logv_error_with_prefix("ERROR: ", format, ap); +} + +void log_file_error(const string &filename, int lineno, + const char *format, ...) +{ + va_list ap; + va_start(ap, format); + std::string prefix = stringf("%s:%d: ERROR: ", + filename.c_str(), lineno); + logv_error_with_prefix(prefix.c_str(), format, ap); +} + void log(const char *format, ...) { va_list ap; @@ -386,7 +421,7 @@ void log_push() void log_pop() { header_count.pop_back(); - log_id_cache.clear(); + log_id_cache_clear(); string_buf.clear(); string_buf_index = -1; log_flush(); @@ -493,7 +528,7 @@ void log_reset_stack() { while (header_count.size() > 1) header_count.pop_back(); - log_id_cache.clear(); + log_id_cache_clear(); string_buf.clear(); string_buf_index = -1; log_flush(); @@ -552,8 +587,8 @@ const char *log_const(const RTLIL::Const &value, bool autoint) const char *log_id(RTLIL::IdString str) { - log_id_cache.insert(str); - const char *p = str.c_str(); + log_id_cache.push_back(strdup(str.c_str())); + const char *p = log_id_cache.back(); if (p[0] != '\\') return p; if (p[1] == '$' || p[1] == '\\' || p[1] == 0) @@ -636,4 +671,3 @@ dict<std::string, std::pair<std::string, int>> get_coverage_data() #endif YOSYS_NAMESPACE_END - diff --git a/kernel/log.h b/kernel/log.h index a2aacfd4d..5f53f533a 100644 --- a/kernel/log.h +++ b/kernel/log.h @@ -64,6 +64,10 @@ extern int log_verbose_level; extern string log_last_error; extern void (*log_error_atexit)(); +extern int log_make_debug; +extern int log_force_debug; +extern int log_debug_suppressed; + void logv(const char *format, va_list ap); void logv_header(RTLIL::Design *design, const char *format, va_list ap); void logv_warning(const char *format, va_list ap); @@ -73,10 +77,55 @@ YS_NORETURN void logv_error(const char *format, va_list ap) YS_ATTRIBUTE(noretur void log(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2)); void log_header(RTLIL::Design *design, const char *format, ...) YS_ATTRIBUTE(format(printf, 2, 3)); 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); +void log_file_error(const string &filename, int lineno, const char *format, ...) YS_ATTRIBUTE(format(printf, 3, 4), noreturn); YS_NORETURN void log_cmd_error(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2), noreturn); +#ifndef NDEBUG +static inline bool ys_debug(int n = 0) { if (log_force_debug) return true; log_debug_suppressed += n; return false; } +# define log_debug(...) do { if (ys_debug(1)) log(__VA_ARGS__); } while (0) +#else +static inline bool ys_debug(int = 0) { return false; } +# define log_debug(_fmt, ...) do { } while (0) +#endif + +static inline void log_suppressed() { + if (log_debug_suppressed && !log_make_debug) { + log("<suppressed ~%d debug messages>\n", log_debug_suppressed); + log_debug_suppressed = 0; + } +} + +struct LogMakeDebugHdl { + bool status = false; + LogMakeDebugHdl(bool start_on = false) { + if (start_on) + on(); + } + ~LogMakeDebugHdl() { + off(); + } + void on() { + if (status) return; + status=true; + log_make_debug++; + } + void off_silent() { + if (!status) return; + status=false; + log_make_debug--; + } + void off() { + off_silent(); + } +}; + void log_spacer(); void log_push(); void log_pop(); @@ -89,7 +138,9 @@ const char *log_signal(const RTLIL::SigSpec &sig, bool autoint = true); const char *log_const(const RTLIL::Const &value, bool autoint = true); const char *log_id(RTLIL::IdString id); -template<typename T> static inline const char *log_id(T *obj) { +template<typename T> static inline const char *log_id(T *obj, const char *nullstr = nullptr) { + if (nullstr && obj == nullptr) + return nullstr; return log_id(obj->name); } @@ -190,7 +241,7 @@ struct PerformanceTimer t += 1000000000ULL * (int64_t) rusage.ru_stime.tv_sec + (int64_t) rusage.ru_stime.tv_usec * 1000ULL; return t; # else -# error Dont know how to measure per-process CPU time. Need alternative method (times()/clocks()/gettimeofday()?). +# error "Don't know how to measure per-process CPU time. Need alternative method (times()/clocks()/gettimeofday()?)." # endif } diff --git a/kernel/macc.h b/kernel/macc.h index 286ce567f..371f6737d 100644 --- a/kernel/macc.h +++ b/kernel/macc.h @@ -70,9 +70,9 @@ struct Macc while (GetSize(port.in_b) > 1 && port.in_b[GetSize(port.in_b)-1] == port.in_b[GetSize(port.in_b)-2]) port.in_b.remove(GetSize(port.in_b)-1); } else { - while (GetSize(port.in_a) > 1 && port.in_a[GetSize(port.in_a)-1] == RTLIL::S0) + while (GetSize(port.in_a) > 1 && port.in_a[GetSize(port.in_a)-1] == State::S0) port.in_a.remove(GetSize(port.in_a)-1); - while (GetSize(port.in_b) > 1 && port.in_b[GetSize(port.in_b)-1] == RTLIL::S0) + while (GetSize(port.in_b) > 1 && port.in_b[GetSize(port.in_b)-1] == State::S0) port.in_b.remove(GetSize(port.in_b)-1); } @@ -80,9 +80,9 @@ struct Macc } for (auto &bit : bit_ports) - if (bit == RTLIL::S1) + if (bit == State::S1) off = const_add(off, RTLIL::Const(1, width), false, false, width); - else if (bit != RTLIL::S0) + else if (bit != State::S0) new_bit_ports.append(bit); if (off.as_bool()) { @@ -99,24 +99,24 @@ struct Macc void from_cell(RTLIL::Cell *cell) { - RTLIL::SigSpec port_a = cell->getPort("\\A"); + RTLIL::SigSpec port_a = cell->getPort(ID::A); ports.clear(); - bit_ports = cell->getPort("\\B"); + bit_ports = cell->getPort(ID::B); - std::vector<RTLIL::State> config_bits = cell->getParam("\\CONFIG").bits; + std::vector<RTLIL::State> config_bits = cell->getParam(ID(CONFIG)).bits; int config_cursor = 0; #ifndef NDEBUG - int config_width = cell->getParam("\\CONFIG_WIDTH").as_int(); + int config_width = cell->getParam(ID(CONFIG_WIDTH)).as_int(); log_assert(GetSize(config_bits) >= config_width); #endif int num_bits = 0; - if (config_bits[config_cursor++] == RTLIL::S1) num_bits |= 1; - if (config_bits[config_cursor++] == RTLIL::S1) num_bits |= 2; - if (config_bits[config_cursor++] == RTLIL::S1) num_bits |= 4; - if (config_bits[config_cursor++] == RTLIL::S1) num_bits |= 8; + if (config_bits[config_cursor++] == State::S1) num_bits |= 1; + if (config_bits[config_cursor++] == State::S1) num_bits |= 2; + if (config_bits[config_cursor++] == State::S1) num_bits |= 4; + if (config_bits[config_cursor++] == State::S1) num_bits |= 8; int port_a_cursor = 0; while (port_a_cursor < GetSize(port_a)) @@ -124,12 +124,12 @@ struct Macc log_assert(config_cursor + 2 + 2*num_bits <= config_width); port_t this_port; - this_port.is_signed = config_bits[config_cursor++] == RTLIL::S1; - this_port.do_subtract = config_bits[config_cursor++] == RTLIL::S1; + this_port.is_signed = config_bits[config_cursor++] == State::S1; + this_port.do_subtract = config_bits[config_cursor++] == State::S1; int size_a = 0; for (int i = 0; i < num_bits; i++) - if (config_bits[config_cursor++] == RTLIL::S1) + if (config_bits[config_cursor++] == State::S1) size_a |= 1 << i; this_port.in_a = port_a.extract(port_a_cursor, size_a); @@ -137,7 +137,7 @@ struct Macc int size_b = 0; for (int i = 0; i < num_bits; i++) - if (config_bits[config_cursor++] == RTLIL::S1) + if (config_bits[config_cursor++] == State::S1) size_b |= 1 << i; this_port.in_b = port_a.extract(port_a_cursor, size_b); @@ -166,43 +166,43 @@ struct Macc num_bits++, max_size /= 2; log_assert(num_bits < 16); - config_bits.push_back(num_bits & 1 ? RTLIL::S1 : RTLIL::S0); - config_bits.push_back(num_bits & 2 ? RTLIL::S1 : RTLIL::S0); - config_bits.push_back(num_bits & 4 ? RTLIL::S1 : RTLIL::S0); - config_bits.push_back(num_bits & 8 ? RTLIL::S1 : RTLIL::S0); + config_bits.push_back(num_bits & 1 ? State::S1 : State::S0); + config_bits.push_back(num_bits & 2 ? State::S1 : State::S0); + config_bits.push_back(num_bits & 4 ? State::S1 : State::S0); + config_bits.push_back(num_bits & 8 ? State::S1 : State::S0); for (auto &port : ports) { if (GetSize(port.in_a) == 0) continue; - config_bits.push_back(port.is_signed ? RTLIL::S1 : RTLIL::S0); - config_bits.push_back(port.do_subtract ? RTLIL::S1 : RTLIL::S0); + config_bits.push_back(port.is_signed ? State::S1 : State::S0); + config_bits.push_back(port.do_subtract ? State::S1 : State::S0); int size_a = GetSize(port.in_a); for (int i = 0; i < num_bits; i++) - config_bits.push_back(size_a & (1 << i) ? RTLIL::S1 : RTLIL::S0); + config_bits.push_back(size_a & (1 << i) ? State::S1 : State::S0); int size_b = GetSize(port.in_b); for (int i = 0; i < num_bits; i++) - config_bits.push_back(size_b & (1 << i) ? RTLIL::S1 : RTLIL::S0); + config_bits.push_back(size_b & (1 << i) ? State::S1 : State::S0); port_a.append(port.in_a); port_a.append(port.in_b); } - cell->setPort("\\A", port_a); - cell->setPort("\\B", bit_ports); - cell->setParam("\\CONFIG", config_bits); - cell->setParam("\\CONFIG_WIDTH", GetSize(config_bits)); - cell->setParam("\\A_WIDTH", GetSize(port_a)); - cell->setParam("\\B_WIDTH", GetSize(bit_ports)); + cell->setPort(ID::A, port_a); + cell->setPort(ID::B, bit_ports); + cell->setParam(ID(CONFIG), config_bits); + cell->setParam(ID(CONFIG_WIDTH), GetSize(config_bits)); + cell->setParam(ID(A_WIDTH), GetSize(port_a)); + cell->setParam(ID(B_WIDTH), GetSize(bit_ports)); } bool eval(RTLIL::Const &result) const { for (auto &bit : result.bits) - bit = RTLIL::S0; + bit = State::S0; for (auto &port : ports) { diff --git a/kernel/modtools.h b/kernel/modtools.h index ffcb48d44..409562eb9 100644 --- a/kernel/modtools.h +++ b/kernel/modtools.h @@ -1,4 +1,4 @@ -/* +/* -*- c++ -*- * yosys -- Yosys Open SYnthesis Suite * * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> @@ -158,7 +158,7 @@ struct ModIndex : public RTLIL::Monitor #endif } - virtual void notify_connect(RTLIL::Cell *cell, const RTLIL::IdString &port, const RTLIL::SigSpec &old_sig, RTLIL::SigSpec &sig) YS_OVERRIDE + void notify_connect(RTLIL::Cell *cell, const RTLIL::IdString &port, const RTLIL::SigSpec &old_sig, RTLIL::SigSpec &sig) YS_OVERRIDE { log_assert(module == cell->module); @@ -169,7 +169,7 @@ struct ModIndex : public RTLIL::Monitor port_add(cell, port, sig); } - virtual void notify_connect(RTLIL::Module *mod YS_ATTRIBUTE(unused), const RTLIL::SigSig &sigsig) YS_OVERRIDE + void notify_connect(RTLIL::Module *mod YS_ATTRIBUTE(unused), const RTLIL::SigSig &sigsig) YS_OVERRIDE { log_assert(module == mod); @@ -214,13 +214,13 @@ struct ModIndex : public RTLIL::Monitor } } - virtual void notify_connect(RTLIL::Module *mod YS_ATTRIBUTE(unused), const std::vector<RTLIL::SigSig>&) YS_OVERRIDE + void notify_connect(RTLIL::Module *mod YS_ATTRIBUTE(unused), const std::vector<RTLIL::SigSig>&) YS_OVERRIDE { log_assert(module == mod); auto_reload_module = true; } - virtual void notify_blackout(RTLIL::Module *mod YS_ATTRIBUTE(unused)) YS_OVERRIDE + void notify_blackout(RTLIL::Module *mod YS_ATTRIBUTE(unused)) YS_OVERRIDE { log_assert(module == mod); auto_reload_module = true; diff --git a/kernel/register.cc b/kernel/register.cc index e30414f44..8131fa279 100644 --- a/kernel/register.cc +++ b/kernel/register.cc @@ -25,6 +25,65 @@ #include <stdio.h> #include <errno.h> +#ifdef YOSYS_ENABLE_ZLIB +#include <zlib.h> + +PRIVATE_NAMESPACE_BEGIN +#define GZ_BUFFER_SIZE 8192 +void decompress_gzip(const std::string &filename, std::stringstream &out) +{ + char buffer[GZ_BUFFER_SIZE]; + int bytes_read; + gzFile gzf = gzopen(filename.c_str(), "rb"); + while(!gzeof(gzf)) { + bytes_read = gzread(gzf, reinterpret_cast<void *>(buffer), GZ_BUFFER_SIZE); + out.write(buffer, bytes_read); + } + gzclose(gzf); +} + +/* +An output stream that uses a stringbuf to buffer data internally, +using zlib to write gzip-compressed data every time the stream is flushed. +*/ +class gzip_ostream : public std::ostream { +public: + gzip_ostream() : std::ostream(nullptr) + { + rdbuf(&outbuf); + } + bool open(const std::string &filename) + { + return outbuf.open(filename); + } +private: + class gzip_streambuf : public std::stringbuf { + public: + gzip_streambuf() { }; + bool open(const std::string &filename) + { + gzf = gzopen(filename.c_str(), "wb"); + return gzf != nullptr; + } + virtual int sync() override + { + gzwrite(gzf, reinterpret_cast<const void *>(str().c_str()), unsigned(str().size())); + str(""); + return 0; + } + virtual ~gzip_streambuf() + { + sync(); + gzclose(gzf); + } + private: + gzFile gzf = nullptr; + } outbuf; +}; +PRIVATE_NAMESPACE_END + +#endif + YOSYS_NAMESPACE_BEGIN #define MAX_REG_COUNT 1000 @@ -86,6 +145,9 @@ Pass::pre_post_exec_state_t Pass::pre_execute() void Pass::post_execute(Pass::pre_post_exec_state_t state) { + IdString::checkpoint(); + log_suppressed(); + int64_t time_ns = PerformanceTimer::query() - state.begin_ns; runtime_ns += time_ns; current_pass = state.parent_pass; @@ -138,7 +200,7 @@ void Pass::extra_args(std::vector<std::string> args, size_t argidx, RTLIL::Desig { std::string arg = args[argidx]; - if (arg.substr(0, 1) == "-") + if (arg.compare(0, 1, "-") == 0) cmd_error(args, argidx, "Unknown option or option in arguments."); if (!select) @@ -233,8 +295,6 @@ void Pass::call(RTLIL::Design *design, std::vector<std::string> args) pass_register[args[0]]->post_execute(state); while (design->selection_stack.size() > orig_sel_stack_pos) design->selection_stack.pop_back(); - - design->check(); } void Pass::call_on_selection(RTLIL::Design *design, const RTLIL::Selection &selection, std::string command) @@ -316,8 +376,10 @@ void ScriptPass::run(std::string command, std::string info) log(" %s\n", command.c_str()); else log(" %s %s\n", command.c_str(), info.c_str()); - } else + } else { Pass::call(active_design, command); + active_design->check(); + } } void ScriptPass::run_script(RTLIL::Design *design, std::string run_from, std::string run_to) @@ -387,7 +449,7 @@ void Frontend::extra_args(std::istream *&f, std::string &filename, std::vector<s { std::string arg = args[argidx]; - if (arg.substr(0, 1) == "-") + if (arg.compare(0, 1, "-") == 0) cmd_error(args, argidx, "Unknown option or option in arguments."); if (f != NULL) cmd_error(args, argidx, "Extra filename argument in direct file mode."); @@ -395,7 +457,7 @@ void Frontend::extra_args(std::istream *&f, std::string &filename, std::vector<s filename = arg; if (filename == "<<" && argidx+1 < args.size()) filename += args[++argidx]; - if (filename.substr(0, 2) == "<<") { + if (filename.compare(0, 2, "<<") == 0) { if (Frontend::current_script_file == NULL) log_error("Unexpected here document '%s' outside of script!\n", filename.c_str()); if (filename.size() <= 2) @@ -413,7 +475,7 @@ void Frontend::extra_args(std::istream *&f, std::string &filename, std::vector<s break; } size_t indent = buffer.find_first_not_of(" \t\r\n"); - if (indent != std::string::npos && buffer.substr(indent, eot_marker.size()) == eot_marker) + if (indent != std::string::npos && buffer.compare(indent, eot_marker.size(), eot_marker) == 0) break; last_here_document += buffer; } @@ -433,12 +495,42 @@ void Frontend::extra_args(std::istream *&f, std::string &filename, std::vector<s delete ff; else f = ff; + if (f != NULL) { + // Check for gzip magic + unsigned char magic[3]; + int n = 0; + while (n < 3) + { + int c = ff->get(); + if (c != EOF) { + magic[n] = (unsigned char) c; + } + n++; + } + if (n == 3 && magic[0] == 0x1f && magic[1] == 0x8b) { + #ifdef YOSYS_ENABLE_ZLIB + log("Found gzip magic in file `%s', decompressing using zlib.\n", filename.c_str()); + if (magic[2] != 8) + log_cmd_error("gzip file `%s' uses unsupported compression type %02x\n", + filename.c_str(), unsigned(magic[2])); + delete ff; + std::stringstream *df = new std::stringstream(); + decompress_gzip(filename, *df); + f = df; + #else + log_cmd_error("File `%s' is a gzip file, but Yosys is compiled without zlib.\n", filename.c_str()); + #endif + } else { + ff->clear(); + ff->seekg(0, std::ios::beg); + } + } } if (f == NULL) log_cmd_error("Can't open input file `%s' for reading: %s\n", filename.c_str(), strerror(errno)); for (size_t i = argidx+1; i < args.size(); i++) - if (args[i].substr(0, 1) == "-") + if (args[i].compare(0, 1, "-") == 0) cmd_error(args, i, "Found option, expected arguments."); if (argidx+1 < args.size()) { @@ -489,8 +581,6 @@ void Frontend::frontend_call(RTLIL::Design *design, std::istream *f, std::string args.push_back(filename); frontend_register[args[0]]->execute(args, design); } - - design->check(); } Backend::Backend(std::string name, std::string short_help) : @@ -530,7 +620,7 @@ void Backend::extra_args(std::ostream *&f, std::string &filename, std::vector<st { std::string arg = args[argidx]; - if (arg.substr(0, 1) == "-" && arg != "-") + if (arg.compare(0, 1, "-") == 0 && arg != "-") cmd_error(args, argidx, "Unknown option or option in arguments."); if (f != NULL) cmd_error(args, argidx, "Extra filename argument in direct file mode."); @@ -542,14 +632,29 @@ void Backend::extra_args(std::ostream *&f, std::string &filename, std::vector<st } filename = arg; - std::ofstream *ff = new std::ofstream; - ff->open(filename.c_str(), std::ofstream::trunc); - yosys_output_files.insert(filename); - if (ff->fail()) { - delete ff; - log_cmd_error("Can't open output file `%s' for writing: %s\n", filename.c_str(), strerror(errno)); + rewrite_filename(filename); + if (filename.size() > 3 && filename.compare(filename.size()-3, std::string::npos, ".gz") == 0) { +#ifdef YOSYS_ENABLE_ZLIB + gzip_ostream *gf = new gzip_ostream; + if (!gf->open(filename)) { + delete gf; + log_cmd_error("Can't open output file `%s' for writing: %s\n", filename.c_str(), strerror(errno)); + } + yosys_output_files.insert(filename); + f = gf; +#else + log_cmd_error("Yosys is compiled without zlib support, unable to write gzip output.\n"); +#endif + } else { + std::ofstream *ff = new std::ofstream; + ff->open(filename.c_str(), std::ofstream::trunc); + yosys_output_files.insert(filename); + if (ff->fail()) { + delete ff; + log_cmd_error("Can't open output file `%s' for writing: %s\n", filename.c_str(), strerror(errno)); + } + f = ff; } - f = ff; } if (called_with_fp) @@ -599,8 +704,6 @@ void Backend::backend_call(RTLIL::Design *design, std::ostream *f, std::string f while (design->selection_stack.size() > orig_sel_stack_pos) design->selection_stack.pop_back(); - - design->check(); } static struct CellHelpMessages { @@ -615,7 +718,7 @@ static struct CellHelpMessages { struct HelpPass : public Pass { HelpPass() : Pass("help", "display help messages") { } - virtual void help() + void help() YS_OVERRIDE { log("\n"); log(" help ................ list all commands\n"); @@ -684,7 +787,7 @@ struct HelpPass : public Pass { fclose(f); } - virtual void execute(std::vector<std::string> args, RTLIL::Design*) + void execute(std::vector<std::string> args, RTLIL::Design*) YS_OVERRIDE { if (args.size() == 1) { log("\n"); @@ -768,7 +871,7 @@ struct HelpPass : public Pass { struct EchoPass : public Pass { EchoPass() : Pass("echo", "turning echoing back of commands on and off") { } - virtual void help() + void help() YS_OVERRIDE { log("\n"); log(" echo on\n"); @@ -781,7 +884,7 @@ struct EchoPass : public Pass { log("Do not print all commands to log before executing them. (default)\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design*) + void execute(std::vector<std::string> args, RTLIL::Design*) YS_OVERRIDE { if (args.size() > 2) cmd_error(args, 2, "Unexpected argument."); @@ -806,10 +909,9 @@ struct MinisatSatSolver : public SatSolver { MinisatSatSolver() : SatSolver("minisat") { yosys_satsolver = this; } - virtual ezSAT *create() YS_OVERRIDE { + ezSAT *create() YS_OVERRIDE { return new ezMiniSAT(); } } MinisatSatSolver; YOSYS_NAMESPACE_END - diff --git a/kernel/register.h b/kernel/register.h index 8024c56a0..c74029823 100644 --- a/kernel/register.h +++ b/kernel/register.h @@ -1,4 +1,4 @@ -/* +/* -*- c++ -*- * yosys -- Yosys Open SYnthesis Suite * * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> @@ -88,9 +88,9 @@ struct Frontend : Pass std::string frontend_name; Frontend(std::string name, std::string short_help = "** document me **"); - virtual void run_register() YS_OVERRIDE; - virtual ~Frontend(); - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE YS_FINAL; + void run_register() YS_OVERRIDE; + ~Frontend() YS_OVERRIDE; + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE YS_FINAL; virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) = 0; static std::vector<std::string> next_args; @@ -104,9 +104,9 @@ struct Backend : Pass { std::string backend_name; Backend(std::string name, std::string short_help = "** document me **"); - virtual void run_register() YS_OVERRIDE; - virtual ~Backend(); - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE YS_FINAL; + void run_register() YS_OVERRIDE; + ~Backend() YS_OVERRIDE; + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE YS_FINAL; virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) = 0; void extra_args(std::ostream *&f, std::string &filename, std::vector<std::string> args, size_t argidx); diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index a4fa2cf04..1d380135b 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -29,10 +29,23 @@ YOSYS_NAMESPACE_BEGIN RTLIL::IdString::destruct_guard_t RTLIL::IdString::destruct_guard; -std::vector<int> RTLIL::IdString::global_refcount_storage_; std::vector<char*> RTLIL::IdString::global_id_storage_; dict<char*, int, hash_cstr_ops> RTLIL::IdString::global_id_index_; +#ifndef YOSYS_NO_IDS_REFCNT +std::vector<int> RTLIL::IdString::global_refcount_storage_; std::vector<int> RTLIL::IdString::global_free_idx_list_; +#endif +#ifdef YOSYS_USE_STICKY_IDS +int RTLIL::IdString::last_created_idx_[8]; +int RTLIL::IdString::last_created_idx_ptr_; +#endif + +IdString RTLIL::ID::A; +IdString RTLIL::ID::B; +IdString RTLIL::ID::Y; +IdString RTLIL::ID::keep; +IdString RTLIL::ID::whitebox; +IdString RTLIL::ID::blackbox; RTLIL::Const::Const() { @@ -45,7 +58,7 @@ RTLIL::Const::Const(std::string str) for (int i = str.size()-1; i >= 0; i--) { unsigned char ch = str[i]; for (int j = 0; j < 8; j++) { - bits.push_back((ch & 1) != 0 ? RTLIL::S1 : RTLIL::S0); + bits.push_back((ch & 1) != 0 ? State::S1 : State::S0); ch = ch >> 1; } } @@ -55,7 +68,7 @@ RTLIL::Const::Const(int val, int width) { flags = RTLIL::CONST_FLAG_NONE; for (int i = 0; i < width; i++) { - bits.push_back((val & 1) != 0 ? RTLIL::S1 : RTLIL::S0); + bits.push_back((val & 1) != 0 ? State::S1 : State::S0); val = val >> 1; } } @@ -71,7 +84,14 @@ RTLIL::Const::Const(const std::vector<bool> &bits) { flags = RTLIL::CONST_FLAG_NONE; for (auto b : bits) - this->bits.push_back(b ? RTLIL::S1 : RTLIL::S0); + this->bits.push_back(b ? State::S1 : State::S0); +} + +RTLIL::Const::Const(const RTLIL::Const &c) +{ + flags = c.flags; + for (auto b : c.bits) + this->bits.push_back(b); } bool RTLIL::Const::operator <(const RTLIL::Const &other) const @@ -97,7 +117,7 @@ bool RTLIL::Const::operator !=(const RTLIL::Const &other) const bool RTLIL::Const::as_bool() const { for (size_t i = 0; i < bits.size(); i++) - if (bits[i] == RTLIL::S1) + if (bits[i] == State::S1) return true; return false; } @@ -106,9 +126,9 @@ int RTLIL::Const::as_int(bool is_signed) const { int32_t ret = 0; for (size_t i = 0; i < bits.size() && i < 32; i++) - if (bits[i] == RTLIL::S1) + if (bits[i] == State::S1) ret |= 1 << i; - if (is_signed && bits.back() == RTLIL::S1) + if (is_signed && bits.back() == State::S1) for (size_t i = bits.size(); i < 32; i++) ret |= 1 << i; return ret; @@ -205,16 +225,23 @@ bool RTLIL::Const::is_fully_undef() const return true; } -void RTLIL::AttrObject::set_bool_attribute(RTLIL::IdString id) +void RTLIL::AttrObject::set_bool_attribute(RTLIL::IdString id, bool value) { - attributes[id] = RTLIL::Const(1); + if (value) + attributes[id] = RTLIL::Const(1); + else { + const auto it = attributes.find(id); + if (it != attributes.end()) + attributes.erase(it); + } } bool RTLIL::AttrObject::get_bool_attribute(RTLIL::IdString id) const { - if (attributes.count(id) == 0) + const auto it = attributes.find(id); + if (it == attributes.end()) return false; - return attributes.at(id).as_bool(); + return it->second.as_bool(); } void RTLIL::AttrObject::set_strpool_attribute(RTLIL::IdString id, const pool<string> &data) @@ -248,16 +275,16 @@ pool<string> RTLIL::AttrObject::get_strpool_attribute(RTLIL::IdString id) const void RTLIL::AttrObject::set_src_attribute(const std::string &src) { if (src.empty()) - attributes.erase("\\src"); + attributes.erase(ID(src)); else - attributes["\\src"] = src; + attributes[ID(src)] = src; } std::string RTLIL::AttrObject::get_src_attribute() const { std::string src; - if (attributes.count("\\src")) - src = attributes.at("\\src").decode_string(); + if (attributes.count(ID(src))) + src = attributes.at(ID(src)).decode_string(); return src; } @@ -358,6 +385,10 @@ RTLIL::Design::Design() refcount_modules_ = 0; selection_stack.push_back(RTLIL::Selection()); + +#ifdef WITH_PYTHON + RTLIL::Design::get_all_designs()->insert(std::pair<unsigned int, RTLIL::Design*>(hashidx_, this)); +#endif } RTLIL::Design::~Design() @@ -368,8 +399,19 @@ RTLIL::Design::~Design() delete n; for (auto n : verilog_globals) delete n; +#ifdef WITH_PYTHON + RTLIL::Design::get_all_designs()->erase(hashidx_); +#endif } +#ifdef WITH_PYTHON +static std::map<unsigned int, RTLIL::Design*> all_designs; +std::map<unsigned int, RTLIL::Design*> *RTLIL::Design::get_all_designs(void) +{ + return &all_designs; +} +#endif + RTLIL::ObjRange<RTLIL::Module*> RTLIL::Design::modules() { return RTLIL::ObjRange<RTLIL::Module*>(&modules_, &refcount_modules_); @@ -386,7 +428,7 @@ RTLIL::Module *RTLIL::Design::top_module() int module_count = 0; for (auto mod : selected_modules()) { - if (mod->get_bool_attribute("\\top")) + if (mod->get_bool_attribute(ID(top))) return mod; module_count++; module = mod; @@ -587,7 +629,7 @@ std::vector<RTLIL::Module*> RTLIL::Design::selected_modules() const std::vector<RTLIL::Module*> result; result.reserve(modules_.size()); for (auto &it : modules_) - if (selected_module(it.first) && !it.second->get_bool_attribute("\\blackbox")) + if (selected_module(it.first) && !it.second->get_blackbox_attribute()) result.push_back(it.second); return result; } @@ -597,7 +639,7 @@ std::vector<RTLIL::Module*> RTLIL::Design::selected_whole_modules() const std::vector<RTLIL::Module*> result; result.reserve(modules_.size()); for (auto &it : modules_) - if (selected_whole_module(it.first) && !it.second->get_bool_attribute("\\blackbox")) + if (selected_whole_module(it.first) && !it.second->get_blackbox_attribute()) result.push_back(it.second); return result; } @@ -607,7 +649,7 @@ std::vector<RTLIL::Module*> RTLIL::Design::selected_whole_modules_warn() const std::vector<RTLIL::Module*> result; result.reserve(modules_.size()); for (auto &it : modules_) - if (it.second->get_bool_attribute("\\blackbox")) + if (it.second->get_blackbox_attribute()) continue; else if (selected_whole_module(it.first)) result.push_back(it.second); @@ -625,6 +667,10 @@ RTLIL::Module::Module() design = nullptr; refcount_wires_ = 0; refcount_cells_ = 0; + +#ifdef WITH_PYTHON + RTLIL::Module::get_all_modules()->insert(std::pair<unsigned int, RTLIL::Module*>(hashidx_, this)); +#endif } RTLIL::Module::~Module() @@ -637,6 +683,46 @@ RTLIL::Module::~Module() delete it->second; for (auto it = processes.begin(); it != processes.end(); ++it) delete it->second; +#ifdef WITH_PYTHON + RTLIL::Module::get_all_modules()->erase(hashidx_); +#endif +} + +#ifdef WITH_PYTHON +static std::map<unsigned int, RTLIL::Module*> all_modules; +std::map<unsigned int, RTLIL::Module*> *RTLIL::Module::get_all_modules(void) +{ + return &all_modules; +} +#endif + +void RTLIL::Module::makeblackbox() +{ + pool<RTLIL::Wire*> delwires; + + for (auto it = wires_.begin(); it != wires_.end(); ++it) + if (!it->second->port_input && !it->second->port_output) + delwires.insert(it->second); + + for (auto it = memories.begin(); it != memories.end(); ++it) + delete it->second; + memories.clear(); + + for (auto it = cells_.begin(); it != cells_.end(); ++it) + delete it->second; + cells_.clear(); + + for (auto it = processes.begin(); it != processes.end(); ++it) + delete it->second; + processes.clear(); + + remove(delwires); + set_bool_attribute(ID::blackbox); +} + +void RTLIL::Module::reprocess_module(RTLIL::Design *, dict<RTLIL::IdString, RTLIL::Module *>) +{ + log_error("Cannot reprocess_module module `%s' !\n", id2cstr(name)); } RTLIL::IdString RTLIL::Module::derive(RTLIL::Design*, dict<RTLIL::IdString, RTLIL::Const>, bool mayfail) @@ -646,6 +732,14 @@ RTLIL::IdString RTLIL::Module::derive(RTLIL::Design*, dict<RTLIL::IdString, RTLI log_error("Module `%s' is used with parameters but is not parametric!\n", id2cstr(name)); } + +RTLIL::IdString RTLIL::Module::derive(RTLIL::Design*, dict<RTLIL::IdString, RTLIL::Const>, dict<RTLIL::IdString, RTLIL::Module*>, dict<RTLIL::IdString, RTLIL::IdString>, bool mayfail) +{ + if (mayfail) + return RTLIL::IdString(); + log_error("Module `%s' is used with parameters but is not parametric!\n", id2cstr(name)); +} + size_t RTLIL::Module::count_id(RTLIL::IdString id) { return wires_.count(id) + memories.count(id) + cells_.count(id) + processes.count(id); @@ -671,7 +765,7 @@ namespace { cell->name.c_str(), cell->type.c_str(), __FILE__, linenr, buf.str().c_str()); } - int param(const char *name) + int param(RTLIL::IdString name) { if (cell->parameters.count(name) == 0) error(__LINE__); @@ -679,7 +773,7 @@ namespace { return cell->parameters.at(name).as_int(); } - int param_bool(const char *name) + int param_bool(RTLIL::IdString name) { int v = param(name); if (cell->parameters.at(name).bits.size() > 32) @@ -689,14 +783,14 @@ namespace { return v; } - void param_bits(const char *name, int width) + void param_bits(RTLIL::IdString name, int width) { param(name); if (int(cell->parameters.at(name).bits.size()) != width) error(__LINE__); } - void port(const char *name, int width) + void port(RTLIL::IdString name, int width) { if (!cell->hasPort(name)) error(__LINE__); @@ -714,9 +808,9 @@ namespace { if (expected_ports.count(conn.first) == 0) error(__LINE__); - if (expected_params.count("\\A_SIGNED") != 0 && expected_params.count("\\B_SIGNED") && check_matched_sign) { - bool a_is_signed = param("\\A_SIGNED") != 0; - bool b_is_signed = param("\\B_SIGNED") != 0; + if (expected_params.count(ID(A_SIGNED)) != 0 && expected_params.count(ID(B_SIGNED)) && check_matched_sign) { + bool a_is_signed = param(ID(A_SIGNED)) != 0; + bool b_is_signed = param(ID(B_SIGNED)) != 0; if (a_is_signed != b_is_signed) error(__LINE__); } @@ -745,441 +839,482 @@ namespace { void check() { - if (cell->type.substr(0, 1) != "$" || cell->type.substr(0, 3) == "$__" || cell->type.substr(0, 8) == "$paramod" || - cell->type.substr(0, 9) == "$verific$" || cell->type.substr(0, 7) == "$array:" || cell->type.substr(0, 8) == "$extern:") + if (!cell->type.begins_with("$") || cell->type.begins_with("$__") || cell->type.begins_with("$paramod") || cell->type.begins_with("$fmcombine") || + cell->type.begins_with("$verific$") || cell->type.begins_with("$array:") || cell->type.begins_with("$extern:")) return; - if (cell->type.in("$not", "$pos", "$neg")) { - param_bool("\\A_SIGNED"); - port("\\A", param("\\A_WIDTH")); - port("\\Y", param("\\Y_WIDTH")); + if (cell->type.in(ID($not), ID($pos), ID($neg))) { + param_bool(ID(A_SIGNED)); + port(ID::A, param(ID(A_WIDTH))); + port(ID::Y, param(ID(Y_WIDTH))); check_expected(); return; } - if (cell->type.in("$and", "$or", "$xor", "$xnor")) { - param_bool("\\A_SIGNED"); - param_bool("\\B_SIGNED"); - port("\\A", param("\\A_WIDTH")); - port("\\B", param("\\B_WIDTH")); - port("\\Y", param("\\Y_WIDTH")); + if (cell->type.in(ID($and), ID($or), ID($xor), ID($xnor))) { + param_bool(ID(A_SIGNED)); + param_bool(ID(B_SIGNED)); + port(ID::A, param(ID(A_WIDTH))); + port(ID::B, param(ID(B_WIDTH))); + port(ID::Y, param(ID(Y_WIDTH))); check_expected(); return; } - if (cell->type.in("$reduce_and", "$reduce_or", "$reduce_xor", "$reduce_xnor", "$reduce_bool")) { - param_bool("\\A_SIGNED"); - port("\\A", param("\\A_WIDTH")); - port("\\Y", param("\\Y_WIDTH")); + if (cell->type.in(ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_xnor), ID($reduce_bool))) { + param_bool(ID(A_SIGNED)); + port(ID::A, param(ID(A_WIDTH))); + port(ID::Y, param(ID(Y_WIDTH))); check_expected(); return; } - if (cell->type.in("$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx")) { - param_bool("\\A_SIGNED"); - param_bool("\\B_SIGNED"); - port("\\A", param("\\A_WIDTH")); - port("\\B", param("\\B_WIDTH")); - port("\\Y", param("\\Y_WIDTH")); + if (cell->type.in(ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx))) { + param_bool(ID(A_SIGNED)); + param_bool(ID(B_SIGNED)); + port(ID::A, param(ID(A_WIDTH))); + port(ID::B, param(ID(B_WIDTH))); + port(ID::Y, param(ID(Y_WIDTH))); check_expected(false); return; } - if (cell->type.in("$lt", "$le", "$eq", "$ne", "$eqx", "$nex", "$ge", "$gt")) { - param_bool("\\A_SIGNED"); - param_bool("\\B_SIGNED"); - port("\\A", param("\\A_WIDTH")); - port("\\B", param("\\B_WIDTH")); - port("\\Y", param("\\Y_WIDTH")); + if (cell->type.in(ID($lt), ID($le), ID($eq), ID($ne), ID($eqx), ID($nex), ID($ge), ID($gt))) { + param_bool(ID(A_SIGNED)); + param_bool(ID(B_SIGNED)); + port(ID::A, param(ID(A_WIDTH))); + port(ID::B, param(ID(B_WIDTH))); + port(ID::Y, param(ID(Y_WIDTH))); check_expected(); return; } - if (cell->type.in("$add", "$sub", "$mul", "$div", "$mod", "$pow")) { - param_bool("\\A_SIGNED"); - param_bool("\\B_SIGNED"); - port("\\A", param("\\A_WIDTH")); - port("\\B", param("\\B_WIDTH")); - port("\\Y", param("\\Y_WIDTH")); - check_expected(cell->type != "$pow"); + if (cell->type.in(ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($pow))) { + param_bool(ID(A_SIGNED)); + param_bool(ID(B_SIGNED)); + port(ID::A, param(ID(A_WIDTH))); + port(ID::B, param(ID(B_WIDTH))); + port(ID::Y, param(ID(Y_WIDTH))); + check_expected(cell->type != ID($pow)); return; } - if (cell->type == "$fa") { - port("\\A", param("\\WIDTH")); - port("\\B", param("\\WIDTH")); - port("\\C", param("\\WIDTH")); - port("\\X", param("\\WIDTH")); - port("\\Y", param("\\WIDTH")); + if (cell->type == ID($fa)) { + port(ID::A, param(ID(WIDTH))); + port(ID::B, param(ID(WIDTH))); + port(ID(C), param(ID(WIDTH))); + port(ID(X), param(ID(WIDTH))); + port(ID::Y, param(ID(WIDTH))); check_expected(); return; } - if (cell->type == "$lcu") { - port("\\P", param("\\WIDTH")); - port("\\G", param("\\WIDTH")); - port("\\CI", 1); - port("\\CO", param("\\WIDTH")); + if (cell->type == ID($lcu)) { + port(ID(P), param(ID(WIDTH))); + port(ID(G), param(ID(WIDTH))); + port(ID(CI), 1); + port(ID(CO), param(ID(WIDTH))); check_expected(); return; } - if (cell->type == "$alu") { - param_bool("\\A_SIGNED"); - param_bool("\\B_SIGNED"); - port("\\A", param("\\A_WIDTH")); - port("\\B", param("\\B_WIDTH")); - port("\\CI", 1); - port("\\BI", 1); - port("\\X", param("\\Y_WIDTH")); - port("\\Y", param("\\Y_WIDTH")); - port("\\CO", param("\\Y_WIDTH")); + if (cell->type == ID($alu)) { + param_bool(ID(A_SIGNED)); + param_bool(ID(B_SIGNED)); + port(ID::A, param(ID(A_WIDTH))); + port(ID::B, param(ID(B_WIDTH))); + port(ID(CI), 1); + port(ID(BI), 1); + port(ID(X), param(ID(Y_WIDTH))); + port(ID::Y, param(ID(Y_WIDTH))); + port(ID(CO), param(ID(Y_WIDTH))); check_expected(); return; } - if (cell->type == "$macc") { - param("\\CONFIG"); - param("\\CONFIG_WIDTH"); - port("\\A", param("\\A_WIDTH")); - port("\\B", param("\\B_WIDTH")); - port("\\Y", param("\\Y_WIDTH")); + if (cell->type == ID($macc)) { + param(ID(CONFIG)); + param(ID(CONFIG_WIDTH)); + port(ID::A, param(ID(A_WIDTH))); + port(ID::B, param(ID(B_WIDTH))); + port(ID::Y, param(ID(Y_WIDTH))); check_expected(); Macc().from_cell(cell); return; } - if (cell->type == "$logic_not") { - param_bool("\\A_SIGNED"); - port("\\A", param("\\A_WIDTH")); - port("\\Y", param("\\Y_WIDTH")); + if (cell->type == ID($logic_not)) { + param_bool(ID(A_SIGNED)); + port(ID::A, param(ID(A_WIDTH))); + port(ID::Y, param(ID(Y_WIDTH))); check_expected(); return; } - if (cell->type == "$logic_and" || cell->type == "$logic_or") { - param_bool("\\A_SIGNED"); - param_bool("\\B_SIGNED"); - port("\\A", param("\\A_WIDTH")); - port("\\B", param("\\B_WIDTH")); - port("\\Y", param("\\Y_WIDTH")); + if (cell->type.in(ID($logic_and), ID($logic_or))) { + param_bool(ID(A_SIGNED)); + param_bool(ID(B_SIGNED)); + port(ID::A, param(ID(A_WIDTH))); + port(ID::B, param(ID(B_WIDTH))); + port(ID::Y, param(ID(Y_WIDTH))); check_expected(false); return; } - if (cell->type == "$slice") { - param("\\OFFSET"); - port("\\A", param("\\A_WIDTH")); - port("\\Y", param("\\Y_WIDTH")); - if (param("\\OFFSET") + param("\\Y_WIDTH") > param("\\A_WIDTH")) + if (cell->type == ID($slice)) { + param(ID(OFFSET)); + port(ID::A, param(ID(A_WIDTH))); + port(ID::Y, param(ID(Y_WIDTH))); + if (param(ID(OFFSET)) + param(ID(Y_WIDTH)) > param(ID(A_WIDTH))) error(__LINE__); check_expected(); return; } - if (cell->type == "$concat") { - port("\\A", param("\\A_WIDTH")); - port("\\B", param("\\B_WIDTH")); - port("\\Y", param("\\A_WIDTH") + param("\\B_WIDTH")); + if (cell->type == ID($concat)) { + port(ID::A, param(ID(A_WIDTH))); + port(ID::B, param(ID(B_WIDTH))); + port(ID::Y, param(ID(A_WIDTH)) + param(ID(B_WIDTH))); + check_expected(); + return; + } + + if (cell->type == ID($mux)) { + port(ID::A, param(ID(WIDTH))); + port(ID::B, param(ID(WIDTH))); + port(ID(S), 1); + port(ID::Y, param(ID(WIDTH))); check_expected(); return; } - if (cell->type == "$mux") { - port("\\A", param("\\WIDTH")); - port("\\B", param("\\WIDTH")); - port("\\S", 1); - port("\\Y", param("\\WIDTH")); + if (cell->type == ID($pmux)) { + port(ID::A, param(ID(WIDTH))); + port(ID::B, param(ID(WIDTH)) * param(ID(S_WIDTH))); + port(ID(S), param(ID(S_WIDTH))); + port(ID::Y, param(ID(WIDTH))); check_expected(); return; } - if (cell->type == "$pmux") { - port("\\A", param("\\WIDTH")); - port("\\B", param("\\WIDTH") * param("\\S_WIDTH")); - port("\\S", param("\\S_WIDTH")); - port("\\Y", param("\\WIDTH")); + if (cell->type == ID($lut)) { + param(ID(LUT)); + port(ID::A, param(ID(WIDTH))); + port(ID::Y, 1); check_expected(); return; } - if (cell->type == "$lut") { - param("\\LUT"); - port("\\A", param("\\WIDTH")); - port("\\Y", 1); + if (cell->type == ID($sop)) { + param(ID(DEPTH)); + param(ID(TABLE)); + port(ID::A, param(ID(WIDTH))); + port(ID::Y, 1); check_expected(); return; } - if (cell->type == "$sop") { - param("\\DEPTH"); - param("\\TABLE"); - port("\\A", param("\\WIDTH")); - port("\\Y", 1); + if (cell->type == ID($sr)) { + param_bool(ID(SET_POLARITY)); + param_bool(ID(CLR_POLARITY)); + port(ID(SET), param(ID(WIDTH))); + port(ID(CLR), param(ID(WIDTH))); + port(ID(Q), param(ID(WIDTH))); check_expected(); return; } - if (cell->type == "$sr") { - param_bool("\\SET_POLARITY"); - param_bool("\\CLR_POLARITY"); - port("\\SET", param("\\WIDTH")); - port("\\CLR", param("\\WIDTH")); - port("\\Q", param("\\WIDTH")); + if (cell->type == ID($ff)) { + port(ID(D), param(ID(WIDTH))); + port(ID(Q), param(ID(WIDTH))); check_expected(); return; } - if (cell->type == "$ff") { - port("\\D", param("\\WIDTH")); - port("\\Q", param("\\WIDTH")); + if (cell->type == ID($dff)) { + param_bool(ID(CLK_POLARITY)); + port(ID(CLK), 1); + port(ID(D), param(ID(WIDTH))); + port(ID(Q), param(ID(WIDTH))); check_expected(); return; } - if (cell->type == "$dff") { - param_bool("\\CLK_POLARITY"); - port("\\CLK", 1); - port("\\D", param("\\WIDTH")); - port("\\Q", param("\\WIDTH")); + if (cell->type == ID($dffe)) { + param_bool(ID(CLK_POLARITY)); + param_bool(ID(EN_POLARITY)); + port(ID(CLK), 1); + port(ID(EN), 1); + port(ID(D), param(ID(WIDTH))); + port(ID(Q), param(ID(WIDTH))); check_expected(); return; } - if (cell->type == "$dffe") { - param_bool("\\CLK_POLARITY"); - param_bool("\\EN_POLARITY"); - port("\\CLK", 1); - port("\\EN", 1); - port("\\D", param("\\WIDTH")); - port("\\Q", param("\\WIDTH")); + if (cell->type == ID($dffsr)) { + param_bool(ID(CLK_POLARITY)); + param_bool(ID(SET_POLARITY)); + param_bool(ID(CLR_POLARITY)); + port(ID(CLK), 1); + port(ID(SET), param(ID(WIDTH))); + port(ID(CLR), param(ID(WIDTH))); + port(ID(D), param(ID(WIDTH))); + port(ID(Q), param(ID(WIDTH))); check_expected(); return; } - if (cell->type == "$dffsr") { - param_bool("\\CLK_POLARITY"); - param_bool("\\SET_POLARITY"); - param_bool("\\CLR_POLARITY"); - port("\\CLK", 1); - port("\\SET", param("\\WIDTH")); - port("\\CLR", param("\\WIDTH")); - port("\\D", param("\\WIDTH")); - port("\\Q", param("\\WIDTH")); + if (cell->type == ID($adff)) { + param_bool(ID(CLK_POLARITY)); + param_bool(ID(ARST_POLARITY)); + param_bits(ID(ARST_VALUE), param(ID(WIDTH))); + port(ID(CLK), 1); + port(ID(ARST), 1); + port(ID(D), param(ID(WIDTH))); + port(ID(Q), param(ID(WIDTH))); check_expected(); return; } - if (cell->type == "$adff") { - param_bool("\\CLK_POLARITY"); - param_bool("\\ARST_POLARITY"); - param_bits("\\ARST_VALUE", param("\\WIDTH")); - port("\\CLK", 1); - port("\\ARST", 1); - port("\\D", param("\\WIDTH")); - port("\\Q", param("\\WIDTH")); + if (cell->type == ID($dlatch)) { + param_bool(ID(EN_POLARITY)); + port(ID(EN), 1); + port(ID(D), param(ID(WIDTH))); + port(ID(Q), param(ID(WIDTH))); check_expected(); return; } - if (cell->type == "$dlatch") { - param_bool("\\EN_POLARITY"); - port("\\EN", 1); - port("\\D", param("\\WIDTH")); - port("\\Q", param("\\WIDTH")); + if (cell->type == ID($dlatchsr)) { + param_bool(ID(EN_POLARITY)); + param_bool(ID(SET_POLARITY)); + param_bool(ID(CLR_POLARITY)); + port(ID(EN), 1); + port(ID(SET), param(ID(WIDTH))); + port(ID(CLR), param(ID(WIDTH))); + port(ID(D), param(ID(WIDTH))); + port(ID(Q), param(ID(WIDTH))); check_expected(); return; } - if (cell->type == "$dlatchsr") { - param_bool("\\EN_POLARITY"); - param_bool("\\SET_POLARITY"); - param_bool("\\CLR_POLARITY"); - port("\\EN", 1); - port("\\SET", param("\\WIDTH")); - port("\\CLR", param("\\WIDTH")); - port("\\D", param("\\WIDTH")); - port("\\Q", param("\\WIDTH")); + if (cell->type == ID($fsm)) { + param(ID(NAME)); + param_bool(ID(CLK_POLARITY)); + param_bool(ID(ARST_POLARITY)); + param(ID(STATE_BITS)); + param(ID(STATE_NUM)); + param(ID(STATE_NUM_LOG2)); + param(ID(STATE_RST)); + param_bits(ID(STATE_TABLE), param(ID(STATE_BITS)) * param(ID(STATE_NUM))); + param(ID(TRANS_NUM)); + param_bits(ID(TRANS_TABLE), param(ID(TRANS_NUM)) * (2*param(ID(STATE_NUM_LOG2)) + param(ID(CTRL_IN_WIDTH)) + param(ID(CTRL_OUT_WIDTH)))); + port(ID(CLK), 1); + port(ID(ARST), 1); + port(ID(CTRL_IN), param(ID(CTRL_IN_WIDTH))); + port(ID(CTRL_OUT), param(ID(CTRL_OUT_WIDTH))); check_expected(); return; } - if (cell->type == "$fsm") { - param("\\NAME"); - param_bool("\\CLK_POLARITY"); - param_bool("\\ARST_POLARITY"); - param("\\STATE_BITS"); - param("\\STATE_NUM"); - param("\\STATE_NUM_LOG2"); - param("\\STATE_RST"); - param_bits("\\STATE_TABLE", param("\\STATE_BITS") * param("\\STATE_NUM")); - param("\\TRANS_NUM"); - param_bits("\\TRANS_TABLE", param("\\TRANS_NUM") * (2*param("\\STATE_NUM_LOG2") + param("\\CTRL_IN_WIDTH") + param("\\CTRL_OUT_WIDTH"))); - port("\\CLK", 1); - port("\\ARST", 1); - port("\\CTRL_IN", param("\\CTRL_IN_WIDTH")); - port("\\CTRL_OUT", param("\\CTRL_OUT_WIDTH")); + if (cell->type == ID($memrd)) { + param(ID(MEMID)); + param_bool(ID(CLK_ENABLE)); + param_bool(ID(CLK_POLARITY)); + param_bool(ID(TRANSPARENT)); + port(ID(CLK), 1); + port(ID(EN), 1); + port(ID(ADDR), param(ID(ABITS))); + port(ID(DATA), param(ID(WIDTH))); check_expected(); return; } - if (cell->type == "$memrd") { - param("\\MEMID"); - param_bool("\\CLK_ENABLE"); - param_bool("\\CLK_POLARITY"); - param_bool("\\TRANSPARENT"); - port("\\CLK", 1); - port("\\EN", 1); - port("\\ADDR", param("\\ABITS")); - port("\\DATA", param("\\WIDTH")); + if (cell->type == ID($memwr)) { + param(ID(MEMID)); + param_bool(ID(CLK_ENABLE)); + param_bool(ID(CLK_POLARITY)); + param(ID(PRIORITY)); + port(ID(CLK), 1); + port(ID(EN), param(ID(WIDTH))); + port(ID(ADDR), param(ID(ABITS))); + port(ID(DATA), param(ID(WIDTH))); check_expected(); return; } - if (cell->type == "$memwr") { - param("\\MEMID"); - param_bool("\\CLK_ENABLE"); - param_bool("\\CLK_POLARITY"); - param("\\PRIORITY"); - port("\\CLK", 1); - port("\\EN", param("\\WIDTH")); - port("\\ADDR", param("\\ABITS")); - port("\\DATA", param("\\WIDTH")); + if (cell->type == ID($meminit)) { + param(ID(MEMID)); + param(ID(PRIORITY)); + port(ID(ADDR), param(ID(ABITS))); + port(ID(DATA), param(ID(WIDTH)) * param(ID(WORDS))); check_expected(); return; } - if (cell->type == "$meminit") { - param("\\MEMID"); - param("\\PRIORITY"); - port("\\ADDR", param("\\ABITS")); - port("\\DATA", param("\\WIDTH") * param("\\WORDS")); + if (cell->type == ID($mem)) { + param(ID(MEMID)); + param(ID(SIZE)); + param(ID(OFFSET)); + param(ID(INIT)); + param_bits(ID(RD_CLK_ENABLE), max(1, param(ID(RD_PORTS)))); + param_bits(ID(RD_CLK_POLARITY), max(1, param(ID(RD_PORTS)))); + param_bits(ID(RD_TRANSPARENT), max(1, param(ID(RD_PORTS)))); + param_bits(ID(WR_CLK_ENABLE), max(1, param(ID(WR_PORTS)))); + param_bits(ID(WR_CLK_POLARITY), max(1, param(ID(WR_PORTS)))); + port(ID(RD_CLK), param(ID(RD_PORTS))); + port(ID(RD_EN), param(ID(RD_PORTS))); + port(ID(RD_ADDR), param(ID(RD_PORTS)) * param(ID(ABITS))); + port(ID(RD_DATA), param(ID(RD_PORTS)) * param(ID(WIDTH))); + port(ID(WR_CLK), param(ID(WR_PORTS))); + port(ID(WR_EN), param(ID(WR_PORTS)) * param(ID(WIDTH))); + port(ID(WR_ADDR), param(ID(WR_PORTS)) * param(ID(ABITS))); + port(ID(WR_DATA), param(ID(WR_PORTS)) * param(ID(WIDTH))); check_expected(); return; } - if (cell->type == "$mem") { - param("\\MEMID"); - param("\\SIZE"); - param("\\OFFSET"); - param("\\INIT"); - param_bits("\\RD_CLK_ENABLE", max(1, param("\\RD_PORTS"))); - param_bits("\\RD_CLK_POLARITY", max(1, param("\\RD_PORTS"))); - param_bits("\\RD_TRANSPARENT", max(1, param("\\RD_PORTS"))); - param_bits("\\WR_CLK_ENABLE", max(1, param("\\WR_PORTS"))); - param_bits("\\WR_CLK_POLARITY", max(1, param("\\WR_PORTS"))); - port("\\RD_CLK", param("\\RD_PORTS")); - port("\\RD_EN", param("\\RD_PORTS")); - port("\\RD_ADDR", param("\\RD_PORTS") * param("\\ABITS")); - port("\\RD_DATA", param("\\RD_PORTS") * param("\\WIDTH")); - port("\\WR_CLK", param("\\WR_PORTS")); - port("\\WR_EN", param("\\WR_PORTS") * param("\\WIDTH")); - port("\\WR_ADDR", param("\\WR_PORTS") * param("\\ABITS")); - port("\\WR_DATA", param("\\WR_PORTS") * param("\\WIDTH")); + if (cell->type == ID($tribuf)) { + port(ID::A, param(ID(WIDTH))); + port(ID::Y, param(ID(WIDTH))); + port(ID(EN), 1); check_expected(); return; } - if (cell->type == "$tribuf") { - port("\\A", param("\\WIDTH")); - port("\\Y", param("\\WIDTH")); - port("\\EN", 1); + if (cell->type.in(ID($assert), ID($assume), ID($live), ID($fair), ID($cover))) { + port(ID::A, 1); + port(ID(EN), 1); check_expected(); return; } - if (cell->type.in("$assert", "$assume", "$live", "$fair", "$cover")) { - port("\\A", 1); - port("\\EN", 1); + if (cell->type == ID($initstate)) { + port(ID::Y, 1); check_expected(); return; } - if (cell->type == "$initstate") { - port("\\Y", 1); + if (cell->type.in(ID($anyconst), ID($anyseq), ID($allconst), ID($allseq))) { + port(ID::Y, param(ID(WIDTH))); check_expected(); return; } - if (cell->type.in("$anyconst", "$anyseq", "$allconst", "$allseq")) { - port("\\Y", param("\\WIDTH")); + if (cell->type == ID($equiv)) { + port(ID::A, 1); + port(ID::B, 1); + port(ID::Y, 1); check_expected(); return; } - if (cell->type == "$equiv") { - port("\\A", 1); - port("\\B", 1); - port("\\Y", 1); + if (cell->type.in(ID($specify2), ID($specify3))) { + param_bool(ID(FULL)); + param_bool(ID(SRC_DST_PEN)); + param_bool(ID(SRC_DST_POL)); + param(ID(T_RISE_MIN)); + param(ID(T_RISE_TYP)); + param(ID(T_RISE_MAX)); + param(ID(T_FALL_MIN)); + param(ID(T_FALL_TYP)); + param(ID(T_FALL_MAX)); + port(ID(EN), 1); + port(ID(SRC), param(ID(SRC_WIDTH))); + port(ID(DST), param(ID(DST_WIDTH))); + if (cell->type == ID($specify3)) { + param_bool(ID(EDGE_EN)); + param_bool(ID(EDGE_POL)); + param_bool(ID(DAT_DST_PEN)); + param_bool(ID(DAT_DST_POL)); + port(ID(DAT), param(ID(DST_WIDTH))); + } check_expected(); return; } - if (cell->type == "$_BUF_") { check_gate("AY"); return; } - if (cell->type == "$_NOT_") { check_gate("AY"); return; } - if (cell->type == "$_AND_") { check_gate("ABY"); return; } - if (cell->type == "$_NAND_") { check_gate("ABY"); return; } - if (cell->type == "$_OR_") { check_gate("ABY"); return; } - if (cell->type == "$_NOR_") { check_gate("ABY"); return; } - if (cell->type == "$_XOR_") { check_gate("ABY"); return; } - if (cell->type == "$_XNOR_") { check_gate("ABY"); return; } - if (cell->type == "$_ANDNOT_") { check_gate("ABY"); return; } - if (cell->type == "$_ORNOT_") { check_gate("ABY"); return; } - if (cell->type == "$_MUX_") { check_gate("ABSY"); return; } - if (cell->type == "$_AOI3_") { check_gate("ABCY"); return; } - if (cell->type == "$_OAI3_") { check_gate("ABCY"); return; } - if (cell->type == "$_AOI4_") { check_gate("ABCDY"); return; } - if (cell->type == "$_OAI4_") { check_gate("ABCDY"); return; } - - if (cell->type == "$_TBUF_") { check_gate("AYE"); return; } - - if (cell->type == "$_MUX4_") { check_gate("ABCDSTY"); return; } - if (cell->type == "$_MUX8_") { check_gate("ABCDEFGHSTUY"); return; } - if (cell->type == "$_MUX16_") { check_gate("ABCDEFGHIJKLMNOPSTUVY"); return; } - - if (cell->type == "$_SR_NN_") { check_gate("SRQ"); return; } - if (cell->type == "$_SR_NP_") { check_gate("SRQ"); return; } - if (cell->type == "$_SR_PN_") { check_gate("SRQ"); return; } - if (cell->type == "$_SR_PP_") { check_gate("SRQ"); return; } - - if (cell->type == "$_FF_") { check_gate("DQ"); return; } - if (cell->type == "$_DFF_N_") { check_gate("DQC"); return; } - if (cell->type == "$_DFF_P_") { check_gate("DQC"); return; } - - if (cell->type == "$_DFFE_NN_") { check_gate("DQCE"); return; } - if (cell->type == "$_DFFE_NP_") { check_gate("DQCE"); return; } - if (cell->type == "$_DFFE_PN_") { check_gate("DQCE"); return; } - if (cell->type == "$_DFFE_PP_") { check_gate("DQCE"); return; } - - if (cell->type == "$_DFF_NN0_") { check_gate("DQCR"); return; } - if (cell->type == "$_DFF_NN1_") { check_gate("DQCR"); return; } - if (cell->type == "$_DFF_NP0_") { check_gate("DQCR"); return; } - if (cell->type == "$_DFF_NP1_") { check_gate("DQCR"); return; } - if (cell->type == "$_DFF_PN0_") { check_gate("DQCR"); return; } - if (cell->type == "$_DFF_PN1_") { check_gate("DQCR"); return; } - if (cell->type == "$_DFF_PP0_") { check_gate("DQCR"); return; } - if (cell->type == "$_DFF_PP1_") { check_gate("DQCR"); return; } - - if (cell->type == "$_DFFSR_NNN_") { check_gate("CSRDQ"); return; } - if (cell->type == "$_DFFSR_NNP_") { check_gate("CSRDQ"); return; } - if (cell->type == "$_DFFSR_NPN_") { check_gate("CSRDQ"); return; } - if (cell->type == "$_DFFSR_NPP_") { check_gate("CSRDQ"); return; } - if (cell->type == "$_DFFSR_PNN_") { check_gate("CSRDQ"); return; } - if (cell->type == "$_DFFSR_PNP_") { check_gate("CSRDQ"); return; } - if (cell->type == "$_DFFSR_PPN_") { check_gate("CSRDQ"); return; } - if (cell->type == "$_DFFSR_PPP_") { check_gate("CSRDQ"); return; } - - if (cell->type == "$_DLATCH_N_") { check_gate("EDQ"); return; } - if (cell->type == "$_DLATCH_P_") { check_gate("EDQ"); return; } - - if (cell->type == "$_DLATCHSR_NNN_") { check_gate("ESRDQ"); return; } - if (cell->type == "$_DLATCHSR_NNP_") { check_gate("ESRDQ"); return; } - if (cell->type == "$_DLATCHSR_NPN_") { check_gate("ESRDQ"); return; } - if (cell->type == "$_DLATCHSR_NPP_") { check_gate("ESRDQ"); return; } - if (cell->type == "$_DLATCHSR_PNN_") { check_gate("ESRDQ"); return; } - if (cell->type == "$_DLATCHSR_PNP_") { check_gate("ESRDQ"); return; } - if (cell->type == "$_DLATCHSR_PPN_") { check_gate("ESRDQ"); return; } - if (cell->type == "$_DLATCHSR_PPP_") { check_gate("ESRDQ"); return; } + if (cell->type == ID($specrule)) { + param(ID(TYPE)); + param_bool(ID(SRC_PEN)); + param_bool(ID(SRC_POL)); + param_bool(ID(DST_PEN)); + param_bool(ID(DST_POL)); + param(ID(T_LIMIT)); + param(ID(T_LIMIT2)); + port(ID(SRC_EN), 1); + port(ID(DST_EN), 1); + port(ID(SRC), param(ID(SRC_WIDTH))); + port(ID(DST), param(ID(DST_WIDTH))); + check_expected(); + return; + } + + if (cell->type == ID($_BUF_)) { check_gate("AY"); return; } + if (cell->type == ID($_NOT_)) { check_gate("AY"); return; } + if (cell->type == ID($_AND_)) { check_gate("ABY"); return; } + if (cell->type == ID($_NAND_)) { check_gate("ABY"); return; } + if (cell->type == ID($_OR_)) { check_gate("ABY"); return; } + if (cell->type == ID($_NOR_)) { check_gate("ABY"); return; } + if (cell->type == ID($_XOR_)) { check_gate("ABY"); return; } + if (cell->type == ID($_XNOR_)) { check_gate("ABY"); return; } + if (cell->type == ID($_ANDNOT_)) { check_gate("ABY"); return; } + if (cell->type == ID($_ORNOT_)) { check_gate("ABY"); return; } + if (cell->type == ID($_MUX_)) { check_gate("ABSY"); return; } + if (cell->type == ID($_NMUX_)) { check_gate("ABSY"); return; } + if (cell->type == ID($_AOI3_)) { check_gate("ABCY"); return; } + if (cell->type == ID($_OAI3_)) { check_gate("ABCY"); return; } + if (cell->type == ID($_AOI4_)) { check_gate("ABCDY"); return; } + if (cell->type == ID($_OAI4_)) { check_gate("ABCDY"); return; } + + if (cell->type == ID($_TBUF_)) { check_gate("AYE"); return; } + + if (cell->type == ID($_MUX4_)) { check_gate("ABCDSTY"); return; } + if (cell->type == ID($_MUX8_)) { check_gate("ABCDEFGHSTUY"); return; } + if (cell->type == ID($_MUX16_)) { check_gate("ABCDEFGHIJKLMNOPSTUVY"); return; } + + if (cell->type == ID($_SR_NN_)) { check_gate("SRQ"); return; } + if (cell->type == ID($_SR_NP_)) { check_gate("SRQ"); return; } + if (cell->type == ID($_SR_PN_)) { check_gate("SRQ"); return; } + if (cell->type == ID($_SR_PP_)) { check_gate("SRQ"); return; } + + if (cell->type == ID($_FF_)) { check_gate("DQ"); return; } + if (cell->type == ID($_DFF_N_)) { check_gate("DQC"); return; } + if (cell->type == ID($_DFF_P_)) { check_gate("DQC"); return; } + + if (cell->type == ID($_DFFE_NN_)) { check_gate("DQCE"); return; } + if (cell->type == ID($_DFFE_NP_)) { check_gate("DQCE"); return; } + if (cell->type == ID($_DFFE_PN_)) { check_gate("DQCE"); return; } + if (cell->type == ID($_DFFE_PP_)) { check_gate("DQCE"); return; } + + if (cell->type == ID($_DFF_NN0_)) { check_gate("DQCR"); return; } + if (cell->type == ID($_DFF_NN1_)) { check_gate("DQCR"); return; } + if (cell->type == ID($_DFF_NP0_)) { check_gate("DQCR"); return; } + if (cell->type == ID($_DFF_NP1_)) { check_gate("DQCR"); return; } + if (cell->type == ID($_DFF_PN0_)) { check_gate("DQCR"); return; } + if (cell->type == ID($_DFF_PN1_)) { check_gate("DQCR"); return; } + if (cell->type == ID($_DFF_PP0_)) { check_gate("DQCR"); return; } + if (cell->type == ID($_DFF_PP1_)) { check_gate("DQCR"); return; } + + if (cell->type == ID($_DFFSR_NNN_)) { check_gate("CSRDQ"); return; } + if (cell->type == ID($_DFFSR_NNP_)) { check_gate("CSRDQ"); return; } + if (cell->type == ID($_DFFSR_NPN_)) { check_gate("CSRDQ"); return; } + if (cell->type == ID($_DFFSR_NPP_)) { check_gate("CSRDQ"); return; } + if (cell->type == ID($_DFFSR_PNN_)) { check_gate("CSRDQ"); return; } + if (cell->type == ID($_DFFSR_PNP_)) { check_gate("CSRDQ"); return; } + if (cell->type == ID($_DFFSR_PPN_)) { check_gate("CSRDQ"); return; } + if (cell->type == ID($_DFFSR_PPP_)) { check_gate("CSRDQ"); return; } + + if (cell->type == ID($_DLATCH_N_)) { check_gate("EDQ"); return; } + if (cell->type == ID($_DLATCH_P_)) { check_gate("EDQ"); return; } + + if (cell->type == ID($_DLATCHSR_NNN_)) { check_gate("ESRDQ"); return; } + if (cell->type == ID($_DLATCHSR_NNP_)) { check_gate("ESRDQ"); return; } + if (cell->type == ID($_DLATCHSR_NPN_)) { check_gate("ESRDQ"); return; } + if (cell->type == ID($_DLATCHSR_NPP_)) { check_gate("ESRDQ"); return; } + if (cell->type == ID($_DLATCHSR_PNN_)) { check_gate("ESRDQ"); return; } + if (cell->type == ID($_DLATCHSR_PNP_)) { check_gate("ESRDQ"); return; } + if (cell->type == ID($_DLATCHSR_PPN_)) { check_gate("ESRDQ"); return; } + if (cell->type == ID($_DLATCHSR_PPP_)) { check_gate("ESRDQ"); return; } error(__LINE__); } @@ -1258,7 +1393,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<CaseRule*> 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_) { @@ -1391,7 +1553,10 @@ void RTLIL::Module::add(RTLIL::Cell *cell) cell->module = this; } -namespace { +void RTLIL::Module::remove(const pool<RTLIL::Wire*> &wires) +{ + log_assert(refcount_wires_ == 0); + struct DeleteWireWorker { RTLIL::Module *module; @@ -1406,17 +1571,29 @@ namespace { } sig = chunks; } - }; -} -void RTLIL::Module::remove(const pool<RTLIL::Wire*> &wires) -{ - log_assert(refcount_wires_ == 0); + void operator()(RTLIL::SigSpec &lhs, RTLIL::SigSpec &rhs) { + log_assert(GetSize(lhs) == GetSize(rhs)); + RTLIL::SigSpec new_lhs, new_rhs; + for (int i = 0; i < GetSize(lhs); i++) { + RTLIL::SigBit lhs_bit = lhs[i]; + if (lhs_bit.wire != nullptr && wires_p->count(lhs_bit.wire)) + continue; + RTLIL::SigBit rhs_bit = rhs[i]; + if (rhs_bit.wire != nullptr && wires_p->count(rhs_bit.wire)) + continue; + new_lhs.append(lhs_bit); + new_rhs.append(rhs_bit); + } + lhs = new_lhs; + rhs = new_rhs; + } + }; DeleteWireWorker delete_wire_worker; delete_wire_worker.module = this; delete_wire_worker.wires_p = &wires; - rewrite_sigspecs(delete_wire_worker); + rewrite_sigspecs2(delete_wire_worker); for (auto &it : wires) { log_assert(wires_.count(it->name) != 0); @@ -1651,11 +1828,11 @@ RTLIL::Cell *RTLIL::Module::addCell(RTLIL::IdString name, const RTLIL::Cell *oth #define DEF_METHOD(_func, _y_size, _type) \ RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, bool is_signed, const std::string &src) { \ RTLIL::Cell *cell = addCell(name, _type); \ - cell->parameters["\\A_SIGNED"] = is_signed; \ - cell->parameters["\\A_WIDTH"] = sig_a.size(); \ - cell->parameters["\\Y_WIDTH"] = sig_y.size(); \ - cell->setPort("\\A", sig_a); \ - cell->setPort("\\Y", sig_y); \ + cell->parameters[ID(A_SIGNED)] = is_signed; \ + cell->parameters[ID(A_WIDTH)] = sig_a.size(); \ + cell->parameters[ID(Y_WIDTH)] = sig_y.size(); \ + cell->setPort(ID::A, sig_a); \ + cell->setPort(ID::Y, sig_y); \ cell->set_src_attribute(src); \ return cell; \ } \ @@ -1664,28 +1841,28 @@ RTLIL::Cell *RTLIL::Module::addCell(RTLIL::IdString name, const RTLIL::Cell *oth add ## _func(name, sig_a, sig_y, is_signed, src); \ return sig_y; \ } -DEF_METHOD(Not, sig_a.size(), "$not") -DEF_METHOD(Pos, sig_a.size(), "$pos") -DEF_METHOD(Neg, sig_a.size(), "$neg") -DEF_METHOD(ReduceAnd, 1, "$reduce_and") -DEF_METHOD(ReduceOr, 1, "$reduce_or") -DEF_METHOD(ReduceXor, 1, "$reduce_xor") -DEF_METHOD(ReduceXnor, 1, "$reduce_xnor") -DEF_METHOD(ReduceBool, 1, "$reduce_bool") -DEF_METHOD(LogicNot, 1, "$logic_not") +DEF_METHOD(Not, sig_a.size(), ID($not)) +DEF_METHOD(Pos, sig_a.size(), ID($pos)) +DEF_METHOD(Neg, sig_a.size(), ID($neg)) +DEF_METHOD(ReduceAnd, 1, ID($reduce_and)) +DEF_METHOD(ReduceOr, 1, ID($reduce_or)) +DEF_METHOD(ReduceXor, 1, ID($reduce_xor)) +DEF_METHOD(ReduceXnor, 1, ID($reduce_xnor)) +DEF_METHOD(ReduceBool, 1, ID($reduce_bool)) +DEF_METHOD(LogicNot, 1, ID($logic_not)) #undef DEF_METHOD #define DEF_METHOD(_func, _y_size, _type) \ RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool is_signed, const std::string &src) { \ RTLIL::Cell *cell = addCell(name, _type); \ - cell->parameters["\\A_SIGNED"] = is_signed; \ - cell->parameters["\\B_SIGNED"] = is_signed; \ - cell->parameters["\\A_WIDTH"] = sig_a.size(); \ - cell->parameters["\\B_WIDTH"] = sig_b.size(); \ - cell->parameters["\\Y_WIDTH"] = sig_y.size(); \ - cell->setPort("\\A", sig_a); \ - cell->setPort("\\B", sig_b); \ - cell->setPort("\\Y", sig_y); \ + cell->parameters[ID(A_SIGNED)] = is_signed; \ + cell->parameters[ID(B_SIGNED)] = is_signed; \ + cell->parameters[ID(A_WIDTH)] = sig_a.size(); \ + cell->parameters[ID(B_WIDTH)] = sig_b.size(); \ + cell->parameters[ID(Y_WIDTH)] = sig_y.size(); \ + cell->setPort(ID::A, sig_a); \ + cell->setPort(ID::B, sig_b); \ + cell->setPort(ID::Y, sig_y); \ cell->set_src_attribute(src); \ return cell; \ } \ @@ -1694,42 +1871,42 @@ DEF_METHOD(LogicNot, 1, "$logic_not") add ## _func(name, sig_a, sig_b, sig_y, is_signed, src); \ return sig_y; \ } -DEF_METHOD(And, max(sig_a.size(), sig_b.size()), "$and") -DEF_METHOD(Or, max(sig_a.size(), sig_b.size()), "$or") -DEF_METHOD(Xor, max(sig_a.size(), sig_b.size()), "$xor") -DEF_METHOD(Xnor, max(sig_a.size(), sig_b.size()), "$xnor") -DEF_METHOD(Shl, sig_a.size(), "$shl") -DEF_METHOD(Shr, sig_a.size(), "$shr") -DEF_METHOD(Sshl, sig_a.size(), "$sshl") -DEF_METHOD(Sshr, sig_a.size(), "$sshr") -DEF_METHOD(Shift, sig_a.size(), "$shift") -DEF_METHOD(Shiftx, sig_a.size(), "$shiftx") -DEF_METHOD(Lt, 1, "$lt") -DEF_METHOD(Le, 1, "$le") -DEF_METHOD(Eq, 1, "$eq") -DEF_METHOD(Ne, 1, "$ne") -DEF_METHOD(Eqx, 1, "$eqx") -DEF_METHOD(Nex, 1, "$nex") -DEF_METHOD(Ge, 1, "$ge") -DEF_METHOD(Gt, 1, "$gt") -DEF_METHOD(Add, max(sig_a.size(), sig_b.size()), "$add") -DEF_METHOD(Sub, max(sig_a.size(), sig_b.size()), "$sub") -DEF_METHOD(Mul, max(sig_a.size(), sig_b.size()), "$mul") -DEF_METHOD(Div, max(sig_a.size(), sig_b.size()), "$div") -DEF_METHOD(Mod, max(sig_a.size(), sig_b.size()), "$mod") -DEF_METHOD(LogicAnd, 1, "$logic_and") -DEF_METHOD(LogicOr, 1, "$logic_or") +DEF_METHOD(And, max(sig_a.size(), sig_b.size()), ID($and)) +DEF_METHOD(Or, max(sig_a.size(), sig_b.size()), ID($or)) +DEF_METHOD(Xor, max(sig_a.size(), sig_b.size()), ID($xor)) +DEF_METHOD(Xnor, max(sig_a.size(), sig_b.size()), ID($xnor)) +DEF_METHOD(Shl, sig_a.size(), ID($shl)) +DEF_METHOD(Shr, sig_a.size(), ID($shr)) +DEF_METHOD(Sshl, sig_a.size(), ID($sshl)) +DEF_METHOD(Sshr, sig_a.size(), ID($sshr)) +DEF_METHOD(Shift, sig_a.size(), ID($shift)) +DEF_METHOD(Shiftx, sig_a.size(), ID($shiftx)) +DEF_METHOD(Lt, 1, ID($lt)) +DEF_METHOD(Le, 1, ID($le)) +DEF_METHOD(Eq, 1, ID($eq)) +DEF_METHOD(Ne, 1, ID($ne)) +DEF_METHOD(Eqx, 1, ID($eqx)) +DEF_METHOD(Nex, 1, ID($nex)) +DEF_METHOD(Ge, 1, ID($ge)) +DEF_METHOD(Gt, 1, ID($gt)) +DEF_METHOD(Add, max(sig_a.size(), sig_b.size()), ID($add)) +DEF_METHOD(Sub, max(sig_a.size(), sig_b.size()), ID($sub)) +DEF_METHOD(Mul, max(sig_a.size(), sig_b.size()), ID($mul)) +DEF_METHOD(Div, max(sig_a.size(), sig_b.size()), ID($div)) +DEF_METHOD(Mod, max(sig_a.size(), sig_b.size()), ID($mod)) +DEF_METHOD(LogicAnd, 1, ID($logic_and)) +DEF_METHOD(LogicOr, 1, ID($logic_or)) #undef DEF_METHOD #define DEF_METHOD(_func, _type, _pmux) \ RTLIL::Cell* RTLIL::Module::add ## _func(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_s, RTLIL::SigSpec sig_y, const std::string &src) { \ RTLIL::Cell *cell = addCell(name, _type); \ - cell->parameters["\\WIDTH"] = sig_a.size(); \ - if (_pmux) cell->parameters["\\S_WIDTH"] = sig_s.size(); \ - cell->setPort("\\A", sig_a); \ - cell->setPort("\\B", sig_b); \ - cell->setPort("\\S", sig_s); \ - cell->setPort("\\Y", sig_y); \ + cell->parameters[ID(WIDTH)] = sig_a.size(); \ + if (_pmux) cell->parameters[ID(S_WIDTH)] = sig_s.size(); \ + cell->setPort(ID::A, sig_a); \ + cell->setPort(ID::B, sig_b); \ + cell->setPort(ID(S), sig_s); \ + cell->setPort(ID::Y, sig_y); \ cell->set_src_attribute(src); \ return cell; \ } \ @@ -1738,8 +1915,8 @@ DEF_METHOD(LogicOr, 1, "$logic_or") add ## _func(name, sig_a, sig_b, sig_s, sig_y, src); \ return sig_y; \ } -DEF_METHOD(Mux, "$mux", 0) -DEF_METHOD(Pmux, "$pmux", 1) +DEF_METHOD(Mux, ID($mux), 0) +DEF_METHOD(Pmux, ID($pmux), 1) #undef DEF_METHOD #define DEF_METHOD_2(_func, _type, _P1, _P2) \ @@ -1800,21 +1977,22 @@ DEF_METHOD(Pmux, "$pmux", 1) add ## _func(name, sig1, sig2, sig3, sig4, sig5, src); \ return sig5; \ } -DEF_METHOD_2(BufGate, "$_BUF_", A, Y) -DEF_METHOD_2(NotGate, "$_NOT_", A, Y) -DEF_METHOD_3(AndGate, "$_AND_", A, B, Y) -DEF_METHOD_3(NandGate, "$_NAND_", A, B, Y) -DEF_METHOD_3(OrGate, "$_OR_", A, B, Y) -DEF_METHOD_3(NorGate, "$_NOR_", A, B, Y) -DEF_METHOD_3(XorGate, "$_XOR_", A, B, Y) -DEF_METHOD_3(XnorGate, "$_XNOR_", A, B, Y) -DEF_METHOD_3(AndnotGate, "$_ANDNOT_", A, B, Y) -DEF_METHOD_3(OrnotGate, "$_ORNOT_", A, B, Y) -DEF_METHOD_4(MuxGate, "$_MUX_", A, B, S, Y) -DEF_METHOD_4(Aoi3Gate, "$_AOI3_", A, B, C, Y) -DEF_METHOD_4(Oai3Gate, "$_OAI3_", A, B, C, Y) -DEF_METHOD_5(Aoi4Gate, "$_AOI4_", A, B, C, D, Y) -DEF_METHOD_5(Oai4Gate, "$_OAI4_", A, B, C, D, Y) +DEF_METHOD_2(BufGate, ID($_BUF_), A, Y) +DEF_METHOD_2(NotGate, ID($_NOT_), A, Y) +DEF_METHOD_3(AndGate, ID($_AND_), A, B, Y) +DEF_METHOD_3(NandGate, ID($_NAND_), A, B, Y) +DEF_METHOD_3(OrGate, ID($_OR_), A, B, Y) +DEF_METHOD_3(NorGate, ID($_NOR_), A, B, Y) +DEF_METHOD_3(XorGate, ID($_XOR_), A, B, Y) +DEF_METHOD_3(XnorGate, ID($_XNOR_), A, B, Y) +DEF_METHOD_3(AndnotGate, ID($_ANDNOT_), A, B, Y) +DEF_METHOD_3(OrnotGate, ID($_ORNOT_), A, B, Y) +DEF_METHOD_4(MuxGate, ID($_MUX_), A, B, S, Y) +DEF_METHOD_4(NmuxGate, ID($_NMUX_), A, B, S, Y) +DEF_METHOD_4(Aoi3Gate, ID($_AOI3_), A, B, C, Y) +DEF_METHOD_4(Oai3Gate, ID($_OAI3_), A, B, C, Y) +DEF_METHOD_5(Aoi4Gate, ID($_AOI4_), A, B, C, D, Y) +DEF_METHOD_5(Oai4Gate, ID($_OAI4_), A, B, C, D, Y) #undef DEF_METHOD_2 #undef DEF_METHOD_3 #undef DEF_METHOD_4 @@ -1822,165 +2000,165 @@ DEF_METHOD_5(Oai4Gate, "$_OAI4_", A, B, C, D, Y) RTLIL::Cell* RTLIL::Module::addPow(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, bool a_signed, bool b_signed, const std::string &src) { - RTLIL::Cell *cell = addCell(name, "$pow"); - cell->parameters["\\A_SIGNED"] = a_signed; - cell->parameters["\\B_SIGNED"] = b_signed; - cell->parameters["\\A_WIDTH"] = sig_a.size(); - cell->parameters["\\B_WIDTH"] = sig_b.size(); - cell->parameters["\\Y_WIDTH"] = sig_y.size(); - cell->setPort("\\A", sig_a); - cell->setPort("\\B", sig_b); - cell->setPort("\\Y", sig_y); + RTLIL::Cell *cell = addCell(name, ID($pow)); + cell->parameters[ID(A_SIGNED)] = a_signed; + cell->parameters[ID(B_SIGNED)] = b_signed; + cell->parameters[ID(A_WIDTH)] = sig_a.size(); + cell->parameters[ID(B_WIDTH)] = sig_b.size(); + cell->parameters[ID(Y_WIDTH)] = sig_y.size(); + cell->setPort(ID::A, sig_a); + cell->setPort(ID::B, sig_b); + cell->setPort(ID::Y, sig_y); cell->set_src_attribute(src); return cell; } RTLIL::Cell* RTLIL::Module::addSlice(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, RTLIL::Const offset, const std::string &src) { - RTLIL::Cell *cell = addCell(name, "$slice"); - cell->parameters["\\A_WIDTH"] = sig_a.size(); - cell->parameters["\\Y_WIDTH"] = sig_y.size(); - cell->parameters["\\OFFSET"] = offset; - cell->setPort("\\A", sig_a); - cell->setPort("\\Y", sig_y); + RTLIL::Cell *cell = addCell(name, ID($slice)); + cell->parameters[ID(A_WIDTH)] = sig_a.size(); + cell->parameters[ID(Y_WIDTH)] = sig_y.size(); + cell->parameters[ID(OFFSET)] = offset; + cell->setPort(ID::A, sig_a); + cell->setPort(ID::Y, sig_y); cell->set_src_attribute(src); return cell; } RTLIL::Cell* RTLIL::Module::addConcat(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, const std::string &src) { - RTLIL::Cell *cell = addCell(name, "$concat"); - cell->parameters["\\A_WIDTH"] = sig_a.size(); - cell->parameters["\\B_WIDTH"] = sig_b.size(); - cell->setPort("\\A", sig_a); - cell->setPort("\\B", sig_b); - cell->setPort("\\Y", sig_y); + RTLIL::Cell *cell = addCell(name, ID($concat)); + cell->parameters[ID(A_WIDTH)] = sig_a.size(); + cell->parameters[ID(B_WIDTH)] = sig_b.size(); + cell->setPort(ID::A, sig_a); + cell->setPort(ID::B, sig_b); + cell->setPort(ID::Y, sig_y); cell->set_src_attribute(src); return cell; } RTLIL::Cell* RTLIL::Module::addLut(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_y, RTLIL::Const lut, const std::string &src) { - RTLIL::Cell *cell = addCell(name, "$lut"); - cell->parameters["\\LUT"] = lut; - cell->parameters["\\WIDTH"] = sig_a.size(); - cell->setPort("\\A", sig_a); - cell->setPort("\\Y", sig_y); + RTLIL::Cell *cell = addCell(name, ID($lut)); + cell->parameters[ID(LUT)] = lut; + cell->parameters[ID(WIDTH)] = sig_a.size(); + cell->setPort(ID::A, sig_a); + cell->setPort(ID::Y, sig_y); cell->set_src_attribute(src); return cell; } RTLIL::Cell* RTLIL::Module::addTribuf(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_y, const std::string &src) { - RTLIL::Cell *cell = addCell(name, "$tribuf"); - cell->parameters["\\WIDTH"] = sig_a.size(); - cell->setPort("\\A", sig_a); - cell->setPort("\\EN", sig_en); - cell->setPort("\\Y", sig_y); + RTLIL::Cell *cell = addCell(name, ID($tribuf)); + cell->parameters[ID(WIDTH)] = sig_a.size(); + cell->setPort(ID::A, sig_a); + cell->setPort(ID(EN), sig_en); + cell->setPort(ID::Y, sig_y); cell->set_src_attribute(src); return cell; } RTLIL::Cell* RTLIL::Module::addAssert(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en, const std::string &src) { - RTLIL::Cell *cell = addCell(name, "$assert"); - cell->setPort("\\A", sig_a); - cell->setPort("\\EN", sig_en); + RTLIL::Cell *cell = addCell(name, ID($assert)); + cell->setPort(ID::A, sig_a); + cell->setPort(ID(EN), sig_en); cell->set_src_attribute(src); return cell; } RTLIL::Cell* RTLIL::Module::addAssume(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en, const std::string &src) { - RTLIL::Cell *cell = addCell(name, "$assume"); - cell->setPort("\\A", sig_a); - cell->setPort("\\EN", sig_en); + RTLIL::Cell *cell = addCell(name, ID($assume)); + cell->setPort(ID::A, sig_a); + cell->setPort(ID(EN), sig_en); cell->set_src_attribute(src); return cell; } RTLIL::Cell* RTLIL::Module::addLive(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en, const std::string &src) { - RTLIL::Cell *cell = addCell(name, "$live"); - cell->setPort("\\A", sig_a); - cell->setPort("\\EN", sig_en); + RTLIL::Cell *cell = addCell(name, ID($live)); + cell->setPort(ID::A, sig_a); + cell->setPort(ID(EN), sig_en); cell->set_src_attribute(src); return cell; } RTLIL::Cell* RTLIL::Module::addFair(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en, const std::string &src) { - RTLIL::Cell *cell = addCell(name, "$fair"); - cell->setPort("\\A", sig_a); - cell->setPort("\\EN", sig_en); + RTLIL::Cell *cell = addCell(name, ID($fair)); + cell->setPort(ID::A, sig_a); + cell->setPort(ID(EN), sig_en); cell->set_src_attribute(src); return cell; } RTLIL::Cell* RTLIL::Module::addCover(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en, const std::string &src) { - RTLIL::Cell *cell = addCell(name, "$cover"); - cell->setPort("\\A", sig_a); - cell->setPort("\\EN", sig_en); + RTLIL::Cell *cell = addCell(name, ID($cover)); + cell->setPort(ID::A, sig_a); + cell->setPort(ID(EN), sig_en); cell->set_src_attribute(src); return cell; } RTLIL::Cell* RTLIL::Module::addEquiv(RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y, const std::string &src) { - RTLIL::Cell *cell = addCell(name, "$equiv"); - cell->setPort("\\A", sig_a); - cell->setPort("\\B", sig_b); - cell->setPort("\\Y", sig_y); + RTLIL::Cell *cell = addCell(name, ID($equiv)); + cell->setPort(ID::A, sig_a); + cell->setPort(ID::B, sig_b); + cell->setPort(ID::Y, sig_y); cell->set_src_attribute(src); return cell; } RTLIL::Cell* RTLIL::Module::addSr(RTLIL::IdString name, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr, RTLIL::SigSpec sig_q, bool set_polarity, bool clr_polarity, const std::string &src) { - RTLIL::Cell *cell = addCell(name, "$sr"); - cell->parameters["\\SET_POLARITY"] = set_polarity; - cell->parameters["\\CLR_POLARITY"] = clr_polarity; - cell->parameters["\\WIDTH"] = sig_q.size(); - cell->setPort("\\SET", sig_set); - cell->setPort("\\CLR", sig_clr); - cell->setPort("\\Q", sig_q); + RTLIL::Cell *cell = addCell(name, ID($sr)); + cell->parameters[ID(SET_POLARITY)] = set_polarity; + cell->parameters[ID(CLR_POLARITY)] = clr_polarity; + cell->parameters[ID(WIDTH)] = sig_q.size(); + cell->setPort(ID(SET), sig_set); + cell->setPort(ID(CLR), sig_clr); + cell->setPort(ID(Q), sig_q); cell->set_src_attribute(src); return cell; } RTLIL::Cell* RTLIL::Module::addFf(RTLIL::IdString name, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, const std::string &src) { - RTLIL::Cell *cell = addCell(name, "$ff"); - cell->parameters["\\WIDTH"] = sig_q.size(); - cell->setPort("\\D", sig_d); - cell->setPort("\\Q", sig_q); + RTLIL::Cell *cell = addCell(name, ID($ff)); + cell->parameters[ID(WIDTH)] = sig_q.size(); + cell->setPort(ID(D), sig_d); + cell->setPort(ID(Q), sig_q); cell->set_src_attribute(src); return cell; } RTLIL::Cell* RTLIL::Module::addDff(RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity, const std::string &src) { - RTLIL::Cell *cell = addCell(name, "$dff"); - cell->parameters["\\CLK_POLARITY"] = clk_polarity; - cell->parameters["\\WIDTH"] = sig_q.size(); - cell->setPort("\\CLK", sig_clk); - cell->setPort("\\D", sig_d); - cell->setPort("\\Q", sig_q); + RTLIL::Cell *cell = addCell(name, ID($dff)); + cell->parameters[ID(CLK_POLARITY)] = clk_polarity; + cell->parameters[ID(WIDTH)] = sig_q.size(); + cell->setPort(ID(CLK), sig_clk); + cell->setPort(ID(D), sig_d); + cell->setPort(ID(Q), sig_q); cell->set_src_attribute(src); return cell; } RTLIL::Cell* RTLIL::Module::addDffe(RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity, bool en_polarity, const std::string &src) { - RTLIL::Cell *cell = addCell(name, "$dffe"); - cell->parameters["\\CLK_POLARITY"] = clk_polarity; - cell->parameters["\\EN_POLARITY"] = en_polarity; - cell->parameters["\\WIDTH"] = sig_q.size(); - cell->setPort("\\CLK", sig_clk); - cell->setPort("\\EN", sig_en); - cell->setPort("\\D", sig_d); - cell->setPort("\\Q", sig_q); + RTLIL::Cell *cell = addCell(name, ID($dffe)); + cell->parameters[ID(CLK_POLARITY)] = clk_polarity; + cell->parameters[ID(EN_POLARITY)] = en_polarity; + cell->parameters[ID(WIDTH)] = sig_q.size(); + cell->setPort(ID(CLK), sig_clk); + cell->setPort(ID(EN), sig_en); + cell->setPort(ID(D), sig_d); + cell->setPort(ID(Q), sig_q); cell->set_src_attribute(src); return cell; } @@ -1988,16 +2166,16 @@ RTLIL::Cell* RTLIL::Module::addDffe(RTLIL::IdString name, RTLIL::SigSpec sig_clk RTLIL::Cell* RTLIL::Module::addDffsr(RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity, bool set_polarity, bool clr_polarity, const std::string &src) { - RTLIL::Cell *cell = addCell(name, "$dffsr"); - cell->parameters["\\CLK_POLARITY"] = clk_polarity; - cell->parameters["\\SET_POLARITY"] = set_polarity; - cell->parameters["\\CLR_POLARITY"] = clr_polarity; - cell->parameters["\\WIDTH"] = sig_q.size(); - cell->setPort("\\CLK", sig_clk); - cell->setPort("\\SET", sig_set); - cell->setPort("\\CLR", sig_clr); - cell->setPort("\\D", sig_d); - cell->setPort("\\Q", sig_q); + RTLIL::Cell *cell = addCell(name, ID($dffsr)); + cell->parameters[ID(CLK_POLARITY)] = clk_polarity; + cell->parameters[ID(SET_POLARITY)] = set_polarity; + cell->parameters[ID(CLR_POLARITY)] = clr_polarity; + cell->parameters[ID(WIDTH)] = sig_q.size(); + cell->setPort(ID(CLK), sig_clk); + cell->setPort(ID(SET), sig_set); + cell->setPort(ID(CLR), sig_clr); + cell->setPort(ID(D), sig_d); + cell->setPort(ID(Q), sig_q); cell->set_src_attribute(src); return cell; } @@ -2005,27 +2183,27 @@ RTLIL::Cell* RTLIL::Module::addDffsr(RTLIL::IdString name, RTLIL::SigSpec sig_cl RTLIL::Cell* RTLIL::Module::addAdff(RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_arst, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, RTLIL::Const arst_value, bool clk_polarity, bool arst_polarity, const std::string &src) { - RTLIL::Cell *cell = addCell(name, "$adff"); - cell->parameters["\\CLK_POLARITY"] = clk_polarity; - cell->parameters["\\ARST_POLARITY"] = arst_polarity; - cell->parameters["\\ARST_VALUE"] = arst_value; - cell->parameters["\\WIDTH"] = sig_q.size(); - cell->setPort("\\CLK", sig_clk); - cell->setPort("\\ARST", sig_arst); - cell->setPort("\\D", sig_d); - cell->setPort("\\Q", sig_q); + RTLIL::Cell *cell = addCell(name, ID($adff)); + cell->parameters[ID(CLK_POLARITY)] = clk_polarity; + cell->parameters[ID(ARST_POLARITY)] = arst_polarity; + cell->parameters[ID(ARST_VALUE)] = arst_value; + cell->parameters[ID(WIDTH)] = sig_q.size(); + cell->setPort(ID(CLK), sig_clk); + cell->setPort(ID(ARST), sig_arst); + cell->setPort(ID(D), sig_d); + cell->setPort(ID(Q), sig_q); cell->set_src_attribute(src); return cell; } RTLIL::Cell* RTLIL::Module::addDlatch(RTLIL::IdString name, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool en_polarity, const std::string &src) { - RTLIL::Cell *cell = addCell(name, "$dlatch"); - cell->parameters["\\EN_POLARITY"] = en_polarity; - cell->parameters["\\WIDTH"] = sig_q.size(); - cell->setPort("\\EN", sig_en); - cell->setPort("\\D", sig_d); - cell->setPort("\\Q", sig_q); + RTLIL::Cell *cell = addCell(name, ID($dlatch)); + cell->parameters[ID(EN_POLARITY)] = en_polarity; + cell->parameters[ID(WIDTH)] = sig_q.size(); + cell->setPort(ID(EN), sig_en); + cell->setPort(ID(D), sig_d); + cell->setPort(ID(Q), sig_q); cell->set_src_attribute(src); return cell; } @@ -2033,25 +2211,25 @@ RTLIL::Cell* RTLIL::Module::addDlatch(RTLIL::IdString name, RTLIL::SigSpec sig_e RTLIL::Cell* RTLIL::Module::addDlatchsr(RTLIL::IdString name, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool en_polarity, bool set_polarity, bool clr_polarity, const std::string &src) { - RTLIL::Cell *cell = addCell(name, "$dlatchsr"); - cell->parameters["\\EN_POLARITY"] = en_polarity; - cell->parameters["\\SET_POLARITY"] = set_polarity; - cell->parameters["\\CLR_POLARITY"] = clr_polarity; - cell->parameters["\\WIDTH"] = sig_q.size(); - cell->setPort("\\EN", sig_en); - cell->setPort("\\SET", sig_set); - cell->setPort("\\CLR", sig_clr); - cell->setPort("\\D", sig_d); - cell->setPort("\\Q", sig_q); + RTLIL::Cell *cell = addCell(name, ID($dlatchsr)); + cell->parameters[ID(EN_POLARITY)] = en_polarity; + cell->parameters[ID(SET_POLARITY)] = set_polarity; + cell->parameters[ID(CLR_POLARITY)] = clr_polarity; + cell->parameters[ID(WIDTH)] = sig_q.size(); + cell->setPort(ID(EN), sig_en); + cell->setPort(ID(SET), sig_set); + cell->setPort(ID(CLR), sig_clr); + cell->setPort(ID(D), sig_d); + cell->setPort(ID(Q), sig_q); cell->set_src_attribute(src); return cell; } RTLIL::Cell* RTLIL::Module::addFfGate(RTLIL::IdString name, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, const std::string &src) { - RTLIL::Cell *cell = addCell(name, "$_FF_"); - cell->setPort("\\D", sig_d); - cell->setPort("\\Q", sig_q); + RTLIL::Cell *cell = addCell(name, ID($_FF_)); + cell->setPort(ID(D), sig_d); + cell->setPort(ID(Q), sig_q); cell->set_src_attribute(src); return cell; } @@ -2059,9 +2237,9 @@ RTLIL::Cell* RTLIL::Module::addFfGate(RTLIL::IdString name, RTLIL::SigSpec sig_d RTLIL::Cell* RTLIL::Module::addDffGate(RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity, const std::string &src) { RTLIL::Cell *cell = addCell(name, stringf("$_DFF_%c_", clk_polarity ? 'P' : 'N')); - cell->setPort("\\C", sig_clk); - cell->setPort("\\D", sig_d); - cell->setPort("\\Q", sig_q); + cell->setPort(ID(C), sig_clk); + cell->setPort(ID(D), sig_d); + cell->setPort(ID(Q), sig_q); cell->set_src_attribute(src); return cell; } @@ -2069,10 +2247,10 @@ RTLIL::Cell* RTLIL::Module::addDffGate(RTLIL::IdString name, RTLIL::SigSpec sig_ RTLIL::Cell* RTLIL::Module::addDffeGate(RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity, bool en_polarity, const std::string &src) { RTLIL::Cell *cell = addCell(name, stringf("$_DFFE_%c%c_", clk_polarity ? 'P' : 'N', en_polarity ? 'P' : 'N')); - cell->setPort("\\C", sig_clk); - cell->setPort("\\E", sig_en); - cell->setPort("\\D", sig_d); - cell->setPort("\\Q", sig_q); + cell->setPort(ID(C), sig_clk); + cell->setPort(ID(E), sig_en); + cell->setPort(ID(D), sig_d); + cell->setPort(ID(Q), sig_q); cell->set_src_attribute(src); return cell; } @@ -2081,11 +2259,11 @@ RTLIL::Cell* RTLIL::Module::addDffsrGate(RTLIL::IdString name, RTLIL::SigSpec si RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity, bool set_polarity, bool clr_polarity, const std::string &src) { RTLIL::Cell *cell = addCell(name, stringf("$_DFFSR_%c%c%c_", clk_polarity ? 'P' : 'N', set_polarity ? 'P' : 'N', clr_polarity ? 'P' : 'N')); - cell->setPort("\\C", sig_clk); - cell->setPort("\\S", sig_set); - cell->setPort("\\R", sig_clr); - cell->setPort("\\D", sig_d); - cell->setPort("\\Q", sig_q); + cell->setPort(ID(C), sig_clk); + cell->setPort(ID(S), sig_set); + cell->setPort(ID(R), sig_clr); + cell->setPort(ID(D), sig_d); + cell->setPort(ID(Q), sig_q); cell->set_src_attribute(src); return cell; } @@ -2094,10 +2272,10 @@ RTLIL::Cell* RTLIL::Module::addAdffGate(RTLIL::IdString name, RTLIL::SigSpec sig bool arst_value, bool clk_polarity, bool arst_polarity, const std::string &src) { RTLIL::Cell *cell = addCell(name, stringf("$_DFF_%c%c%c_", clk_polarity ? 'P' : 'N', arst_polarity ? 'P' : 'N', arst_value ? '1' : '0')); - cell->setPort("\\C", sig_clk); - cell->setPort("\\R", sig_arst); - cell->setPort("\\D", sig_d); - cell->setPort("\\Q", sig_q); + cell->setPort(ID(C), sig_clk); + cell->setPort(ID(R), sig_arst); + cell->setPort(ID(D), sig_d); + cell->setPort(ID(Q), sig_q); cell->set_src_attribute(src); return cell; } @@ -2105,9 +2283,9 @@ RTLIL::Cell* RTLIL::Module::addAdffGate(RTLIL::IdString name, RTLIL::SigSpec sig RTLIL::Cell* RTLIL::Module::addDlatchGate(RTLIL::IdString name, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool en_polarity, const std::string &src) { RTLIL::Cell *cell = addCell(name, stringf("$_DLATCH_%c_", en_polarity ? 'P' : 'N')); - cell->setPort("\\E", sig_en); - cell->setPort("\\D", sig_d); - cell->setPort("\\Q", sig_q); + cell->setPort(ID(E), sig_en); + cell->setPort(ID(D), sig_d); + cell->setPort(ID(Q), sig_q); cell->set_src_attribute(src); return cell; } @@ -2116,11 +2294,11 @@ RTLIL::Cell* RTLIL::Module::addDlatchsrGate(RTLIL::IdString name, RTLIL::SigSpec RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool en_polarity, bool set_polarity, bool clr_polarity, const std::string &src) { RTLIL::Cell *cell = addCell(name, stringf("$_DLATCHSR_%c%c%c_", en_polarity ? 'P' : 'N', set_polarity ? 'P' : 'N', clr_polarity ? 'P' : 'N')); - cell->setPort("\\E", sig_en); - cell->setPort("\\S", sig_set); - cell->setPort("\\R", sig_clr); - cell->setPort("\\D", sig_d); - cell->setPort("\\Q", sig_q); + cell->setPort(ID(E), sig_en); + cell->setPort(ID(S), sig_set); + cell->setPort(ID(R), sig_clr); + cell->setPort(ID(D), sig_d); + cell->setPort(ID(Q), sig_q); cell->set_src_attribute(src); return cell; } @@ -2128,9 +2306,9 @@ RTLIL::Cell* RTLIL::Module::addDlatchsrGate(RTLIL::IdString name, RTLIL::SigSpec RTLIL::SigSpec RTLIL::Module::Anyconst(RTLIL::IdString name, int width, const std::string &src) { RTLIL::SigSpec sig = addWire(NEW_ID, width); - Cell *cell = addCell(name, "$anyconst"); - cell->setParam("\\WIDTH", width); - cell->setPort("\\Y", sig); + Cell *cell = addCell(name, ID($anyconst)); + cell->setParam(ID(WIDTH), width); + cell->setPort(ID::Y, sig); cell->set_src_attribute(src); return sig; } @@ -2138,9 +2316,9 @@ RTLIL::SigSpec RTLIL::Module::Anyconst(RTLIL::IdString name, int width, const st RTLIL::SigSpec RTLIL::Module::Anyseq(RTLIL::IdString name, int width, const std::string &src) { RTLIL::SigSpec sig = addWire(NEW_ID, width); - Cell *cell = addCell(name, "$anyseq"); - cell->setParam("\\WIDTH", width); - cell->setPort("\\Y", sig); + Cell *cell = addCell(name, ID($anyseq)); + cell->setParam(ID(WIDTH), width); + cell->setPort(ID::Y, sig); cell->set_src_attribute(src); return sig; } @@ -2148,9 +2326,9 @@ RTLIL::SigSpec RTLIL::Module::Anyseq(RTLIL::IdString name, int width, const std: RTLIL::SigSpec RTLIL::Module::Allconst(RTLIL::IdString name, int width, const std::string &src) { RTLIL::SigSpec sig = addWire(NEW_ID, width); - Cell *cell = addCell(name, "$allconst"); - cell->setParam("\\WIDTH", width); - cell->setPort("\\Y", sig); + Cell *cell = addCell(name, ID($allconst)); + cell->setParam(ID(WIDTH), width); + cell->setPort(ID::Y, sig); cell->set_src_attribute(src); return sig; } @@ -2158,9 +2336,9 @@ RTLIL::SigSpec RTLIL::Module::Allconst(RTLIL::IdString name, int width, const st RTLIL::SigSpec RTLIL::Module::Allseq(RTLIL::IdString name, int width, const std::string &src) { RTLIL::SigSpec sig = addWire(NEW_ID, width); - Cell *cell = addCell(name, "$allseq"); - cell->setParam("\\WIDTH", width); - cell->setPort("\\Y", sig); + Cell *cell = addCell(name, ID($allseq)); + cell->setParam(ID(WIDTH), width); + cell->setPort(ID::Y, sig); cell->set_src_attribute(src); return sig; } @@ -2168,8 +2346,8 @@ RTLIL::SigSpec RTLIL::Module::Allseq(RTLIL::IdString name, int width, const std: RTLIL::SigSpec RTLIL::Module::Initstate(RTLIL::IdString name, const std::string &src) { RTLIL::SigSpec sig = addWire(NEW_ID); - Cell *cell = addCell(name, "$initstate"); - cell->setPort("\\Y", sig); + Cell *cell = addCell(name, ID($initstate)); + cell->setPort(ID::Y, sig); cell->set_src_attribute(src); return sig; } @@ -2187,8 +2365,27 @@ RTLIL::Wire::Wire() port_input = false; port_output = false; upto = false; + +#ifdef WITH_PYTHON + RTLIL::Wire::get_all_wires()->insert(std::pair<unsigned int, RTLIL::Wire*>(hashidx_, this)); +#endif +} + +RTLIL::Wire::~Wire() +{ +#ifdef WITH_PYTHON + RTLIL::Wire::get_all_wires()->erase(hashidx_); +#endif } +#ifdef WITH_PYTHON +static std::map<unsigned int, RTLIL::Wire*> all_wires; +std::map<unsigned int, RTLIL::Wire*> *RTLIL::Wire::get_all_wires(void) +{ + return &all_wires; +} +#endif + RTLIL::Memory::Memory() { static unsigned int hashidx_count = 123456789; @@ -2198,6 +2395,9 @@ RTLIL::Memory::Memory() width = 1; start_offset = 0; size = 0; +#ifdef WITH_PYTHON + RTLIL::Memory::get_all_memorys()->insert(std::pair<unsigned int, RTLIL::Memory*>(hashidx_, this)); +#endif } RTLIL::Cell::Cell() : module(nullptr) @@ -2208,8 +2408,27 @@ RTLIL::Cell::Cell() : module(nullptr) // log("#memtrace# %p\n", this); memhasher(); + +#ifdef WITH_PYTHON + RTLIL::Cell::get_all_cells()->insert(std::pair<unsigned int, RTLIL::Cell*>(hashidx_, this)); +#endif +} + +RTLIL::Cell::~Cell() +{ +#ifdef WITH_PYTHON + RTLIL::Cell::get_all_cells()->erase(hashidx_); +#endif } +#ifdef WITH_PYTHON +static std::map<unsigned int, RTLIL::Cell*> all_cells; +std::map<unsigned int, RTLIL::Cell*> *RTLIL::Cell::get_all_cells(void) +{ + return &all_cells; +} +#endif + bool RTLIL::Cell::hasPort(RTLIL::IdString portname) const { return connections_.count(portname) != 0; @@ -2345,57 +2564,60 @@ void RTLIL::Cell::check() void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed) { - if (type.substr(0, 1) != "$" || type.substr(0, 2) == "$_" || type.substr(0, 8) == "$paramod" || - type.substr(0, 9) == "$verific$" || type.substr(0, 7) == "$array:" || type.substr(0, 8) == "$extern:") + if (!type.begins_with("$") || type.begins_with("$_") || type.begins_with("$paramod") || type.begins_with("$fmcombine") || + type.begins_with("$verific$") || type.begins_with("$array:") || type.begins_with("$extern:")) return; - if (type == "$mux" || type == "$pmux") { - parameters["\\WIDTH"] = GetSize(connections_["\\Y"]); - if (type == "$pmux") - parameters["\\S_WIDTH"] = GetSize(connections_["\\S"]); + if (type == ID($mux) || type == ID($pmux)) { + parameters[ID(WIDTH)] = GetSize(connections_[ID::Y]); + if (type == ID($pmux)) + parameters[ID(S_WIDTH)] = GetSize(connections_[ID(S)]); check(); return; } - if (type == "$lut" || type == "$sop") { - parameters["\\WIDTH"] = GetSize(connections_["\\A"]); + if (type == ID($lut) || type == ID($sop)) { + parameters[ID(WIDTH)] = GetSize(connections_[ID::A]); return; } - if (type == "$fa") { - parameters["\\WIDTH"] = GetSize(connections_["\\Y"]); + if (type == ID($fa)) { + parameters[ID(WIDTH)] = GetSize(connections_[ID::Y]); return; } - if (type == "$lcu") { - parameters["\\WIDTH"] = GetSize(connections_["\\CO"]); + if (type == ID($lcu)) { + parameters[ID(WIDTH)] = GetSize(connections_[ID(CO)]); return; } - bool signedness_ab = !type.in("$slice", "$concat", "$macc"); + bool signedness_ab = !type.in(ID($slice), ID($concat), ID($macc)); - if (connections_.count("\\A")) { + if (connections_.count(ID::A)) { if (signedness_ab) { if (set_a_signed) - parameters["\\A_SIGNED"] = true; - else if (parameters.count("\\A_SIGNED") == 0) - parameters["\\A_SIGNED"] = false; + parameters[ID(A_SIGNED)] = true; + else if (parameters.count(ID(A_SIGNED)) == 0) + parameters[ID(A_SIGNED)] = false; } - parameters["\\A_WIDTH"] = GetSize(connections_["\\A"]); + parameters[ID(A_WIDTH)] = GetSize(connections_[ID::A]); } - if (connections_.count("\\B")) { + if (connections_.count(ID::B)) { if (signedness_ab) { if (set_b_signed) - parameters["\\B_SIGNED"] = true; - else if (parameters.count("\\B_SIGNED") == 0) - parameters["\\B_SIGNED"] = false; + parameters[ID(B_SIGNED)] = true; + else if (parameters.count(ID(B_SIGNED)) == 0) + parameters[ID(B_SIGNED)] = false; } - parameters["\\B_WIDTH"] = GetSize(connections_["\\B"]); + parameters[ID(B_WIDTH)] = GetSize(connections_[ID::B]); } - if (connections_.count("\\Y")) - parameters["\\Y_WIDTH"] = GetSize(connections_["\\Y"]); + if (connections_.count(ID::Y)) + parameters[ID(Y_WIDTH)] = GetSize(connections_[ID::Y]); + + if (connections_.count(ID(Q))) + parameters[ID(WIDTH)] = GetSize(connections_[ID(Q)]); check(); } @@ -2466,6 +2688,14 @@ RTLIL::SigChunk::SigChunk(RTLIL::SigBit bit) width = 1; } +RTLIL::SigChunk::SigChunk(const RTLIL::SigChunk &sigchunk) : data(sigchunk.data) +{ + wire = sigchunk.wire; + data = sigchunk.data; + width = sigchunk.width; + offset = sigchunk.offset; +} + RTLIL::SigChunk RTLIL::SigChunk::extract(int offset, int length) const { RTLIL::SigChunk ret; @@ -3219,7 +3449,7 @@ void RTLIL::SigSpec::extend_u0(int width, bool is_signed) remove(width, width_ - width); if (width_ < width) { - RTLIL::SigBit padding = width_ > 0 ? (*this)[width_ - 1] : RTLIL::State::S0; + RTLIL::SigBit padding = width_ > 0 ? (*this)[width_ - 1] : RTLIL::State::Sx; if (!is_signed) padding = RTLIL::State::S0; while (width_ < width) @@ -3325,7 +3555,7 @@ bool RTLIL::SigSpec::operator ==(const RTLIL::SigSpec &other) const pack(); other.pack(); - if (chunks_.size() != chunks_.size()) + if (chunks_.size() != other.chunks_.size()) return false; updhash(); @@ -3780,6 +4010,11 @@ RTLIL::CaseRule::~CaseRule() delete *it; } +bool RTLIL::CaseRule::empty() const +{ + return actions.empty() && switches.empty(); +} + RTLIL::CaseRule *RTLIL::CaseRule::clone() const { RTLIL::CaseRule *new_caserule = new RTLIL::CaseRule; @@ -3796,6 +4031,11 @@ RTLIL::SwitchRule::~SwitchRule() delete *it; } +bool RTLIL::SwitchRule::empty() const +{ + return cases.empty(); +} + RTLIL::SwitchRule *RTLIL::SwitchRule::clone() const { RTLIL::SwitchRule *new_switchrule = new RTLIL::SwitchRule; @@ -3840,5 +4080,15 @@ RTLIL::Process *RTLIL::Process::clone() const return new_proc; } +#ifdef WITH_PYTHON +RTLIL::Memory::~Memory() +{ + RTLIL::Memory::get_all_memorys()->erase(hashidx_); +} +static std::map<unsigned int, RTLIL::Memory*> all_memorys; +std::map<unsigned int, RTLIL::Memory*> *RTLIL::Memory::get_all_memorys(void) +{ + return &all_memorys; +} +#endif YOSYS_NAMESPACE_END - diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 54d0b8c22..c08653b65 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1,4 +1,4 @@ -/* +/* -*- c++ -*- * yosys -- Yosys Open SYnthesis Suite * * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> @@ -50,7 +50,7 @@ namespace RTLIL CONST_FLAG_NONE = 0, CONST_FLAG_STRING = 1, CONST_FLAG_SIGNED = 2, // only used for parameters - CONST_FLAG_REAL = 4 // unused -- to be used for parameters + CONST_FLAG_REAL = 4 // only used for parameters }; struct Const; @@ -76,6 +76,11 @@ namespace RTLIL struct IdString { + #undef YOSYS_XTRACE_GET_PUT + #undef YOSYS_SORT_ID_FREE_LIST + #undef YOSYS_USE_STICKY_IDS + #undef YOSYS_NO_IDS_REFCNT + // the global id string cache static struct destruct_guard_t { @@ -84,33 +89,89 @@ namespace RTLIL ~destruct_guard_t() { ok = false; } } destruct_guard; - static std::vector<int> global_refcount_storage_; static std::vector<char*> global_id_storage_; static dict<char*, int, hash_cstr_ops> global_id_index_; + #ifndef YOSYS_NO_IDS_REFCNT + static std::vector<int> global_refcount_storage_; static std::vector<int> global_free_idx_list_; + #endif + + #ifdef YOSYS_USE_STICKY_IDS + static int last_created_idx_ptr_; + static int last_created_idx_[8]; + #endif + + static inline void xtrace_db_dump() + { + #ifdef YOSYS_XTRACE_GET_PUT + for (int idx = 0; idx < GetSize(global_id_storage_); idx++) + { + if (global_id_storage_.at(idx) == nullptr) + log("#X# DB-DUMP index %d: FREE\n", idx); + else + log("#X# DB-DUMP index %d: '%s' (ref %d)\n", idx, global_id_storage_.at(idx), global_refcount_storage_.at(idx)); + } + #endif + } + + static inline void checkpoint() + { + #ifdef YOSYS_USE_STICKY_IDS + last_created_idx_ptr_ = 0; + for (int i = 0; i < 8; i++) { + if (last_created_idx_[i]) + put_reference(last_created_idx_[i]); + last_created_idx_[i] = 0; + } + #endif + #ifdef YOSYS_SORT_ID_FREE_LIST + std::sort(global_free_idx_list_.begin(), global_free_idx_list_.end(), std::greater<int>()); + #endif + } static inline int get_reference(int idx) { - global_refcount_storage_.at(idx)++; + if (idx) { + #ifndef YOSYS_NO_IDS_REFCNT + global_refcount_storage_[idx]++; + #endif + #ifdef YOSYS_XTRACE_GET_PUT + if (yosys_xtrace) + log("#X# GET-BY-INDEX '%s' (index %d, refcount %d)\n", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx)); + #endif + } return idx; } - static inline int get_reference(const char *p) + static int get_reference(const char *p) { log_assert(destruct_guard.ok); - if (p[0]) { - log_assert(p[1] != 0); - log_assert(p[0] == '$' || p[0] == '\\'); - } + if (!p[0]) + return 0; + + log_assert(p[0] == '$' || p[0] == '\\'); + log_assert(p[1] != 0); auto it = global_id_index_.find((char*)p); if (it != global_id_index_.end()) { + #ifndef YOSYS_NO_IDS_REFCNT global_refcount_storage_.at(it->second)++; + #endif + #ifdef YOSYS_XTRACE_GET_PUT + if (yosys_xtrace) + log("#X# GET-BY-NAME '%s' (index %d, refcount %d)\n", global_id_storage_.at(it->second), it->second, global_refcount_storage_.at(it->second)); + #endif return it->second; } + #ifndef YOSYS_NO_IDS_REFCNT if (global_free_idx_list_.empty()) { + if (global_id_storage_.empty()) { + global_refcount_storage_.push_back(0); + global_id_storage_.push_back((char*)""); + global_id_index_[global_id_storage_.back()] = 0; + } log_assert(global_id_storage_.size() < 0x40000000); global_free_idx_list_.push_back(global_id_storage_.size()); global_id_storage_.push_back(nullptr); @@ -122,33 +183,59 @@ namespace RTLIL global_id_storage_.at(idx) = strdup(p); global_id_index_[global_id_storage_.at(idx)] = idx; global_refcount_storage_.at(idx)++; - - // Avoid Create->Delete->Create pattern - static IdString last_created_id; - put_reference(last_created_id.index_); - last_created_id.index_ = idx; - get_reference(last_created_id.index_); + #else + if (global_id_storage_.empty()) { + global_id_storage_.push_back((char*)""); + global_id_index_[global_id_storage_.back()] = 0; + } + int idx = global_id_storage_.size(); + global_id_storage_.push_back(strdup(p)); + global_id_index_[global_id_storage_.back()] = idx; + #endif if (yosys_xtrace) { log("#X# New IdString '%s' with index %d.\n", p, idx); log_backtrace("-X- ", yosys_xtrace-1); } + #ifdef YOSYS_XTRACE_GET_PUT + if (yosys_xtrace) + log("#X# GET-BY-NAME '%s' (index %d, refcount %d)\n", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx)); + #endif + + #ifdef YOSYS_USE_STICKY_IDS + // Avoid Create->Delete->Create pattern + if (last_created_idx_[last_created_idx_ptr_]) + put_reference(last_created_idx_[last_created_idx_ptr_]); + last_created_idx_[last_created_idx_ptr_] = idx; + get_reference(last_created_idx_[last_created_idx_ptr_]); + last_created_idx_ptr_ = (last_created_idx_ptr_ + 1) & 7; + #endif + return idx; } + #ifndef YOSYS_NO_IDS_REFCNT static inline void put_reference(int idx) { // put_reference() may be called from destructors after the destructor of // global_refcount_storage_ has been run. in this case we simply do nothing. - if (!destruct_guard.ok) + if (!destruct_guard.ok || !idx) return; - log_assert(global_refcount_storage_.at(idx) > 0); + #ifdef YOSYS_XTRACE_GET_PUT + if (yosys_xtrace) { + log("#X# PUT '%s' (index %d, refcount %d)\n", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx)); + } + #endif + + int &refcount = global_refcount_storage_[idx]; - if (--global_refcount_storage_.at(idx) != 0) + if (--refcount > 0) return; + log_assert(refcount == 0); + if (yosys_xtrace) { log("#X# Removed IdString '%s' with index %d.\n", global_id_storage_.at(idx), idx); log_backtrace("-X- ", yosys_xtrace-1); @@ -159,46 +246,50 @@ namespace RTLIL global_id_storage_.at(idx) = nullptr; global_free_idx_list_.push_back(idx); } + #else + static inline void put_reference(int) { } + #endif // the actual IdString object is just is a single int int index_; - IdString() : index_(get_reference("")) { } - IdString(const char *str) : index_(get_reference(str)) { } - IdString(const IdString &str) : index_(get_reference(str.index_)) { } - IdString(const std::string &str) : index_(get_reference(str.c_str())) { } - ~IdString() { put_reference(index_); } + inline IdString() : index_(0) { } + inline IdString(const char *str) : index_(get_reference(str)) { } + inline IdString(const IdString &str) : index_(get_reference(str.index_)) { } + inline IdString(IdString &&str) : index_(str.index_) { str.index_ = 0; } + inline IdString(const std::string &str) : index_(get_reference(str.c_str())) { } + inline ~IdString() { put_reference(index_); } - void operator=(const IdString &rhs) { + inline void operator=(const IdString &rhs) { put_reference(index_); index_ = get_reference(rhs.index_); } - void operator=(const char *rhs) { + inline void operator=(const char *rhs) { IdString id(rhs); *this = id; } - void operator=(const std::string &rhs) { + inline void operator=(const std::string &rhs) { IdString id(rhs); *this = id; } - const char *c_str() const { + inline const char *c_str() const { return global_id_storage_.at(index_); } - std::string str() const { + inline std::string str() const { return std::string(global_id_storage_.at(index_)); } - bool operator<(const IdString &rhs) const { + inline bool operator<(const IdString &rhs) const { return index_ < rhs.index_; } - bool operator==(const IdString &rhs) const { return index_ == rhs.index_; } - bool operator!=(const IdString &rhs) const { return index_ != rhs.index_; } + inline bool operator==(const IdString &rhs) const { return index_ == rhs.index_; } + inline bool operator!=(const IdString &rhs) const { return index_ != rhs.index_; } // The methods below are just convenience functions for better compatibility with std::string. @@ -222,8 +313,24 @@ namespace RTLIL return std::string(c_str() + pos, len); } + int compare(size_t pos, size_t len, const char* s) const { + return strncmp(c_str()+pos, s, len); + } + + bool begins_with(const char* prefix) const { + size_t len = strlen(prefix); + if (size() < len) return false; + return compare(0, len, prefix) == 0; + } + + bool ends_with(const char* suffix) const { + size_t len = strlen(suffix); + if (size() < len) return false; + return compare(size()-len, len, suffix) == 0; + } + size_t size() const { - return str().size(); + return strlen(c_str()); } bool empty() const { @@ -262,6 +369,14 @@ namespace RTLIL bool in(const pool<IdString> &rhs) const { return rhs.count(*this) != 0; } }; + namespace ID { + // defined in rtlil.cc, initialized in yosys.cc + extern IdString A, B, Y; + extern IdString keep; + extern IdString whitebox; + extern IdString blackbox; + }; + static inline std::string escape_id(std::string str) { if (str.size() > 0 && str[0] != '\\' && str[0] != '$') return "\\" + str; @@ -354,8 +469,12 @@ namespace RTLIL // It maintains a reference counter that is used to make sure that the container is not modified while being iterated over. template<typename T> - struct ObjIterator - { + struct ObjIterator { + using iterator_category = std::forward_iterator_tag; + using value_type = T; + using difference_type = ptrdiff_t; + using pointer = T*; + using reference = T&; typename dict<RTLIL::IdString, T>::iterator it; dict<RTLIL::IdString, T> *list_p; int *refcount_p; @@ -408,13 +527,25 @@ namespace RTLIL return it != other.it; } - inline void operator++() { + + inline bool operator==(const RTLIL::ObjIterator<T> &other) const { + return !(*this != other); + } + + inline ObjIterator<T>& operator++() { log_assert(list_p != nullptr); if (++it == list_p->end()) { (*refcount_p)--; list_p = nullptr; refcount_p = nullptr; } + return *this; + } + + inline const ObjIterator<T> operator++(int) { + ObjIterator<T> result(*this); + ++(*this); + return result; } }; @@ -463,6 +594,8 @@ struct RTLIL::Const Const(RTLIL::State bit, int width = 1); Const(const std::vector<RTLIL::State> &bits) : bits(bits) { flags = CONST_FLAG_NONE; } Const(const std::vector<bool> &bits); + Const(const RTLIL::Const &c); + RTLIL::Const &operator =(const RTLIL::Const &other) = default; bool operator <(const RTLIL::Const &other) const; bool operator ==(const RTLIL::Const &other) const; @@ -492,6 +625,14 @@ struct RTLIL::Const return ret; } + void extu(int width) { + bits.resize(width, RTLIL::State::S0); + } + + void exts(int width) { + bits.resize(width, bits.empty() ? RTLIL::State::Sx : bits.back()); + } + inline unsigned int hash() const { unsigned int h = mkhash_init; for (auto b : bits) @@ -504,9 +645,13 @@ struct RTLIL::AttrObject { dict<RTLIL::IdString, RTLIL::Const> attributes; - void set_bool_attribute(RTLIL::IdString id); + void set_bool_attribute(RTLIL::IdString id, bool value=true); bool get_bool_attribute(RTLIL::IdString id) const; + bool get_blackbox_attribute(bool ignore_wb=false) const { + return get_bool_attribute(ID::blackbox) || (!ignore_wb && get_bool_attribute(ID::whitebox)); + } + void set_strpool_attribute(RTLIL::IdString id, const pool<string> &data); void add_strpool_attribute(RTLIL::IdString id, const pool<string> &data); pool<string> get_strpool_attribute(RTLIL::IdString id) const; @@ -529,8 +674,11 @@ struct RTLIL::SigChunk SigChunk(int val, int width = 32); SigChunk(RTLIL::State bit, int width = 1); SigChunk(RTLIL::SigBit bit); + SigChunk(const RTLIL::SigChunk &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; @@ -553,6 +701,8 @@ struct RTLIL::SigBit SigBit(const RTLIL::SigChunk &chunk); SigBit(const RTLIL::SigChunk &chunk, int index); SigBit(const RTLIL::SigSpec &sig); + SigBit(const RTLIL::SigBit &sigbit); + RTLIL::SigBit &operator =(const RTLIL::SigBit &other) = default; bool operator <(const RTLIL::SigBit &other) const; bool operator ==(const RTLIL::SigBit &other) const; @@ -687,6 +837,7 @@ public: RTLIL::SigSpec extract(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec *other = NULL) const; RTLIL::SigSpec extract(const pool<RTLIL::SigBit> &pattern, const RTLIL::SigSpec *other = NULL) const; RTLIL::SigSpec extract(int offset, int length = 1) const; + RTLIL::SigSpec extract_end(int offset) const { return extract(offset, width_ - offset); } void append(const RTLIL::SigSpec &signal); void append_bit(const RTLIL::SigBit &bit); @@ -733,6 +884,7 @@ public: operator std::vector<RTLIL::SigChunk>() const { return chunks(); } operator std::vector<RTLIL::SigBit>() const { return bits(); } + RTLIL::SigBit at(int offset, const RTLIL::SigBit &defval) { return offset < width_ ? (*this)[offset] : defval; } unsigned int hash() const { if (!hash_) updhash(); return hash_; }; @@ -874,9 +1026,13 @@ struct RTLIL::Design } } + std::vector<RTLIL::Module*> selected_modules() const; std::vector<RTLIL::Module*> selected_whole_modules() const; std::vector<RTLIL::Module*> selected_whole_modules_warn() const; +#ifdef WITH_PYTHON + static std::map<unsigned int, RTLIL::Design*> *get_all_designs(void); +#endif }; struct RTLIL::Module : public RTLIL::AttrObject @@ -907,11 +1063,14 @@ public: Module(); virtual ~Module(); virtual RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, bool mayfail = false); + virtual RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, dict<RTLIL::IdString, RTLIL::Module*> interfaces, dict<RTLIL::IdString, RTLIL::IdString> modports, bool mayfail = false); virtual size_t count_id(RTLIL::IdString id); + virtual void reprocess_module(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Module *> local_interfaces); virtual void sort(); virtual void check(); virtual void optimize(); + virtual void makeblackbox(); void connect(const RTLIL::SigSig &conn); void connect(const RTLIL::SigSpec &lhs, const RTLIL::SigSpec &rhs); @@ -922,6 +1081,7 @@ public: void fixup_ports(); template<typename T> void rewrite_sigspecs(T &functor); + template<typename T> void rewrite_sigspecs2(T &functor); void cloneInto(RTLIL::Module *new_mod) const; virtual RTLIL::Module *clone() const; @@ -1045,6 +1205,7 @@ public: RTLIL::Cell* addAndnotGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y, const std::string &src = ""); RTLIL::Cell* addOrnotGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_y, const std::string &src = ""); RTLIL::Cell* addMuxGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_s, RTLIL::SigBit sig_y, const std::string &src = ""); + RTLIL::Cell* addNmuxGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_s, RTLIL::SigBit sig_y, const std::string &src = ""); RTLIL::Cell* addAoi3Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_y, const std::string &src = ""); RTLIL::Cell* addOai3Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_y, const std::string &src = ""); RTLIL::Cell* addAoi4Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_d, RTLIL::SigBit sig_y, const std::string &src = ""); @@ -1120,6 +1281,7 @@ public: RTLIL::SigBit AndnotGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, const std::string &src = ""); RTLIL::SigBit OrnotGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, const std::string &src = ""); RTLIL::SigBit MuxGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_s, const std::string &src = ""); + RTLIL::SigBit NmuxGate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_s, const std::string &src = ""); RTLIL::SigBit Aoi3Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, const std::string &src = ""); RTLIL::SigBit Oai3Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, const std::string &src = ""); RTLIL::SigBit Aoi4Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_d, const std::string &src = ""); @@ -1130,6 +1292,10 @@ public: RTLIL::SigSpec Allconst (RTLIL::IdString name, int width = 1, const std::string &src = ""); RTLIL::SigSpec Allseq (RTLIL::IdString name, int width = 1, const std::string &src = ""); RTLIL::SigSpec Initstate (RTLIL::IdString name, const std::string &src = ""); + +#ifdef WITH_PYTHON + static std::map<unsigned int, RTLIL::Module*> *get_all_modules(void); +#endif }; struct RTLIL::Wire : public RTLIL::AttrObject @@ -1141,7 +1307,7 @@ protected: // use module->addWire() and module->remove() to create or destroy wires friend struct RTLIL::Module; Wire(); - ~Wire() { }; + ~Wire(); public: // do not simply copy wires @@ -1152,6 +1318,10 @@ public: RTLIL::IdString name; int width, start_offset, port_id; bool port_input, port_output, upto; + +#ifdef WITH_PYTHON + static std::map<unsigned int, RTLIL::Wire*> *get_all_wires(void); +#endif }; struct RTLIL::Memory : public RTLIL::AttrObject @@ -1163,6 +1333,10 @@ struct RTLIL::Memory : public RTLIL::AttrObject RTLIL::IdString name; int width, start_offset, size; +#ifdef WITH_PYTHON + ~Memory(); + static std::map<unsigned int, RTLIL::Memory*> *get_all_memorys(void); +#endif }; struct RTLIL::Cell : public RTLIL::AttrObject @@ -1174,6 +1348,7 @@ protected: // use module->addCell() and module->remove() to create or destroy cells friend struct RTLIL::Module; Cell(); + ~Cell(); public: // do not simply copy cells @@ -1209,14 +1384,19 @@ public: void fixup_parameters(bool set_a_signed = false, bool set_b_signed = false); bool has_keep_attr() const { - return get_bool_attribute("\\keep") || (module && module->design && module->design->module(type) && - module->design->module(type)->get_bool_attribute("\\keep")); + return get_bool_attribute(ID::keep) || (module && module->design && module->design->module(type) && + module->design->module(type)->get_bool_attribute(ID::keep)); } template<typename T> void rewrite_sigspecs(T &functor); + template<typename T> void rewrite_sigspecs2(T &functor); + +#ifdef WITH_PYTHON + static std::map<unsigned int, RTLIL::Cell*> *get_all_cells(void); +#endif }; -struct RTLIL::CaseRule +struct RTLIL::CaseRule : public RTLIL::AttrObject { std::vector<RTLIL::SigSpec> compare; std::vector<RTLIL::SigSig> actions; @@ -1225,7 +1405,10 @@ struct RTLIL::CaseRule ~CaseRule(); void optimize(); + bool empty() const; + template<typename T> void rewrite_sigspecs(T &functor); + template<typename T> void rewrite_sigspecs2(T &functor); RTLIL::CaseRule *clone() const; }; @@ -1236,7 +1419,10 @@ struct RTLIL::SwitchRule : public RTLIL::AttrObject ~SwitchRule(); + bool empty() const; + template<typename T> void rewrite_sigspecs(T &functor); + template<typename T> void rewrite_sigspecs2(T &functor); RTLIL::SwitchRule *clone() const; }; @@ -1247,6 +1433,7 @@ struct RTLIL::SyncRule std::vector<RTLIL::SigSig> actions; template<typename T> void rewrite_sigspecs(T &functor); + template<typename T> void rewrite_sigspecs2(T &functor); RTLIL::SyncRule *clone() const; }; @@ -1259,24 +1446,26 @@ struct RTLIL::Process : public RTLIL::AttrObject ~Process(); template<typename T> void rewrite_sigspecs(T &functor); + template<typename T> void rewrite_sigspecs2(T &functor); RTLIL::Process *clone() const; }; inline RTLIL::SigBit::SigBit() : wire(NULL), data(RTLIL::State::S0) { } inline RTLIL::SigBit::SigBit(RTLIL::State bit) : wire(NULL), data(bit) { } -inline RTLIL::SigBit::SigBit(bool bit) : wire(NULL), data(bit ? RTLIL::S1 : RTLIL::S0) { } +inline RTLIL::SigBit::SigBit(bool bit) : wire(NULL), data(bit ? State::S1 : State::S0) { } inline RTLIL::SigBit::SigBit(RTLIL::Wire *wire) : wire(wire), offset(0) { log_assert(wire && wire->width == 1); } inline RTLIL::SigBit::SigBit(RTLIL::Wire *wire, int offset) : wire(wire), offset(offset) { log_assert(wire != nullptr); } inline RTLIL::SigBit::SigBit(const RTLIL::SigChunk &chunk) : wire(chunk.wire) { log_assert(chunk.width == 1); if (wire) offset = chunk.offset; else data = chunk.data[0]; } inline RTLIL::SigBit::SigBit(const RTLIL::SigChunk &chunk, int index) : wire(chunk.wire) { if (wire) offset = chunk.offset + index; else data = chunk.data[index]; } +inline RTLIL::SigBit::SigBit(const RTLIL::SigBit &sigbit) : wire(sigbit.wire), data(sigbit.data){if(wire) offset = sigbit.offset;} inline bool RTLIL::SigBit::operator<(const RTLIL::SigBit &other) const { if (wire == other.wire) return wire ? (offset < other.offset) : (data < other.data); if (wire != nullptr && other.wire != nullptr) return wire->name < other.wire->name; - return wire < other.wire; + return (wire != nullptr) < (other.wire != nullptr); } inline bool RTLIL::SigBit::operator==(const RTLIL::SigBit &other) const { @@ -1320,12 +1509,30 @@ void RTLIL::Module::rewrite_sigspecs(T &functor) } template<typename T> +void RTLIL::Module::rewrite_sigspecs2(T &functor) +{ + for (auto &it : cells_) + it.second->rewrite_sigspecs2(functor); + for (auto &it : processes) + it.second->rewrite_sigspecs2(functor); + for (auto &it : connections_) { + functor(it.first, it.second); + } +} + +template<typename T> void RTLIL::Cell::rewrite_sigspecs(T &functor) { for (auto &it : connections_) functor(it.second); } template<typename T> +void RTLIL::Cell::rewrite_sigspecs2(T &functor) { + for (auto &it : connections_) + functor(it.second); +} + +template<typename T> void RTLIL::CaseRule::rewrite_sigspecs(T &functor) { for (auto &it : compare) functor(it); @@ -1338,6 +1545,17 @@ void RTLIL::CaseRule::rewrite_sigspecs(T &functor) { } template<typename T> +void RTLIL::CaseRule::rewrite_sigspecs2(T &functor) { + for (auto &it : compare) + functor(it); + for (auto &it : actions) { + functor(it.first, it.second); + } + for (auto it : switches) + it->rewrite_sigspecs2(functor); +} + +template<typename T> void RTLIL::SwitchRule::rewrite_sigspecs(T &functor) { functor(signal); @@ -1346,6 +1564,14 @@ void RTLIL::SwitchRule::rewrite_sigspecs(T &functor) } template<typename T> +void RTLIL::SwitchRule::rewrite_sigspecs2(T &functor) +{ + functor(signal); + for (auto it : cases) + it->rewrite_sigspecs2(functor); +} + +template<typename T> void RTLIL::SyncRule::rewrite_sigspecs(T &functor) { functor(signal); @@ -1356,6 +1582,15 @@ void RTLIL::SyncRule::rewrite_sigspecs(T &functor) } template<typename T> +void RTLIL::SyncRule::rewrite_sigspecs2(T &functor) +{ + functor(signal); + for (auto &it : actions) { + functor(it.first, it.second); + } +} + +template<typename T> void RTLIL::Process::rewrite_sigspecs(T &functor) { root_case.rewrite_sigspecs(functor); @@ -1363,6 +1598,14 @@ void RTLIL::Process::rewrite_sigspecs(T &functor) it->rewrite_sigspecs(functor); } +template<typename T> +void RTLIL::Process::rewrite_sigspecs2(T &functor) +{ + root_case.rewrite_sigspecs2(functor); + for (auto it : syncs) + it->rewrite_sigspecs2(functor); +} + YOSYS_NAMESPACE_END #endif diff --git a/kernel/satgen.h b/kernel/satgen.h index 8d760fff7..133389eee 100644 --- a/kernel/satgen.h +++ b/kernel/satgen.h @@ -1,4 +1,4 @@ -/* +/* -*- c++ -*- * yosys -- Yosys Open SYnthesis Suite * * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> @@ -224,8 +224,8 @@ struct SatGen void extendSignalWidth(std::vector<int> &vec_a, std::vector<int> &vec_b, RTLIL::Cell *cell, size_t y_width = 0, bool forced_signed = false) { bool is_signed = forced_signed; - if (!forced_signed && cell->parameters.count("\\A_SIGNED") > 0 && cell->parameters.count("\\B_SIGNED") > 0) - is_signed = cell->parameters["\\A_SIGNED"].as_bool() && cell->parameters["\\B_SIGNED"].as_bool(); + if (!forced_signed && cell->parameters.count(ID(A_SIGNED)) > 0 && cell->parameters.count(ID(B_SIGNED)) > 0) + is_signed = cell->parameters[ID(A_SIGNED)].as_bool() && cell->parameters[ID(B_SIGNED)].as_bool(); while (vec_a.size() < vec_b.size() || vec_a.size() < y_width) vec_a.push_back(is_signed && vec_a.size() > 0 ? vec_a.back() : ez->CONST_FALSE); while (vec_b.size() < vec_a.size() || vec_b.size() < y_width) @@ -241,7 +241,7 @@ struct SatGen void extendSignalWidthUnary(std::vector<int> &vec_a, std::vector<int> &vec_y, RTLIL::Cell *cell, bool forced_signed = false) { - bool is_signed = forced_signed || (cell->parameters.count("\\A_SIGNED") > 0 && cell->parameters["\\A_SIGNED"].as_bool()); + bool is_signed = forced_signed || (cell->parameters.count(ID(A_SIGNED)) > 0 && cell->parameters[ID(A_SIGNED)].as_bool()); while (vec_a.size() < vec_y.size()) vec_a.push_back(is_signed && vec_a.size() > 0 ? vec_a.back() : ez->CONST_FALSE); while (vec_y.size() < vec_a.size()) @@ -277,13 +277,13 @@ struct SatGen bool importCell(RTLIL::Cell *cell, int timestep = -1) { bool arith_undef_handled = false; - bool is_arith_compare = cell->type.in("$lt", "$le", "$ge", "$gt"); + bool is_arith_compare = cell->type.in(ID($lt), ID($le), ID($ge), ID($gt)); - if (model_undef && (cell->type.in("$add", "$sub", "$mul", "$div", "$mod") || is_arith_compare)) + if (model_undef && (cell->type.in(ID($add), ID($sub), ID($mul), ID($div), ID($mod)) || is_arith_compare)) { - std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); - std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep); - std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); + std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); + std::vector<int> undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); + std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); if (is_arith_compare) extendSignalWidth(undef_a, undef_b, cell, true); else @@ -293,8 +293,8 @@ struct SatGen int undef_any_b = ez->expression(ezSAT::OpOr, undef_b); int undef_y_bit = ez->OR(undef_any_a, undef_any_b); - if (cell->type == "$div" || cell->type == "$mod") { - std::vector<int> b = importSigSpec(cell->getPort("\\B"), timestep); + if (cell->type.in(ID($div), ID($mod))) { + std::vector<int> b = importSigSpec(cell->getPort(ID::B), timestep); undef_y_bit = ez->OR(undef_y_bit, ez->NOT(ez->expression(ezSAT::OpOr, b))); } @@ -310,68 +310,68 @@ struct SatGen arith_undef_handled = true; } - if (cell->type.in("$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_", - "$and", "$or", "$xor", "$xnor", "$add", "$sub")) + if (cell->type.in(ID($_AND_), ID($_NAND_), ID($_OR_), ID($_NOR_), ID($_XOR_), ID($_XNOR_), ID($_ANDNOT_), ID($_ORNOT_), + ID($and), ID($or), ID($xor), ID($xnor), ID($add), ID($sub))) { - std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep); - std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep); - std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep); + std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep); + std::vector<int> b = importDefSigSpec(cell->getPort(ID::B), timestep); + std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep); extendSignalWidth(a, b, y, cell); std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y; - if (cell->type == "$and" || cell->type == "$_AND_") + if (cell->type.in(ID($and), ID($_AND_))) ez->assume(ez->vec_eq(ez->vec_and(a, b), yy)); - if (cell->type == "$_NAND_") + if (cell->type == ID($_NAND_)) ez->assume(ez->vec_eq(ez->vec_not(ez->vec_and(a, b)), yy)); - if (cell->type == "$or" || cell->type == "$_OR_") + if (cell->type.in(ID($or), ID($_OR_))) ez->assume(ez->vec_eq(ez->vec_or(a, b), yy)); - if (cell->type == "$_NOR_") + if (cell->type == ID($_NOR_)) ez->assume(ez->vec_eq(ez->vec_not(ez->vec_or(a, b)), yy)); - if (cell->type == "$xor" || cell->type == "$_XOR_") + if (cell->type.in(ID($xor), ID($_XOR_))) ez->assume(ez->vec_eq(ez->vec_xor(a, b), yy)); - if (cell->type == "$xnor" || cell->type == "$_XNOR_") + if (cell->type.in(ID($xnor), ID($_XNOR_))) ez->assume(ez->vec_eq(ez->vec_not(ez->vec_xor(a, b)), yy)); - if (cell->type == "$_ANDNOT_") + if (cell->type == ID($_ANDNOT_)) ez->assume(ez->vec_eq(ez->vec_and(a, ez->vec_not(b)), yy)); - if (cell->type == "$_ORNOT_") + if (cell->type == ID($_ORNOT_)) ez->assume(ez->vec_eq(ez->vec_or(a, ez->vec_not(b)), yy)); - if (cell->type == "$add") + if (cell->type == ID($add)) ez->assume(ez->vec_eq(ez->vec_add(a, b), yy)); - if (cell->type == "$sub") + if (cell->type == ID($sub)) ez->assume(ez->vec_eq(ez->vec_sub(a, b), yy)); if (model_undef && !arith_undef_handled) { - std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); - std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep); - std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); + std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); + std::vector<int> undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); + std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); extendSignalWidth(undef_a, undef_b, undef_y, cell, false); - if (cell->type.in("$and", "$_AND_", "$_NAND_")) { + if (cell->type.in(ID($and), ID($_AND_), ID($_NAND_))) { std::vector<int> a0 = ez->vec_and(ez->vec_not(a), ez->vec_not(undef_a)); std::vector<int> b0 = ez->vec_and(ez->vec_not(b), ez->vec_not(undef_b)); std::vector<int> yX = ez->vec_and(ez->vec_or(undef_a, undef_b), ez->vec_not(ez->vec_or(a0, b0))); ez->assume(ez->vec_eq(yX, undef_y)); } - else if (cell->type.in("$or", "$_OR_", "$_NOR_")) { + else if (cell->type.in(ID($or), ID($_OR_), ID($_NOR_))) { std::vector<int> a1 = ez->vec_and(a, ez->vec_not(undef_a)); std::vector<int> b1 = ez->vec_and(b, ez->vec_not(undef_b)); std::vector<int> yX = ez->vec_and(ez->vec_or(undef_a, undef_b), ez->vec_not(ez->vec_or(a1, b1))); ez->assume(ez->vec_eq(yX, undef_y)); } - else if (cell->type.in("$xor", "$xnor", "$_XOR_", "$_XNOR_")) { + else if (cell->type.in(ID($xor), ID($xnor), ID($_XOR_), ID($_XNOR_))) { std::vector<int> yX = ez->vec_or(undef_a, undef_b); ez->assume(ez->vec_eq(yX, undef_y)); } - else if (cell->type == "$_ANDNOT_") { + else if (cell->type == ID($_ANDNOT_)) { std::vector<int> a0 = ez->vec_and(ez->vec_not(a), ez->vec_not(undef_a)); std::vector<int> b1 = ez->vec_and(b, ez->vec_not(undef_b)); std::vector<int> yX = ez->vec_and(ez->vec_or(undef_a, undef_b), ez->vec_not(ez->vec_or(a0, b1))); ez->assume(ez->vec_eq(yX, undef_y)); } - else if (cell->type == "$_ORNOT_") { + else if (cell->type == ID($_ORNOT_)) { std::vector<int> a1 = ez->vec_and(a, ez->vec_not(undef_a)); std::vector<int> b0 = ez->vec_and(ez->vec_not(b), ez->vec_not(undef_b)); std::vector<int> yX = ez->vec_and(ez->vec_or(undef_a, undef_b), ez->vec_not(ez->vec_or(a1, b0))); @@ -384,36 +384,36 @@ struct SatGen } else if (model_undef) { - std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); + std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); undefGating(y, yy, undef_y); } return true; } - if (cell->type.in("$_AOI3_", "$_OAI3_", "$_AOI4_", "$_OAI4_")) + if (cell->type.in(ID($_AOI3_), ID($_OAI3_), ID($_AOI4_), ID($_OAI4_))) { - bool aoi_mode = cell->type.in("$_AOI3_", "$_AOI4_"); - bool three_mode = cell->type.in("$_AOI3_", "$_OAI3_"); - - int a = importDefSigSpec(cell->getPort("\\A"), timestep).at(0); - int b = importDefSigSpec(cell->getPort("\\B"), timestep).at(0); - int c = importDefSigSpec(cell->getPort("\\C"), timestep).at(0); - int d = three_mode ? (aoi_mode ? ez->CONST_TRUE : ez->CONST_FALSE) : importDefSigSpec(cell->getPort("\\D"), timestep).at(0); - int y = importDefSigSpec(cell->getPort("\\Y"), timestep).at(0); + bool aoi_mode = cell->type.in(ID($_AOI3_), ID($_AOI4_)); + bool three_mode = cell->type.in(ID($_AOI3_), ID($_OAI3_)); + + int a = importDefSigSpec(cell->getPort(ID::A), timestep).at(0); + int b = importDefSigSpec(cell->getPort(ID::B), timestep).at(0); + int c = importDefSigSpec(cell->getPort(ID(C)), timestep).at(0); + int d = three_mode ? (aoi_mode ? ez->CONST_TRUE : ez->CONST_FALSE) : importDefSigSpec(cell->getPort(ID(D)), timestep).at(0); + int y = importDefSigSpec(cell->getPort(ID::Y), timestep).at(0); int yy = model_undef ? ez->literal() : y; - if (cell->type.in("$_AOI3_", "$_AOI4_")) + if (cell->type.in(ID($_AOI3_), ID($_AOI4_))) ez->assume(ez->IFF(ez->NOT(ez->OR(ez->AND(a, b), ez->AND(c, d))), yy)); else ez->assume(ez->IFF(ez->NOT(ez->AND(ez->OR(a, b), ez->OR(c, d))), yy)); if (model_undef) { - int undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep).at(0); - int undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep).at(0); - int undef_c = importUndefSigSpec(cell->getPort("\\C"), timestep).at(0); - int undef_d = three_mode ? ez->CONST_FALSE : importUndefSigSpec(cell->getPort("\\D"), timestep).at(0); - int undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep).at(0); + int undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep).at(0); + int undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep).at(0); + int undef_c = importUndefSigSpec(cell->getPort(ID(C)), timestep).at(0); + int undef_d = three_mode ? ez->CONST_FALSE : importUndefSigSpec(cell->getPort(ID(D)), timestep).at(0); + int undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep).at(0); if (aoi_mode) { @@ -456,18 +456,18 @@ struct SatGen return true; } - if (cell->type == "$_NOT_" || cell->type == "$not") + if (cell->type.in(ID($_NOT_), ID($not))) { - std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep); - std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep); + std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep); + std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep); extendSignalWidthUnary(a, y, cell); std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y; ez->assume(ez->vec_eq(ez->vec_not(a), yy)); if (model_undef) { - std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); - std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); + std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); + std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); extendSignalWidthUnary(undef_a, undef_y, cell, false); ez->assume(ez->vec_eq(undef_a, undef_y)); undefGating(y, yy, undef_y); @@ -475,22 +475,25 @@ struct SatGen return true; } - if (cell->type == "$_MUX_" || cell->type == "$mux") + if (cell->type.in(ID($_MUX_), ID($mux), ID($_NMUX_))) { - std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep); - std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep); - std::vector<int> s = importDefSigSpec(cell->getPort("\\S"), timestep); - std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep); + std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep); + std::vector<int> b = importDefSigSpec(cell->getPort(ID::B), timestep); + std::vector<int> s = importDefSigSpec(cell->getPort(ID(S)), timestep); + std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep); std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y; - ez->assume(ez->vec_eq(ez->vec_ite(s.at(0), b, a), yy)); + if (cell->type == ID($_NMUX_)) + ez->assume(ez->vec_eq(ez->vec_not(ez->vec_ite(s.at(0), b, a)), yy)); + else + ez->assume(ez->vec_eq(ez->vec_ite(s.at(0), b, a), yy)); if (model_undef) { - std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); - std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep); - std::vector<int> undef_s = importUndefSigSpec(cell->getPort("\\S"), timestep); - std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); + std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); + std::vector<int> undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); + std::vector<int> undef_s = importUndefSigSpec(cell->getPort(ID(S)), timestep); + std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); std::vector<int> unequal_ab = ez->vec_not(ez->vec_iff(a, b)); std::vector<int> undef_ab = ez->vec_or(unequal_ab, ez->vec_or(undef_a, undef_b)); @@ -501,12 +504,12 @@ struct SatGen return true; } - if (cell->type == "$pmux") + if (cell->type == ID($pmux)) { - std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep); - std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep); - std::vector<int> s = importDefSigSpec(cell->getPort("\\S"), timestep); - std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep); + std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep); + std::vector<int> b = importDefSigSpec(cell->getPort(ID::B), timestep); + std::vector<int> s = importDefSigSpec(cell->getPort(ID(S)), timestep); + std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep); std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y; @@ -519,10 +522,10 @@ struct SatGen if (model_undef) { - std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); - std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep); - std::vector<int> undef_s = importUndefSigSpec(cell->getPort("\\S"), timestep); - std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); + std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); + std::vector<int> undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); + std::vector<int> undef_s = importUndefSigSpec(cell->getPort(ID(S)), timestep); + std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); int maybe_a = ez->CONST_TRUE; @@ -552,15 +555,15 @@ struct SatGen return true; } - if (cell->type == "$pos" || cell->type == "$neg") + if (cell->type.in(ID($pos), ID($neg))) { - std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep); - std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep); + std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep); + std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep); extendSignalWidthUnary(a, y, cell); std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y; - if (cell->type == "$pos") { + if (cell->type == ID($pos)) { ez->assume(ez->vec_eq(a, yy)); } else { std::vector<int> zero(a.size(), ez->CONST_FALSE); @@ -569,11 +572,11 @@ struct SatGen if (model_undef) { - std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); - std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); + std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); + std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); extendSignalWidthUnary(undef_a, undef_y, cell); - if (cell->type == "$pos") { + if (cell->type == ID($pos)) { ez->assume(ez->vec_eq(undef_a, undef_y)); } else { int undef_any_a = ez->expression(ezSAT::OpOr, undef_a); @@ -586,42 +589,41 @@ struct SatGen return true; } - if (cell->type == "$reduce_and" || cell->type == "$reduce_or" || cell->type == "$reduce_xor" || - cell->type == "$reduce_xnor" || cell->type == "$reduce_bool" || cell->type == "$logic_not") + if (cell->type.in(ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_xnor), ID($reduce_bool), ID($logic_not))) { - std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep); - std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep); + std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep); + std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep); std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y; - if (cell->type == "$reduce_and") + if (cell->type == ID($reduce_and)) ez->SET(ez->expression(ez->OpAnd, a), yy.at(0)); - if (cell->type == "$reduce_or" || cell->type == "$reduce_bool") + if (cell->type.in(ID($reduce_or), ID($reduce_bool))) ez->SET(ez->expression(ez->OpOr, a), yy.at(0)); - if (cell->type == "$reduce_xor") + if (cell->type == ID($reduce_xor)) ez->SET(ez->expression(ez->OpXor, a), yy.at(0)); - if (cell->type == "$reduce_xnor") + if (cell->type == ID($reduce_xnor)) ez->SET(ez->NOT(ez->expression(ez->OpXor, a)), yy.at(0)); - if (cell->type == "$logic_not") + if (cell->type == ID($logic_not)) ez->SET(ez->NOT(ez->expression(ez->OpOr, a)), yy.at(0)); for (size_t i = 1; i < y.size(); i++) ez->SET(ez->CONST_FALSE, yy.at(i)); if (model_undef) { - std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); - std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); + std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); + std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); int aX = ez->expression(ezSAT::OpOr, undef_a); - if (cell->type == "$reduce_and") { + if (cell->type == ID($reduce_and)) { int a0 = ez->expression(ezSAT::OpOr, ez->vec_and(ez->vec_not(a), ez->vec_not(undef_a))); ez->assume(ez->IFF(ez->AND(ez->NOT(a0), aX), undef_y.at(0))); } - else if (cell->type == "$reduce_or" || cell->type == "$reduce_bool" || cell->type == "$logic_not") { + else if (cell->type.in(ID($reduce_or), ID($reduce_bool), ID($logic_not))) { int a1 = ez->expression(ezSAT::OpOr, ez->vec_and(a, ez->vec_not(undef_a))); ez->assume(ez->IFF(ez->AND(ez->NOT(a1), aX), undef_y.at(0))); } - else if (cell->type == "$reduce_xor" || cell->type == "$reduce_xnor") { + else if (cell->type.in(ID($reduce_xor), ID($reduce_xnor))) { ez->assume(ez->IFF(aX, undef_y.at(0))); } else log_abort(); @@ -634,18 +636,18 @@ struct SatGen return true; } - if (cell->type == "$logic_and" || cell->type == "$logic_or") + if (cell->type.in(ID($logic_and), ID($logic_or))) { - std::vector<int> vec_a = importDefSigSpec(cell->getPort("\\A"), timestep); - std::vector<int> vec_b = importDefSigSpec(cell->getPort("\\B"), timestep); + std::vector<int> vec_a = importDefSigSpec(cell->getPort(ID::A), timestep); + std::vector<int> vec_b = importDefSigSpec(cell->getPort(ID::B), timestep); int a = ez->expression(ez->OpOr, vec_a); int b = ez->expression(ez->OpOr, vec_b); - std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep); + std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep); std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y; - if (cell->type == "$logic_and") + if (cell->type == ID($logic_and)) ez->SET(ez->expression(ez->OpAnd, a, b), yy.at(0)); else ez->SET(ez->expression(ez->OpOr, a, b), yy.at(0)); @@ -654,9 +656,9 @@ struct SatGen if (model_undef) { - std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); - std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep); - std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); + std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); + std::vector<int> undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); + std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); int a0 = ez->NOT(ez->OR(ez->expression(ezSAT::OpOr, vec_a), ez->expression(ezSAT::OpOr, undef_a))); int b0 = ez->NOT(ez->OR(ez->expression(ezSAT::OpOr, vec_b), ez->expression(ezSAT::OpOr, undef_b))); @@ -665,9 +667,9 @@ struct SatGen int aX = ez->expression(ezSAT::OpOr, undef_a); int bX = ez->expression(ezSAT::OpOr, undef_b); - if (cell->type == "$logic_and") + if (cell->type == ID($logic_and)) ez->SET(ez->AND(ez->OR(aX, bX), ez->NOT(ez->AND(a1, b1)), ez->NOT(a0), ez->NOT(b0)), undef_y.at(0)); - else if (cell->type == "$logic_or") + else if (cell->type == ID($logic_or)) ez->SET(ez->AND(ez->OR(aX, bX), ez->NOT(ez->AND(a0, b0)), ez->NOT(a1), ez->NOT(b1)), undef_y.at(0)); else log_abort(); @@ -680,47 +682,47 @@ struct SatGen return true; } - if (cell->type == "$lt" || cell->type == "$le" || cell->type == "$eq" || cell->type == "$ne" || cell->type == "$eqx" || cell->type == "$nex" || cell->type == "$ge" || cell->type == "$gt") + if (cell->type.in(ID($lt), ID($le), ID($eq), ID($ne), ID($eqx), ID($nex), ID($ge), ID($gt))) { - bool is_signed = cell->parameters["\\A_SIGNED"].as_bool() && cell->parameters["\\B_SIGNED"].as_bool(); - std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep); - std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep); - std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep); + bool is_signed = cell->parameters[ID(A_SIGNED)].as_bool() && cell->parameters[ID(B_SIGNED)].as_bool(); + std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep); + std::vector<int> b = importDefSigSpec(cell->getPort(ID::B), timestep); + std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep); extendSignalWidth(a, b, cell); std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y; - if (model_undef && (cell->type == "$eqx" || cell->type == "$nex")) { - std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); - std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep); + if (model_undef && cell->type.in(ID($eqx), ID($nex))) { + std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); + std::vector<int> undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); extendSignalWidth(undef_a, undef_b, cell, true); a = ez->vec_or(a, undef_a); b = ez->vec_or(b, undef_b); } - if (cell->type == "$lt") + if (cell->type == ID($lt)) ez->SET(is_signed ? ez->vec_lt_signed(a, b) : ez->vec_lt_unsigned(a, b), yy.at(0)); - if (cell->type == "$le") + if (cell->type == ID($le)) ez->SET(is_signed ? ez->vec_le_signed(a, b) : ez->vec_le_unsigned(a, b), yy.at(0)); - if (cell->type == "$eq" || cell->type == "$eqx") + if (cell->type.in(ID($eq), ID($eqx))) ez->SET(ez->vec_eq(a, b), yy.at(0)); - if (cell->type == "$ne" || cell->type == "$nex") + if (cell->type.in(ID($ne), ID($nex))) ez->SET(ez->vec_ne(a, b), yy.at(0)); - if (cell->type == "$ge") + if (cell->type == ID($ge)) ez->SET(is_signed ? ez->vec_ge_signed(a, b) : ez->vec_ge_unsigned(a, b), yy.at(0)); - if (cell->type == "$gt") + if (cell->type == ID($gt)) ez->SET(is_signed ? ez->vec_gt_signed(a, b) : ez->vec_gt_unsigned(a, b), yy.at(0)); for (size_t i = 1; i < y.size(); i++) ez->SET(ez->CONST_FALSE, yy.at(i)); - if (model_undef && (cell->type == "$eqx" || cell->type == "$nex")) + if (model_undef && cell->type.in(ID($eqx), ID($nex))) { - std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); - std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep); - std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); + std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); + std::vector<int> undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); + std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); extendSignalWidth(undef_a, undef_b, cell, true); - if (cell->type == "$eqx") + if (cell->type == ID($eqx)) yy.at(0) = ez->AND(yy.at(0), ez->vec_eq(undef_a, undef_b)); else yy.at(0) = ez->OR(yy.at(0), ez->vec_ne(undef_a, undef_b)); @@ -730,11 +732,11 @@ struct SatGen ez->assume(ez->vec_eq(y, yy)); } - else if (model_undef && (cell->type == "$eq" || cell->type == "$ne")) + else if (model_undef && cell->type.in(ID($eq), ID($ne))) { - std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); - std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep); - std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); + std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); + std::vector<int> undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); + std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); extendSignalWidth(undef_a, undef_b, cell, true); int undef_any_a = ez->expression(ezSAT::OpOr, undef_a); @@ -756,7 +758,7 @@ struct SatGen else { if (model_undef) { - std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); + std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); undefGating(y, yy, undef_y); } log_assert(!model_undef || arith_undef_handled); @@ -764,15 +766,15 @@ struct SatGen return true; } - if (cell->type == "$shl" || cell->type == "$shr" || cell->type == "$sshl" || cell->type == "$sshr" || cell->type == "$shift" || cell->type == "$shiftx") + if (cell->type.in(ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx))) { - std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep); - std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep); - std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep); + std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep); + std::vector<int> b = importDefSigSpec(cell->getPort(ID::B), timestep); + std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep); int extend_bit = ez->CONST_FALSE; - if (!cell->type.in("$shift", "$shiftx") && cell->parameters["\\A_SIGNED"].as_bool()) + if (!cell->type.in(ID($shift), ID($shiftx)) && cell->parameters[ID(A_SIGNED)].as_bool()) extend_bit = a.back(); while (y.size() < a.size()) @@ -783,29 +785,29 @@ struct SatGen std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y; std::vector<int> shifted_a; - if (cell->type == "$shl" || cell->type == "$sshl") + if (cell->type.in( ID($shl), ID($sshl))) shifted_a = ez->vec_shift_left(a, b, false, ez->CONST_FALSE, ez->CONST_FALSE); - if (cell->type == "$shr") + if (cell->type == ID($shr)) shifted_a = ez->vec_shift_right(a, b, false, ez->CONST_FALSE, ez->CONST_FALSE); - if (cell->type == "$sshr") - shifted_a = ez->vec_shift_right(a, b, false, cell->parameters["\\A_SIGNED"].as_bool() ? a.back() : ez->CONST_FALSE, ez->CONST_FALSE); + if (cell->type == ID($sshr)) + shifted_a = ez->vec_shift_right(a, b, false, cell->parameters[ID(A_SIGNED)].as_bool() ? a.back() : ez->CONST_FALSE, ez->CONST_FALSE); - if (cell->type == "$shift" || cell->type == "$shiftx") - shifted_a = ez->vec_shift_right(a, b, cell->parameters["\\B_SIGNED"].as_bool(), ez->CONST_FALSE, ez->CONST_FALSE); + if (cell->type.in(ID($shift), ID($shiftx))) + shifted_a = ez->vec_shift_right(a, b, cell->parameters[ID(B_SIGNED)].as_bool(), ez->CONST_FALSE, ez->CONST_FALSE); ez->assume(ez->vec_eq(shifted_a, yy)); if (model_undef) { - std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); - std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep); - std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); + std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); + std::vector<int> undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); + std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); std::vector<int> undef_a_shifted; - extend_bit = cell->type == "$shiftx" ? ez->CONST_TRUE : ez->CONST_FALSE; - if (!cell->type.in("$shift", "$shiftx") && cell->parameters["\\A_SIGNED"].as_bool()) + extend_bit = cell->type == ID($shiftx) ? ez->CONST_TRUE : ez->CONST_FALSE; + if (!cell->type.in(ID($shift), ID($shiftx)) && cell->parameters[ID(A_SIGNED)].as_bool()) extend_bit = undef_a.back(); while (undef_y.size() < undef_a.size()) @@ -813,20 +815,20 @@ struct SatGen while (undef_y.size() > undef_a.size()) undef_a.push_back(extend_bit); - if (cell->type == "$shl" || cell->type == "$sshl") + if (cell->type.in(ID($shl), ID($sshl))) undef_a_shifted = ez->vec_shift_left(undef_a, b, false, ez->CONST_FALSE, ez->CONST_FALSE); - if (cell->type == "$shr") + if (cell->type == ID($shr)) undef_a_shifted = ez->vec_shift_right(undef_a, b, false, ez->CONST_FALSE, ez->CONST_FALSE); - if (cell->type == "$sshr") - undef_a_shifted = ez->vec_shift_right(undef_a, b, false, cell->parameters["\\A_SIGNED"].as_bool() ? undef_a.back() : ez->CONST_FALSE, ez->CONST_FALSE); + if (cell->type == ID($sshr)) + undef_a_shifted = ez->vec_shift_right(undef_a, b, false, cell->parameters[ID(A_SIGNED)].as_bool() ? undef_a.back() : ez->CONST_FALSE, ez->CONST_FALSE); - if (cell->type == "$shift") - undef_a_shifted = ez->vec_shift_right(undef_a, b, cell->parameters["\\B_SIGNED"].as_bool(), ez->CONST_FALSE, ez->CONST_FALSE); + if (cell->type == ID($shift)) + undef_a_shifted = ez->vec_shift_right(undef_a, b, cell->parameters[ID(B_SIGNED)].as_bool(), ez->CONST_FALSE, ez->CONST_FALSE); - if (cell->type == "$shiftx") - undef_a_shifted = ez->vec_shift_right(undef_a, b, cell->parameters["\\B_SIGNED"].as_bool(), ez->CONST_TRUE, ez->CONST_TRUE); + if (cell->type == ID($shiftx)) + undef_a_shifted = ez->vec_shift_right(undef_a, b, cell->parameters[ID(B_SIGNED)].as_bool(), ez->CONST_TRUE, ez->CONST_TRUE); int undef_any_b = ez->expression(ezSAT::OpOr, undef_b); std::vector<int> undef_all_y_bits(undef_y.size(), undef_any_b); @@ -836,11 +838,11 @@ struct SatGen return true; } - if (cell->type == "$mul") + if (cell->type == ID($mul)) { - std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep); - std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep); - std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep); + std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep); + std::vector<int> b = importDefSigSpec(cell->getPort(ID::B), timestep); + std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep); extendSignalWidth(a, b, y, cell); std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y; @@ -857,17 +859,17 @@ struct SatGen if (model_undef) { log_assert(arith_undef_handled); - std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); + std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); undefGating(y, yy, undef_y); } return true; } - if (cell->type == "$macc") + if (cell->type == ID($macc)) { - std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep); - std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep); - std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep); + std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep); + std::vector<int> b = importDefSigSpec(cell->getPort(ID::B), timestep); + std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep); Macc macc; macc.from_cell(cell); @@ -916,13 +918,13 @@ struct SatGen if (model_undef) { - std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); - std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep); + std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); + std::vector<int> undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); int undef_any_a = ez->expression(ezSAT::OpOr, undef_a); int undef_any_b = ez->expression(ezSAT::OpOr, undef_b); - std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); + std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); ez->assume(ez->vec_eq(undef_y, std::vector<int>(GetSize(y), ez->OR(undef_any_a, undef_any_b)))); undefGating(y, tmp, undef_y); @@ -933,17 +935,17 @@ struct SatGen return true; } - if (cell->type == "$div" || cell->type == "$mod") + if (cell->type.in(ID($div), ID($mod))) { - std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep); - std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep); - std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep); + std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep); + std::vector<int> b = importDefSigSpec(cell->getPort(ID::B), timestep); + std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep); extendSignalWidth(a, b, y, cell); std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y; std::vector<int> a_u, b_u; - if (cell->parameters["\\A_SIGNED"].as_bool() && cell->parameters["\\B_SIGNED"].as_bool()) { + if (cell->parameters[ID(A_SIGNED)].as_bool() && cell->parameters[ID(B_SIGNED)].as_bool()) { a_u = ez->vec_ite(a.back(), ez->vec_neg(a), a); b_u = ez->vec_ite(b.back(), ez->vec_neg(b), b); } else { @@ -968,13 +970,13 @@ struct SatGen } std::vector<int> y_tmp = ignore_div_by_zero ? yy : ez->vec_var(y.size()); - if (cell->type == "$div") { - if (cell->parameters["\\A_SIGNED"].as_bool() && cell->parameters["\\B_SIGNED"].as_bool()) + if (cell->type == ID($div)) { + if (cell->parameters[ID(A_SIGNED)].as_bool() && cell->parameters[ID(B_SIGNED)].as_bool()) ez->assume(ez->vec_eq(y_tmp, ez->vec_ite(ez->XOR(a.back(), b.back()), ez->vec_neg(y_u), y_u))); else ez->assume(ez->vec_eq(y_tmp, y_u)); } else { - if (cell->parameters["\\A_SIGNED"].as_bool() && cell->parameters["\\B_SIGNED"].as_bool()) + if (cell->parameters[ID(A_SIGNED)].as_bool() && cell->parameters[ID(B_SIGNED)].as_bool()) ez->assume(ez->vec_eq(y_tmp, ez->vec_ite(a.back(), ez->vec_neg(chain_buf), chain_buf))); else ez->assume(ez->vec_eq(y_tmp, chain_buf)); @@ -984,20 +986,20 @@ struct SatGen ez->assume(ez->expression(ezSAT::OpOr, b)); } else { std::vector<int> div_zero_result; - if (cell->type == "$div") { - if (cell->parameters["\\A_SIGNED"].as_bool() && cell->parameters["\\B_SIGNED"].as_bool()) { + if (cell->type == ID($div)) { + if (cell->parameters[ID(A_SIGNED)].as_bool() && cell->parameters[ID(B_SIGNED)].as_bool()) { std::vector<int> all_ones(y.size(), ez->CONST_TRUE); std::vector<int> only_first_one(y.size(), ez->CONST_FALSE); only_first_one.at(0) = ez->CONST_TRUE; div_zero_result = ez->vec_ite(a.back(), only_first_one, all_ones); } else { - div_zero_result.insert(div_zero_result.end(), cell->getPort("\\A").size(), ez->CONST_TRUE); + div_zero_result.insert(div_zero_result.end(), cell->getPort(ID::A).size(), ez->CONST_TRUE); div_zero_result.insert(div_zero_result.end(), y.size() - div_zero_result.size(), ez->CONST_FALSE); } } else { - int copy_a_bits = min(cell->getPort("\\A").size(), cell->getPort("\\B").size()); + int copy_a_bits = min(cell->getPort(ID::A).size(), cell->getPort(ID::B).size()); div_zero_result.insert(div_zero_result.end(), a.begin(), a.begin() + copy_a_bits); - if (cell->parameters["\\A_SIGNED"].as_bool() && cell->parameters["\\B_SIGNED"].as_bool()) + if (cell->parameters[ID(A_SIGNED)].as_bool() && cell->parameters[ID(B_SIGNED)].as_bool()) div_zero_result.insert(div_zero_result.end(), y.size() - div_zero_result.size(), div_zero_result.back()); else div_zero_result.insert(div_zero_result.end(), y.size() - div_zero_result.size(), ez->CONST_FALSE); @@ -1007,27 +1009,27 @@ struct SatGen if (model_undef) { log_assert(arith_undef_handled); - std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); + std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); undefGating(y, yy, undef_y); } return true; } - if (cell->type == "$lut") + if (cell->type == ID($lut)) { - std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep); - std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep); + std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep); + std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep); std::vector<int> lut; - for (auto bit : cell->getParam("\\LUT").bits) - lut.push_back(bit == RTLIL::S1 ? ez->CONST_TRUE : ez->CONST_FALSE); + for (auto bit : cell->getParam(ID(LUT)).bits) + lut.push_back(bit == State::S1 ? ez->CONST_TRUE : ez->CONST_FALSE); while (GetSize(lut) < (1 << GetSize(a))) lut.push_back(ez->CONST_FALSE); lut.resize(1 << GetSize(a)); if (model_undef) { - std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); + std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); std::vector<int> t(lut), u(GetSize(t), ez->CONST_FALSE); for (int i = GetSize(a)-1; i >= 0; i--) @@ -1045,7 +1047,7 @@ struct SatGen log_assert(GetSize(t) == 1); log_assert(GetSize(u) == 1); undefGating(y, t, u); - ez->assume(ez->vec_eq(importUndefSigSpec(cell->getPort("\\Y"), timestep), u)); + ez->assume(ez->vec_eq(importUndefSigSpec(cell->getPort(ID::Y), timestep), u)); } else { @@ -1063,15 +1065,15 @@ struct SatGen return true; } - if (cell->type == "$sop") + if (cell->type == ID($sop)) { - std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep); - int y = importDefSigSpec(cell->getPort("\\Y"), timestep).at(0); + std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep); + int y = importDefSigSpec(cell->getPort(ID::Y), timestep).at(0); - int width = cell->getParam("\\WIDTH").as_int(); - int depth = cell->getParam("\\DEPTH").as_int(); + int width = cell->getParam(ID(WIDTH)).as_int(); + int depth = cell->getParam(ID(DEPTH)).as_int(); - vector<State> table_raw = cell->getParam("\\TABLE").bits; + vector<State> table_raw = cell->getParam(ID(TABLE)).bits; while (GetSize(table_raw) < 2*width*depth) table_raw.push_back(State::S0); @@ -1094,8 +1096,8 @@ struct SatGen if (model_undef) { std::vector<int> products, undef_products; - std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); - int undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep).at(0); + std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); + int undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep).at(0); for (int i = 0; i < depth; i++) { @@ -1145,13 +1147,13 @@ struct SatGen return true; } - if (cell->type == "$fa") + if (cell->type == ID($fa)) { - std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep); - std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep); - std::vector<int> c = importDefSigSpec(cell->getPort("\\C"), timestep); - std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep); - std::vector<int> x = importDefSigSpec(cell->getPort("\\X"), timestep); + std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep); + std::vector<int> b = importDefSigSpec(cell->getPort(ID::B), timestep); + std::vector<int> c = importDefSigSpec(cell->getPort(ID(C)), timestep); + std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep); + std::vector<int> x = importDefSigSpec(cell->getPort(ID(X)), timestep); std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y; std::vector<int> xx = model_undef ? ez->vec_var(x.size()) : x; @@ -1165,12 +1167,12 @@ struct SatGen if (model_undef) { - std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); - std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep); - std::vector<int> undef_c = importUndefSigSpec(cell->getPort("\\C"), timestep); + std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); + std::vector<int> undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); + std::vector<int> undef_c = importUndefSigSpec(cell->getPort(ID(C)), timestep); - std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); - std::vector<int> undef_x = importUndefSigSpec(cell->getPort("\\X"), timestep); + std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); + std::vector<int> undef_x = importUndefSigSpec(cell->getPort(ID(X)), timestep); ez->assume(ez->vec_eq(undef_y, ez->vec_or(ez->vec_or(undef_a, undef_b), undef_c))); ez->assume(ez->vec_eq(undef_x, undef_y)); @@ -1181,12 +1183,12 @@ struct SatGen return true; } - if (cell->type == "$lcu") + if (cell->type == ID($lcu)) { - std::vector<int> p = importDefSigSpec(cell->getPort("\\P"), timestep); - std::vector<int> g = importDefSigSpec(cell->getPort("\\G"), timestep); - std::vector<int> ci = importDefSigSpec(cell->getPort("\\CI"), timestep); - std::vector<int> co = importDefSigSpec(cell->getPort("\\CO"), timestep); + std::vector<int> p = importDefSigSpec(cell->getPort(ID(P)), timestep); + std::vector<int> g = importDefSigSpec(cell->getPort(ID(G)), timestep); + std::vector<int> ci = importDefSigSpec(cell->getPort(ID(CI)), timestep); + std::vector<int> co = importDefSigSpec(cell->getPort(ID(CO)), timestep); std::vector<int> yy = model_undef ? ez->vec_var(co.size()) : co; @@ -1195,10 +1197,10 @@ struct SatGen if (model_undef) { - std::vector<int> undef_p = importUndefSigSpec(cell->getPort("\\P"), timestep); - std::vector<int> undef_g = importUndefSigSpec(cell->getPort("\\G"), timestep); - std::vector<int> undef_ci = importUndefSigSpec(cell->getPort("\\CI"), timestep); - std::vector<int> undef_co = importUndefSigSpec(cell->getPort("\\CO"), timestep); + std::vector<int> undef_p = importUndefSigSpec(cell->getPort(ID(P)), timestep); + std::vector<int> undef_g = importUndefSigSpec(cell->getPort(ID(G)), timestep); + std::vector<int> undef_ci = importUndefSigSpec(cell->getPort(ID(CI)), timestep); + std::vector<int> undef_co = importUndefSigSpec(cell->getPort(ID(CO)), timestep); int undef_any_p = ez->expression(ezSAT::OpOr, undef_p); int undef_any_g = ez->expression(ezSAT::OpOr, undef_g); @@ -1213,15 +1215,15 @@ struct SatGen return true; } - if (cell->type == "$alu") + if (cell->type == ID($alu)) { - std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep); - std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep); - std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep); - std::vector<int> x = importDefSigSpec(cell->getPort("\\X"), timestep); - std::vector<int> ci = importDefSigSpec(cell->getPort("\\CI"), timestep); - std::vector<int> bi = importDefSigSpec(cell->getPort("\\BI"), timestep); - std::vector<int> co = importDefSigSpec(cell->getPort("\\CO"), timestep); + std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep); + std::vector<int> b = importDefSigSpec(cell->getPort(ID::B), timestep); + std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep); + std::vector<int> x = importDefSigSpec(cell->getPort(ID(X)), timestep); + std::vector<int> ci = importDefSigSpec(cell->getPort(ID(CI)), timestep); + std::vector<int> bi = importDefSigSpec(cell->getPort(ID(BI)), timestep); + std::vector<int> co = importDefSigSpec(cell->getPort(ID(CO)), timestep); extendSignalWidth(a, b, y, cell); extendSignalWidth(a, b, x, cell); @@ -1246,14 +1248,14 @@ struct SatGen if (model_undef) { - std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); - std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep); - std::vector<int> undef_ci = importUndefSigSpec(cell->getPort("\\CI"), timestep); - std::vector<int> undef_bi = importUndefSigSpec(cell->getPort("\\BI"), timestep); + std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); + std::vector<int> undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); + std::vector<int> undef_ci = importUndefSigSpec(cell->getPort(ID(CI)), timestep); + std::vector<int> undef_bi = importUndefSigSpec(cell->getPort(ID(BI)), timestep); - std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); - std::vector<int> undef_x = importUndefSigSpec(cell->getPort("\\X"), timestep); - std::vector<int> undef_co = importUndefSigSpec(cell->getPort("\\CO"), timestep); + std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); + std::vector<int> undef_x = importUndefSigSpec(cell->getPort(ID(X)), timestep); + std::vector<int> undef_co = importUndefSigSpec(cell->getPort(ID(CO)), timestep); extendSignalWidth(undef_a, undef_b, undef_y, cell); extendSignalWidth(undef_a, undef_b, undef_x, cell); @@ -1279,19 +1281,19 @@ struct SatGen return true; } - if (cell->type == "$slice") + if (cell->type == ID($slice)) { - RTLIL::SigSpec a = cell->getPort("\\A"); - RTLIL::SigSpec y = cell->getPort("\\Y"); - ez->assume(signals_eq(a.extract(cell->parameters.at("\\OFFSET").as_int(), y.size()), y, timestep)); + RTLIL::SigSpec a = cell->getPort(ID::A); + RTLIL::SigSpec y = cell->getPort(ID::Y); + ez->assume(signals_eq(a.extract(cell->parameters.at(ID(OFFSET)).as_int(), y.size()), y, timestep)); return true; } - if (cell->type == "$concat") + if (cell->type == ID($concat)) { - RTLIL::SigSpec a = cell->getPort("\\A"); - RTLIL::SigSpec b = cell->getPort("\\B"); - RTLIL::SigSpec y = cell->getPort("\\Y"); + RTLIL::SigSpec a = cell->getPort(ID::A); + RTLIL::SigSpec b = cell->getPort(ID::B); + RTLIL::SigSpec y = cell->getPort(ID::Y); RTLIL::SigSpec ab = a; ab.append(b); @@ -1300,24 +1302,24 @@ struct SatGen return true; } - if (timestep > 0 && cell->type.in("$ff", "$dff", "$_FF_", "$_DFF_N_", "$_DFF_P_")) + if (timestep > 0 && cell->type.in(ID($ff), ID($dff), ID($_FF_), ID($_DFF_N_), ID($_DFF_P_))) { if (timestep == 1) { - initial_state.add((*sigmap)(cell->getPort("\\Q"))); + initial_state.add((*sigmap)(cell->getPort(ID(Q)))); } else { - std::vector<int> d = importDefSigSpec(cell->getPort("\\D"), timestep-1); - std::vector<int> q = importDefSigSpec(cell->getPort("\\Q"), timestep); + std::vector<int> d = importDefSigSpec(cell->getPort(ID(D)), timestep-1); + std::vector<int> q = importDefSigSpec(cell->getPort(ID(Q)), timestep); std::vector<int> qq = model_undef ? ez->vec_var(q.size()) : q; ez->assume(ez->vec_eq(d, qq)); if (model_undef) { - std::vector<int> undef_d = importUndefSigSpec(cell->getPort("\\D"), timestep-1); - std::vector<int> undef_q = importUndefSigSpec(cell->getPort("\\Q"), timestep); + std::vector<int> undef_d = importUndefSigSpec(cell->getPort(ID(D)), timestep-1); + std::vector<int> undef_q = importUndefSigSpec(cell->getPort(ID(Q)), timestep); ez->assume(ez->vec_eq(undef_d, undef_q)); undefGating(q, qq, undef_q); @@ -1326,21 +1328,21 @@ struct SatGen return true; } - if (cell->type == "$anyconst") + if (cell->type == ID($anyconst)) { if (timestep < 2) return true; - std::vector<int> d = importDefSigSpec(cell->getPort("\\Y"), timestep-1); - std::vector<int> q = importDefSigSpec(cell->getPort("\\Y"), timestep); + std::vector<int> d = importDefSigSpec(cell->getPort(ID::Y), timestep-1); + std::vector<int> q = importDefSigSpec(cell->getPort(ID::Y), timestep); std::vector<int> qq = model_undef ? ez->vec_var(q.size()) : q; ez->assume(ez->vec_eq(d, qq)); if (model_undef) { - std::vector<int> undef_d = importUndefSigSpec(cell->getPort("\\Y"), timestep-1); - std::vector<int> undef_q = importUndefSigSpec(cell->getPort("\\Y"), timestep); + std::vector<int> undef_d = importUndefSigSpec(cell->getPort(ID::Y), timestep-1); + std::vector<int> undef_q = importUndefSigSpec(cell->getPort(ID::Y), timestep); ez->assume(ez->vec_eq(undef_d, undef_q)); undefGating(q, qq, undef_q); @@ -1348,23 +1350,23 @@ struct SatGen return true; } - if (cell->type == "$anyseq") + if (cell->type == ID($anyseq)) { return true; } - if (cell->type == "$_BUF_" || cell->type == "$equiv") + if (cell->type.in(ID($_BUF_), ID($equiv))) { - std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep); - std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep); + std::vector<int> a = importDefSigSpec(cell->getPort(ID::A), timestep); + std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep); extendSignalWidthUnary(a, y, cell); std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y; ez->assume(ez->vec_eq(a, yy)); if (model_undef) { - std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep); - std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); + std::vector<int> undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); + std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); extendSignalWidthUnary(undef_a, undef_y, cell, false); ez->assume(ez->vec_eq(undef_a, undef_y)); undefGating(y, yy, undef_y); @@ -1372,18 +1374,18 @@ struct SatGen return true; } - if (cell->type == "$initstate") + if (cell->type == ID($initstate)) { auto key = make_pair(prefix, timestep); if (initstates.count(key) == 0) initstates[key] = false; - std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep); + std::vector<int> y = importDefSigSpec(cell->getPort(ID::Y), timestep); log_assert(GetSize(y) == 1); ez->SET(y[0], initstates[key] ? ez->CONST_TRUE : ez->CONST_FALSE); if (model_undef) { - std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep); + std::vector<int> undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); log_assert(GetSize(undef_y) == 1); ez->SET(undef_y[0], ez->CONST_FALSE); } @@ -1391,19 +1393,19 @@ struct SatGen return true; } - if (cell->type == "$assert") + if (cell->type == ID($assert)) { std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep)); - asserts_a[pf].append((*sigmap)(cell->getPort("\\A"))); - asserts_en[pf].append((*sigmap)(cell->getPort("\\EN"))); + asserts_a[pf].append((*sigmap)(cell->getPort(ID::A))); + asserts_en[pf].append((*sigmap)(cell->getPort(ID(EN)))); return true; } - if (cell->type == "$assume") + if (cell->type == ID($assume)) { std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep)); - assumes_a[pf].append((*sigmap)(cell->getPort("\\A"))); - assumes_en[pf].append((*sigmap)(cell->getPort("\\EN"))); + assumes_a[pf].append((*sigmap)(cell->getPort(ID::A))); + assumes_en[pf].append((*sigmap)(cell->getPort(ID(EN)))); return true; } diff --git a/kernel/sigtools.h b/kernel/sigtools.h index 4e97bb775..2517d6de3 100644 --- a/kernel/sigtools.h +++ b/kernel/sigtools.h @@ -135,9 +135,11 @@ struct SigPool } }; -template <typename T, class Compare = std::less<T>> +template <typename T, class Compare = void> struct SigSet { + static_assert(!std::is_same<Compare,void>::value, "Default value for `Compare' class not found for SigSet<T>. Please specify."); + struct bitDef_t : public std::pair<RTLIL::Wire*, int> { bitDef_t() : std::pair<RTLIL::Wire*, int>(NULL, 0) { } bitDef_t(const RTLIL::SigBit &bit) : std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset) { } @@ -220,6 +222,13 @@ struct SigSet } }; +template<typename T> +class SigSet<T, typename std::enable_if<!std::is_pointer<T>::value>::type> : public SigSet<T, std::less<T>> {}; +template<typename T> +using sort_by_name_id_guard = typename std::enable_if<std::is_same<T,RTLIL::Cell*>::value>::type; +template<typename T> +class SigSet<T, sort_by_name_id_guard<T>> : public SigSet<T, RTLIL::sort_by_name_id<typename std::remove_pointer<T>::type>> {}; + struct SigMap { mfp<SigBit> database; diff --git a/kernel/yosys.cc b/kernel/yosys.cc index 750a154e6..5018a4888 100644 --- a/kernel/yosys.cc +++ b/kernel/yosys.cc @@ -33,7 +33,7 @@ # include <dlfcn.h> #endif -#ifdef _WIN32 +#if defined(_WIN32) # include <windows.h> # include <io.h> #elif defined(__APPLE__) @@ -41,13 +41,15 @@ # include <unistd.h> # include <dirent.h> # include <sys/stat.h> -# include <glob.h> #else # include <unistd.h> # include <dirent.h> # include <sys/types.h> # include <sys/wait.h> # include <sys/stat.h> +#endif + +#if !defined(_WIN32) && defined(YOSYS_ENABLE_GLOB) # include <glob.h> #endif @@ -55,6 +57,16 @@ # include <sys/sysctl.h> #endif +#ifdef WITH_PYTHON +#if PY_MAJOR_VERSION >= 3 +# define INIT_MODULE PyInit_libyosys + extern "C" PyObject* INIT_MODULE(); +#else +# define INIT_MODULE initlibyosys + extern "C" void INIT_MODULE(); +#endif +#endif + #include <limits.h> #include <errno.h> @@ -117,7 +129,7 @@ void yosys_banner() log(" | |\n"); log(" | yosys -- Yosys Open SYnthesis Suite |\n"); log(" | |\n"); - log(" | Copyright (C) 2012 - 2018 Clifford Wolf <clifford@clifford.at> |\n"); + log(" | Copyright (C) 2012 - 2019 Clifford Wolf <clifford@clifford.at> |\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"); @@ -139,14 +151,16 @@ void yosys_banner() int ceil_log2(int x) { +#if defined(__GNUC__) + return x > 1 ? (8*sizeof(int)) - __builtin_clz(x-1) : 0; +#else if (x <= 0) return 0; - for (int i = 0; i < 32; i++) if (((x-1) >> i) == 0) return i; - log_abort(); +#endif } std::string stringf(const char *fmt, ...) @@ -166,7 +180,7 @@ std::string vstringf(const char *fmt, va_list ap) std::string string; char *str = NULL; -#ifdef _WIN32 +#if defined(_WIN32 )|| defined(__CYGWIN__) int sz = 64, rc; while (1) { va_list apc; @@ -216,12 +230,18 @@ std::string next_token(std::string &text, const char *sep, bool long_strings) if (long_strings && pos_begin != text.size() && text[pos_begin] == '"') { string sep_string = sep; - for (size_t i = pos_begin+1; i < text.size(); i++) + for (size_t i = pos_begin+1; i < text.size(); i++) { if (text[i] == '"' && (i+1 == text.size() || sep_string.find(text[i+1]) != std::string::npos)) { std::string token = text.substr(pos_begin, i-pos_begin+1); text = text.substr(i+1); return token; } + if (i+1 < text.size() && text[i] == '"' && text[i+1] == ';' && (i+2 == text.size() || sep_string.find(text[i+2]) != std::string::npos)) { + std::string token = text.substr(pos_begin, i-pos_begin+1); + text = text.substr(i+2); + return token + ";"; + } + } } size_t pos_end = text.find_first_of(sep, pos_begin); @@ -464,17 +484,45 @@ void remove_directory(std::string dirname) #endif } +std::string escape_filename_spaces(const std::string& filename) +{ + std::string out; + out.reserve(filename.size()); + for (auto c : filename) + { + if (c == ' ') + out += "\\ "; + else + out.push_back(c); + } + return out; +} + int GetSize(RTLIL::Wire *wire) { return wire->width; } +bool already_setup = false; + void yosys_setup() { - // if there are already IdString objects then we have a global initialization order bug - IdString empty_id; - log_assert(empty_id.index_ == 0); - IdString::get_reference(empty_id.index_); + if(already_setup) + return; + already_setup = true; + + RTLIL::ID::A = "\\A"; + RTLIL::ID::B = "\\B"; + RTLIL::ID::Y = "\\Y"; + RTLIL::ID::keep = "\\keep"; + RTLIL::ID::whitebox = "\\whitebox"; + RTLIL::ID::blackbox = "\\blackbox"; + + #ifdef WITH_PYTHON + PyImport_AppendInittab((char*)"libyosys", INIT_MODULE); + Py_Initialize(); + PyRun_SimpleString("import sys"); + #endif Pass::init_register(); yosys_design = new RTLIL::Design; @@ -482,8 +530,18 @@ void yosys_setup() log_push(); } +bool yosys_already_setup() +{ + return already_setup; +} + +bool already_shutdown = false; + void yosys_shutdown() { + if(already_shutdown) + return; + already_shutdown = true; log_pop(); delete yosys_design; @@ -511,11 +569,15 @@ void yosys_shutdown() dlclose(it.second); loaded_plugins.clear(); +#ifdef WITH_PYTHON + loaded_python_plugins.clear(); +#endif loaded_plugin_aliases.clear(); #endif - IdString empty_id; - IdString::put_reference(empty_id.index_); +#ifdef WITH_PYTHON + Py_Finalize(); +#endif } RTLIL::IdString new_id(std::string file, int line, std::string func) @@ -564,7 +626,7 @@ std::vector<std::string> glob_filename(const std::string &filename_pattern) { std::vector<std::string> results; -#ifdef _WIN32 +#if defined(_WIN32) || !defined(YOSYS_ENABLE_GLOB) results.push_back(filename_pattern); #else glob_t globbuf; @@ -585,10 +647,14 @@ std::vector<std::string> glob_filename(const std::string &filename_pattern) void rewrite_filename(std::string &filename) { - if (filename.substr(0, 1) == "\"" && filename.substr(GetSize(filename)-1) == "\"") + if (filename.compare(0, 1, "\"") == 0 && filename.compare(GetSize(filename)-1, std::string::npos, "\"") == 0) filename = filename.substr(1, GetSize(filename)-2); - if (filename.substr(0, 2) == "+/") + if (filename.compare(0, 2, "+/") == 0) filename = proc_share_dirname() + filename.substr(2); +#ifndef _WIN32 + if (filename.compare(0, 2, "~/") == 0) + filename = filename.replace(0, 1, getenv("HOME")); +#endif } #ifdef YOSYS_ENABLE_TCL @@ -636,9 +702,10 @@ extern Tcl_Interp *yosys_get_tcl_interp() struct TclPass : public Pass { TclPass() : Pass("tcl", "execute a TCL script file") { } - virtual void help() { + void help() YS_OVERRIDE { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); - log(" tcl <filename>\n"); + log(" tcl <filename> [args]\n"); log("\n"); log("This command executes the tcl commands in the specified file.\n"); log("Use 'yosys cmd' to run the yosys command 'cmd' from tcl.\n"); @@ -648,14 +715,24 @@ struct TclPass : public Pass { log("'proc' and 'rename' are wrapped to tcl commands 'procs' and 'renames'\n"); log("in order to avoid a name collision with the built in commands.\n"); log("\n"); + log("If any arguments are specified, these arguments are provided to the script via\n"); + log("the standard $argc and $argv variables.\n"); + log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { + void execute(std::vector<std::string> args, RTLIL::Design *) YS_OVERRIDE { if (args.size() < 2) log_cmd_error("Missing script file.\n"); - if (args.size() > 2) - extra_args(args, 1, design, false); - if (Tcl_EvalFile(yosys_get_tcl_interp(), args[1].c_str()) != TCL_OK) - log_cmd_error("TCL interpreter returned an error: %s\n", Tcl_GetStringResult(yosys_get_tcl_interp())); + + std::vector<Tcl_Obj*> script_args; + for (auto it = args.begin() + 2; it != args.end(); ++it) + script_args.push_back(Tcl_NewStringObj((*it).c_str(), (*it).size())); + + Tcl_Interp *interp = yosys_get_tcl_interp(); + Tcl_ObjSetVar2(interp, Tcl_NewStringObj("argc", 4), NULL, Tcl_NewIntObj(script_args.size()), 0); + Tcl_ObjSetVar2(interp, Tcl_NewStringObj("argv", 4), NULL, Tcl_NewListObj(script_args.size(), script_args.data()), 0); + Tcl_ObjSetVar2(interp, Tcl_NewStringObj("argv0", 5), NULL, Tcl_NewStringObj(args[1].c_str(), args[1].size()), 0); + if (Tcl_EvalFile(interp, args[1].c_str()) != TCL_OK) + log_cmd_error("TCL interpreter returned an error: %s\n", Tcl_GetStringResult(interp)); } } TclPass; #endif @@ -733,7 +810,7 @@ std::string proc_self_dirname() return "/"; } #else - #error Dont know how to determine process executable base path! + #error "Don't know how to determine process executable base path!" #endif #ifdef EMSCRIPTEN @@ -799,7 +876,7 @@ static void handle_label(std::string &command, bool &from_to_active, const std:: while (pos < GetSize(command) && command[pos] != ' ' && command[pos] != '\t' && command[pos] != '\r' && command[pos] != '\n') label += command[pos++]; - if (label.back() == ':' && GetSize(label) > 1) + if (GetSize(label) > 1 && label.back() == ':') { label = label.substr(0, GetSize(label)-1); command = command.substr(pos); @@ -817,21 +894,26 @@ void run_frontend(std::string filename, std::string command, std::string *backen design = yosys_design; if (command == "auto") { - if (filename.size() > 2 && filename.substr(filename.size()-2) == ".v") + std::string filename_trim = filename; + if (filename_trim.size() > 3 && filename_trim.compare(filename_trim.size()-3, std::string::npos, ".gz") == 0) + filename_trim.erase(filename_trim.size()-3); + if (filename_trim.size() > 2 && filename_trim.compare(filename_trim.size()-2, std::string::npos, ".v") == 0) command = "verilog"; - else if (filename.size() > 2 && filename.substr(filename.size()-3) == ".sv") + else if (filename_trim.size() > 2 && filename_trim.compare(filename_trim.size()-3, std::string::npos, ".sv") == 0) command = "verilog -sv"; - else if (filename.size() > 2 && filename.substr(filename.size()-4) == ".vhd") + else if (filename_trim.size() > 3 && filename_trim.compare(filename_trim.size()-4, std::string::npos, ".vhd") == 0) command = "vhdl"; - else if (filename.size() > 4 && filename.substr(filename.size()-5) == ".blif") + else if (filename_trim.size() > 4 && filename_trim.compare(filename_trim.size()-5, std::string::npos, ".blif") == 0) command = "blif"; - else if (filename.size() > 4 && filename.substr(filename.size()-5) == ".json") + else if (filename_trim.size() > 5 && filename_trim.compare(filename_trim.size()-6, std::string::npos, ".eblif") == 0) + command = "blif"; + else if (filename_trim.size() > 4 && filename_trim.compare(filename_trim.size()-5, std::string::npos, ".json") == 0) command = "json"; - else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".il") + else if (filename_trim.size() > 3 && filename_trim.compare(filename_trim.size()-3, std::string::npos, ".il") == 0) command = "ilang"; - else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".ys") + else if (filename_trim.size() > 3 && filename_trim.compare(filename_trim.size()-3, std::string::npos, ".ys") == 0) command = "script"; - else if (filename.size() > 2 && filename.substr(filename.size()-4) == ".tcl") + else if (filename_trim.size() > 3 && filename_trim.compare(filename_trim.size()-4, std::string::npos, ".tcl") == 0) command = "tcl"; else if (filename == "-") command = "script"; @@ -882,14 +964,18 @@ void run_frontend(std::string filename, std::string command, std::string *backen command += next_line; } handle_label(command, from_to_active, run_from, run_to); - if (from_to_active) + if (from_to_active) { Pass::call(design, command); + design->check(); + } } if (!command.empty()) { handle_label(command, from_to_active, run_from, run_to); - if (from_to_active) + if (from_to_active) { Pass::call(design, command); + design->check(); + } } } catch (...) { @@ -918,6 +1004,7 @@ void run_frontend(std::string filename, std::string command, std::string *backen Pass::call(design, vector<string>({command, filename})); else Frontend::frontend_call(design, NULL, filename, command); + design->check(); } void run_frontend(std::string filename, std::string command, RTLIL::Design *design) @@ -941,17 +1028,17 @@ void run_backend(std::string filename, std::string command, RTLIL::Design *desig design = yosys_design; if (command == "auto") { - if (filename.size() > 2 && filename.substr(filename.size()-2) == ".v") + if (filename.size() > 2 && filename.compare(filename.size()-2, std::string::npos, ".v") == 0) command = "verilog"; - else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".il") + else if (filename.size() > 3 && filename.compare(filename.size()-3, std::string::npos, ".il") == 0) command = "ilang"; - else if (filename.size() > 4 && filename.substr(filename.size()-4) == ".aig") + else if (filename.size() > 4 && filename.compare(filename.size()-4, std::string::npos, ".aig") == 0) command = "aiger"; - else if (filename.size() > 5 && filename.substr(filename.size()-5) == ".blif") + else if (filename.size() > 5 && filename.compare(filename.size()-5, std::string::npos, ".blif") == 0) command = "blif"; - else if (filename.size() > 5 && filename.substr(filename.size()-5) == ".edif") + else if (filename.size() > 5 && filename.compare(filename.size()-5, std::string::npos, ".edif") == 0) command = "edif"; - else if (filename.size() > 5 && filename.substr(filename.size()-5) == ".json") + else if (filename.size() > 5 && filename.compare(filename.size()-5, std::string::npos, ".json") == 0) command = "json"; else if (filename == "-") command = "ilang"; @@ -985,7 +1072,7 @@ static char *readline_cmd_generator(const char *text, int state) } for (; it != pass_register.end(); it++) { - if (it->first.substr(0, len) == text) + if (it->first.compare(0, len, text) == 0) return strdup((it++)->first.c_str()); } return NULL; @@ -1007,7 +1094,7 @@ static char *readline_obj_generator(const char *text, int state) if (design->selected_active_module.empty()) { for (auto &it : design->modules_) - if (RTLIL::unescape_id(it.first).substr(0, len) == text) + if (RTLIL::unescape_id(it.first).compare(0, len, text) == 0) obj_names.push_back(strdup(RTLIL::id2cstr(it.first))); } else @@ -1016,19 +1103,19 @@ static char *readline_obj_generator(const char *text, int state) RTLIL::Module *module = design->modules_.at(design->selected_active_module); for (auto &it : module->wires_) - if (RTLIL::unescape_id(it.first).substr(0, len) == text) + if (RTLIL::unescape_id(it.first).compare(0, len, text) == 0) obj_names.push_back(strdup(RTLIL::id2cstr(it.first))); for (auto &it : module->memories) - if (RTLIL::unescape_id(it.first).substr(0, len) == text) + if (RTLIL::unescape_id(it.first).compare(0, len, text) == 0) obj_names.push_back(strdup(RTLIL::id2cstr(it.first))); for (auto &it : module->cells_) - if (RTLIL::unescape_id(it.first).substr(0, len) == text) + if (RTLIL::unescape_id(it.first).compare(0, len, text) == 0) obj_names.push_back(strdup(RTLIL::id2cstr(it.first))); for (auto &it : module->processes) - if (RTLIL::unescape_id(it.first).substr(0, len) == text) + if (RTLIL::unescape_id(it.first).compare(0, len, text) == 0) obj_names.push_back(strdup(RTLIL::id2cstr(it.first))); } @@ -1101,6 +1188,7 @@ void shell(RTLIL::Design *design) design->selection_stack.pop_back(); log_reset_stack(); } + design->check(); } if (command == NULL) printf("exit\n"); @@ -1111,7 +1199,7 @@ void shell(RTLIL::Design *design) struct ShellPass : public Pass { ShellPass() : Pass("shell", "enter interactive command mode") { } - virtual void help() { + void help() YS_OVERRIDE { log("\n"); log(" shell\n"); log("\n"); @@ -1143,7 +1231,7 @@ struct ShellPass : public Pass { log("Press Ctrl-D or type 'exit' to leave the interactive shell.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { extra_args(args, 1, design, false); shell(design); } @@ -1152,7 +1240,7 @@ struct ShellPass : public Pass { #if defined(YOSYS_ENABLE_READLINE) || defined(YOSYS_ENABLE_EDITLINE) struct HistoryPass : public Pass { HistoryPass() : Pass("history", "show last interactive commands") { } - virtual void help() { + void help() YS_OVERRIDE { log("\n"); log(" history\n"); log("\n"); @@ -1161,7 +1249,7 @@ struct HistoryPass : public Pass { log("from executed scripts.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { extra_args(args, 1, design, false); #ifdef YOSYS_ENABLE_READLINE for(HIST_ENTRY **list = history_list(); *list != NULL; list++) @@ -1175,24 +1263,59 @@ struct HistoryPass : public Pass { #endif struct ScriptCmdPass : public Pass { - ScriptCmdPass() : Pass("script", "execute commands from script file") { } - virtual void help() { + ScriptCmdPass() : Pass("script", "execute commands from file or wire") { } + void help() YS_OVERRIDE { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); log(" script <filename> [<from_label>:<to_label>]\n"); + log(" script -scriptwire [selection]\n"); log("\n"); - log("This command executes the yosys commands in the specified file.\n"); + log("This command executes the yosys commands in the specified file (default\n"); + log("behaviour), or commands embedded in the constant text value connected to the\n"); + log("selected wires.\n"); log("\n"); - log("The 2nd argument can be used to only execute the section of the\n"); - log("file between the specified labels. An empty from label is synonymous\n"); - log("for the beginning of the file and an empty to label is synonymous\n"); - log("for the end of the file.\n"); + log("In the default (file) case, the 2nd argument can be used to only execute the\n"); + log("section of the file between the specified labels. An empty from label is\n"); + log("synonymous with the beginning of the file and an empty to label is synonymous\n"); + log("with the end of the file.\n"); log("\n"); log("If only one label is specified (without ':') then only the block\n"); log("marked with that label (until the next label) is executed.\n"); log("\n"); + log("In \"-scriptwire\" mode, the commands on the selected wire(s) will be executed\n"); + log("in the scope of (and thus, relative to) the wires' owning module(s). This\n"); + log("'-module' mode can be exited by using the 'cd' command.\n"); + log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { - if (args.size() < 2) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + bool scriptwire = false; + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + if (args[argidx] == "-scriptwire") { + scriptwire = true; + continue; + } + break; + } + if (scriptwire) { + extra_args(args, argidx, design); + + for (auto mod : design->selected_modules()) + for (auto &c : mod->connections()) { + if (!c.first.is_wire()) + continue; + auto w = c.first.as_wire(); + if (!mod->selected(w)) + continue; + if (!c.second.is_fully_const()) + log_error("RHS of selected wire %s.%s is not constant.\n", log_id(mod), log_id(w)); + auto v = c.second.as_const(); + Pass::call_on_module(design, mod, v.decode_string()); + } + } + else if (args.size() < 2) log_cmd_error("Missing script file.\n"); else if (args.size() == 2) run_frontend(args[1], "script", design); diff --git a/kernel/yosys.h b/kernel/yosys.h index 14cbcd610..a80cb00b4 100644 --- a/kernel/yosys.h +++ b/kernel/yosys.h @@ -1,4 +1,4 @@ -/* +/* -*- c++ -*- * yosys -- Yosys Open SYnthesis Suite * * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> @@ -52,6 +52,7 @@ #include <stdexcept> #include <memory> #include <cmath> +#include <cstddef> #include <sstream> #include <fstream> @@ -66,6 +67,10 @@ #include <stdio.h> #include <limits.h> +#ifdef WITH_PYTHON +#include <Python.h> +#endif + #ifndef _YOSYS_ # error It looks like you are trying to build Yosys without the config defines set. \ When building Yosys with a custom make system, make sure you set all the \ @@ -83,6 +88,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 @@ -115,6 +124,7 @@ extern const char *Tcl_GetStringResult(Tcl_Interp *interp); # define PATH_MAX 4096 #endif +#define YOSYS_NAMESPACE Yosys #define PRIVATE_NAMESPACE_BEGIN namespace { #define PRIVATE_NAMESPACE_END } #define YOSYS_NAMESPACE_BEGIN namespace Yosys { @@ -239,7 +249,7 @@ extern bool memhasher_active; inline void memhasher() { if (memhasher_active) memhasher_do(); } void yosys_banner(); -int ceil_log2(int x); +int ceil_log2(int x) YS_ATTRIBUTE(const); std::string stringf(const char *fmt, ...) YS_ATTRIBUTE(format(printf, 1, 2)); std::string vstringf(const char *fmt, va_list ap); int readsome(std::istream &f, char *s, int n); @@ -252,6 +262,7 @@ std::string make_temp_dir(std::string template_str = "/tmp/yosys_XXXXXX"); bool check_file_exists(std::string filename, bool is_exec = false); bool is_absolute_path(std::string filename); void remove_directory(std::string dirname); +std::string escape_filename_spaces(const std::string& filename); template<typename T> int GetSize(const T &obj) { return obj.size(); } int GetSize(RTLIL::Wire *wire); @@ -276,6 +287,11 @@ namespace hashlib { } void yosys_setup(); + +#ifdef WITH_PYTHON +bool yosys_already_setup(); +#endif + void yosys_shutdown(); #ifdef YOSYS_ENABLE_TCL @@ -289,8 +305,17 @@ RTLIL::IdString new_id(std::string file, int line, std::string func); #define NEW_ID \ YOSYS_NAMESPACE_PREFIX new_id(__FILE__, __LINE__, __FUNCTION__) -#define ID(_str) \ - ([]() { static YOSYS_NAMESPACE_PREFIX RTLIL::IdString _id(_str); return _id; })() +// Create a statically allocated IdString object, using for example ID(A) or ID($add). +// +// Recipe for Converting old code that is using conversion of strings like "\\A" and +// "$add" for creating IdStrings: Run below SED command on the .cc file and then use for +// example "meld foo.cc foo.cc.orig" to manually compile errors, if necessary. +// +// sed -i.orig -r 's/"\\\\([a-zA-Z0-9_]+)"/ID(\1)/g; s/"(\$[a-zA-Z0-9_]+)"/ID(\1)/g;' <filename> +// +#define ID(_id) ([]() { const char *p = "\\" #_id, *q = p[1] == '$' ? p+1 : p; \ + static const YOSYS_NAMESPACE_PREFIX RTLIL::IdString id(q); return id; })() +namespace ID = RTLIL::ID; RTLIL::Design *yosys_get_design(); std::string proc_self_dirname(); @@ -317,6 +342,9 @@ extern std::vector<RTLIL::Design*> pushed_designs; // from passes/cmds/pluginc.cc extern std::map<std::string, void*> loaded_plugins; +#ifdef WITH_PYTHON +extern std::map<std::string, void*> loaded_python_plugins; +#endif extern std::map<std::string, std::string> loaded_plugin_aliases; void load_plugin(std::string filename, std::vector<std::string> aliases); diff --git a/libs/ezsat/ezminisat.h b/libs/ezsat/ezminisat.h index 983e6fd0e..3a34c13c8 100644 --- a/libs/ezsat/ezminisat.h +++ b/libs/ezsat/ezminisat.h @@ -28,7 +28,7 @@ #include <time.h> // minisat is using limit macros and format macros in their headers that -// can be the source of some troubles when used from c++11. thefore we +// can be the source of some troubles when used from c++11. therefore we // don't force ezSAT users to use minisat headers.. namespace Minisat { class Solver; diff --git a/libs/subcircuit/README b/libs/subcircuit/README index b1335681e..ecaa987db 100644 --- a/libs/subcircuit/README +++ b/libs/subcircuit/README @@ -109,7 +109,7 @@ look at the demo.cc example program in this directory. Setting up graphs ----------------- -Instanciate the SubCircuit::Graph class and use the methods of this class to +Instantiate the SubCircuit::Graph class and use the methods of this class to set up the circuit. SubCircuit::Graph myGraph; @@ -152,7 +152,7 @@ rotate shift, The method createConstant() can be used to add a constant driver to a signal. The signal value is encoded as one char by bit, allowing for multi-valued -logic matching. The follwoing command sets the lowest bit of cell6.A to a +logic matching. The following command sets the lowest bit of cell6.A to a logic 1: myGraph.createConnection("cell6", "A", 0, '1'); @@ -314,7 +314,7 @@ bool userCompareEdge(needleGraphId, needleFromNodeId, needleFromUserData, needle Perform additional checks on a pair of a pair of adjacent nodes (one adjacent pair from the needle and one adjacent pair from the haystack) - to determine wheter this edge from the needle is compatible with + to determine whether this edge from the needle is compatible with that edge from the haystack. The default implementation always returns true. diff --git a/libs/subcircuit/subcircuit.cc b/libs/subcircuit/subcircuit.cc index 7c7236833..e8361a67e 100644 --- a/libs/subcircuit/subcircuit.cc +++ b/libs/subcircuit/subcircuit.cc @@ -320,12 +320,10 @@ class SubCircuit::SolverWorker static int numberOfPermutations(const std::vector<std::string> &list) { - int numPermutations = 1; - for (int i = 0; i < int(list.size()); i++) { - assert(numPermutations < maxPermutationsLimit); - numPermutations *= i+1; - } - return numPermutations; + constexpr size_t mappedPermutationsSize = 10; + constexpr int mappedPermutations[mappedPermutationsSize] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880}; + assert(list.size() < mappedPermutationsSize); + return mappedPermutations[list.size()]; } static void permutateVectorToMap(std::map<std::string, std::string> &map, const std::vector<std::string> &list, int idx) diff --git a/manual/CHAPTER_CellLib.tex b/manual/CHAPTER_CellLib.tex index 277e89328..0106059b6 100644 --- a/manual/CHAPTER_CellLib.tex +++ b/manual/CHAPTER_CellLib.tex @@ -119,6 +119,12 @@ than one bit from \B{S} is set the output is undefined. Cells of this type are u ``parallel cases'' (defined by using the {\tt parallel\_case} attribute or detected by an optimization). +The {\tt \$tribuf} cell is used to implement tristate logic. Cells of this type have a \B{WIDTH} +parameter and inputs \B{A} and \B{EN} and an output \B{Y}. The \B{A} input and \B{Y} output are +\B{WIDTH} bits wide, and the \B{EN} input is one bit wide. When \B{EN} is 0, the output \B{Y} +is not driven. When \B{EN} is 1, the value from \B{A} input is sent to the \B{Y} output. Therefore, +the {\tt \$tribuf} cell implements the function \lstinline[language=Verilog]; Y = EN ? A : 'bz;. + Behavioural code with cascaded {\tt if-then-else}- and {\tt case}-statements usually results in trees of multiplexer cells. Many passes (from various optimizations to FSM extraction) heavily depend on these multiplexer trees to @@ -211,14 +217,15 @@ Add information about {\tt \$sr} cells (set-reset flip-flops) and d-type latches \subsection{Memories} \label{sec:memcells} -Memories are either represented using RTLIL::Memory objects and {\tt \$memrd} and {\tt \$memwr} cells -or simply by using {\tt \$mem} cells. +Memories are either represented using RTLIL::Memory objects, {\tt \$memrd}, {\tt \$memwr}, and {\tt \$meminit} +cells, or by {\tt \$mem} cells alone. In the first alternative the RTLIL::Memory objects hold the general metadata for the memory (bit width, size in number of words, etc.) and for each port a {\tt \$memrd} (read port) or {\tt \$memwr} (write port) cell is created. Having individual cells for read and write ports has the advantage that they can be consolidated using resource sharing passes. In some cases this drastically reduces the number of required -ports on the memory cell. +ports on the memory cell. In this alternative, memory initialization data is represented by {\tt \$meminit} cells, +which allow delaying constant folding for initialization addresses and data until after the frontend finishes. The {\tt \$memrd} cells have a clock input \B{CLK}, an enable input \B{EN}, an address input \B{ADDR}, and a data output \B{DATA}. They also have the @@ -253,7 +260,7 @@ enable bit for each data bit), an address input \B{ADDR} and a data input \begin{itemize} \item \B{MEMID} \\ -The name of the RTLIL::Memory object that is associated with this read port. +The name of the RTLIL::Memory object that is associated with this write port. \item \B{ABITS} \\ The number of address bits (width of the \B{ADDR} input port). @@ -262,7 +269,7 @@ The number of address bits (width of the \B{ADDR} input port). The number of data bits (width of the \B{DATA} output port). \item \B{CLK\_ENABLE} \\ -When this parameter is non-zero, the clock is used. Otherwise this read port is asynchronous and +When this parameter is non-zero, the clock is used. Otherwise this write port is asynchronous and the \B{CLK} input is not used. \item \B{CLK\_POLARITY} \\ @@ -273,6 +280,27 @@ edge if this parameter is {\tt 1'b0}. The cell with the higher integer value in this parameter wins a write conflict. \end{itemize} +The {\tt \$meminit} cells have an address input \B{ADDR} and a data input \B{DATA}, with the width +of the \B{DATA} port equal to \B{WIDTH} parameter times \B{WORDS} parameter. Both of the inputs +must resolve to a constant for synthesis to succeed. + +\begin{itemize} +\item \B{MEMID} \\ +The name of the RTLIL::Memory object that is associated with this initialization cell. + +\item \B{ABITS} \\ +The number of address bits (width of the \B{ADDR} input port). + +\item \B{WIDTH} \\ +The number of data bits per memory location. + +\item \B{WORDS} \\ +The number of consecutive memory locations initialized by this cell. + +\item \B{PRIORITY} \\ +The cell with the higher integer value in this parameter wins an initialization conflict. +\end{itemize} + The HDL frontend models a memory using RTLIL::Memory objects and asynchronous {\tt \$memrd} and {\tt \$memwr} cells. The {\tt memory} pass (i.e.~its various sub-passes) migrates {\tt \$dff} cells into the {\tt \$memrd} and {\tt \$memwr} cells making them synchronous, then @@ -295,6 +323,9 @@ The number of address bits. \item \B{WIDTH} \\ The number of data bits per word. +\item \B{INIT} \\ +The initial memory contents. + \item \B{RD\_PORTS} \\ The number of read ports on this memory cell. @@ -345,9 +376,11 @@ This input is \B{WR\_PORTS}*\B{ABITS} bits wide, containing all address signals This input is \B{WR\_PORTS}*\B{WIDTH} bits wide, containing all data signals for the write ports. \end{itemize} -The {\tt techmap} pass can be used to manually map {\tt \$mem} cells to -specialized memory cells on the target architecture, such as block ram resources -on an FPGA. +The {\tt memory\_collect} pass can be used to convert discrete {\tt \$memrd}, {\tt \$memwr}, and {\tt \$meminit} cells +belonging to the same memory to a single {\tt \$mem} cell, whereas the {\tt memory\_unpack} pass performs the inverse operation. +The {\tt memory\_dff} pass can combine asynchronous memory ports that are fed by or feeding registers into synchronous memory ports. +The {\tt memory\_bram} pass can be used to recognize {\tt \$mem} cells that can be implemented with a block RAM resource on an FPGA. +The {\tt memory\_map} pass can be used to implement {\tt \$mem} cells as basic logic: word-wide DFFs and address decoders. \subsection{Finite State Machines} @@ -371,9 +404,15 @@ Verilog & Cell Type \\ \hline \lstinline[language=Verilog]; Y = ~A; & {\tt \$\_NOT\_} \\ \lstinline[language=Verilog]; Y = A & B; & {\tt \$\_AND\_} \\ +\lstinline[language=Verilog]; Y = ~(A & B); & {\tt \$\_NAND\_} \\ +\lstinline[language=Verilog]; Y = A & ~B; & {\tt \$\_ANDNOT\_} \\ \lstinline[language=Verilog]; Y = A | B; & {\tt \$\_OR\_} \\ +\lstinline[language=Verilog]; Y = ~(A | B); & {\tt \$\_NOR\_} \\ +\lstinline[language=Verilog]; Y = A | ~B; & {\tt \$\_ORNOT\_} \\ \lstinline[language=Verilog]; Y = A ^ B; & {\tt \$\_XOR\_} \\ +\lstinline[language=Verilog]; Y = ~(A ^ B); & {\tt \$\_XNOR\_} \\ \lstinline[language=Verilog]; Y = S ? B : A; & {\tt \$\_MUX\_} \\ +\lstinline[language=Verilog]; Y = EN ? A : 'bz; & {\tt \$\_TBUF\_} \\ \hline \lstinline[language=Verilog]; always @(negedge C) Q <= D; & {\tt \$\_DFF\_N\_} \\ \lstinline[language=Verilog]; always @(posedge C) Q <= D; & {\tt \$\_DFF\_P\_} \\ @@ -396,9 +435,10 @@ $ClkEdge$ & $RstLvl$ & $RstVal$ & Cell Type \\ \end{table} Table~\ref{tab:CellLib_gates} lists all cell types used for gate level logic. The cell types -{\tt \$\_NOT\_}, {\tt \$\_AND\_}, {\tt \$\_OR\_}, {\tt \$\_XOR\_} and {\tt \$\_MUX\_} -are used to model combinatorial logic. The cell types {\tt \$\_DFF\_N\_} and {\tt \$\_DFF\_P\_} -represent d-type flip-flops. +{\tt \$\_NOT\_}, {\tt \$\_AND\_}, {\tt \$\_NAND\_}, {\tt \$\_ANDNOT\_}, {\tt \$\_OR\_}, {\tt \$\_NOR\_}, +{\tt \$\_ORNOT\_}, {\tt \$\_XOR\_}, {\tt \$\_XNOR\_} and {\tt \$\_MUX\_} are used to model combinatorial logic. +The cell type {\tt \$\_TBUF\_} is used to model tristate logic. +The cell types {\tt \$\_DFF\_N\_} and {\tt \$\_DFF\_P\_} represent d-type flip-flops. The cell types {\tt \$\_DFF\_NN0\_}, {\tt \$\_DFF\_NN1\_}, {\tt \$\_DFF\_NP0\_}, {\tt \$\_DFF\_NP1\_}, {\tt \$\_DFF\_PN0\_}, {\tt \$\_DFF\_PN1\_}, {\tt \$\_DFF\_PP0\_} and {\tt \$\_DFF\_PP1\_} implement @@ -410,7 +450,7 @@ otherwise. \begin{lstlisting}[mathescape,language=Verilog] always @($ClkEdge$ C, $RstEdge$ R) if (R == $RstLvl$) - Q <= $RstVa$l; + Q <= $RstVal$; else Q <= D; \end{lstlisting} @@ -426,6 +466,10 @@ Add information about {\tt \$assert}, {\tt \$assume}, {\tt \$live}, {\tt \$fair} \end{fixme} \begin{fixme} +Add information about {\tt \$specify2}, {\tt \$specify3}, and {\tt \$specrule} cells. +\end{fixme} + +\begin{fixme} Add information about {\tt \$slice} and {\tt \$concat} cells. \end{fixme} @@ -450,7 +494,6 @@ Add information about {\tt \$\_DFFE\_??\_}, {\tt \$\_DFFSR\_???\_}, {\tt \$\_DLA \end{fixme} \begin{fixme} -Add information about {\tt \$\_NAND\_}, {\tt \$\_NOR\_}, {\tt \$\_XNOR\_}, {\tt \$\_ANDNOT\_}, {\tt \$\_ORNOT\_}, -{\tt \$\_AOI3\_}, {\tt \$\_OAI3\_}, {\tt \$\_AOI4\_}, and {\tt \$\_OAI4\_} cells. +Add information about {\tt \$\_AOI3\_}, {\tt \$\_OAI3\_}, {\tt \$\_AOI4\_}, {\tt \$\_OAI4\_}, and {\tt \$\_NMUX\_} cells. \end{fixme} diff --git a/manual/CHAPTER_Overview.tex b/manual/CHAPTER_Overview.tex index 964875d57..3009bf2c0 100644 --- a/manual/CHAPTER_Overview.tex +++ b/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}. @@ -428,8 +441,8 @@ memory object has the following properties: All read accesses to the memory are transformed to {\tt \$memrd} cells and all write accesses to {\tt \$memwr} cells by the language frontend. These cells consist of independent read- and write-ports -to the memory. The \B{MEMID} parameter on these cells is used to link them together and to the -RTLIL::Memory object they belong to. +to the memory. Memory initialization is transformed to {\tt \$meminit} cells by the language frontend. +The \B{MEMID} parameter on these cells is used to link them together and to the RTLIL::Memory object they belong to. The rationale behind using separate cells for the individual ports versus creating a large multiport memory cell right in the language frontend is that diff --git a/manual/CHAPTER_Prog/stubnets.cc b/manual/CHAPTER_Prog/stubnets.cc index eb77bd404..8123e63db 100644 --- a/manual/CHAPTER_Prog/stubnets.cc +++ b/manual/CHAPTER_Prog/stubnets.cc @@ -98,7 +98,7 @@ static void find_stub_nets(RTLIL::Design *design, RTLIL::Module *module, bool re // each pass contains a singleton object that is derived from Pass struct StubnetsPass : public Pass { StubnetsPass() : Pass("stubnets") { } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { // variables to mirror information from passed options bool report_bits = 0; diff --git a/manual/PRESENTATION_Prog/my_cmd.cc b/manual/PRESENTATION_Prog/my_cmd.cc index d99bfe1e8..5d9a7e13b 100644 --- a/manual/PRESENTATION_Prog/my_cmd.cc +++ b/manual/PRESENTATION_Prog/my_cmd.cc @@ -6,7 +6,7 @@ PRIVATE_NAMESPACE_BEGIN struct MyPass : public Pass { MyPass() : Pass("my_cmd", "just a simple test") { } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log("Arguments to my_cmd:\n"); for (auto &arg : args) @@ -22,7 +22,7 @@ struct MyPass : public Pass { struct Test1Pass : public Pass { Test1Pass() : Pass("test1", "creating the absval module") { } - virtual void execute(std::vector<std::string>, RTLIL::Design *design) + void execute(std::vector<std::string>, RTLIL::Design *design) YS_OVERRIDE { if (design->has("\\absval") != 0) log_error("A module with the name absval already exists!\n"); @@ -49,7 +49,7 @@ struct Test1Pass : public Pass { struct Test2Pass : public Pass { Test2Pass() : Pass("test2", "demonstrating sigmap on test module") { } - virtual void execute(std::vector<std::string>, RTLIL::Design *design) + void execute(std::vector<std::string>, RTLIL::Design *design) YS_OVERRIDE { if (design->selection_stack.back().empty()) log_cmd_error("This command can't operator on an empty selection!\n"); diff --git a/manual/command-reference-manual.tex b/manual/command-reference-manual.tex index 8af8ccdd0..bed6326e2 100644 --- a/manual/command-reference-manual.tex +++ b/manual/command-reference-manual.tex @@ -23,45 +23,47 @@ library to a target architecture. if no -script parameter is given, the following scripts are used: for -liberty without -constr: - strash; dc2; scorr; ifraig; retime -o {D}; strash; dch -f; - map {D} + strash; ifraig; scorr; dc2; dretime; strash; &get -n; &dch -f; + &nf {D}; &put for -liberty with -constr: - strash; dc2; scorr; ifraig; retime -o {D}; strash; dch -f; - map {D}; buffer; upsize {D}; dnsize {D}; stime -p + strash; ifraig; scorr; dc2; dretime; strash; &get -n; &dch -f; + &nf {D}; &put; buffer; upsize {D}; dnsize {D}; stime -p for -lut/-luts (only one LUT size): - strash; dc2; scorr; ifraig; retime -o; strash; dch -f; if; mfs; - lutpack + strash; ifraig; scorr; dc2; dretime; strash; dch -f; if; mfs2; + lutpack {S} for -lut/-luts (different LUT sizes): - strash; dc2; scorr; ifraig; retime -o; strash; dch -f; if; mfs + strash; ifraig; scorr; dc2; dretime; strash; dch -f; if; mfs2 for -sop: - strash; dc2; scorr; ifraig; retime -o; strash; dch -f; + strash; ifraig; scorr; dc2; dretime; strash; dch -f; cover {I} {P} otherwise: - strash; dc2; scorr; ifraig; retime -o; strash; dch -f; map + strash; ifraig; scorr; dc2; dretime; strash; &get -n; &dch -f; + &nf {D}; &put -fast use different default scripts that are slightly faster (at the cost of output quality): for -liberty without -constr: - retime -o {D}; map {D} + strash; dretime; map {D} for -liberty with -constr: - retime -o {D}; map {D}; buffer; upsize {D}; dnsize {D}; stime -p + strash; dretime; map {D}; buffer; upsize {D}; dnsize {D}; + stime -p for -lut/-luts: - retime -o; if + strash; dretime; if for -sop: - retime -o; cover -I {I} -P {P} + strash; dretime; cover -I {I} -P {P} otherwise: - retime -o; map + strash; dretime; map -liberty <file> generate netlists for the specified cell library (using the liberty @@ -81,6 +83,8 @@ library to a target architecture. -D <picoseconds> set delay target. the string {D} in the default scripts above is replaced by this option when used, and an empty string otherwise. + this also replaces 'dretime' with 'dretime; retime -o {D}' in the + default scripts above. -I <num> maximum number of SOP inputs. @@ -90,6 +94,10 @@ library to a target architecture. maximum number of SOP products. (replaces {P} in the default scripts above) + -S <num> + maximum number of LUT inputs shared. + (replaces {S} in the default scripts above, default: -S 1) + -lut <width> generate netlist using luts of (max) the specified width. @@ -107,10 +115,21 @@ library to a target architecture. map to sum-of-product cells and inverters -g type1,type2,... - Map the the specified list of gate types. Supported gates types are: - AND, NAND, OR, NOR, XOR, XNOR, MUX, AOI3, OAI3, AOI4, OAI4. + Map to the specified list of gate types. Supported gates types are: + AND, NAND, OR, NOR, XOR, XNOR, ANDNOT, ORNOT, MUX, AOI3, OAI3, AOI4, OAI4. (The NOT gate is always added to this list automatically.) + The following aliases can be used to reference common sets of gate types: + simple: AND OR XOR MUX + cmos2: NAND NOR + cmos3: NAND NOR AOI3 OAI3 + cmos4: NAND NOR AOI3 OAI3 AOI4 OAI4 + gates: AND NAND OR NOR XOR XNOR ANDNOT ORNOT + aig: AND NAND OR NOR ANDNOT ORNOT + + Prefix a gate type with a '-' to remove it from the list. For example + the arguments 'AND,OR,XOR' and 'simple,-MUX' are equivalent. + -dff also pass $_DFF_?_ and $_DFFE_??_ cells through ABC. modules with many clock domains are automatically partitioned in clock domains and each @@ -140,8 +159,12 @@ library to a target architecture. When neither -liberty nor -lut is used, the Yosys standard cell library is loaded into ABC before the ABC script is executed. -This pass does not operate on modules with unprocessed processes in it. -(I.e. the 'proc' pass should be used first to convert processes to netlists.) +Note that this is a logic optimization pass within Yosys that is calling ABC +internally. This is not going to "run ABC on your design". It will instead run +ABC on logic snippets extracted from your design. You will not get any useful +output when passing an ABC script that writes a file. Instead write your full +design as BLIF file with write_blif and the load that into ABC externally if +you want to use ABC to convert your design into another format. [1] http://www.eecs.berkeley.edu/~alanmi/abc/ \end{lstlisting} @@ -206,6 +229,22 @@ This command adds asserts to the design that assert that all parallel muxes additional constrained and check the $pmux condition always. \end{lstlisting} +\section{async2sync -- convert async FF inputs to sync circuits} +\label{cmd:async2sync} +\begin{lstlisting}[numbers=left,frame=single] + async2sync [options] [selection] + +This command replaces async FF inputs with sync circuits emulating the same +behavior for when the async signals are actually synchronized to the clock. + +This pass assumes negative hold time for the async FF inputs. For example when +a reset deasserts with the clock edge, then the FF output will still drive the +reset value in the next cycle regardless of the data-in value at the time of +the clock edge. + +Currently only $adff cells are supported by this pass. +\end{lstlisting} + \section{attrmap -- renaming attributes} \label{cmd:attrmap} \begin{lstlisting}[numbers=left,frame=single] @@ -268,6 +307,15 @@ Move or copy attributes on wires to the cells driving them. multiple times. \end{lstlisting} +\section{blackbox -- change type of cells in the design} +\label{cmd:blackbox} +\begin{lstlisting}[numbers=left,frame=single] + blackbox [options] [selection] + +Convert modules into blackbox modules (remove contents and set the blackbox +module attribute). +\end{lstlisting} + \section{cd -- a shortcut for 'select -module <name>'} \label{cmd:cd} \begin{lstlisting}[numbers=left,frame=single] @@ -284,6 +332,12 @@ to 'cd <celltype>'. cd .. +Remove trailing substrings that start with '.' in current module name until +the name of a module in the current design is generated, then switch to that +module. Otherwise clear the current selection. + + cd + This is just a shortcut for 'select -clear'. \end{lstlisting} @@ -303,10 +357,49 @@ This pass identifies the following problems in the current design: When called with -noinit then this command also checks for wires which have the 'init' attribute set. +When called with -initdrv then this command also checks for wires which have +the 'init' attribute set and aren't driven by a FF cell type. + When called with -assert then the command will produce an error if any problems are found in the current design. \end{lstlisting} +\section{chformal -- change formal constraints of the design} +\label{cmd:chformal} +\begin{lstlisting}[numbers=left,frame=single] + chformal [types] [mode] [options] [selection] + +Make changes to the formal constraints of the design. The [types] options +the type of constraint to operate on. If none of the folling options is given, +the command will operate on all constraint types: + + -assert $assert cells, representing assert(...) constraints + -assume $assume cells, representing assume(...) constraints + -live $live cells, representing assert(s_eventually ...) + -fair $fair cells, representing assume(s_eventually ...) + -cover $cover cells, representing cover() statements + +Exactly one of the following modes must be specified: + + -remove + remove the cells and thus constraints from the design + + -early + bypass FFs that only delay the activation of a constraint + + -delay <N> + delay activation of the constraint by <N> clock cycles + + -skip <N> + ignore activation of the constraint in the first <N> clock cycles + + -assert2assume + -assume2assert + -live2fair + -fair2live + change the roles of cells as indicated. this options can be combined +\end{lstlisting} + \section{chparam -- re-evaluate modules with new parameters} \label{cmd:chparam} \begin{lstlisting}[numbers=left,frame=single] @@ -321,6 +414,20 @@ passed in double quotes ("). List the available parameters of the selected modules. \end{lstlisting} +\section{chtype -- change type of cells in the design} +\label{cmd:chtype} +\begin{lstlisting}[numbers=left,frame=single] + chtype [options] [selection] + +Change the types of cells in the design. + + -set <type> + set the cell type to the given type + + -map <old_type> <new_type> + change cells types that match <old_type> to <new_type> +\end{lstlisting} + \section{clean -- remove unused cells and wires} \label{cmd:clean} \begin{lstlisting}[numbers=left,frame=single] @@ -376,7 +483,7 @@ be selected or an active module must be set using the 'cd' command. This command does not operate on module with processes. \end{lstlisting} -\section{connwrappers -- replace undef values with defined constants} +\section{connwrappers -- match width of input-output port pairs} \label{cmd:connwrappers} \begin{lstlisting}[numbers=left,frame=single] connwrappers [options] [selection] @@ -397,6 +504,14 @@ the driving cell. The options -signed, -unsigned, and -port can be specified multiple times. \end{lstlisting} +\section{coolrunner2\_sop -- break \$sop cells into ANDTERM/ORTERM cells} +\label{cmd:coolrunner2_sop} +\begin{lstlisting}[numbers=left,frame=single] + coolrunner2_sop [options] [selection] + +Break $sop cells into ANDTERM/ORTERM cells. +\end{lstlisting} + \section{copy -- copy modules in the design} \label{cmd:copy} \begin{lstlisting}[numbers=left,frame=single] @@ -519,6 +634,19 @@ evaluated in the other design. design -copy-to <name> [-as <new_mod_name>] [selection] Copy modules from the current design into the specified one. + + + design -import <name> [-as <new_top_name>] [selection] + +Import the specified design into the current design. The source design must +either have a selected top module or the selection must contain exactly one +module that is then used as top module for this command. + + + design -reset-vlog + +The Verilog front-end remembers defined macros and top-level declarations +between calls to 'read_verilog'. This command resets this memory. \end{lstlisting} \section{dff2dffe -- transform \$dff cells to \$dffe cells} @@ -546,8 +674,18 @@ $_DFF_P_, $_DFF_N_ and $_MUX_. -direct-match <pattern> like -direct for all DFF cell types matching the expression. this will use $__DFFE_* as <external_gate_type> matching the - internal gate type $_DFF_*_, except for $_DFF_[NP]_, which is - converted to $_DFFE_[NP]_. + internal gate type $_DFF_*_, and $__DFFSE_* for those matching + $_DFFS_*_, except for $_DFF_[NP]_, which is converted to + $_DFFE_[NP]_. +\end{lstlisting} + +\section{dff2dffs -- process sync set/reset with SR over CE priority} +\label{cmd:dff2dffs} +\begin{lstlisting}[numbers=left,frame=single] + dff2dffs [options] [selection] + +Merge synchronous set/reset $_MUX_ cells to create $__DFFS_[NP][NP][01], to be run before +dff2dffe for SR over CE priority. \end{lstlisting} \section{dffinit -- set INIT param on FF cells} @@ -561,6 +699,11 @@ drives. (This is primarily used in FPGA flows.) -ff <cell_name> <output_port> <init_param> operate on the specified cell type. this option can be used multiple times. + + -highlow + use the string values "high" and "low" to represent a single-bit + initial value of 1 or 0. (multi-bit values are not supported in this + mode.) \end{lstlisting} \section{dfflibmap -- technology mapping of flip-flops} @@ -767,6 +910,10 @@ This command tries to prove $equiv cells using a simple direct SAT approach. -undef enable modelling of undef states + -short + create shorter input cones that stop at shared nodes. This yields + simpler SAT problems but sometimes fails to prove equivalence. + -nogroup disabling grouping of $equiv cells by output wire @@ -852,6 +999,10 @@ outputs. when exposing a wire, create an input/output pair and cut the internal signal path at that wire. + -input + when exposing a wire, create an input port and disconnect the internal + driver. + -shared only expose those signals that are shared among the selected modules. this is useful for preparing modules for equivalence checking. @@ -956,6 +1107,64 @@ tries to map the modules to the design (ascending, default value is 0). See 'help techmap' for a pass that does the opposite thing. \end{lstlisting} +\section{extract\_counter -- Extract GreenPak4 counter cells} +\label{cmd:extract_counter} +\begin{lstlisting}[numbers=left,frame=single] + extract_counter [options] [selection] + +This pass converts non-resettable or async resettable down counters to +counter cells. Use a target-specific 'techmap' map file to convert those cells +to the actual target cells. + + -maxwidth N + Only extract counters up to N bits wide + + -pout X,Y,... + Only allow parallel output from the counter to the listed cell types + (if not specified, parallel outputs are not restricted) +\end{lstlisting} + +\section{extract\_fa -- find and extract full/half adders} +\label{cmd:extract_fa} +\begin{lstlisting}[numbers=left,frame=single] + extract_fa [options] [selection] + +This pass extracts full/half adders from a gate-level design. + + -fa, -ha + Enable cell types (fa=full adder, ha=half adder) + All types are enabled if none of this options is used + + -d <int> + Set maximum depth for extracted logic cones (default=20) + + -b <int> + Set maximum breadth for extracted logic cones (default=6) + + -v + Verbose output +\end{lstlisting} + +\section{extract\_reduce -- converts gate chains into \$reduce\_* cells} +\label{cmd:extract_reduce} +\begin{lstlisting}[numbers=left,frame=single] + extract_reduce [options] [selection] + +converts gate chains into $reduce_* cells + +This command finds chains of $_AND_, $_OR_, and $_XOR_ cells and replaces them +with their corresponding $reduce_* cells. Because this command only operates on +these cell types, it is recommended to map the design to only these cell types +using the `abc -g` command. Note that, in some cases, it may be more effective +to map the design to only $_AND_ cells, run extract_reduce, map the remaining +parts of the design to AND/OR/XOR cells, and run extract_reduce a second time. + + -allow-off-chain + Allows matching of cells that have loads outside the chain. These cells + will be replicated and folded into the $reduce_* cell, but the original + cell will remain, driving its original loads. +\end{lstlisting} + \section{flatten -- flatten design} \label{cmd:flatten} \begin{lstlisting}[numbers=left,frame=single] @@ -1155,21 +1364,12 @@ one-hot encoding and binary encoding is supported. .map <old_bitpattern> <new_bitpattern> \end{lstlisting} -\section{greenpak4\_counters -- Extract GreenPak4 counter cells} -\label{cmd:greenpak4_counters} -\begin{lstlisting}[numbers=left,frame=single] - greenpak4_counters [options] [selection] - -This pass converts non-resettable or async resettable down counters to GreenPak4 -counter cells (All other GreenPak4 counter modes must be instantiated manually.) -\end{lstlisting} - -\section{greenpak4\_dffinv -- merge greenpak4 inverters and DFFs} +\section{greenpak4\_dffinv -- merge greenpak4 inverters and DFF/latches} \label{cmd:greenpak4_dffinv} \begin{lstlisting}[numbers=left,frame=single] greenpak4_dffinv [options] [selection] -Merge GP_INV cells with GP_DFF* cells. +Merge GP_INV cells with GP_DFF* and GP_DLATCH* cells. \end{lstlisting} \section{help -- display help messages} @@ -1199,6 +1399,10 @@ needed. also check the design hierarchy. this generates an error when an unknown module is used as cell type. + -simcheck + like -check, but also thow an error if blackbox modules are + instantiated, and throw an error if the design has no top module + -purge_lib by default the hierarchy command will not remove library (blackbox) modules. use this option to also remove unused blackbox modules. @@ -1212,6 +1416,11 @@ needed. per default this pass also converts positional arguments in cells to arguments using port names. this option disables this behavior. + -keep_portwidths + per default this pass adjusts the port width on cells that are + module instances when the width does not match the module port. this + option disables this behavior. + -nokeep_asserts per default this pass sets the "keep" attribute on all modules that directly or indirectly contain one or more $assert cells. this @@ -1416,6 +1625,18 @@ When no active module is selected, this prints a list of modules. When an active module is selected, this prints a list of objects in the module. \end{lstlisting} +\section{ltp -- print longest topological path} +\label{cmd:ltp} +\begin{lstlisting}[numbers=left,frame=single] + ltp [options] [selection] + +This command prints the longest topological path in the design. (Only considers +paths within a single module, so the design must be flattened.) + + -noff + automatically exclude FF cell types +\end{lstlisting} + \section{lut2mux -- convert \$lut to \$\_MUX\_} \label{cmd:lut2mux} \begin{lstlisting}[numbers=left,frame=single] @@ -1582,6 +1803,15 @@ This pass adds additional circuitry that emulates the Verilog simulation behavior for out-of-bounds memory reads and writes. \end{lstlisting} +\section{memory\_nordff -- extract read port FFs from memories} +\label{cmd:memory_nordff} +\begin{lstlisting}[numbers=left,frame=single] + memory_nordff [options] [selection] + +This pass extracts FFs from memory read ports. This results in a netlist +similar to what one would get from calling memory_dff with -nordff. +\end{lstlisting} + \section{memory\_share -- consolidate memory ports} \label{cmd:memory_share} \begin{lstlisting}[numbers=left,frame=single] @@ -1745,6 +1975,15 @@ This pass only operates on completely selected modules without processes. also remove internal nets if they have a public name \end{lstlisting} +\section{opt\_demorgan -- Optimize reductions with DeMorgan equivalents} +\label{cmd:opt_demorgan} +\begin{lstlisting}[numbers=left,frame=single] + opt_demorgan [selection] + +This pass pushes inverters through $reduce_* cells if this will reduce the +overall gate count of the circuit +\end{lstlisting} + \section{opt\_expr -- perform const folding and simple expression rewriting} \label{cmd:opt_expr} \begin{lstlisting}[numbers=left,frame=single] @@ -1884,15 +2123,16 @@ on partly selected designs. -memx simulate verilog simulation behavior for out-of-bounds memory accesses - using the 'memory_memx' pass. This option implies -nordff. + using the 'memory_memx' pass. -nomem do not run any of the memory_* passes - -nordff - passed to 'memory_dff'. prohibits merging of FFs into memory read ports + -rdff + do not pass -nordff to 'memory_dff'. This enables merging of FFs into + memory read ports. - -nokeepdc + -nokeepdc do not call opt_* with -keepdc -run <from_label>[:<to_label>] @@ -2058,6 +2298,38 @@ Note: This implementation of a quadratic wirelength placer uses exact dense matrix operations. It is only a toy-placer for small circuits. \end{lstlisting} +\section{read -- load HDL designs} +\label{cmd:read} +\begin{lstlisting}[numbers=left,frame=single] + read {-vlog95|-vlog2k|-sv2005|-sv2009|-sv2012|-sv|-formal} <verilog-file>.. + +Load the specified Verilog/SystemVerilog files. (Full SystemVerilog support +is only available via Verific.) + +Additional -D<macro>[=<value>] options may be added after the option indicating +the language version (and before file names) to set additional verilog defines. + + + read {-vhdl87|-vhdl93|-vhdl2k|-vhdl2008|-vhdl} <vhdl-file>.. + +Load the specified VHDL files. (Requires Verific.) + + + read -define <macro>[=<value>].. + +Set global Verilog/SystemVerilog defines. + + + read -undef <macro>.. + +Unset global Verilog/SystemVerilog defines. + + + read -incdir <directory> + +Add directory to global Verilog/SystemVerilog include directories. +\end{lstlisting} + \section{read\_blif -- read BLIF file} \label{cmd:read_blif} \begin{lstlisting}[numbers=left,frame=single] @@ -2067,6 +2339,10 @@ Load modules from a BLIF file into the current design. -sop Create $sop cells instead of $lut cells + + -wideports + Merge ports that match the pattern 'name[int]' into a single + multi-bit port 'name'. \end{lstlisting} \section{read\_ilang -- read modules from ilang file} @@ -2078,6 +2354,15 @@ Load modules from an ilang file to the current design. (ilang is a text representation of a design in yosys's internal format.) \end{lstlisting} +\section{read\_json -- read JSON file} +\label{cmd:read_json} +\begin{lstlisting}[numbers=left,frame=single] + read_json [filename] + +Load modules from a JSON file into the current design See "help write_json" +for a description of the file format. +\end{lstlisting} + \section{read\_liberty -- read cells from liberty file} \label{cmd:read_liberty} \begin{lstlisting}[numbers=left,frame=single] @@ -2088,9 +2373,13 @@ Read cells from liberty file as modules into current design. -lib only create empty blackbox modules - -ignore_redef + -nooverwrite ignore re-definitions of modules. (the default behavior is to - create an error message.) + create an error message if the existing module is not a blackbox + module, and overwrite the existing module if it is a blackbox module.) + + -overwrite + overwrite existing modules with the same name -ignore_miss_func ignore cells with missing function specification of outputs @@ -2099,6 +2388,9 @@ Read cells from liberty file as modules into current design. ignore cells with a missing or invalid direction specification on a pin + -ignore_miss_data_latch + ignore latches with missing data and/or enable pins + -setattr <attribute_name> set the specified attribute (to the value 1) on all loaded modules \end{lstlisting} @@ -2131,6 +2423,9 @@ Verilog-2005 is supported. -dump_ast2 dump abstract syntax tree (after simplification) + -no_dump_ptr + do not include hex memory addresses in dump (easier to diff dumps) + -dump_vlog dump ast as Verilog code (after simplification) @@ -2190,9 +2485,13 @@ Verilog-2005 is supported. -icells interpret cell types starting with '$' as internal cell types - -ignore_redef + -nooverwrite ignore re-definitions of modules. (the default behavior is to - create an error message.) + create an error message if the existing module is not a black box + module, and overwrite the existing module otherwise.) + + -overwrite + overwrite existing modules with the same name -defer only read the abstract syntax tree and defer actual compilation @@ -2221,6 +2520,10 @@ verilog input, but has not very good error reporting. It generally is recommended to use a simulator (for example Icarus Verilog) for checking the syntax of the code, rather than to rely on read_verilog for that. +Depending on if read_verilog is run in -formal mode, either the macro +SYNTHESIS or FORMAL is defined automatically. In addition, read_verilog +always defines the macro YOSYS. + See the Yosys README file for a list of non-standard Verilog features supported by the Yosys Verilog front-end. \end{lstlisting} @@ -2251,6 +2554,15 @@ with public names. This ignores all selected ports. Rename top module. \end{lstlisting} +\section{rmports -- remove module ports with no connections} +\label{cmd:rmports} +\begin{lstlisting}[numbers=left,frame=single] + rmports [selection] + +This pass identifies ports in the selected modules which are not used or +driven and removes them. +\end{lstlisting} + \section{sat -- solve a SAT problem in the circuit} \label{cmd:sat} \begin{lstlisting}[numbers=left,frame=single] @@ -2457,11 +2769,9 @@ design. are assumed to be bidirectional 'inout' ports. -set_attr <name> <value> - -set_cell_attr <name> <value> - -set_wire_attr <name> <value> - set the specified attribute on all cells and/or wires that are part of - a logic loop. the special token {} in the value is replaced with a - unique identifier for the logic loop. + set the specified attribute on all cells that are part of a logic + loop. the special token {} in the value is replaced with a unique + identifier for the logic loop. -select replace the current selection with a selection of all cells and wires @@ -2497,7 +2807,7 @@ of the design to operate on. This command can be used to modify and view this list of selected objects. Note that many commands support an optional [selection] argument that can be -used to override the global selection for the command. The syntax of this +used to YS_OVERRIDE the global selection for the command. The syntax of this optional argument is identical to the syntax of the <selection> argument described here. @@ -2728,17 +3038,29 @@ The -type option can be used to change the cell type of the selected cells. \begin{lstlisting}[numbers=left,frame=single] setundef [options] [selection] -This command replaced undef (x) constants with defined (0/1) constants. +This command replaces undef (x) constants with defined (0/1) constants. -undriven also set undriven nets to constant values + -expose + also expose undriven nets as inputs (use with -undriven) + -zero replace with bits cleared (0) -one replace with bits set (1) + -undef + replace with undef (x) bits, may be used with -undriven + + -anyseq + replace with $anyseq drivers (for formal) + + -anyconst + replace with $anyconst drivers (for formal) + -random <seed> replace with random bits using the specified integer als seed value for the random number generator. @@ -2821,6 +3143,7 @@ to a graphics file (usually SVG or PostScript). -viewer <viewer> Run the specified command with the graphics file as parameter. + On Windows, this pauses yosys until the viewer exits. -format <format> Generate a graphics file in the specified format. Use 'dot' to just @@ -2882,7 +3205,7 @@ to a graphics file (usually SVG or PostScript). do not add the module name as graph title to the dot file When no <format> is specified, 'dot' is used. When no <format> and <viewer> is -specified, 'xdot' is used to display the schematic. +specified, 'xdot' is used to display the schematic (POSIX systems only). The generated output files are '~/.yosys_show.dot' and '~/.yosys_show.<format>', unless another prefix is specified using -prefix <prefix>. @@ -2949,6 +3272,47 @@ will use the same interface as the original $_DFF_*_ cells. The cell parameter map to greenpak4 shift registers. \end{lstlisting} +\section{sim -- simulate the circuit} +\label{cmd:sim} +\begin{lstlisting}[numbers=left,frame=single] + sim [options] [top-level] + +This command simulates the circuit using the given top-level module. + + -vcd <filename> + write the simulation results to the given VCD file + + -clock <portname> + name of top-level clock input + + -clockn <portname> + name of top-level clock input (inverse polarity) + + -reset <portname> + name of top-level reset input (active high) + + -resetn <portname> + name of top-level inverted reset input (active low) + + -rstlen <integer> + number of cycles reset should stay active (default: 1) + + -zinit + zero-initialize all uninitialized regs and memories + + -n <integer> + number of cycles to simulate (default: 20) + + -a + include all nets in VCD output, not just those with public names + + -w + writeback mode: use final simulation state as new init state + + -d + enable debug output +\end{lstlisting} + \section{simplemap -- mapping simple coarse-grain cells} \label{cmd:simplemap} \begin{lstlisting}[numbers=left,frame=single] @@ -2963,22 +3327,6 @@ primitives. The following internal cell types are mapped by this pass: $sr, $ff, $dff, $dffsr, $adff, $dlatch \end{lstlisting} -\section{singleton -- create singleton modules} -\label{cmd:singleton} -\begin{lstlisting}[numbers=left,frame=single] - singleton [selection] - -By default, a module that is instantiated by several other modules is only -kept once in the design. This preserves the original modularity of the design -and reduces the overall size of the design in memory. But it prevents certain -optimizations and other operations on the design. This pass creates singleton -modules for all selected cells. The created modules are marked with the -'singleton' attribute. - -This commands only operates on modules that by themself have the 'singleton' -attribute set (the 'top' module is a singleton implicitly). -\end{lstlisting} - \section{splice -- create explicit splicing cells} \label{cmd:splice} \begin{lstlisting}[numbers=left,frame=single] @@ -3122,6 +3470,9 @@ on partly selected designs. -nordff passed to 'memory'. prohibits merging of FFs into memory read ports + -noshare + do not run SAT-based resource sharing + -run <from_label>[:<to_label>] only run the commands between the labels (see below). an empty from label is synonymous to 'begin', and empty to label is @@ -3164,6 +3515,344 @@ The following commands are executed by this synthesis command: check \end{lstlisting} +\section{synth\_achronix -- synthesis for Acrhonix Speedster22i FPGAs.} +\label{cmd:synth_achronix} +\begin{lstlisting}[numbers=left,frame=single] + synth_achronix [options] + +This command runs synthesis for Achronix Speedster eFPGAs. This work is still experimental. + + -top <module> + use the specified module as top module (default='top') + + -vout <file> + write the design to the specified Verilog netlist file. writing of an + output file is omitted if this parameter is not specified. + + -run <from_label>:<to_label> + only run the commands between the labels (see below). an empty + from label is synonymous to 'begin', and empty to label is + synonymous to the end of the command list. + + -noflatten + do not flatten design before synthesis + + -retime + run 'abc' with -dff option + + +The following commands are executed by this synthesis command: + + begin: + read_verilog -sv -lib +/achronix/speedster22i/cells_sim.v + hierarchy -check -top <top> + + flatten: (unless -noflatten) + proc + flatten + tribuf -logic + deminout + + coarse: + synth -run coarse + + fine: + opt -fast -mux_undef -undriven -fine -full + memory_map + opt -undriven -fine + dffsr2dff + dff2dffe -direct-match $_DFF_* + opt -fine + techmap -map +/techmap.v + opt -full + clean -purge + setundef -undriven -zero + abc -markgroups -dff (only if -retime) + + map_luts: + abc -lut 4 + clean + + map_cells: + iopadmap -bits -outpad $__outpad I:O -inpad $__inpad O:I + techmap -map +/achronix/speedster22i/cells_map.v + clean -purge + + check: + hierarchy -check + stat + check -noinit + + vout: + write_verilog -nodec -attr2comment -defparam -renameprefix syn_ <file-name> +\end{lstlisting} + +\section{synth\_coolrunner2 -- synthesis for Xilinx Coolrunner-II CPLDs} +\label{cmd:synth_coolrunner2} +\begin{lstlisting}[numbers=left,frame=single] + synth_coolrunner2 [options] + +This command runs synthesis for Coolrunner-II CPLDs. This work is experimental. +It is intended to be used with https://github.com/azonenberg/openfpga as the +place-and-route. + + -top <module> + use the specified module as top module (default='top') + + -json <file> + write the design to the specified JSON file. writing of an output file + is omitted if this parameter is not specified. + + -run <from_label>:<to_label> + only run the commands between the labels (see below). an empty + from label is synonymous to 'begin', and empty to label is + synonymous to the end of the command list. + + -noflatten + do not flatten design before synthesis + + -retime + run 'abc' with -dff option + + +The following commands are executed by this synthesis command: + + begin: + read_verilog -lib +/coolrunner2/cells_sim.v + hierarchy -check -top <top> + + flatten: (unless -noflatten) + proc + flatten + tribuf -logic + + coarse: + synth -run coarse + + fine: + opt -fast -full + techmap + techmap -map +/coolrunner2/cells_latch.v + dfflibmap -prepare -liberty +/coolrunner2/xc2_dff.lib + + map_tff: + abc -g AND,XOR + clean + extract -map +/coolrunner2/tff_extract.v + + map_pla: + abc -sop -I 40 -P 56 + clean + + map_cells: + dfflibmap -liberty +/coolrunner2/xc2_dff.lib + dffinit -ff FDCP Q INIT + dffinit -ff FDCP_N Q INIT + dffinit -ff FTCP Q INIT + dffinit -ff FTCP_N Q INIT + dffinit -ff LDCP Q INIT + dffinit -ff LDCP_N Q INIT + coolrunner2_sop + iopadmap -bits -inpad IBUF O:I -outpad IOBUFE I:IO -inoutpad IOBUFE O:IO -toutpad IOBUFE E:I:IO -tinoutpad IOBUFE E:O:I:IO + attrmvcp -attr src -attr LOC t:IOBUFE n:* + attrmvcp -attr src -attr LOC -driven t:IBUF n:* + splitnets + clean + + check: + hierarchy -check + stat + check -noinit + + json: + write_json <file-name> +\end{lstlisting} + +\section{synth\_easic -- synthesis for eASIC platform} +\label{cmd:synth_easic} +\begin{lstlisting}[numbers=left,frame=single] + synth_easic [options] + +This command runs synthesis for eASIC platform. + + -top <module> + use the specified module as top module + + -vlog <file> + write the design to the specified structural Verilog file. writing of + an output file is omitted if this parameter is not specified. + + -etools <path> + set path to the eTools installation. (default=/opt/eTools) + + -run <from_label>:<to_label> + only run the commands between the labels (see below). an empty + from label is synonymous to 'begin', and empty to label is + synonymous to the end of the command list. + + -noflatten + do not flatten design before synthesis + + -retime + run 'abc' with -dff option + + +The following commands are executed by this synthesis command: + + begin: + read_liberty -lib <etools_phys_clk_lib> + read_liberty -lib <etools_logic_lut_lib> + hierarchy -check -top <top> + + flatten: (unless -noflatten) + proc + flatten + + coarse: + synth -run coarse + + fine: + opt -fast -mux_undef -undriven -fine + memory_map + opt -undriven -fine + techmap + opt -fast + abc -dff (only if -retime) + opt_clean (only if -retime) + + map: + dfflibmap -liberty <etools_phys_clk_lib> + abc -liberty <etools_logic_lut_lib> + opt_clean + + check: + hierarchy -check + stat + check -noinit + + vlog: + write_verilog -noexpr -attr2comment <file-name> +\end{lstlisting} + +\section{synth\_ecp5 -- synthesis for ECP5 FPGAs} +\label{cmd:synth_ecp5} +\begin{lstlisting}[numbers=left,frame=single] + synth_ecp5 [options] + +This command runs synthesis for ECP5 FPGAs. + + -top <module> + use the specified module as top module + + -blif <file> + write the design to the specified BLIF file. writing of an output file + is omitted if this parameter is not specified. + + -edif <file> + write the design to the specified EDIF file. writing of an output file + is omitted if this parameter is not specified. + + -json <file> + write the design to the specified JSON file. writing of an output file + is omitted if this parameter is not specified. + + -run <from_label>:<to_label> + only run the commands between the labels (see below). an empty + from label is synonymous to 'begin', and empty to label is + synonymous to the end of the command list. + + -noflatten + do not flatten design before synthesis + + -retime + run 'abc' with -dff option + + -noccu2 + do not use CCU2 cells in output netlist + + -nodffe + do not use flipflops with CE in output netlist + + -nobram + do not use BRAM cells in output netlist + + -nodram + do not use distributed RAM cells in output netlist + + -nomux + do not use PFU muxes to implement LUTs larger than LUT4s + + -abc2 + run two passes of 'abc' for slightly improved logic density + + -vpr + generate an output netlist (and BLIF file) suitable for VPR + (this feature is experimental and incomplete) + + +The following commands are executed by this synthesis command: + + begin: + read_verilog -lib +/ecp5/cells_sim.v + hierarchy -check -top <top> + + flatten: (unless -noflatten) + proc + flatten + tribuf -logic + deminout + + coarse: + synth -run coarse + + bram: (skip if -nobram) + + dram: (skip if -nodram) + memory_bram -rules +/ecp5/dram.txt + techmap -map +/ecp5/drams_map.v + + fine: + opt -fast -mux_undef -undriven -fine + memory_map + opt -undriven -fine + techmap -map +/techmap.v -map +/ecp5/arith_map.v + abc -dff (only if -retime) + + map_ffs: + dffsr2dff + dff2dffs + opt_clean + dff2dffe -direct-match $_DFF_* -direct-match $__DFFS_* + techmap -D NO_LUT -map +/ecp5/cells_map.v + opt_expr -mux_undef + simplemap + + map_luts: + abc (only if -abc2) + abc -lut 4:7 + clean + + map_cells: + techmap -map +/ecp5/cells_map.v (with -D NO_LUT in vpr mode) + clean + + check: + hierarchy -check + stat + check -noinit + + blif: + opt_clean -purge (vpr mode) + write_blif -attr -cname -conn -param <file-name> (vpr mode) + write_blif -gates -attr -param <file-name> (non-vpr mode) + + edif: + write_edif <file-name> + + json: + write_json <file-name> +\end{lstlisting} + \section{synth\_gowin -- synthesis for Gowin FPGAs} \label{cmd:synth_gowin} \begin{lstlisting}[numbers=left,frame=single] @@ -3228,7 +3917,7 @@ The following commands are executed by this synthesis command: check -noinit vout: - write_verilog -attr2comment -defparam -renameprefix gen <file-name> + write_verilog -nodec -attr2comment -defparam -renameprefix gen <file-name> \end{lstlisting} \section{synth\_greenpak4 -- synthesis for GreenPAK4 FPGAs} @@ -3237,6 +3926,8 @@ The following commands are executed by this synthesis command: synth_greenpak4 [options] This command runs synthesis for GreenPAK4 FPGAs. This work is experimental. +It is intended to be used with https://github.com/azonenberg/openfpga as the +place-and-route. -top <module> use the specified module as top module (default='top') @@ -3276,12 +3967,13 @@ The following commands are executed by this synthesis command: synth -run coarse fine: - greenpak4_counters + extract_counter -pout GP_DCMP,GP_DAC -maxwidth 14 clean opt -fast -mux_undef -undriven -fine memory_map opt -undriven -fine techmap + techmap -map +/greenpak4/cells_latch.v dfflibmap -prepare -liberty +/greenpak4/gp_dff.lib opt -fast abc -dff (only if -retime) @@ -3323,14 +4015,18 @@ The following commands are executed by this synthesis command: This command runs synthesis for iCE40 FPGAs. -top <module> - use the specified module as top module (default='top') + use the specified module as top module -blif <file> write the design to the specified BLIF file. writing of an output file is omitted if this parameter is not specified. -edif <file> - write the design to the specified edif file. writing of an output file + write the design to the specified EDIF file. writing of an output file + is omitted if this parameter is not specified. + + -json <file> + write the design to the specified JSON file. writing of an output file is omitted if this parameter is not specified. -run <from_label>:<to_label> @@ -3347,12 +4043,19 @@ This command runs synthesis for iCE40 FPGAs. -nocarry do not use SB_CARRY cells in output netlist + -nodffe + do not use SB_DFFE* cells in output netlist + -nobram do not use SB_RAM40_4K* cells in output netlist -abc2 run two passes of 'abc' for slightly improved logic density + -vpr + generate an output netlist (and BLIF file) suitable for VPR + (this feature is experimental and incomplete) + The following commands are executed by this synthesis command: @@ -3384,7 +4087,7 @@ The following commands are executed by this synthesis command: map_ffs: dffsr2dff dff2dffe -direct-match $_DFF_* - techmap -map +/ice40/cells_map.v + techmap -D NO_LUT -map +/ice40/cells_map.v opt_expr -mux_undef simplemap ice40_ffinit @@ -3399,7 +4102,7 @@ The following commands are executed by this synthesis command: clean map_cells: - techmap -map +/ice40/cells_map.v + techmap -map +/ice40/cells_map.v (with -D NO_LUT in vpr mode) clean check: @@ -3408,10 +4111,116 @@ The following commands are executed by this synthesis command: check -noinit blif: - write_blif -gates -attr -param <file-name> + opt_clean -purge (vpr mode) + write_blif -attr -cname -conn -param <file-name> (vpr mode) + write_blif -gates -attr -param <file-name> (non-vpr mode) edif: write_edif <file-name> + + json: + write_json <file-name> +\end{lstlisting} + +\section{synth\_intel -- synthesis for Intel (Altera) FPGAs.} +\label{cmd:synth_intel} +\begin{lstlisting}[numbers=left,frame=single] + synth_intel [options] + +This command runs synthesis for Intel FPGAs. + + -family < max10 | a10gx | cyclone10 | cyclonev | cycloneiv | cycloneive> + generate the synthesis netlist for the specified family. + MAX10 is the default target if not family argument specified. + For Cyclone GX devices, use cycloneiv argument; For Cyclone E, use cycloneive. + Cyclone V and Arria 10 GX devices are experimental, use it with a10gx argument. + + -top <module> + use the specified module as top module (default='top') + + -vqm <file> + write the design to the specified Verilog Quartus Mapping File. Writing of an + output file is omitted if this parameter is not specified. + + -vpr <file> + write BLIF files for VPR flow experiments. The synthesized BLIF output file is not + compatible with the Quartus flow. Writing of an + output file is omitted if this parameter is not specified. + + -run <from_label>:<to_label> + only run the commands between the labels (see below). an empty + from label is synonymous to 'begin', and empty to label is + synonymous to the end of the command list. + + -noiopads + do not use altsyncram cells in output netlist + + -nobram + do not use altsyncram cells in output netlist + + -noflatten + do not flatten design before synthesis + + -retime + run 'abc' with -dff option + +The following commands are executed by this synthesis command: + + begin: + + family: + read_verilog -sv -lib +/intel/max10/cells_sim.v + read_verilog -sv -lib +/intel/common/m9k_bb.v + read_verilog -sv -lib +/intel/common/altpll_bb.v + hierarchy -check -top <top> + + flatten: (unless -noflatten) + proc + flatten + tribuf -logic + deminout + + coarse: + synth -run coarse + + bram: (skip if -nobram) + memory_bram -rules +/intel/common/brams.txt + techmap -map +/intel/common/brams_map.v + + fine: + opt -fast -mux_undef -undriven -fine -full + memory_map + opt -undriven -fine + dffsr2dff + dff2dffe -direct-match $_DFF_* + opt -fine + techmap -map +/techmap.v + opt -full + clean -purge + setundef -undriven -zero + abc -markgroups -dff (only if -retime) + + map_luts: + abc -lut 4 + clean + + map_cells: + iopadmap -bits -outpad $__outpad I:O -inpad $__inpad O:I (unless -noiopads) + techmap -map +/intel/max10/cells_map.v + dffinit -highlow -ff dffeas q power_up + clean -purge + + check: + hierarchy -check + stat + check -noinit + + vqm: + write_verilog -attr2comment -defparam -nohex -decimal -renameprefix syn_ <file-name> + + vpr: + opt_clean -purge + write_blif <file-name> \end{lstlisting} \section{synth\_xilinx -- synthesis for Xilinx FPGAs} @@ -3430,6 +4239,14 @@ compatible with 7-Series Xilinx devices. write the design to the specified edif file. writing of an output file is omitted if this parameter is not specified. + -blif <file> + write the design to the specified BLIF file. writing of an output file + is omitted if this parameter is not specified. + + -vpr + generate an output netlist (and BLIF file) suitable for VPR + (this feature is experimental and incomplete) + -run <from_label>:<to_label> only run the commands between the labels (see below). an empty from label is synonymous to 'begin', and empty to label is @@ -3448,7 +4265,6 @@ The following commands are executed by this synthesis command: read_verilog -lib +/xilinx/cells_sim.v read_verilog -lib +/xilinx/cells_xtra.v read_verilog -lib +/xilinx/brams_bb.v - read_verilog -lib +/xilinx/drams_bb.v hierarchy -check -top <top> flatten: (only if -flatten) @@ -3480,7 +4296,7 @@ The following commands are executed by this synthesis command: clean map_cells: - techmap -map +/xilinx/cells_map.v + techmap -map +/xilinx/cells_map.v (with -D NO_LUT in vpr mode) dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT clean @@ -3491,6 +4307,9 @@ The following commands are executed by this synthesis command: edif: (only if -edif) write_edif <file-name> + + blif: (only if -blif) + write_blif <file-name> \end{lstlisting} \section{tcl -- execute a TCL script file} @@ -3502,9 +4321,9 @@ This command executes the tcl commands in the specified file. Use 'yosys cmd' to run the yosys command 'cmd' from tcl. The tcl command 'yosys -import' can be used to import all yosys -commands directly as tcl commands to the tcl shell. The yosys -command 'proc' is wrapped using the tcl command 'procs' in order -to avoid a name collision with the tcl builtin command 'proc'. +commands directly as tcl commands to the tcl shell. Yosys commands +'proc' and 'rename' are wrapped to tcl commands 'procs' and 'renames' +in order to avoid a name collision with the built in commands. \end{lstlisting} \section{techmap -- generic technology mapper} @@ -3548,7 +4367,7 @@ file. -D <define>, -I <incdir> this options are passed as-is to the Verilog frontend for loading the map file. Note that the Verilog frontend is also called with the - '-ignore_redef' option set. + '-nooverwrite' option set. When a module in the map file has the 'techmap_celltype' attribute set, it will match cells with a type that match the text value of this attribute. Otherwise @@ -3629,7 +4448,7 @@ the design is connected to a constant value. The parameter is then set to the constant value. A cell with the name _TECHMAP_REPLACE_ in the map file will inherit the name -of the cell that is being replaced. +and attributes of the cell that is being replaced. See 'help extract' for a pass that does the opposite thing. @@ -3795,24 +4614,134 @@ This pass transforms $mux cells with 'z' inputs to tristate buffers. to non-tristate logic. this option implies -merge. \end{lstlisting} +\section{uniquify -- create unique copies of modules} +\label{cmd:uniquify} +\begin{lstlisting}[numbers=left,frame=single] + uniquify [selection] + +By default, a module that is instantiated by several other modules is only +kept once in the design. This preserves the original modularity of the design +and reduces the overall size of the design in memory. But it prevents certain +optimizations and other operations on the design. This pass creates unique +modules for all selected cells. The created modules are marked with the +'unique' attribute. + +This commands only operates on modules that by themself have the 'unique' +attribute set (the 'top' module is unique implicitly). +\end{lstlisting} + \section{verific -- load Verilog and VHDL designs using Verific} \label{cmd:verific} \begin{lstlisting}[numbers=left,frame=single] - verific {-vlog95|-vlog2k|-sv2005|-sv2009|-sv} <verilog-file>.. + verific {-vlog95|-vlog2k|-sv2005|-sv2009|-sv2012|-sv} <verilog-file>.. Load the specified Verilog/SystemVerilog files into Verific. +All files specified in one call to this command are one compilation unit. +Files passed to different calls to this command are treated as belonging to +different compilation units. + +Additional -D<macro>[=<value>] options may be added after the option indicating +the language version (and before file names) to set additional verilog defines. +The macros SYNTHESIS and VERIFIC are defined implicitly. + + + verific -formal <verilog-file>.. - verific {-vhdl87|-vhdl93|-vhdl2k|-vhdl2008} <vhdl-file>.. +Like -sv, but define FORMAL instead of SYNTHESIS. + + + verific {-vhdl87|-vhdl93|-vhdl2k|-vhdl2008|-vhdl} <vhdl-file>.. Load the specified VHDL files into Verific. - verific -import [-gates] {-all | <top-module>..} + verific -work <libname> {-sv|-vhdl|...} <hdl-file> + +Load the specified Verilog/SystemVerilog/VHDL file into the specified library. +(default library when -work is not present: "work") + + + verific -vlog-incdir <directory>.. + +Add Verilog include directories. + + + verific -vlog-libdir <directory>.. + +Add Verilog library directories. Verific will search in this directories to +find undefined modules. + + + verific -vlog-define <macro>[=<value>].. + +Add Verilog defines. + + + verific -vlog-undef <macro>.. + +Remove Verilog defines previously set with -vlog-define. + + + verific -set-error <msg_id>.. + verific -set-warning <msg_id>.. + verific -set-info <msg_id>.. + verific -set-ignore <msg_id>.. + +Set message severity. <msg_id> is the string in square brackets when a message +is printed, such as VERI-1209. + + + verific -import [options] <top-module>.. Elaborate the design for the specified top modules, import to Yosys and -reset the internal state of Verific. A gate-level netlist is created -when called with -gates. +reset the internal state of Verific. + +Import options: + + -all + Elaborate all modules, not just the hierarchy below the given top + modules. With this option the list of modules to import is optional. + + -gates + Create a gate-level netlist. + + -flatten + Flatten the design in Verific before importing. + + -extnets + Resolve references to external nets by adding module ports as needed. + + -autocover + Generate automatic cover statements for all asserts + + -v, -vv + Verbose log messages. (-vv is even more verbose than -v.) + +The following additional import options are useful for debugging the Verific +bindings (for Yosys and/or Verific developers): + + -k + Keep going after an unsupported verific primitive is found. The + unsupported primitive is added as blockbox module to the design. + This will also add all SVA related cells to the design parallel to + the checker logic inferred by it. + + -V + Import Verific netlist as-is without translating to Yosys cell types. + + -nosva + Ignore SVA properties, do not infer checker logic. + + -L <int> + Maximum number of ctrl bits for SVA checker FSMs (default=16). + + -n + Keep all Verific names on instances and nets. By default only + user-declared names are preserved. + + -d <dump_file> + Dump the Verific netlist as a verilog file. Visit http://verific.com/ for more information on Verific. \end{lstlisting} @@ -3837,40 +4766,19 @@ Push or pop the list of default options to a stack. Note that -push does not imply -clear. \end{lstlisting} -\section{vhdl2verilog -- importing VHDL designs using vhdl2verilog} -\label{cmd:vhdl2verilog} +\section{verilog\_defines -- define and undefine verilog defines} +\label{cmd:verilog_defines} \begin{lstlisting}[numbers=left,frame=single] - vhdl2verilog [options] <vhdl-file>.. - -This command reads VHDL source files using the 'vhdl2verilog' tool and the -Yosys Verilog frontend. - - -out <out_file> - do not import the vhdl2verilog output. instead write it to the - specified file. - - -vhdl2verilog_dir <directory> - do use the specified vhdl2verilog installation. this is the directory - that contains the setup_env.sh file. when this option is not present, - it is assumed that vhdl2verilog is in the PATH environment variable. + verilog_defines [options] - -top <top-entity-name> - The name of the top entity. This option is mandatory. +Define and undefine verilog preprocessor macros. -The following options are passed as-is to vhdl2verilog: - - -arch <architecture_name> - -unroll_generate - -nogenericeval - -nouniquify - -oldparser - -suppress <list> - -quiet - -nobanner - -mapfile <file> + -Dname[=definition] + define the preprocessor symbol 'name' and set its optional value + 'definition' -vhdl2verilog can be obtained from: -http://www.edautils.com/vhdl2verilog.html + -Uname[=definition] + undefine the preprocessor symbol 'name' \end{lstlisting} \section{wreduce -- reduce the word size of operations if possible} @@ -3892,6 +4800,38 @@ Options: flows that use the 'memory_memx' pass. \end{lstlisting} +\section{write\_aiger -- write design to AIGER file} +\label{cmd:write_aiger} +\begin{lstlisting}[numbers=left,frame=single] + write_aiger [options] [filename] + +Write the current design to an AIGER file. The design must be flattened and +must not contain any cell types except $_AND_, $_NOT_, simple FF types, +$assert and $assume cells, and $initstate cells. + +$assert and $assume cells are converted to AIGER bad state properties and +invariant constraints. + + -ascii + write ASCII version of AGIER format + + -zinit + convert FFs to zero-initialized FFs, adding additional inputs for + uninitialized FFs. + + -miter + design outputs are AIGER bad state properties + + -symbols + include a symbol table in the generated AIGER file + + -map <filename> + write an extra file with port and latch symbols + + -vmap <filename> + like -map, but more verbose +\end{lstlisting} + \section{write\_blif -- write design to BLIF file} \label{cmd:write_blif} \begin{lstlisting}[numbers=left,frame=single] @@ -3949,6 +4889,11 @@ file *.blif when any of this options is used. -cname use the non-standard .cname statement to write cell names + -iname, -iattr + enable -cname and -attr functionality for .names statements + (the .cname and .attr statements will be included in the BLIF + output after the truth table for the .names statement) + -blackbox write blackbox cells with .blackbox statement. @@ -3959,9 +4904,15 @@ file *.blif when any of this options is used. \section{write\_btor -- write design to BTOR file} \label{cmd:write_btor} \begin{lstlisting}[numbers=left,frame=single] - write_btor [filename] + write_btor [options] [filename] + +Write a BTOR description of the current design. -Write the current design to an BTOR file. + -v + Add comments and indentation to BTOR output file + + -s + Output only a single bad property for all asserts \end{lstlisting} \section{write\_edif -- write design to EDIF netlist file} @@ -3979,6 +4930,10 @@ Write the current design to an EDIF netlist file. if the design contains constant nets. use "hilomap" to map to custom constant drivers first) + -pvector {par|bra|ang} + sets the delimiting character for module port rename clauses to + parentheses, square brackets, or angle brackets. + Unfortunately there are different "flavors" of the EDIF file format. This command generates EDIF files for the Xilinx place&route tools. It might be necessary to make small modifications to this command when a different tool @@ -4003,6 +4958,14 @@ Inside a script the input file can also can a here-document: EOT \end{lstlisting} +\section{write\_firrtl -- write design to a FIRRTL file} +\label{cmd:write_firrtl} +\begin{lstlisting}[numbers=left,frame=single] + write_firrtl [options] [filename] + +Write a FIRRTL netlist of the current design. +\end{lstlisting} + \section{write\_ilang -- write design to ilang file} \label{cmd:write_ilang} \begin{lstlisting}[numbers=left,frame=single] @@ -4123,6 +5086,10 @@ values referenced above are vectors of this integers. Signal bits that are connected to a constant driver are denoted as string "0" or "1" instead of a number. +Numeric parameter and attribute values up to 32 bits are written as decimal +values. Numbers larger than that are written as string holding the binary +representation of the value. + For example the following Verilog code: module test(input x, y); @@ -4242,43 +5209,109 @@ Future version of Yosys might add support for additional fields in the JSON format. A program processing this format must ignore all unknown fields. \end{lstlisting} -\section{write\_smt2 -- write design to SMT-LIBv2 file} -\label{cmd:write_smt2} +\section{write\_simplec -- convert design to simple C code} +\label{cmd:write_simplec} \begin{lstlisting}[numbers=left,frame=single] - write_smt2 [options] [filename] + write_simplec [options] [filename] -Write a SMT-LIBv2 [1] description of the current design. For a module with name -'<mod>' this will declare the sort '<mod>_s' (state of the module) and the -functions operating on that state. +Write simple C code for simulating the design. The C code writen can be used to +simulate the design in a C environment, but the purpose of this command is to +generate code that works well with C-based formal verification. -The '<mod>_s' sort represents a module state. Additional '<mod>_n' functions -are provided that can be used to access the values of the signals in the module. -By default only ports, registers, and wires with the 'keep' attribute set are -made available via such functions. With the -nobv option, multi-bit wires are -exported as separate functions of type Bool for the individual bits. Without --nobv multi-bit wires are exported as single functions of type BitVec. + -verbose + this will print the recursive walk used to export the modules. -The '<mod>_t' function evaluates to 'true' when the given pair of states -describes a valid state transition. + -i8, -i16, -i32, -i64 + set the maximum integer bit width to use in the generated code. -The '<mod>_a' function evaluates to 'true' when the given state satisfies -the asserts in the module. +THIS COMMAND IS UNDER CONSTRUCTION +\end{lstlisting} -The '<mod>_u' function evaluates to 'true' when the given state satisfies -the assumptions in the module. +\section{write\_smt2 -- write design to SMT-LIBv2 file} +\label{cmd:write_smt2} +\begin{lstlisting}[numbers=left,frame=single] + write_smt2 [options] [filename] -The '<mod>_i' function evaluates to 'true' when the given state conforms -to the initial state. Furthermore the '<mod>_is' function should be asserted -to be true for initial states in addition to '<mod>_i', and should be -asserted to be false for non-initial states. +Write a SMT-LIBv2 [1] description of the current design. For a module with name +'<mod>' this will declare the sort '<mod>_s' (state of the module) and will +define and declare functions operating on that state. + +The following SMT2 functions are generated for a module with name '<mod>'. +Some declarations/definitions are printed with a special comment. A prover +using the SMT2 files can use those comments to collect all relevant metadata +about the design. + + ; yosys-smt2-module <mod> + (declare-sort |<mod>_s| 0) + The sort representing a state of module <mod>. + + (define-fun |<mod>_h| ((state |<mod>_s|)) Bool (...)) + This function must be asserted for each state to establish the + design hierarchy. + + ; yosys-smt2-input <wirename> <width> + ; yosys-smt2-output <wirename> <width> + ; yosys-smt2-register <wirename> <width> + ; yosys-smt2-wire <wirename> <width> + (define-fun |<mod>_n <wirename>| (|<mod>_s|) (_ BitVec <width>)) + (define-fun |<mod>_n <wirename>| (|<mod>_s|) Bool) + For each port, register, and wire with the 'keep' attribute set an + accessor function is generated. Single-bit wires are returned as Bool, + multi-bit wires as BitVec. + + ; yosys-smt2-cell <submod> <instancename> + (declare-fun |<mod>_h <instancename>| (|<mod>_s|) |<submod>_s|) + There is a function like that for each hierarchical instance. It + returns the sort that represents the state of the sub-module that + implements the instance. + + (declare-fun |<mod>_is| (|<mod>_s|) Bool) + This function must be asserted 'true' for initial states, and 'false' + otherwise. + + (define-fun |<mod>_i| ((state |<mod>_s|)) Bool (...)) + This function must be asserted 'true' for initial states. For + non-initial states it must be left unconstrained. + + (define-fun |<mod>_t| ((state |<mod>_s|) (next_state |<mod>_s|)) Bool (...)) + This function evaluates to 'true' if the states 'state' and + 'next_state' form a valid state transition. + + (define-fun |<mod>_a| ((state |<mod>_s|)) Bool (...)) + This function evaluates to 'true' if all assertions hold in the state. + + (define-fun |<mod>_u| ((state |<mod>_s|)) Bool (...)) + This function evaluates to 'true' if all assumptions hold in the state. + + ; yosys-smt2-assert <id> <filename:linenum> + (define-fun |<mod>_a <id>| ((state |<mod>_s|)) Bool (...)) + Each $assert cell is converted into one of this functions. The function + evaluates to 'true' if the assert statement holds in the state. + + ; yosys-smt2-assume <id> <filename:linenum> + (define-fun |<mod>_u <id>| ((state |<mod>_s|)) Bool (...)) + Each $assume cell is converted into one of this functions. The function + evaluates to 'true' if the assume statement holds in the state. + + ; yosys-smt2-cover <id> <filename:linenum> + (define-fun |<mod>_c <id>| ((state |<mod>_s|)) Bool (...)) + Each $cover cell is converted into one of this functions. The function + evaluates to 'true' if the cover statement is activated in the state. -For hierarchical designs, the '<mod>_h' function must be asserted for each -state to establish the design hierarchy. The '<mod>_h <cellname>' function -evaluates to the state corresponding to the given cell within <mod>. +Options: -verbose this will print the recursive walk used to export the modules. + -stbv + Use a BitVec sort to represent a state instead of an uninterpreted + sort. As a side-effect this will prevent use of arrays to model + memories. + + -stdt + Use SMT-LIB 2.6 style datatypes to represent a state instead of an + uninterpreted sort. + -nobv disable support for BitVec (FixedSizeBitVectors theory). without this option multi-bit wires are represented using the BitVec sort and @@ -4394,6 +5427,25 @@ Write the current design to an SPICE netlist file. set the specified module as design top module \end{lstlisting} +\section{write\_table -- write design as connectivity table} +\label{cmd:write_table} +\begin{lstlisting}[numbers=left,frame=single] + write_table [options] [filename] + +Write the current design as connectivity table. The output is a tab-separated +ASCII table with the following columns: + + module name + cell name + cell type + cell port + direction + signal + +module inputs and outputs are output using cell type and port '-' and with +'pi' (primary input) or 'po' (primary output) or 'pio' as direction. +\end{lstlisting} + \section{write\_verilog -- write design to Verilog file} \label{cmd:write_verilog} \begin{lstlisting}[numbers=left,frame=single] @@ -4421,13 +5473,21 @@ Write the current design to a Verilog file. -nodec 32-bit constant values are by default dumped as decimal numbers, - not bit pattern. This option decativates this feature and instead + not bit pattern. This option deactivates this feature and instead will write out all constants in binary. + -decimal + dump 32-bit constants in decimal and without size and radix + + -nohex + constant values that are compatible with hex output are usually + dumped as hex values. This option deactivates this feature and + instead will write out all constants in binary. + -nostr Parameters and attributes that are specified as strings in the original input will be output as strings by this back-end. This - decativates this feature and instead will write string constants + deactivates this feature and instead will write string constants as binary numbers. -defparam diff --git a/misc/__init__.py b/misc/__init__.py new file mode 100644 index 000000000..330fd6d86 --- /dev/null +++ b/misc/__init__.py @@ -0,0 +1,5 @@ +import os +import sys +sys.setdlopenflags(os.RTLD_NOW | os.RTLD_GLOBAL) + +__all__ = ["libyosys"] diff --git a/misc/create_vcxsrc.sh b/misc/create_vcxsrc.sh index 215e27c53..924d2722e 100644 --- a/misc/create_vcxsrc.sh +++ b/misc/create_vcxsrc.sh @@ -5,11 +5,11 @@ vcxsrc="$1-$2" yosysver="$2" gitsha="$3" -rm -rf YosysVS-Tpl-v1.zip YosysVS -wget http://www.clifford.at/yosys/nogit/YosysVS-Tpl-v1.zip +rm -rf YosysVS-Tpl-v2.zip YosysVS +wget http://www.clifford.at/yosys/nogit/YosysVS-Tpl-v2.zip -unzip YosysVS-Tpl-v1.zip -rm -f YosysVS-Tpl-v1.zip +unzip YosysVS-Tpl-v2.zip +rm -f YosysVS-Tpl-v2.zip mv YosysVS "$vcxsrc" { diff --git a/misc/launcher.c b/misc/launcher.c new file mode 100644 index 000000000..49d6414e7 --- /dev/null +++ b/misc/launcher.c @@ -0,0 +1,359 @@ +/* This file comes from the PyPA Setuptools repository, commit 16e452a: +https://github.com/pypa/setuptools +Modifications include this comment and inline inclusion of the LICENSE text. */ + +/* Copyright (C) 2016 Jason R Coombs <jaraco@jaraco.com> + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. */ + +/* Setuptools Script Launcher for Windows + + This is a stub executable for Windows that functions somewhat like + Effbot's "exemaker", in that it runs a script with the same name but + a .py extension, using information from a #! line. It differs in that + it spawns the actual Python executable, rather than attempting to + hook into the Python DLL. This means that the script will run with + sys.executable set to the Python executable, where exemaker ends up with + sys.executable pointing to itself. (Which means it won't work if you try + to run another Python process using sys.executable.) + + To build/rebuild with mingw32, do this in the setuptools project directory: + + gcc -DGUI=0 -mno-cygwin -O -s -o setuptools/cli.exe launcher.c + gcc -DGUI=1 -mwindows -mno-cygwin -O -s -o setuptools/gui.exe launcher.c + + To build for Windows RT, install both Visual Studio Express for Windows 8 + and for Windows Desktop (both freeware), create "win32" application using + "Windows Desktop" version, create new "ARM" target via + "Configuration Manager" menu and modify ".vcxproj" file by adding + "<WindowsSDKDesktopARMSupport>true</WindowsSDKDesktopARMSupport>" tag + as child of "PropertyGroup" tags that has "Debug|ARM" and "Release|ARM" + properties. + + It links to msvcrt.dll, but this shouldn't be a problem since it doesn't + actually run Python in the same process. Note that using 'exec' instead + of 'spawn' doesn't work, because on Windows this leads to the Python + executable running in the *background*, attached to the same console + window, meaning you get a command prompt back *before* Python even finishes + starting. So, we have to use spawnv() and wait for Python to exit before + continuing. :( +*/ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <windows.h> +#include <tchar.h> +#include <fcntl.h> +#include <unistd.h> + +int child_pid=0; + +int fail(const char *format, const char *data) { + /* Print error message to stderr and return 2 */ + fprintf(stderr, format, data); + return 2; +} + +char *quoted(char *data) { + int i, ln = strlen(data), nb; + + /* We allocate twice as much space as needed to deal with worse-case + of having to escape everything. */ + char *result = (char *)calloc(ln*2+3, sizeof(char)); + char *presult = result; + + *presult++ = '"'; + for (nb=0, i=0; i < ln; i++) + { + if (data[i] == '\\') + nb += 1; + else if (data[i] == '"') + { + for (; nb > 0; nb--) + *presult++ = '\\'; + *presult++ = '\\'; + } + else + nb = 0; + *presult++ = data[i]; + } + + for (; nb > 0; nb--) /* Deal w trailing slashes */ + *presult++ = '\\'; + + *presult++ = '"'; + *presult++ = 0; + return result; +} + + + + + + + + + + +char *loadable_exe(char *exename) { + /* HINSTANCE hPython; DLL handle for python executable */ + char *result; + + /* hPython = LoadLibraryEx(exename, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); + if (!hPython) return NULL; */ + + /* Return the absolute filename for spawnv */ + result = (char *)calloc(MAX_PATH, sizeof(char)); + strncpy(result, exename, MAX_PATH); + /*if (result) GetModuleFileNameA(hPython, result, MAX_PATH); + + FreeLibrary(hPython); */ + return result; +} + + +char *find_exe(char *exename, char *script) { + char drive[_MAX_DRIVE], dir[_MAX_DIR], fname[_MAX_FNAME], ext[_MAX_EXT]; + char path[_MAX_PATH], c, *result; + + /* convert slashes to backslashes for uniform search below */ + result = exename; + while (c = *result++) if (c=='/') result[-1] = '\\'; + + _splitpath(exename, drive, dir, fname, ext); + if (drive[0] || dir[0]=='\\') { + return loadable_exe(exename); /* absolute path, use directly */ + } + /* Use the script's parent directory, which should be the Python home + (This should only be used for bdist_wininst-installed scripts, because + easy_install-ed scripts use the absolute path to python[w].exe + */ + _splitpath(script, drive, dir, fname, ext); + result = dir + strlen(dir) -1; + if (*result == '\\') result--; + while (*result != '\\' && result>=dir) *result-- = 0; + _makepath(path, drive, dir, exename, NULL); + return loadable_exe(path); +} + + +char **parse_argv(char *cmdline, int *argc) +{ + /* Parse a command line in-place using MS C rules */ + + char **result = (char **)calloc(strlen(cmdline), sizeof(char *)); + char *output = cmdline; + char c; + int nb = 0; + int iq = 0; + *argc = 0; + + result[0] = output; + while (isspace(*cmdline)) cmdline++; /* skip leading spaces */ + + do { + c = *cmdline++; + if (!c || (isspace(c) && !iq)) { + while (nb) {*output++ = '\\'; nb--; } + *output++ = 0; + result[++*argc] = output; + if (!c) return result; + while (isspace(*cmdline)) cmdline++; /* skip leading spaces */ + if (!*cmdline) return result; /* avoid empty arg if trailing ws */ + continue; + } + if (c == '\\') + ++nb; /* count \'s */ + else { + if (c == '"') { + if (!(nb & 1)) { iq = !iq; c = 0; } /* skip " unless odd # of \ */ + nb = nb >> 1; /* cut \'s in half */ + } + while (nb) {*output++ = '\\'; nb--; } + if (c) *output++ = c; + } + } while (1); +} + +void pass_control_to_child(DWORD control_type) { + /* + * distribute-issue207 + * passes the control event to child process (Python) + */ + if (!child_pid) { + return; + } + GenerateConsoleCtrlEvent(child_pid,0); +} + +BOOL control_handler(DWORD control_type) { + /* + * distribute-issue207 + * control event handler callback function + */ + switch (control_type) { + case CTRL_C_EVENT: + pass_control_to_child(0); + break; + } + return TRUE; +} + +int create_and_wait_for_subprocess(char* command) { + /* + * distribute-issue207 + * launches child process (Python) + */ + DWORD return_value = 0; + LPSTR commandline = command; + STARTUPINFOA s_info; + PROCESS_INFORMATION p_info; + ZeroMemory(&p_info, sizeof(p_info)); + ZeroMemory(&s_info, sizeof(s_info)); + s_info.cb = sizeof(STARTUPINFO); + // set-up control handler callback funciotn + SetConsoleCtrlHandler((PHANDLER_ROUTINE) control_handler, TRUE); + if (!CreateProcessA(NULL, commandline, NULL, NULL, TRUE, 0, NULL, NULL, &s_info, &p_info)) { + fprintf(stderr, "failed to create process.\n"); + return 0; + } + child_pid = p_info.dwProcessId; + // wait for Python to exit + WaitForSingleObject(p_info.hProcess, INFINITE); + if (!GetExitCodeProcess(p_info.hProcess, &return_value)) { + fprintf(stderr, "failed to get exit code from process.\n"); + return 0; + } + return return_value; +} + +char* join_executable_and_args(char *executable, char **args, int argc) +{ + /* + * distribute-issue207 + * CreateProcess needs a long string of the executable and command-line arguments, + * so we need to convert it from the args that was built + */ + int len,counter; + char* cmdline; + + len=strlen(executable)+2; + for (counter=1; counter<argc; counter++) { + len+=strlen(args[counter])+1; + } + + cmdline = (char*)calloc(len, sizeof(char)); + sprintf(cmdline, "%s", executable); + len=strlen(executable); + for (counter=1; counter<argc; counter++) { + sprintf(cmdline+len, " %s", args[counter]); + len+=strlen(args[counter])+1; + } + return cmdline; +} + +int run(int argc, char **argv, int is_gui) { + + char python[256]; /* python executable's filename*/ + char *pyopt; /* Python option */ + char script[256]; /* the script's filename */ + + int scriptf; /* file descriptor for script file */ + + char **newargs, **newargsp, **parsedargs; /* argument array for exec */ + char *ptr, *end; /* working pointers for string manipulation */ + char *cmdline; + int i, parsedargc; /* loop counter */ + + /* compute script name from our .exe name*/ + GetModuleFileNameA(NULL, script, sizeof(script)); + end = script + strlen(script); + while( end>script && *end != '.') + *end-- = '\0'; + *end-- = '\0'; + strcat(script, (GUI ? "-script.pyw" : "-script.py")); + + /* figure out the target python executable */ + + scriptf = open(script, O_RDONLY); + if (scriptf == -1) { + return fail("Cannot open %s\n", script); + } + end = python + read(scriptf, python, sizeof(python)); + close(scriptf); + + ptr = python-1; + while(++ptr < end && *ptr && *ptr!='\n' && *ptr!='\r') {;} + + *ptr-- = '\0'; + + if (strncmp(python, "#!", 2)) { + /* default to python.exe if no #! header */ + strcpy(python, "#!python.exe"); + } + + parsedargs = parse_argv(python+2, &parsedargc); + + /* Using spawnv() can fail strangely if you e.g. find the Cygwin + Python, so we'll make sure Windows can find and load it */ + + ptr = find_exe(parsedargs[0], script); + if (!ptr) { + return fail("Cannot find Python executable %s\n", parsedargs[0]); + } + + /* printf("Python executable: %s\n", ptr); */ + + /* Argument array needs to be + parsedargc + argc, plus 1 for null sentinel */ + + newargs = (char **)calloc(parsedargc + argc + 1, sizeof(char *)); + newargsp = newargs; + + *newargsp++ = quoted(ptr); + for (i = 1; i<parsedargc; i++) *newargsp++ = quoted(parsedargs[i]); + + *newargsp++ = quoted(script); + for (i = 1; i < argc; i++) *newargsp++ = quoted(argv[i]); + + *newargsp++ = NULL; + + /* printf("args 0: %s\nargs 1: %s\n", newargs[0], newargs[1]); */ + + if (is_gui) { + /* Use exec, we don't need to wait for the GUI to finish */ + execv(ptr, (char * const *)(newargs)); + return fail("Could not exec %s", ptr); /* shouldn't get here! */ + } + + /* + * distribute-issue207: using CreateProcessA instead of spawnv + */ + cmdline = join_executable_and_args(ptr, newargs, parsedargc + argc); + return create_and_wait_for_subprocess(cmdline); +} + +int WINAPI WinMain(HINSTANCE hI, HINSTANCE hP, LPSTR lpCmd, int nShow) { + return run(__argc, __argv, GUI); +} + +int main(int argc, char** argv) { + return run(argc, argv, GUI); +} diff --git a/misc/py_wrap_generator.py b/misc/py_wrap_generator.py new file mode 100644 index 000000000..2bf364470 --- /dev/null +++ b/misc/py_wrap_generator.py @@ -0,0 +1,2091 @@ +# +# yosys -- Yosys Open SYnthesis Suite +# +# Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> +# +# 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. +# +# Author Benedikt Tutzer +# + +import copy + +#Map c++ operator Syntax to Python functions +wrappable_operators = { + "<" : "__lt__", + "==": "__eq__", + "!=": "__ne__", + "+" : "__add__", + "-" : "__sub__", + "*" : "__mul__", + "/" : "__div__", + "()": "__call__" + } + +#Restrict certain strings from being function names in Python +keyword_aliases = { + "in" : "in_", + "False" : "False_", + "None" : "None_", + "True" : "True_", + "and" : "and_", + "as" : "as_", + "assert" : "assert_", + "break" : "break_", + "class" : "class_", + "continue" : "continue_", + "def" : "def_", + "del" : "del_", + "elif" : "elif_", + "else" : "else_", + "except" : "except_", + "for" : "for_", + "from" : "from_", + "global" : "global_", + "if" : "if_", + "import" : "import_", + "in" : "in_", + "is" : "is_", + "lambda" : "lambda_", + "nonlocal" : "nonlocal_", + "not" : "not_", + "or" : "or_", + "pass" : "pass_", + "raise" : "raise_", + "return" : "return_", + "try" : "try_", + "while" : "while_", + "with" : "with_", + "yield" : "yield_" + } + +#These can be used without any explicit conversion +primitive_types = ["void", "bool", "int", "double", "size_t", "std::string", + "string", "State", "char_p"] + +from enum import Enum + +#Ways to link between Python- and C++ Objects +class link_types(Enum): + global_list = 1 #Manage a global list of objects in C++, the Python + #object contains a key to find the corresponding C++ + #object and a Pointer to the object to verify it is + #still the same, making collisions unlikely to happen + ref_copy = 2 #The Python object contains a copy of the C++ object. + #The C++ object is deleted when the Python object gets + #deleted + pointer = 3 #The Python Object contains a pointer to it's C++ + #counterpart + derive = 4 #The Python-Wrapper is derived from the C++ object. + +class attr_types(Enum): + star = "*" + amp = "&" + ampamp = "&&" + default = "" + +#For source-files +class Source: + name = "" + classes = [] + + def __init__(self, name, classes): + self.name = name + self.classes = classes + +#Splits a list by the given delimiter, without splitting strings inside +#pointy-brackets (< and >) +def split_list(str_def, delim): + str_def = str_def.strip() + if len(str_def) == 0: + return [] + if str_def.count(delim) == 0: + return [str_def] + if str_def.count("<") == 0: + return str_def.split(delim) + if str_def.find("<") < str_def.find(" "): + closing = find_closing(str_def[str_def.find("<")+1:], "<", ">") + str_def.find("<") + comma = str_def[closing:].find(delim) + if comma == -1: + return [str_def] + comma = closing + comma + else: + comma = str_def.find(delim) + rest = split_list(str_def[comma+1:], delim) + ret = [str_def[:comma]] + if rest != None and len(rest) != 0: + ret.extend(rest) + return ret + +#Represents a Type +class WType: + name = "" + cont = None + attr_type = attr_types.default + + def __init__(self, name = "", cont = None, attr_type = attr_types.default): + self.name = name + self.cont = cont + self.attr_type = attr_type + + #Python type-string + def gen_text(self): + text = self.name + if self.name in enum_names: + text = enum_by_name(self.name).namespace + "::" + self.name + if self.cont != None: + return known_containers[self.name].typename + return text + + #C++ type-string + def gen_text_cpp(self): + postfix = "" + if self.attr_type == attr_types.star: + postfix = "*" + if self.name in primitive_types: + return self.name + postfix + if self.name in enum_names: + return enum_by_name(self.name).namespace + "::" + self.name + postfix + if self.name in classnames: + return class_by_name(self.name).namespace + "::" + self.name + postfix + text = self.name + if self.cont != None: + text += "<" + for a in self.cont.args: + text += a.gen_text_cpp() + ", " + text = text[:-2] + text += ">" + return text + + @staticmethod + def from_string(str_def, containing_file, line_number): + str_def = str_def.strip() + if len(str_def) == 0: + return None + str_def = str_def.replace("RTLIL::SigSig", "std::pair<SigSpec, SigSpec>").replace("SigSig", "std::pair<SigSpec, SigSpec>") + t = WType() + t.name = "" + t.cont = None + t.attr_type = attr_types.default + if str_def.find("<") != -1:# and str_def.find("<") < str_def.find(" "): + candidate = WContainer.from_string(str_def, containing_file, line_number) + if candidate == None: + return None + t.name = str_def[:str_def.find("<")] + + if t.name.count("*") + t.name.count("&") > 1: + return None + + if t.name.count("*") == 1 or str_def[0] == '*' or str_def[-1] == '*': + t.attr_type = attr_types.star + t.name = t.name.replace("*","") + elif t.name.count("&&") == 1: + t.attr_type = attr_types.ampamp + t.name = t.name.replace("&&","") + elif t.name.count("&") == 1 or str_def[0] == '&' or str_def[-1] == '&': + t.attr_type = attr_types.amp + t.name = t.name.replace("&","") + + t.cont = candidate + if(t.name not in known_containers): + return None + return t + + prefix = "" + + if str.startswith(str_def, "unsigned "): + prefix = "unsigned " + str_def = str_def[9:] + while str.startswith(str_def, "long "): + prefix= "long " + prefix + str_def = str_def[5:] + while str.startswith(str_def, "short "): + prefix = "short " + prefix + str_def = str_def[6:] + + str_def = str_def.split("::")[-1] + + if str_def.count("*") + str_def.count("&") >= 2: + return None + + if str_def.count("*") == 1: + t.attr_type = attr_types.star + str_def = str_def.replace("*","") + elif str_def.count("&&") == 1: + t.attr_type = attr_types.ampamp + str_def = str_def.replace("&&","") + elif str_def.count("&") == 1: + t.attr_type = attr_types.amp + str_def = str_def.replace("&","") + + if len(str_def) > 0 and str_def.split("::")[-1] not in primitive_types and str_def.split("::")[-1] not in classnames and str_def.split("::")[-1] not in enum_names: + return None + + if str_def.count(" ") == 0: + t.name = (prefix + str_def).replace("char_p", "char *") + t.cont = None + return t + return None + +#Represents a container-type +class WContainer: + name = "" + args = [] + + def from_string(str_def, containing_file, line_number): + if str_def == None or len(str_def) < 4: + return None + cont = WContainer() + cont.name = str_def[:str_def.find("<")] + str_def = str_def[str_def.find("<")+1:find_closing(str_def, "<", ">")] + cont.args = [] + for arg in split_list(str_def, ","): + candidate = WType.from_string(arg.strip(), containing_file, line_number) + if candidate == None: + return None + cont.args.append(candidate) + return cont + +#Translators between Python and C++ containers +#Base Type +class Translator: + tmp_cntr = 0 + typename = "DefaultType" + orig_name = "DefaultCpp" + + @classmethod + def gen_type(c, types): + return "\nImplement a function that outputs the c++ type of this container here\n" + + @classmethod + def translate(c, varname, types, prefix): + return "\nImplement a function translating a python container to a c++ container here\n" + + @classmethod + def translate_cpp(c, varname, types, prefix, ref): + return "\nImplement a function translating a c++ container to a python container here\n" + +#Translates list-types (vector, pool, set), that only differ in their name and +#the name of the insertion function +class PythonListTranslator(Translator): + typename = "boost::python::list" + insert_name = "Default" + + #generate the c++ type string + @classmethod + def gen_type(c, types): + text = c.orig_name + "<" + if types[0].name in primitive_types: + text += types[0].name + elif types[0].name in known_containers: + text += known_containers[types[0].name].gen_type(types[0].cont.args) + else: + text += class_by_name(types[0].name).namespace + "::" + types[0].name + if types[0].attr_type == attr_types.star: + text += "*" + text += ">" + return text + + #Generate C++ code to translate from a boost::python::list + @classmethod + def translate(c, varname, types, prefix): + text = prefix + c.gen_type(types) + " " + varname + "___tmp;" + cntr_name = "cntr_" + str(Translator.tmp_cntr) + Translator.tmp_cntr = Translator.tmp_cntr + 1 + text += prefix + "for(int " + cntr_name + " = 0; " + cntr_name + " < len(" + varname + "); " + cntr_name + "++)" + text += prefix + "{" + tmp_name = "tmp_" + str(Translator.tmp_cntr) + Translator.tmp_cntr = Translator.tmp_cntr + 1 + if types[0].name in known_containers: + text += prefix + "\t" + known_containers[types[0].name].typename + " " + tmp_name + " = boost::python::extract<" + known_containers[types[0].name].typename + ">(" + varname + "[" + cntr_name + "]);" + text += known_containers[types[0].name].translate(tmp_name, types[0].cont.args, prefix+"\t") + tmp_name = tmp_name + "___tmp" + text += prefix + "\t" + varname + "___tmp." + c.insert_name + "(" + tmp_name + ");" + elif types[0].name in classnames: + text += prefix + "\t" + types[0].name + "* " + tmp_name + " = boost::python::extract<" + types[0].name + "*>(" + varname + "[" + cntr_name + "]);" + if types[0].attr_type == attr_types.star: + text += prefix + "\t" + varname + "___tmp." + c.insert_name + "(" + tmp_name + "->get_cpp_obj());" + else: + text += prefix + "\t" + varname + "___tmp." + c.insert_name + "(*" + tmp_name + "->get_cpp_obj());" + else: + text += prefix + "\t" + types[0].name + " " + tmp_name + " = boost::python::extract<" + types[0].name + ">(" + varname + "[" + cntr_name + "]);" + text += prefix + "\t" + varname + "___tmp." + c.insert_name + "(" + tmp_name + ");" + text += prefix + "}" + return text + + #Generate C++ code to translate to a boost::python::list + @classmethod + def translate_cpp(c, varname, types, prefix, ref): + text = prefix + c.typename + " " + varname + "___tmp;" + tmp_name = "tmp_" + str(Translator.tmp_cntr) + Translator.tmp_cntr = Translator.tmp_cntr + 1 + if ref: + text += prefix + "for(auto " + tmp_name + " : *" + varname + ")" + else: + text += prefix + "for(auto " + tmp_name + " : " + varname + ")" + text += prefix + "{" + if types[0].name in classnames: + if types[0].attr_type == attr_types.star: + text += prefix + "\t" + varname + "___tmp.append(" + types[0].name + "::get_py_obj(" + tmp_name + "));" + else: + text += prefix + "\t" + varname + "___tmp.append(*" + types[0].name + "::get_py_obj(&" + tmp_name + "));" + elif types[0].name in known_containers: + text += known_containers[types[0].name].translate_cpp(tmp_name, types[0].cont.args, prefix + "\t", types[0].attr_type == attr_types.star) + text += prefix + "\t" + varname + "___tmp.append(" + tmp_name + "___tmp);" + else: + text += prefix + "\t" + varname + "___tmp.append(" + tmp_name + ");" + text += prefix + "}" + return text + +#Sub-type for std::set +class SetTranslator(PythonListTranslator): + insert_name = "insert" + orig_name = "std::set" + +#Sub-type for std::vector +class VectorTranslator(PythonListTranslator): + insert_name = "push_back" + orig_name = "std::vector" + +#Sub-type for pool +class PoolTranslator(PythonListTranslator): + insert_name = "insert" + orig_name = "pool" + +#Translates dict-types (dict, std::map), that only differ in their name and +#the name of the insertion function +class PythonDictTranslator(Translator): + typename = "boost::python::dict" + insert_name = "Default" + + @classmethod + def gen_type(c, types): + text = c.orig_name + "<" + if types[0].name in primitive_types: + text += types[0].name + elif types[0].name in known_containers: + text += known_containers[types[0].name].gen_type(types[0].cont.args) + else: + text += class_by_name(types[0].name).namespace + "::" + types[0].name + if types[0].attr_type == attr_types.star: + text += "*" + text += ", " + if types[1].name in primitive_types: + text += types[1].name + elif types[1].name in known_containers: + text += known_containers[types[1].name].gen_type(types[1].cont.args) + else: + text += class_by_name(types[1].name).namespace + "::" + types[1].name + if types[1].attr_type == attr_types.star: + text += "*" + text += ">" + return text + + #Generate c++ code to translate from a boost::python::dict + @classmethod + def translate(c, varname, types, prefix): + text = prefix + c.gen_type(types) + " " + varname + "___tmp;" + text += prefix + "boost::python::list " + varname + "_keylist = " + varname + ".keys();" + cntr_name = "cntr_" + str(Translator.tmp_cntr) + Translator.tmp_cntr = Translator.tmp_cntr + 1 + text += prefix + "for(int " + cntr_name + " = 0; " + cntr_name + " < len(" + varname + "_keylist); " + cntr_name + "++)" + text += prefix + "{" + key_tmp_name = "key_tmp_" + str(Translator.tmp_cntr) + val_tmp_name = "val_tmp_" + str(Translator.tmp_cntr) + Translator.tmp_cntr = Translator.tmp_cntr + 1 + + if types[0].name in known_containers: + text += prefix + "\t" + known_containers[types[0].name].typename + " " + key_tmp_name + " = boost::python::extract<" + known_containers[types[0].name].typename + ">(" + varname + "_keylist[ " + cntr_name + " ]);" + text += known_containers[types[0].name].translate(key_tmp_name, types[0].cont.args, prefix+"\t") + key_tmp_name = key_tmp_name + "___tmp" + elif types[0].name in classnames: + text += prefix + "\t" + types[0].name + "* " + key_tmp_name + " = boost::python::extract<" + types[0].name + "*>(" + varname + "_keylist[ " + cntr_name + " ]);" + else: + text += prefix + "\t" + types[0].name + " " + key_tmp_name + " = boost::python::extract<" + types[0].name + ">(" + varname + "_keylist[ " + cntr_name + " ]);" + + if types[1].name in known_containers: + text += prefix + "\t" + known_containers[types[1].name].typename + " " + val_tmp_name + " = boost::python::extract<" + known_containers[types[1].name].typename + ">(" + varname + "[" + varname + "_keylist[ " + cntr_name + " ]]);" + text += known_containers[types[1].name].translate(val_tmp_name, types[1].cont.args, prefix+"\t") + val_tmp_name = val_tmp_name + "___tmp" + elif types[1].name in classnames: + text += prefix + "\t" + types[1].name + "* " + val_tmp_name + " = boost::python::extract<" + types[1].name + "*>(" + varname + "[" + varname + "_keylist[ " + cntr_name + " ]]);" + else: + text += prefix + "\t" + types[1].name + " " + val_tmp_name + " = boost::python::extract<" + types[1].name + ">(" + varname + "[" + varname + "_keylist[ " + cntr_name + " ]]);" + + text += prefix + "\t" + varname + "___tmp." + c.insert_name + "(std::pair<" + types[0].gen_text_cpp() + ", " + types[1].gen_text_cpp() + ">(" + + if types[0].name not in classnames: + text += key_tmp_name + else: + if types[0].attr_type != attr_types.star: + text += "*" + text += key_tmp_name + "->get_cpp_obj()" + + text += ", " + if types[1].name not in classnames: + text += val_tmp_name + else: + if types[1].attr_type != attr_types.star: + text += "*" + text += val_tmp_name + "->get_cpp_obj()" + text += "));\n" + prefix + "}" + return text + + #Generate c++ code to translate to a boost::python::dict + @classmethod + def translate_cpp(c, varname, types, prefix, ref): + text = prefix + c.typename + " " + varname + "___tmp;" + tmp_name = "tmp_" + str(Translator.tmp_cntr) + Translator.tmp_cntr = Translator.tmp_cntr + 1 + if ref: + text += prefix + "for(auto " + tmp_name + " : *" + varname + ")" + else: + text += prefix + "for(auto " + tmp_name + " : " + varname + ")" + text += prefix + "{" + if types[1].name in known_containers: + text += prefix + "\tauto " + tmp_name + "_second = " + tmp_name + ".second;" + text += known_containers[types[1].name].translate_cpp(tmp_name + "_second", types[1].cont.args, prefix + "\t", types[1].attr_type == attr_types.star) + + if types[0].name in classnames: + text += prefix + "\t" + varname + "___tmp[" + types[0].name + "::get_py_obj(" + tmp_name + ".first)] = " + elif types[0].name not in known_containers: + text += prefix + "\t" + varname + "___tmp[" + tmp_name + ".first] = " + + if types[1].name in classnames: + if types[1].attr_type == attr_types.star: + text += types[1].name + "::get_py_obj(" + tmp_name + ".second);" + else: + text += "*" + types[1].name + "::get_py_obj(&" + tmp_name + ".second);" + elif types[1].name in known_containers: + text += tmp_name + "_second___tmp;" + else: + text += tmp_name + ".second;" + text += prefix + "}" + return text + +#Sub-type for dict +class DictTranslator(PythonDictTranslator): + insert_name = "insert" + orig_name = "dict" + +#Sub_type for std::map +class MapTranslator(PythonDictTranslator): + insert_name = "insert" + orig_name = "std::map" + +#Translator for std::pair. Derived from PythonDictTranslator because the +#gen_type function is the same (because both have two template parameters) +class TupleTranslator(PythonDictTranslator): + typename = "boost::python::tuple" + orig_name = "std::pair" + + #Generate c++ code to translate from a boost::python::tuple + @classmethod + def translate(c, varname, types, prefix): + text = prefix + types[0].name + " " + varname + "___tmp_0 = boost::python::extract<" + types[0].name + ">(" + varname + "[0]);" + text += prefix + types[1].name + " " + varname + "___tmp_1 = boost::python::extract<" + types[1].name + ">(" + varname + "[1]);" + text += prefix + TupleTranslator.gen_type(types) + " " + varname + "___tmp(" + if types[0].name.split(" ")[-1] in primitive_types: + text += varname + "___tmp_0, " + else: + text += varname + "___tmp_0.get_cpp_obj(), " + if types[1].name.split(" ")[-1] in primitive_types: + text += varname + "___tmp_1);" + else: + text += varname + "___tmp_1.get_cpp_obj());" + return text + + #Generate c++ code to translate to a boost::python::tuple + @classmethod + def translate_cpp(c, varname, types, prefix, ref): + # if the tuple is a pair of SigSpecs (aka SigSig), then we need + # to call get_py_obj() on each item in the tuple + if types[0].name in classnames: + first_var = types[0].name + "::get_py_obj(" + varname + ".first)" + else: + first_var = varname + ".first" + if types[1].name in classnames: + second_var = types[1].name + "::get_py_obj(" + varname + ".second)" + else: + second_var = varname + ".second" + text = prefix + TupleTranslator.typename + " " + varname + "___tmp = boost::python::make_tuple(" + first_var + ", " + second_var + ");" + return text + +#Associate the Translators with their c++ type +known_containers = { + "std::set" : SetTranslator, + "std::vector" : VectorTranslator, + "pool" : PoolTranslator, + "dict" : DictTranslator, + "std::pair" : TupleTranslator, + "std::map" : MapTranslator +} + +class Attribute: + wtype = None + varname = None + is_const = False + default_value = None + pos = None + pos_counter = 0 + + def __init__(self, wtype, varname, is_const = False, default_value = None): + self.wtype = wtype + self.varname = varname + self.is_const = is_const + self.default_value = None + self.container = None + + @staticmethod + def from_string(str_def, containing_file, line_number): + if len(str_def) < 3: + return None + orig = str_def + arg = Attribute(None, None) + prefix = "" + arg.wtype = None + arg.varname = None + arg.is_const = False + arg.default_value = None + arg.container = None + if str.startswith(str_def, "const "): + arg.is_const = True + str_def = str_def[6:] + if str.startswith(str_def, "unsigned "): + prefix = "unsigned " + str_def = str_def[9:] + while str.startswith(str_def, "long "): + prefix= "long " + prefix + str_def = str_def[5:] + while str.startswith(str_def, "short "): + prefix = "short " + prefix + str_def = str_def[6:] + + if str_def.find("<") != -1 and str_def.find("<") < str_def.find(" "): + closing = find_closing(str_def[str_def.find("<"):], "<", ">") + str_def.find("<") + 1 + arg.wtype = WType.from_string(str_def[:closing].strip(), containing_file, line_number) + str_def = str_def[closing+1:] + else: + if str_def.count(" ") > 0: + arg.wtype = WType.from_string(prefix + str_def[:str_def.find(" ")].strip(), containing_file, line_number) + str_def = str_def[str_def.find(" ")+1:] + else: + arg.wtype = WType.from_string(prefix + str_def.strip(), containing_file, line_number) + str_def = "" + arg.varname = "" + + if arg.wtype == None: + return None + if str_def.count("=") == 0: + arg.varname = str_def.strip() + if arg.varname.find(" ") > 0: + return None + else: + arg.varname = str_def[:str_def.find("=")].strip() + if arg.varname.find(" ") > 0: + return None + str_def = str_def[str_def.find("=")+1:].strip() + arg.default_value = str_def[arg.varname.find("=")+1:].strip() + if len(arg.varname) == 0: + arg.varname = None + return arg + if arg.varname[0] == '*': + arg.wtype.attr_type = attr_types.star + arg.varname = arg.varname[1:] + elif arg.varname[0] == '&': + if arg.wtype.attr_type != attr_types.default: + return None + if arg.varname[1] == '&': + arg.wtype.attr_type = attr_types.ampamp + arg.varname = arg.varname[2:] + else: + arg.wtype.attr_type = attr_types.amp + arg.varname = arg.varname[1:] + return arg + + #Generates the varname. If the attribute has no name in the header file, + #a name is generated + def gen_varname(self): + if self.varname != None: + return self.varname + if self.wtype.name == "void": + return "" + if self.pos == None: + self.pos = Attribute.pos_counter + Attribute.pos_counter = Attribute.pos_counter + 1 + return "gen_varname_" + str(self.pos) + + #Generates the text for the function headers with wrapper types + def gen_listitem(self): + prefix = "" + if self.is_const: + prefix = "const " + if self.wtype.name in classnames: + return prefix + self.wtype.name + "* " + self.gen_varname() + if self.wtype.name in known_containers: + return prefix + known_containers[self.wtype.name].typename + " " + self.gen_varname() + return prefix + self.wtype.name + " " + self.gen_varname() + + #Generates the test for the function headers with c++ types + def gen_listitem_cpp(self): + prefix = "" + if self.is_const: + prefix = "const " + infix = "" + if self.wtype.attr_type == attr_types.star: + infix = "*" + elif self.wtype.attr_type == attr_types.amp: + infix = "&" + elif self.wtype.attr_type == attr_types.ampamp: + infix = "&&" + if self.wtype.name in known_containers: + return prefix + known_containers[self.wtype.name].gen_type(self.wtype.cont.args) + " " + infix + self.gen_varname() + if self.wtype.name in classnames: + return prefix + class_by_name(self.wtype.name).namespace + "::" + self.wtype.name + " " + infix + self.gen_varname() + return prefix + self.wtype.name + " " + infix + self.gen_varname() + + #Generates the listitem withtout the varname, so the signature can be + #compared + def gen_listitem_hash(self): + prefix = "" + if self.is_const: + prefix = "const " + if self.wtype.name in classnames: + return prefix + self.wtype.name + "* " + if self.wtype.name in known_containers: + return known_containers[self.wtype.name].typename + return prefix + self.wtype.name + + #Generate Translation code for the attribute + def gen_translation(self): + if self.wtype.name in known_containers: + return known_containers[self.wtype.name].translate(self.gen_varname(), self.wtype.cont.args, "\n\t\t") + return "" + + #Generate Translation code from c++ for the attribute + def gen_translation_cpp(self): + if self.wtype.name in known_containers: + return known_containers[self.wtype.name].translate_cpp(self.gen_varname(), self.wtype.cont.args, "\n\t\t", self.wtype.attr_type == attr_types.star) + return "" + + #Generate Text for the call + def gen_call(self): + ret = self.gen_varname() + if self.wtype.name in known_containers: + if self.wtype.attr_type == attr_types.star: + return "&" + ret + "___tmp" + return ret + "___tmp" + if self.wtype.name in classnames: + if self.wtype.attr_type != attr_types.star: + ret = "*" + ret + return ret + "->get_cpp_obj()" + if self.wtype.name == "char *" and self.gen_varname() in ["format", "fmt"]: + return "\"%s\", " + self.gen_varname() + if self.wtype.attr_type == attr_types.star: + return "&" + ret + return ret + + def gen_call_cpp(self): + ret = self.gen_varname() + if self.wtype.name.split(" ")[-1] in primitive_types or self.wtype.name in enum_names: + if self.wtype.attr_type == attr_types.star: + return "&" + ret + return ret + if self.wtype.name not in classnames: + if self.wtype.attr_type == attr_types.star: + return "&" + ret + "___tmp" + return ret + "___tmp" + if self.wtype.attr_type != attr_types.star: + ret = "*" + ret + return self.wtype.name + "::get_py_obj(" + self.gen_varname() + ")" + + #Generate cleanup code + def gen_cleanup(self): + if self.wtype.name in primitive_types or self.wtype.name in classnames or self.wtype.name in enum_names or not self.wtype.attr_type == attr_types.star or (self.wtype.name in known_containers and self.wtype.attr_type == attr_types.star): + return "" + return "\n\t\tdelete " + self.gen_varname() + "___tmp;" + +class WClass: + name = None + namespace = None + link_type = None + id_ = None + string_id = None + hash_id = None + needs_clone = False + found_funs = [] + found_vars = [] + found_constrs = [] + + def __init__(self, name, link_type, id_, string_id = None, hash_id = None, needs_clone = False): + self.name = name + self.namespace = None + self.link_type = link_type + self.id_ = id_ + self.string_id = string_id + self.hash_id = hash_id + self.needs_clone = needs_clone + self.found_funs = [] + self.found_vars = [] + self.found_constrs = [] + + def printable_constrs(self): + ret = 0 + for con in self.found_constrs: + if not con.protected: + ret += 1 + return ret + + def gen_decl(self, filename): + long_name = self.namespace + "::" + self.name + + text = "\n\t// WRAPPED from " + filename + text += "\n\tstruct " + self.name + if self.link_type == link_types.derive: + text += " : public " + self.namespace + "::" + self.name + text += "\n\t{\n" + + if self.link_type != link_types.derive: + + text += "\t\t" + long_name + "* ref_obj;\n" + + if self.link_type == link_types.ref_copy or self.link_type == link_types.pointer: + text += "\n\t\t" + long_name + "* get_cpp_obj() const\n\t\t{\n\t\t\treturn ref_obj;\n\t\t}\n" + elif self.link_type == link_types.global_list: + text += "\t\t" + self.id_.wtype.name + " " + self.id_.varname + ";\n" + text += "\n\t\t" + long_name + "* get_cpp_obj() const\n\t\t{" + text += "\n\t\t\t" + long_name + "* ret = " + long_name + "::get_all_" + self.name.lower() + "s()->at(this->" + self.id_.varname + ");" + text += "\n\t\t\tif(ret != NULL && ret == this->ref_obj)" + text += "\n\t\t\t\treturn ret;" + text += "\n\t\t\tthrow std::runtime_error(\"" + self.name + "'s c++ object does not exist anymore.\");" + text += "\n\t\t\treturn NULL;" + text += "\n\t\t}\n" + + #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;" + if self.link_type == link_types.ref_copy: + if self.needs_clone: + text += "\n\t\t\tret->ref_obj = ref->clone();" + else: + text += "\n\t\t\tret->ref_obj = new "+long_name+"(*ref);" + if self.link_type == link_types.global_list: + text += "\n\t\t\tret->ref_obj = ref;" + text += "\n\t\t\tret->" + self.id_.varname + " = ret->ref_obj->" + self.id_.varname + ";" + text += "\n\t\t\treturn ret;" + text += "\n\t\t}\n" + + if self.link_type == link_types.ref_copy: + text += "\n\t\tstatic " + self.name + "* get_py_obj(" + long_name + " ref)\n\t\t{" + text += "\n\t\t\t" + self.name + "* ret = (" + self.name + "*)malloc(sizeof(" + self.name + "));" + if self.needs_clone: + text += "\n\t\t\tret->ref_obj = ref.clone();" + else: + text += "\n\t\t\tret->ref_obj = new "+long_name+"(ref);" + text += "\n\t\t\treturn ret;" + text += "\n\t\t}\n" + + for con in self.found_constrs: + text += con.gen_decl() + for var in self.found_vars: + text += var.gen_decl() + for fun in self.found_funs: + text += fun.gen_decl() + + + if self.link_type == link_types.derive: + duplicates = {} + for fun in self.found_funs: + if fun.name in duplicates: + fun.gen_alias() + duplicates[fun.name].gen_alias() + else: + duplicates[fun.name] = fun + + text += "\n\t\t" + long_name + "* get_cpp_obj() const\n\t\t{\n\t\t\treturn (" + self.namespace + "::" + self.name +"*)this;\n\t\t}\n" + text += "\n\t\tstatic " + self.name + "* get_py_obj(" + long_name + "* ref)\n\t\t{" + text += "\n\t\t\treturn (" + self.name + "*)ref;" + text += "\n\t\t}\n" + + for con in self.found_constrs: + text += con.gen_decl_derive() + for var in self.found_vars: + text += var.gen_decl() + for fun in self.found_funs: + text += fun.gen_decl_virtual() + + if self.hash_id != None: + text += "\n\t\tunsigned int get_hash_py()" + text += "\n\t\t{" + text += "\n\t\t\treturn get_cpp_obj()->" + self.hash_id + ";" + text += "\n\t\t}" + + text += "\n\t};\n" + + if self.link_type == link_types.derive: + text += "\n\tstruct " + self.name + "Wrap : " + self.name + ", boost::python::wrapper<" + self.name + ">" + text += "\n\t{" + + for con in self.found_constrs: + text += con.gen_decl_wrapperclass() + for fun in self.found_funs: + text += fun.gen_default_impl() + + text += "\n\t};" + + text += "\n\tstd::ostream &operator<<(std::ostream &ostr, const " + self.name + " &ref)" + text += "\n\t{" + text += "\n\t\tostr << \"" + self.name + if self.string_id != None: + text +=" \\\"\"" + text += " << ref.get_cpp_obj()->" + self.string_id + text += " << \"\\\"\"" + else: + text += " at \" << ref.get_cpp_obj()" + text += ";" + text += "\n\t\treturn ostr;" + text += "\n\t}" + text += "\n" + + return text + + def gen_funs(self, filename): + text = "" + if self.link_type != link_types.derive: + for con in self.found_constrs: + text += con.gen_def() + for var in self.found_vars: + text += var.gen_def() + for fun in self.found_funs: + text += fun.gen_def() + else: + for var in self.found_vars: + text += var.gen_def() + for fun in self.found_funs: + text += fun.gen_def_virtual() + return text + + def gen_boost_py(self): + text = "\n\t\tclass_<" + self.name + if self.link_type == link_types.derive: + text += "Wrap, boost::noncopyable" + text += ">(\"" + self.name + "\"" + if self.printable_constrs() == 0 or not self.contains_default_constr(): + text += ", no_init" + text += ")" + text += "\n\t\t\t.def(boost::python::self_ns::str(boost::python::self_ns::self))" + text += "\n\t\t\t.def(boost::python::self_ns::repr(boost::python::self_ns::self))" + for con in self.found_constrs: + text += con.gen_boost_py() + for var in self.found_vars: + text += var.gen_boost_py() + static_funs = [] + for fun in self.found_funs: + text += fun.gen_boost_py() + if fun.is_static and fun.alias not in static_funs: + static_funs.append(fun.alias) + for fun in static_funs: + text += "\n\t\t\t.staticmethod(\"" + fun + "\")" + + if self.hash_id != None: + text += "\n\t\t\t.def(\"__hash__\", &" + self.name + "::get_hash_py)" + text += "\n\t\t\t;\n" + return text + + def contains_default_constr(self): + for c in self.found_constrs: + if len(c.args) == 0: + return True + return False + +#CONFIGURE HEADER-FILES TO BE PARSED AND CLASSES EXPECTED IN THEM HERE + +sources = [ + Source("kernel/celltypes",[ + WClass("CellType", link_types.pointer, None, None, "type.hash()", True), + WClass("CellTypes", link_types.pointer, None, None, None, True) + ] + ), + Source("kernel/consteval",[ + WClass("ConstEval", link_types.pointer, None, None, None, True) + ] + ), + Source("kernel/log",[]), + Source("kernel/register",[ + WClass("Pass", link_types.derive, None, None, None, True), + ] + ), + Source("kernel/rtlil",[ + WClass("IdString", link_types.ref_copy, None, "str()", "hash()"), + WClass("Const", link_types.ref_copy, None, "as_string()", "hash()"), + WClass("AttrObject", link_types.ref_copy, None, None, None), + WClass("Selection", link_types.ref_copy, None, None, None), + WClass("Monitor", link_types.derive, None, None, None), + WClass("CaseRule",link_types.ref_copy, None, None, None, True), + WClass("SwitchRule",link_types.ref_copy, None, None, None, True), + WClass("SyncRule", link_types.ref_copy, None, None, None, True), + WClass("Process", link_types.ref_copy, None, "name.c_str()", "name.hash()"), + WClass("SigChunk", link_types.ref_copy, None, None, None), + WClass("SigBit", link_types.ref_copy, None, None, "hash()"), + WClass("SigSpec", link_types.ref_copy, None, None, "hash()"), + WClass("Cell", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", "hash()"), + WClass("Wire", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", "hash()"), + WClass("Memory", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", "hash()"), + WClass("Module", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "name.c_str()", "hash()"), + WClass("Design", link_types.global_list, Attribute(WType("unsigned int"), "hashidx_"), "hashidx_", "hash()") + ] + ), + #Source("kernel/satgen",[ + # ] + # ), + #Source("libs/ezsat/ezsat",[ + # ] + # ), + #Source("libs/ezsat/ezminisat",[ + # ] + # ), + Source("kernel/sigtools",[ + WClass("SigMap", link_types.pointer, None, None, None, True) + ] + ), + Source("kernel/yosys",[ + ] + ), + Source("kernel/cost",[]) + ] + +blacklist_methods = ["YOSYS_NAMESPACE::Pass::run_register", "YOSYS_NAMESPACE::Module::Pow", "YOSYS_NAMESPACE::Module::Bu0", "YOSYS_NAMESPACE::CaseRule::optimize"] + +enum_names = ["State","SyncType","ConstFlags"] + +enums = [] #Do not edit + +unowned_functions = [] + +classnames = [] +for source in sources: + for wclass in source.classes: + classnames.append(wclass.name) + +def class_by_name(name): + for source in sources: + for wclass in source.classes: + if wclass.name == name: + return wclass + return None + +def enum_by_name(name): + for e in enums: + if e.name == name: + return e + return None + +def find_closing(text, open_tok, close_tok): + if text.find(open_tok) == -1 or text.find(close_tok) <= text.find(open_tok): + return text.find(close_tok) + return text.find(close_tok) + find_closing(text[text.find(close_tok)+1:], open_tok, close_tok) + 1 + +def unpretty_string(s): + s = s.strip() + while s.find(" ") != -1: + s = s.replace(" "," ") + while s.find("\t") != -1: + s = s.replace("\t"," ") + s = s.replace(" (","(") + return s + +class WEnum: + name = None + namespace = None + values = [] + + def from_string(str_def, namespace, line_number): + str_def = str_def.strip() + if not str.startswith(str_def, "enum "): + return None + if str_def.count(";") != 1: + return None + str_def = str_def[5:] + enum = WEnum() + split = str_def.split(":") + if(len(split) != 2): + return None + enum.name = split[0].strip() + if enum.name not in enum_names: + return None + str_def = split[1] + if str_def.count("{") != str_def.count("}") != 1: + return None + if len(str_def) < str_def.find("}")+2 or str_def[str_def.find("}")+1] != ';': + return None + str_def = str_def.split("{")[-1].split("}")[0] + enum.values = [] + for val in str_def.split(','): + enum.values.append(val.strip().split('=')[0].strip()) + enum.namespace = namespace + return enum + + def gen_boost_py(self): + text = "\n\t\tenum_<" + self.namespace + "::" + self.name + ">(\"" + self.name + "\")\n" + for value in self.values: + text += "\t\t\t.value(\"" + value + "\"," + self.namespace + "::" + value + ")\n" + text += "\t\t\t;\n" + return text + + def __str__(self): + ret = "Enum " + self.namespace + "::" + self.name + "(\n" + for val in self.values: + ret = ret + "\t" + val + "\n" + return ret + ")" + + def __repr__(self): + return __str__(self) + +class WConstructor: + orig_text = None + args = [] + containing_file = None + member_of = None + duplicate = False + protected = False + + def __init__(self, containing_file, class_): + self.orig_text = "Auto generated default constructor" + self.args = [] + self.containing_file = containing_file + self.member_of = class_ + self.protected = False + + def from_string(str_def, containing_file, class_, line_number, protected = False): + if class_ == None: + return None + if str_def.count("delete;") > 0: + return None + con = WConstructor(containing_file, class_) + con.orig_text = str_def + con.args = [] + con.duplicate = False + con.protected = protected + if not str.startswith(str_def, class_.name + "("): + return None + str_def = str_def[len(class_.name)+1:] + found = find_closing(str_def, "(", ")") + if found == -1: + return None + str_def = str_def[0:found].strip() + if len(str_def) == 0: + return con + for arg in split_list(str_def, ","): + parsed = Attribute.from_string(arg.strip(), containing_file, line_number) + if parsed == None: + return None + con.args.append(parsed) + return con + + def gen_decl(self): + if self.duplicate or self.protected: + return "" + text = "\n\t\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file + text += "\n\t\t" + self.member_of.name + "(" + for arg in self.args: + text += arg.gen_listitem() + ", " + if len(self.args) > 0: + text = text[:-2] + text += ");\n" + return text + + def gen_decl_derive(self): + if self.duplicate or self.protected: + return "" + text = "\n\t\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file + text += "\n\t\t" + self.member_of.name + "(" + for arg in self.args: + text += arg.gen_listitem() + ", " + if len(self.args) > 0: + text = text[:-2] + text += ")" + if len(self.args) == 0: + return text + "{}" + text += " : " + text += self.member_of.namespace + "::" + self.member_of.name + "(" + for arg in self.args: + text += arg.gen_call() + ", " + if len(self.args) > 0: + text = text[:-2] + text += "){}\n" + return text + + def gen_decl_wrapperclass(self): + if self.duplicate or self.protected: + return "" + text = "\n\t\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file + text += "\n\t\t" + self.member_of.name + "Wrap(" + for arg in self.args: + text += arg.gen_listitem() + ", " + if len(self.args) > 0: + text = text[:-2] + text += ")" + if len(self.args) == 0: + return text + "{}" + text += " : " + text += self.member_of.name + "(" + for arg in self.args: + text += arg.gen_call() + ", " + if len(self.args) > 0: + text = text[:-2] + text += "){}\n" + return text + + def gen_decl_hash_py(self): + text = self.member_of.name + "(" + for arg in self.args: + text += arg.gen_listitem_hash() + ", " + if len(self.args) > 0: + text = text[:-2] + text += ");" + return text + + def gen_def(self): + if self.duplicate or self.protected: + return "" + text = "\n\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file + text += "\n\t" + self.member_of.name + "::" + self.member_of.name + "(" + for arg in self.args: + text += arg.gen_listitem() + ", " + if len(self.args) > 0: + text = text[:-2] + text +=")\n\t{" + for arg in self.args: + text += arg.gen_translation() + if self.member_of.link_type != link_types.derive: + text += "\n\t\tthis->ref_obj = new " + self.member_of.namespace + "::" + self.member_of.name + "(" + for arg in self.args: + text += arg.gen_call() + ", " + if len(self.args) > 0: + text = text[:-2] + if self.member_of.link_type != link_types.derive: + text += ");" + if self.member_of.link_type == link_types.global_list: + text += "\n\t\tthis->" + self.member_of.id_.varname + " = this->ref_obj->" + self.member_of.id_.varname + ";" + for arg in self.args: + text += arg.gen_cleanup() + text += "\n\t}\n" + return text + + def gen_boost_py(self): + if self.duplicate or self.protected or len(self.args) == 0: + return "" + text = "\n\t\t\t.def(init" + text += "<" + for a in self.args: + text += a.gen_listitem_hash() + ", " + text = text[0:-2] + ">())" + return text + +class WFunction: + orig_text = None + is_static = False + is_inline = False + is_virtual = False + ret_attr_type = attr_types.default + is_operator = False + ret_type = None + name = None + alias = None + args = [] + containing_file = None + member_of = None + duplicate = False + namespace = "" + + def from_string(str_def, containing_file, class_, line_number, namespace): + if str_def.count("delete;") > 0: + return None + func = WFunction() + func.is_static = False + func.is_inline = False + func.is_virtual = False + func.ret_attr_type = attr_types.default + func.is_operator = False + func.member_of = None + func.orig_text = str_def + func.args = [] + func.containing_file = containing_file + func.member_of = class_ + func.duplicate = False + func.namespace = namespace + str_def = str_def.replace("operator ","operator") + if str.startswith(str_def, "static "): + func.is_static = True + str_def = str_def[7:] + else: + func.is_static = False + if str.startswith(str_def, "inline "): + func.is_inline = True + str_def = str_def[7:] + else: + func.is_inline = False + if str.startswith(str_def, "virtual "): + func.is_virtual = True + str_def = str_def[8:] + else: + func.is_virtual = False + + if str_def.count(" ") == 0: + return None + + parts = split_list(str_def.strip(), " ") + + prefix = "" + i = 0 + for part in parts: + if part in ["unsigned", "long", "short"]: + prefix += part + " " + i += 1 + else: + break + parts = parts[i:] + + if len(parts) <= 1: + return None + + func.ret_type = WType.from_string(prefix + parts[0], containing_file, line_number) + + if func.ret_type == None: + return None + + str_def = parts[1] + for part in parts[2:]: + str_def = str_def + " " + part + + found = str_def.find("(") + if found == -1 or (str_def.find(" ") != -1 and found > str_def.find(" ")): + return None + func.name = str_def[:found] + str_def = str_def[found:] + if func.name.find("operator") != -1 and str.startswith(str_def, "()("): + func.name += "()" + str_def = str_def[2:] + str_def = str_def[1:] + if func.name.find("operator") != -1: + func.is_operator = True + if func.name.find("*") == 0: + func.name = func.name.replace("*", "") + func.ret_type.attr_type = attr_types.star + if func.name.find("&&") == 0: + func.name = func.name.replace("&&", "") + func.ret_type.attr_type = attr_types.ampamp + if func.name.find("&") == 0: + func.name = func.name.replace("&", "") + func.ret_type.attr_type = attr_types.amp + + found = find_closing(str_def, "(", ")") + if found == -1: + return None + str_def = str_def[0:found] + if func.name in blacklist_methods: + return None + if func.namespace != None and func.namespace != "": + if (func.namespace + "::" + func.name) in blacklist_methods: + return None + if func.member_of != None: + if (func.namespace + "::" + func.member_of.name + "::" + func.name) in blacklist_methods: + return None + if func.is_operator and func.name.replace(" ","").replace("operator","").split("::")[-1] not in wrappable_operators: + return None + + testname = func.name + if func.is_operator: + testname = testname[:testname.find("operator")] + if testname.count(")") != 0 or testname.count("(") != 0 or testname.count("~") != 0 or testname.count(";") != 0 or testname.count(">") != 0 or testname.count("<") != 0 or testname.count("throw") != 0: + return None + + func.alias = func.name + if func.name in keyword_aliases: + func.alias = keyword_aliases[func.name] + str_def = str_def[:found].strip() + if(len(str_def) == 0): + return func + for arg in split_list(str_def, ","): + if arg.strip() == "...": + continue + parsed = Attribute.from_string(arg.strip(), containing_file, line_number) + if parsed == None: + return None + func.args.append(parsed) + return func + + def gen_alias(self): + self.alias = self.name + for arg in self.args: + self.alias += "__" + arg.wtype.gen_text_cpp().replace("::", "_").replace("<","_").replace(">","_").replace(" ","").replace("*","").replace(",","") + + def gen_decl(self): + if self.duplicate: + return "" + text = "\n\t\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file + text += "\n\t\t" + if self.is_static: + text += "static " + text += self.ret_type.gen_text() + " " + self.alias + "(" + for arg in self.args: + text += arg.gen_listitem() + text += ", " + if len(self.args) > 0: + text = text[:-2] + text += ");\n" + return text + + def gen_decl_virtual(self): + if self.duplicate: + return "" + if not self.is_virtual: + return self.gen_decl() + text = "\n\t\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file + text += "\n\t\tvirtual " + if self.is_static: + text += "static " + text += self.ret_type.gen_text() + " py_" + self.alias + "(" + for arg in self.args: + text += arg.gen_listitem() + text += ", " + if len(self.args) > 0: + text = text[:-2] + text += ")" + if len(self.args) == 0: + text += "{}" + else: + text += "\n\t\t{" + for arg in self.args: + text += "\n\t\t\t(void)" + arg.gen_varname() + ";" + text += "\n\t\t}\n" + text += "\n\t\tvirtual " + if self.is_static: + text += "static " + text += self.ret_type.gen_text() + " " + self.name + "(" + for arg in self.args: + text += arg.gen_listitem_cpp() + text += ", " + if len(self.args) > 0: + text = text[:-2] + text += ") YS_OVERRIDE;\n" + return text + + def gen_decl_hash_py(self): + text = self.ret_type.gen_text() + " " + self.alias + "(" + for arg in self.args: + text += arg.gen_listitem_hash() + ", " + if len(self.args) > 0: + text = text[:-2] + text += ");" + return text + + def gen_def(self): + if self.duplicate: + return "" + text = "\n\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file + text += "\n\t" + self.ret_type.gen_text() + " " + if self.member_of != None: + text += self.member_of.name + "::" + text += self.alias + "(" + for arg in self.args: + text += arg.gen_listitem() + text += ", " + if len(self.args) > 0: + text = text[:-2] + text +=")\n\t{" + for arg in self.args: + text += arg.gen_translation() + text += "\n\t\t" + if self.ret_type.name != "void": + if self.ret_type.name in known_containers: + text += self.ret_type.gen_text_cpp() + else: + text += self.ret_type.gen_text() + if self.ret_type.name in classnames or (self.ret_type.name in known_containers and self.ret_type.attr_type == attr_types.star): + text += "*" + text += " ret_ = " + if self.ret_type.name in classnames: + text += self.ret_type.name + "::get_py_obj(" + if self.member_of == None: + text += "::" + self.namespace + "::" + self.alias + "(" + elif self.is_static: + text += self.member_of.namespace + "::" + self.member_of.name + "::" + self.name + "(" + else: + text += "this->get_cpp_obj()->" + self.name + "(" + for arg in self.args: + text += arg.gen_call() + ", " + if len(self.args) > 0: + text = text[:-2] + if self.ret_type.name in classnames: + text += ")" + text += ");" + for arg in self.args: + text += arg.gen_cleanup() + if self.ret_type.name != "void": + if self.ret_type.name in classnames: + text += "\n\t\treturn *ret_;" + elif self.ret_type.name in known_containers: + text += known_containers[self.ret_type.name].translate_cpp("ret_", self.ret_type.cont.args, "\n\t\t", self.ret_type.attr_type == attr_types.star) + text += "\n\t\treturn ret____tmp;" + else: + text += "\n\t\treturn ret_;" + text += "\n\t}\n" + return text + + def gen_def_virtual(self): + if self.duplicate: + return "" + if not self.is_virtual: + return self.gen_def() + text = "\n\t// WRAPPED from \"" + self.orig_text.replace("\n"," ") + "\" in " + self.containing_file + text += "\n\t" + if self.is_static: + text += "static " + text += self.ret_type.gen_text() + " " + self.member_of.name + "::" + self.name + "(" + for arg in self.args: + text += arg.gen_listitem_cpp() + text += ", " + if len(self.args) > 0: + text = text[:-2] + text += ")\n\t{" + for arg in self.args: + text += arg.gen_translation_cpp() + text += "\n\t\t" + if self.member_of == None: + text += "::" + self.namespace + "::" + self.alias + "(" + elif self.is_static: + text += self.member_of.namespace + "::" + self.member_of.name + "::" + self.name + "(" + else: + text += "py_" + self.alias + "(" + for arg in self.args: + text += arg.gen_call_cpp() + ", " + if len(self.args) > 0: + text = text[:-2] + if self.ret_type.name in classnames: + text += ")" + text += ");" + for arg in self.args: + text += arg.gen_cleanup() + text += "\n\t}\n" + return text + + def gen_default_impl(self): + if self.duplicate: + return "" + if not self.is_virtual: + return "" + text = "\n\n\t\t" + self.ret_type.gen_text() + " py_" + self.alias + "(" + for arg in self.args: + text += arg.gen_listitem() + ", " + if len(self.args) > 0: + text = text[:-2] + + call_string = "py_" + self.alias + "(" + for arg in self.args: + call_string += arg.gen_varname() + ", " + if len(self.args) > 0: + call_string = call_string[0:-2] + call_string += ");" + + text += ")\n\t\t{" + text += "\n\t\t\tif(boost::python::override py_" + self.alias + " = this->get_override(\"py_" + self.alias + "\"))" + text += "\n\t\t\t\t" + call_string + text += "\n\t\t\telse" + text += "\n\t\t\t\t" + self.member_of.name + "::" + call_string + text += "\n\t\t}" + + text += "\n\n\t\t" + self.ret_type.gen_text() + " default_py_" + self.alias + "(" + for arg in self.args: + text += arg.gen_listitem() + ", " + if len(self.args) > 0: + text = text[:-2] + text += ")\n\t\t{" + text += "\n\t\t\tthis->" + self.member_of.name + "::" + call_string + text += "\n\t\t}" + return text + + + def gen_boost_py(self): + if self.duplicate: + return "" + if self.member_of == None: + text = "\n\t\tdef" + else: + text = "\n\t\t\t.def" + if len(self.args) > -1: + if self.ret_type.name in known_containers: + text += "<" + known_containers[self.ret_type.name].typename + " " + else: + text += "<" + self.ret_type.name + " " + if self.member_of == None or self.is_static: + text += "(*)(" + else: + text += "(" + self.member_of.name + "::*)(" + for a in self.args: + text += a.gen_listitem_hash() + ", " + if len(self.args) > 0: + text = text[0:-2] + ")>" + else: + text += "void)>" + + if self.is_operator: + text += "(\"" + wrappable_operators[self.name.replace("operator","")] + "\"" + else: + if self.member_of != None and self.member_of.link_type == link_types.derive and self.is_virtual: + text += "(\"py_" + self.alias + "\"" + else: + text += "(\"" + self.alias + "\"" + if self.member_of != None: + text += ", &" + self.member_of.name + "::" + if self.member_of.link_type == link_types.derive and self.is_virtual: + text += "py_" + self.alias + text += ", &" + self.member_of.name + "Wrap::default_py_" + self.alias + else: + text += self.alias + + text += ")" + else: + text += ", " + "YOSYS_PYTHON::" + self.alias + ");" + return text + +class WMember: + orig_text = None + wtype = attr_types.default + name = None + containing_file = None + member_of = None + namespace = "" + is_const = False + + def from_string(str_def, containing_file, class_, line_number, namespace): + member = WMember() + member.orig_text = str_def + member.wtype = None + member.name = "" + member.containing_file = containing_file + member.member_of = class_ + member.namespace = namespace + member.is_const = False + + if str.startswith(str_def, "const "): + member.is_const = True + str_def = str_def[6:] + + if str_def.count(" ") == 0: + return None + + parts = split_list(str_def.strip(), " ") + + prefix = "" + i = 0 + for part in parts: + if part in ["unsigned", "long", "short"]: + prefix += part + " " + i += 1 + else: + break + parts = parts[i:] + + if len(parts) <= 1: + return None + + member.wtype = WType.from_string(prefix + parts[0], containing_file, line_number) + + if member.wtype == None: + return None + + str_def = parts[1] + for part in parts[2:]: + str_def = str_def + " " + part + + if str_def.find("(") != -1 or str_def.find(")") != -1 or str_def.find("{") != -1 or str_def.find("}") != -1: + return None + + found = str_def.find(";") + if found == -1: + return None + + found_eq = str_def.find("=") + if found_eq != -1: + found = found_eq + + member.name = str_def[:found] + str_def = str_def[found+1:] + if member.name.find("*") == 0: + member.name = member.name.replace("*", "") + member.wtype.attr_type = attr_types.star + if member.name.find("&&") == 0: + member.name = member.name.replace("&&", "") + member.wtype.attr_type = attr_types.ampamp + if member.name.find("&") == 0: + member.name = member.name.replace("&", "") + member.wtype.attr_type = attr_types.amp + + if(len(str_def.strip()) != 0): + return None + + if len(member.name.split(",")) > 1: + member_list = [] + for name in member.name.split(","): + name = name.strip(); + member_list.append(WMember()) + member_list[-1].orig_text = member.orig_text + member_list[-1].wtype = member.wtype + member_list[-1].name = name + member_list[-1].containing_file = member.containing_file + member_list[-1].member_of = member.member_of + member_list[-1].namespace = member.namespace + member_list[-1].is_const = member.is_const + return member_list + + return member + + def gen_decl(self): + text = "\n\t\t" + self.wtype.gen_text() + " get_var_py_" + self.name + "();\n" + if self.is_const: + return text + if self.wtype.name in classnames: + text += "\n\t\tvoid set_var_py_" + self.name + "(" + self.wtype.gen_text() + " *rhs);\n" + else: + text += "\n\t\tvoid set_var_py_" + self.name + "(" + self.wtype.gen_text() + " rhs);\n" + return text + + def gen_def(self): + text = "\n\t" + self.wtype.gen_text() + " " + self.member_of.name +"::get_var_py_" + self.name + "()" + text += "\n\t{\n\t\t" + if self.wtype.attr_type == attr_types.star: + text += "if(this->get_cpp_obj()->" + self.name + " == NULL)\n\t\t\t" + text += "throw std::runtime_error(\"Member \\\"" + self.name + "\\\" is NULL\");\n\t\t" + if self.wtype.name in known_containers: + text += self.wtype.gen_text_cpp() + else: + text += self.wtype.gen_text() + + if self.wtype.name in classnames or (self.wtype.name in known_containers and self.wtype.attr_type == attr_types.star): + text += "*" + text += " ret_ = " + if self.wtype.name in classnames: + text += self.wtype.name + "::get_py_obj(" + if self.wtype.attr_type != attr_types.star: + text += "&" + text += "this->get_cpp_obj()->" + self.name + if self.wtype.name in classnames: + text += ")" + text += ";" + + if self.wtype.name in classnames: + text += "\n\t\treturn *ret_;" + elif self.wtype.name in known_containers: + text += known_containers[self.wtype.name].translate_cpp("ret_", self.wtype.cont.args, "\n\t\t", self.wtype.attr_type == attr_types.star) + text += "\n\t\treturn ret____tmp;" + else: + text += "\n\t\treturn ret_;" + text += "\n\t}\n" + + if self.is_const: + return text + + ret = Attribute(self.wtype, "rhs"); + + if self.wtype.name in classnames: + text += "\n\tvoid " + self.member_of.name+ "::set_var_py_" + self.name + "(" + self.wtype.gen_text() + " *rhs)" + else: + text += "\n\tvoid " + self.member_of.name+ "::set_var_py_" + self.name + "(" + self.wtype.gen_text() + " rhs)" + text += "\n\t{" + text += ret.gen_translation() + text += "\n\t\tthis->get_cpp_obj()->" + self.name + " = " + ret.gen_call() + ";" + text += "\n\t}\n" + + return text; + + def gen_boost_py(self): + text = "\n\t\t\t.add_property(\"" + self.name + "\", &" + self.member_of.name + "::get_var_py_" + self.name + if not self.is_const: + text += ", &" + self.member_of.name + "::set_var_py_" + self.name + text += ")" + return text + +def concat_namespace(tuple_list): + if len(tuple_list) == 0: + return "" + ret = "" + for namespace in tuple_list: + ret += "::" + namespace[0] + return ret[2:] + +def calc_ident(text): + if len(text) == 0 or text[0] != ' ': + return 0 + return calc_ident(text[1:]) + 1 + +def assure_length(text, length, left = False): + if len(text) > length: + return text[:length] + if left: + return text + " "*(length - len(text)) + return " "*(length - len(text)) + text + +def parse_header(source): + debug("Parsing " + source.name + ".pyh",1) + source_file = open(source.name + ".pyh", "r") + + source_text = [] + in_line = source_file.readline() + + namespaces = [] + + while(in_line): + if(len(in_line)>1): + source_text.append(in_line.replace("char *", "char_p ").replace("char* ", "char_p ")) + in_line = source_file.readline() + + i = 0 + + namespaces = [] + class_ = None + private_segment = False + + while i < len(source_text): + line = source_text[i].replace("YOSYS_NAMESPACE_BEGIN", " namespace YOSYS_NAMESPACE{").replace("YOSYS_NAMESPACE_END"," }") + ugly_line = unpretty_string(line) + + if str.startswith(ugly_line, "namespace "):# and ugly_line.find("std") == -1 and ugly_line.find("__") == -1: + namespace_name = ugly_line[10:].replace("{","").strip() + namespaces.append((namespace_name, ugly_line.count("{"))) + debug("-----NAMESPACE " + concat_namespace(namespaces) + "-----",3) + i += 1 + continue + + if len(namespaces) != 0: + namespaces[-1] = (namespaces[-1][0], namespaces[-1][1] + ugly_line.count("{") - ugly_line.count("}")) + if namespaces[-1][1] == 0: + debug("-----END NAMESPACE " + concat_namespace(namespaces) + "-----",3) + del namespaces[-1] + i += 1 + continue + + if class_ == None and (str.startswith(ugly_line, "struct ") or str.startswith(ugly_line, "class")) and ugly_line.count(";") == 0: + + struct_name = ugly_line.split(" ")[1].split("::")[-1] + impl_namespaces = ugly_line.split(" ")[1].split("::")[:-1] + complete_namespace = concat_namespace(namespaces) + for namespace in impl_namespaces: + complete_namespace += "::" + namespace + debug("\tFound " + struct_name + " in " + complete_namespace,2) + class_ = (class_by_name(struct_name), ugly_line.count("{"))#calc_ident(line)) + if struct_name in classnames: + class_[0].namespace = complete_namespace + i += 1 + continue + + if class_ != None: + class_ = (class_[0], class_[1] + ugly_line.count("{") - ugly_line.count("}")) + if class_[1] == 0: + if class_[0] == None: + debug("\tExiting unknown class", 3) + else: + debug("\tExiting class " + class_[0].name, 3) + class_ = None + private_segment = False + i += 1 + continue + + if class_ != None and (line.find("private:") != -1 or line.find("protected:") != -1): + private_segment = True + i += 1 + continue + if class_ != None and line.find("public:") != -1: + private_segment = False + i += 1 + continue + + candidate = None + + if private_segment and class_ != None and class_[0] != None: + candidate = WConstructor.from_string(ugly_line, source.name, class_[0], i, True) + if candidate != None: + debug("\t\tFound constructor of class \"" + class_[0].name + "\" in namespace " + concat_namespace(namespaces),2) + class_[0].found_constrs.append(candidate) + i += 1 + continue + + if not private_segment and (class_ == None or class_[0] != None): + if class_ != None: + candidate = WFunction.from_string(ugly_line, source.name, class_[0], i, concat_namespace(namespaces)) + else: + candidate = WFunction.from_string(ugly_line, source.name, None, i, concat_namespace(namespaces)) + if candidate != None and candidate.name.find("::") == -1: + if class_ == None: + debug("\tFound unowned function \"" + candidate.name + "\" in namespace " + concat_namespace(namespaces),2) + unowned_functions.append(candidate) + else: + debug("\t\tFound function \"" + candidate.name + "\" of class \"" + class_[0].name + "\" in namespace " + concat_namespace(namespaces),2) + class_[0].found_funs.append(candidate) + else: + candidate = WEnum.from_string(ugly_line, concat_namespace(namespaces), i) + if candidate != None: + enums.append(candidate) + debug("\tFound enum \"" + candidate.name + "\" in namespace " + concat_namespace(namespaces),2) + elif class_ != None and class_[1] == 1: + candidate = WConstructor.from_string(ugly_line, source.name, class_[0], i) + if candidate != None: + debug("\t\tFound constructor of class \"" + class_[0].name + "\" in namespace " + concat_namespace(namespaces),2) + class_[0].found_constrs.append(candidate) + else: + candidate = WMember.from_string(ugly_line, source.name, class_[0], i, concat_namespace(namespaces)) + if candidate != None: + if type(candidate) == list: + for c in candidate: + debug("\t\tFound member \"" + c.name + "\" of class \"" + class_[0].name + "\" of type \"" + c.wtype.name + "\"", 2) + class_[0].found_vars.extend(candidate) + else: + debug("\t\tFound member \"" + candidate.name + "\" of class \"" + class_[0].name + "\" of type \"" + candidate.wtype.name + "\"", 2) + class_[0].found_vars.append(candidate) + + j = i + line = unpretty_string(line) + while candidate == None and j+1 < len(source_text) and line.count(';') <= 1 and line.count("(") >= line.count(")"): + j += 1 + line = line + "\n" + unpretty_string(source_text[j]) + if class_ != None: + candidate = WFunction.from_string(ugly_line, source.name, class_[0], i, concat_namespace(namespaces)) + else: + candidate = WFunction.from_string(ugly_line, source.name, None, i, concat_namespace(namespaces)) + if candidate != None and candidate.name.find("::") == -1: + if class_ == None: + debug("\tFound unowned function \"" + candidate.name + "\" in namespace " + concat_namespace(namespaces),2) + unowned_functions.append(candidate) + else: + debug("\t\tFound function \"" + candidate.name + "\" of class \"" + class_[0].name + "\" in namespace " + concat_namespace(namespaces),2) + class_[0].found_funs.append(candidate) + continue + candidate = WEnum.from_string(line, concat_namespace(namespaces), i) + if candidate != None: + enums.append(candidate) + debug("\tFound enum \"" + candidate.name + "\" in namespace " + concat_namespace(namespaces),2) + continue + if class_ != None: + candidate = WConstructor.from_string(line, source.name, class_[0], i) + if candidate != None: + debug("\t\tFound constructor of class \"" + class_[0].name + "\" in namespace " + concat_namespace(namespaces),2) + class_[0].found_constrs.append(candidate) + continue + if candidate != None: + while i < j: + i += 1 + line = source_text[i].replace("YOSYS_NAMESPACE_BEGIN", " namespace YOSYS_NAMESPACE{").replace("YOSYS_NAMESPACE_END"," }") + ugly_line = unpretty_string(line) + if len(namespaces) != 0: + namespaces[-1] = (namespaces[-1][0], namespaces[-1][1] + ugly_line.count("{") - ugly_line.count("}")) + if namespaces[-1][1] == 0: + debug("-----END NAMESPACE " + concat_namespace(namespaces) + "-----",3) + del namespaces[-1] + if class_ != None: + class_ = (class_[0] , class_[1] + ugly_line.count("{") - ugly_line.count("}")) + if class_[1] == 0: + if class_[0] == None: + debug("\tExiting unknown class", 3) + else: + debug("\tExiting class " + class_[0].name, 3) + class_ = None + private_segment = False + i += 1 + else: + i += 1 + +def debug(message, level): + if level <= debug.debug_level: + print(message) + +def expand_function(f): + fun_list = [] + arg_list = [] + for arg in f.args: + if arg.default_value != None and (arg.wtype.name.split(" ")[-1] in primitive_types or arg.wtype.name in enum_names or (arg.wtype.name in classnames and arg.default_value == "nullptr")): + fi = copy.deepcopy(f) + fi.args = copy.deepcopy(arg_list) + fun_list.append(fi) + arg_list.append(arg) + fun_list.append(f) + return fun_list + +def expand_functions(): + global unowned_functions + new_funs = [] + for fun in unowned_functions: + new_funs.extend(expand_function(fun)) + unowned_functions = new_funs + for source in sources: + for class_ in source.classes: + new_funs = [] + for fun in class_.found_funs: + new_funs.extend(expand_function(fun)) + class_.found_funs = new_funs + +def clean_duplicates(): + for source in sources: + for class_ in source.classes: + known_decls = {} + for fun in class_.found_funs: + if fun.gen_decl_hash_py() in known_decls: + debug("Multiple declarations of " + fun.gen_decl_hash_py(),3) + other = known_decls[fun.gen_decl_hash_py()] + other.gen_alias() + fun.gen_alias() + if fun.gen_decl_hash_py() == other.gen_decl_hash_py(): + fun.duplicate = True + debug("Disabled \"" + fun.gen_decl_hash_py() + "\"", 3) + else: + known_decls[fun.gen_decl_hash_py()] = fun + known_decls = [] + for con in class_.found_constrs: + if con.gen_decl_hash_py() in known_decls: + debug("Multiple declarations of " + con.gen_decl_hash_py(),3) + con.duplicate = True + else: + known_decls.append(con.gen_decl_hash_py()) + known_decls = [] + for fun in unowned_functions: + if fun.gen_decl_hash_py() in known_decls: + debug("Multiple declarations of " + fun.gen_decl_hash_py(),3) + fun.duplicate = True + else: + known_decls.append(fun.gen_decl_hash_py()) + +def gen_wrappers(filename, debug_level_ = 0): + debug.debug_level = debug_level_ + for source in sources: + parse_header(source) + + expand_functions() + clean_duplicates() + + import shutil + import math + col = shutil.get_terminal_size((80,20)).columns + debug("-"*col, 1) + debug("-"*math.floor((col-7)/2)+"SUMMARY"+"-"*math.ceil((col-7)/2), 1) + debug("-"*col, 1) + for source in sources: + for class_ in source.classes: + debug("Class " + assure_length(class_.name, len(max(classnames, key=len)), True) + " contains " + assure_length(str(len(class_.found_vars)), 3, False) + " member variables, "+ assure_length(str(len(class_.found_funs)), 3, False) + " methods and " + assure_length(str(len(class_.found_constrs)), 2, False) + " constructors", 1) + if len(class_.found_constrs) == 0: + class_.found_constrs.append(WConstructor(source.name, class_)) + debug(str(len(unowned_functions)) + " functions are unowned", 1) + for enum in enums: + debug("Enum " + assure_length(enum.name, len(max(enum_names, key=len)), True) + " contains " + assure_length(str(len(enum.values)), 2, False) + " values", 1) + debug("-"*col, 1) + wrapper_file = open(filename, "w+") + wrapper_file.write( +"""/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * + * 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. + * + * This is a generated file and can be overwritten by make + */ + +#ifdef WITH_PYTHON +""") + for source in sources: + wrapper_file.write("#include \""+source.name+".h\"\n") + wrapper_file.write(""" +#include <boost/python/module.hpp> +#include <boost/python/class.hpp> +#include <boost/python/wrapper.hpp> +#include <boost/python/call.hpp> +#include <boost/python.hpp> + +USING_YOSYS_NAMESPACE + +namespace YOSYS_PYTHON { +""") + + for source in sources: + for wclass in source.classes: + wrapper_file.write("\n\tstruct " + wclass.name + ";") + + wrapper_file.write("\n") + + for source in sources: + for wclass in source.classes: + wrapper_file.write(wclass.gen_decl(source.name)) + + wrapper_file.write("\n") + + for source in sources: + for wclass in source.classes: + wrapper_file.write(wclass.gen_funs(source.name)) + + for fun in unowned_functions: + wrapper_file.write(fun.gen_def()) + + wrapper_file.write(""" struct Initializer + { + Initializer() { + if(!Yosys::yosys_already_setup()) + { + Yosys::log_streams.push_back(&std::cout); + Yosys::log_error_stderr = true; + Yosys::yosys_setup(); + } + } + + Initializer(Initializer const &) {} + + ~Initializer() { + Yosys::yosys_shutdown(); + } + }; + + BOOST_PYTHON_MODULE(libyosys) + { + using namespace boost::python; + + class_<Initializer>("Initializer"); + scope().attr("_hidden") = new Initializer(); +""") + + for enum in enums: + wrapper_file.write(enum.gen_boost_py()) + + for source in sources: + for wclass in source.classes: + wrapper_file.write(wclass.gen_boost_py()) + + for fun in unowned_functions: + wrapper_file.write(fun.gen_boost_py()) + + wrapper_file.write("\n\t}\n}\n#endif") + +def print_includes(): + for source in sources: + print(source.name + ".pyh") diff --git a/misc/yosys.proto b/misc/yosys.proto index 2870176cb..a583e6265 100644 --- a/misc/yosys.proto +++ b/misc/yosys.proto @@ -1,12 +1,12 @@ // // yosys -- Yosys Open SYnthesis Suite -// +// // Copyright (C) 2018 Serge Bazanski <q3k@symbioticeda.com> -// +// // 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 @@ -73,7 +73,7 @@ message Module { BitVector bits = 2; } map<string, Port> port = 2; - + // Named cells in this module. message Cell { // Set to true when the name of this cell is automatically created and @@ -129,7 +129,7 @@ message Model { TYPE_FALSE = 6; }; Type type = 1; - + message Port { // Name of port. string portname = 1; @@ -148,7 +148,7 @@ message Model { // Set for AND, NAND. Gate gate = 3; } - + // Set when the node drives given output port(s). message OutPort { // Name of port. diff --git a/passes/cmds/Makefile.inc b/passes/cmds/Makefile.inc index 44a83b2b9..cf9663d1d 100644 --- a/passes/cmds/Makefile.inc +++ b/passes/cmds/Makefile.inc @@ -25,8 +25,9 @@ OBJS += passes/cmds/plugin.o OBJS += passes/cmds/check.o OBJS += passes/cmds/qwp.o OBJS += passes/cmds/edgetypes.o +OBJS += passes/cmds/portlist.o OBJS += passes/cmds/chformal.o OBJS += passes/cmds/chtype.o OBJS += passes/cmds/blackbox.o OBJS += passes/cmds/ltp.o - +OBJS += passes/cmds/bugpoint.o diff --git a/passes/cmds/add.cc b/passes/cmds/add.cc index e698926f9..dd05ac81f 100644 --- a/passes/cmds/add.cc +++ b/passes/cmds/add.cc @@ -71,7 +71,7 @@ static void add_wire(RTLIL::Design *design, RTLIL::Module *module, std::string n RTLIL::Module *mod = design->modules_.at(it.second->type); if (!design->selected_whole_module(mod->name)) continue; - if (mod->get_bool_attribute("\\blackbox")) + if (mod->get_blackbox_attribute()) continue; if (it.second->hasPort(name)) continue; @@ -83,7 +83,7 @@ static void add_wire(RTLIL::Design *design, RTLIL::Module *module, std::string n struct AddPass : public Pass { AddPass() : Pass("add", "add objects to the design") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -105,14 +105,20 @@ struct AddPass : public Pass { log("Like 'add -input', but also connect the signal between instances of the\n"); log("selected modules.\n"); log("\n"); + log("\n"); + log(" add -mod <name[s]>\n"); + log("\n"); + log("Add module[s] with the specified name[s].\n"); + log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { std::string command; std::string arg_name; bool arg_flag_input = false; bool arg_flag_output = false; bool arg_flag_global = false; + bool mod_mode = false; int arg_width = 0; size_t argidx; @@ -133,8 +139,20 @@ struct AddPass : public Pass { arg_width = atoi(args[++argidx].c_str()); continue; } + if (arg == "-mod") { + mod_mode = true; + argidx++; + break; + } break; } + + if (mod_mode) { + for (; argidx < args.size(); argidx++) + design->addModule(RTLIL::escape_id(args[argidx])); + return; + } + extra_args(args, argidx, design); for (auto &mod : design->modules_) diff --git a/passes/cmds/blackbox.cc b/passes/cmds/blackbox.cc index 497b35f5c..d09ed872e 100644 --- a/passes/cmds/blackbox.cc +++ b/passes/cmds/blackbox.cc @@ -23,8 +23,8 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN struct BlackboxPass : public Pass { - BlackboxPass() : Pass("blackbox", "change type of cells in the design") { } - virtual void help() + BlackboxPass() : Pass("blackbox", "convert modules into blackbox modules") { } + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -34,7 +34,7 @@ struct BlackboxPass : public Pass { log("module attribute).\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) diff --git a/passes/cmds/bugpoint.cc b/passes/cmds/bugpoint.cc new file mode 100644 index 000000000..5a47988ec --- /dev/null +++ b/passes/cmds/bugpoint.cc @@ -0,0 +1,443 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2018 whitequark <whitequark@whitequark.org> + * + * 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 "backends/ilang/ilang_backend.h" + +USING_YOSYS_NAMESPACE +using namespace ILANG_BACKEND; +PRIVATE_NAMESPACE_BEGIN + +struct BugpointPass : public Pass { + BugpointPass() : Pass("bugpoint", "minimize testcases") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" bugpoint [options]\n"); + log("\n"); + log("This command minimizes testcases that crash Yosys. It removes an arbitrary part\n"); + log("of the design and recursively invokes Yosys with a given script, repeating these\n"); + log("steps while it can find a smaller design that still causes a crash. Once this\n"); + log("command finishes, it replaces the current design with the smallest testcase it\n"); + log("was able to produce.\n"); + log("\n"); + log("It is possible to specify the kinds of design part that will be removed. If none\n"); + log("are specified, all parts of design will be removed.\n"); + log("\n"); + log(" -yosys <filename>\n"); + log(" use this Yosys binary. if not specified, `yosys` is used.\n"); + log("\n"); + log(" -script <filename>\n"); + log(" use this script to crash Yosys. required.\n"); + log("\n"); + log(" -grep <string>\n"); + log(" only consider crashes that place this string in the log file.\n"); + log("\n"); + log(" -fast\n"); + log(" run `proc_clean; clean -purge` after each minimization step. converges\n"); + log(" faster, but produces larger testcases, and may fail to produce any\n"); + log(" testcase at all if the crash is related to dangling wires.\n"); + log("\n"); + log(" -clean\n"); + log(" run `proc_clean; clean -purge` before checking testcase and after\n"); + log(" finishing. produces smaller and more useful testcases, but may fail to\n"); + log(" produce any testcase at all if the crash is related to dangling wires.\n"); + log("\n"); + log(" -modules\n"); + log(" try to remove modules.\n"); + log("\n"); + log(" -ports\n"); + log(" try to remove module ports.\n"); + log("\n"); + log(" -cells\n"); + log(" try to remove cells.\n"); + log("\n"); + log(" -connections\n"); + log(" try to reconnect ports to 'x.\n"); + log("\n"); + log(" -assigns\n"); + log(" try to remove process assigns from cases.\n"); + log("\n"); + log(" -updates\n"); + log(" try to remove process updates from syncs.\n"); + log("\n"); + } + + bool run_yosys(RTLIL::Design *design, string yosys_cmd, string script) + { + design->sort(); + + std::ofstream f("bugpoint-case.il"); + ILANG_BACKEND::dump_design(f, design, /*only_selected=*/false, /*flag_m=*/true, /*flag_n=*/false); + f.close(); + + string yosys_cmdline = stringf("%s -qq -L bugpoint-case.log -s %s bugpoint-case.il", yosys_cmd.c_str(), script.c_str()); + return run_command(yosys_cmdline) == 0; + } + + bool check_logfile(string grep) + { + if (grep.empty()) + return true; + + std::ifstream f("bugpoint-case.log"); + while (!f.eof()) + { + string line; + getline(f, line); + if (line.find(grep) != std::string::npos) + return true; + } + return false; + } + + RTLIL::Design *clean_design(RTLIL::Design *design, bool do_clean = true, bool do_delete = false) + { + if (!do_clean) + return design; + + RTLIL::Design *design_copy = new RTLIL::Design; + for (auto &it : design->modules_) + design_copy->add(it.second->clone()); + Pass::call(design_copy, "proc_clean -quiet"); + Pass::call(design_copy, "clean -purge"); + + if (do_delete) + delete design; + return design_copy; + } + + RTLIL::Design *simplify_something(RTLIL::Design *design, int &seed, bool stage2, bool modules, bool ports, bool cells, bool connections, bool assigns, bool updates) + { + RTLIL::Design *design_copy = new RTLIL::Design; + for (auto &it : design->modules_) + design_copy->add(it.second->clone()); + + int index = 0; + if (modules) + { + for (auto &it : design_copy->modules_) + { + if (it.second->get_blackbox_attribute()) + continue; + + if (index++ == seed) + { + log("Trying to remove module %s.\n", it.first.c_str()); + design_copy->remove(it.second); + return design_copy; + } + } + } + if (ports) + { + for (auto mod : design_copy->modules()) + { + if (mod->get_blackbox_attribute()) + continue; + + for (auto wire : mod->wires()) + { + if (!stage2 && wire->get_bool_attribute("$bugpoint")) + continue; + + if (wire->port_input || wire->port_output) + { + if (index++ == seed) + { + log("Trying to remove module port %s.\n", log_signal(wire)); + wire->port_input = wire->port_output = false; + mod->fixup_ports(); + return design_copy; + } + } + } + } + } + if (cells) + { + for (auto mod : design_copy->modules()) + { + if (mod->get_blackbox_attribute()) + continue; + + for (auto &it : mod->cells_) + { + if (index++ == seed) + { + log("Trying to remove cell %s.%s.\n", mod->name.c_str(), it.first.c_str()); + mod->remove(it.second); + return design_copy; + } + } + } + } + if (connections) + { + for (auto mod : design_copy->modules()) + { + if (mod->get_blackbox_attribute()) + continue; + + for (auto cell : mod->cells()) + { + for (auto it : cell->connections_) + { + RTLIL::SigSpec port = cell->getPort(it.first); + bool is_undef = port.is_fully_undef(); + bool is_port = port.is_wire() && (port.as_wire()->port_input || port.as_wire()->port_output); + + if(is_undef || (!stage2 && is_port)) + continue; + + if (index++ == seed) + { + log("Trying to remove cell port %s.%s.%s.\n", mod->name.c_str(), cell->name.c_str(), it.first.c_str()); + RTLIL::SigSpec port_x(State::Sx, port.size()); + cell->unsetPort(it.first); + cell->setPort(it.first, port_x); + return design_copy; + } + + if (!stage2 && (cell->input(it.first) || cell->output(it.first)) && index++ == seed) + { + log("Trying to expose cell port %s.%s.%s as module port.\n", mod->name.c_str(), cell->name.c_str(), it.first.c_str()); + RTLIL::Wire *wire = mod->addWire(NEW_ID, port.size()); + wire->set_bool_attribute("$bugpoint"); + wire->port_input = cell->input(it.first); + wire->port_output = cell->output(it.first); + cell->unsetPort(it.first); + cell->setPort(it.first, wire); + mod->fixup_ports(); + return design_copy; + } + } + } + } + } + if (assigns) + { + for (auto mod : design_copy->modules()) + { + if (mod->get_blackbox_attribute()) + continue; + + for (auto &pr : mod->processes) + { + vector<RTLIL::CaseRule*> cases = {&pr.second->root_case}; + while (!cases.empty()) + { + RTLIL::CaseRule *cs = cases[0]; + cases.erase(cases.begin()); + for (auto it = cs->actions.begin(); it != cs->actions.end(); ++it) + { + if (index++ == seed) + { + log("Trying to remove assign %s %s in %s.%s.\n", log_signal((*it).first), log_signal((*it).second), mod->name.c_str(), pr.first.c_str()); + cs->actions.erase(it); + return design_copy; + } + } + for (auto &sw : cs->switches) + cases.insert(cases.end(), sw->cases.begin(), sw->cases.end()); + } + } + } + } + if (updates) + { + for (auto mod : design_copy->modules()) + { + if (mod->get_blackbox_attribute()) + continue; + + for (auto &pr : mod->processes) + { + for (auto &sy : pr.second->syncs) + { + for (auto it = sy->actions.begin(); it != sy->actions.end(); ++it) + { + if (index++ == seed) + { + log("Trying to remove sync %s update %s %s in %s.%s.\n", log_signal(sy->signal), log_signal((*it).first), log_signal((*it).second), mod->name.c_str(), pr.first.c_str()); + sy->actions.erase(it); + return design_copy; + } + } + } + } + } + } + return NULL; + } + + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + string yosys_cmd = "yosys", script, grep; + bool fast = false, clean = false; + bool modules = false, ports = false, cells = false, connections = false, assigns = false, updates = false, has_part = false; + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + if (args[argidx] == "-yosys" && argidx + 1 < args.size()) { + yosys_cmd = args[++argidx]; + continue; + } + if (args[argidx] == "-script" && argidx + 1 < args.size()) { + script = args[++argidx]; + continue; + } + if (args[argidx] == "-grep" && argidx + 1 < args.size()) { + grep = args[++argidx]; + continue; + } + if (args[argidx] == "-fast") { + fast = true; + continue; + } + if (args[argidx] == "-clean") { + clean = true; + continue; + } + if (args[argidx] == "-modules") { + modules = true; + has_part = true; + continue; + } + if (args[argidx] == "-ports") { + ports = true; + has_part = true; + continue; + } + if (args[argidx] == "-cells") { + cells = true; + has_part = true; + continue; + } + if (args[argidx] == "-connections") { + connections = true; + has_part = true; + continue; + } + if (args[argidx] == "-assigns") { + assigns = true; + has_part = true; + continue; + } + if (args[argidx] == "-updates") { + updates = true; + has_part = true; + continue; + } + break; + } + extra_args(args, argidx, design); + + if (script.empty()) + log_cmd_error("Missing -script option.\n"); + + if (!has_part) + { + modules = true; + ports = true; + cells = true; + connections = true; + assigns = true; + updates = true; + } + + if (!design->full_selection()) + log_cmd_error("This command only operates on fully selected designs!\n"); + + RTLIL::Design *crashing_design = clean_design(design, clean); + if (run_yosys(crashing_design, yosys_cmd, script)) + log_cmd_error("The provided script file and Yosys binary do not crash on this design!\n"); + if (!check_logfile(grep)) + log_cmd_error("The provided grep string is not found in the log file!\n"); + + int seed = 0; + bool found_something = false, stage2 = false; + while (true) + { + if (RTLIL::Design *simplified = simplify_something(crashing_design, seed, stage2, modules, ports, cells, connections, assigns, updates)) + { + simplified = clean_design(simplified, fast, /*do_delete=*/true); + + bool crashes; + if (clean) + { + RTLIL::Design *testcase = clean_design(simplified); + crashes = !run_yosys(testcase, yosys_cmd, script); + delete testcase; + } + else + { + crashes = !run_yosys(simplified, yosys_cmd, script); + } + + if (crashes && check_logfile(grep)) + { + log("Testcase crashes.\n"); + if (crashing_design != design) + delete crashing_design; + crashing_design = simplified; + found_something = true; + } + else + { + log("Testcase does not crash.\n"); + delete simplified; + seed++; + } + } + else + { + seed = 0; + if (found_something) + found_something = false; + else + { + if (!stage2) + { + log("Demoting introduced module ports.\n"); + stage2 = true; + } + else + { + log("Simplifications exhausted.\n"); + break; + } + } + } + } + + if (crashing_design != design) + { + Pass::call(design, "design -reset"); + crashing_design = clean_design(crashing_design, clean, /*do_delete=*/true); + for (auto &it : crashing_design->modules_) + design->add(it.second->clone()); + delete crashing_design; + } + } +} BugpointPass; + +PRIVATE_NAMESPACE_END diff --git a/passes/cmds/check.cc b/passes/cmds/check.cc index bb8fe6856..64697c134 100644 --- a/passes/cmds/check.cc +++ b/passes/cmds/check.cc @@ -27,7 +27,7 @@ PRIVATE_NAMESPACE_BEGIN struct CheckPass : public Pass { CheckPass() : Pass("check", "check for obvious problems in the design") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -51,7 +51,7 @@ struct CheckPass : public Pass { log("problems are found in the current design.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { int counter = 0; bool noinit = false; diff --git a/passes/cmds/chformal.cc b/passes/cmds/chformal.cc index a8c1fef85..7e32da65f 100644 --- a/passes/cmds/chformal.cc +++ b/passes/cmds/chformal.cc @@ -25,14 +25,14 @@ PRIVATE_NAMESPACE_BEGIN struct ChformalPass : public Pass { ChformalPass() : Pass("chformal", "change formal constraints of the design") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); log(" chformal [types] [mode] [options] [selection]\n"); log("\n"); log("Make changes to the formal constraints of the design. The [types] options\n"); - log("the type of constraint to operate on. If none of the folling options is given,\n"); + log("the type of constraint to operate on. If none of the following options are given,\n"); log("the command will operate on all constraint types:\n"); log("\n"); log(" -assert $assert cells, representing assert(...) constraints\n"); @@ -59,10 +59,10 @@ struct ChformalPass : public Pass { log(" -assume2assert\n"); log(" -live2fair\n"); log(" -fair2live\n"); - log(" change the roles of cells as indicated. this options can be combined\n"); + log(" change the roles of cells as indicated. these options can be combined\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { bool assert2assume = false; bool assume2assert = false; diff --git a/passes/cmds/chtype.cc b/passes/cmds/chtype.cc index 90d51667c..979aeadd4 100644 --- a/passes/cmds/chtype.cc +++ b/passes/cmds/chtype.cc @@ -24,7 +24,7 @@ PRIVATE_NAMESPACE_BEGIN struct ChtypePass : public Pass { ChtypePass() : Pass("chtype", "change type of cells in the design") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -40,7 +40,7 @@ struct ChtypePass : public Pass { log("\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { IdString set_type; dict<IdString, IdString> map_types; diff --git a/passes/cmds/connect.cc b/passes/cmds/connect.cc index 52611cf44..f93bada27 100644 --- a/passes/cmds/connect.cc +++ b/passes/cmds/connect.cc @@ -43,7 +43,7 @@ static void unset_drivers(RTLIL::Design *design, RTLIL::Module *module, SigMap & struct ConnectPass : public Pass { ConnectPass() : Pass("connect", "create or remove connections") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -75,7 +75,7 @@ struct ConnectPass : public Pass { log("This command does not operate on module with processes.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { RTLIL::Module *module = NULL; for (auto &it : design->modules_) { @@ -137,7 +137,7 @@ struct ConnectPass : public Pass { if (!set_lhs.empty()) { if (!unset_expr.empty() || !port_cell.empty()) - log_cmd_error("Cant use -set together with -unset and/or -port.\n"); + log_cmd_error("Can't use -set together with -unset and/or -port.\n"); RTLIL::SigSpec sig_lhs, sig_rhs; if (!RTLIL::SigSpec::parse_sel(sig_lhs, design, module, set_lhs)) @@ -157,7 +157,7 @@ struct ConnectPass : public Pass { if (!unset_expr.empty()) { if (!port_cell.empty() || flag_nounset) - log_cmd_error("Cant use -unset together with -port and/or -nounset.\n"); + log_cmd_error("Can't use -unset together with -port and/or -nounset.\n"); RTLIL::SigSpec sig; if (!RTLIL::SigSpec::parse_sel(sig, design, module, unset_expr)) @@ -170,7 +170,7 @@ struct ConnectPass : public Pass { if (!port_cell.empty()) { if (flag_nounset) - log_cmd_error("Cant use -port together with -nounset.\n"); + log_cmd_error("Can't use -port together with -nounset.\n"); if (module->cells_.count(RTLIL::escape_id(port_cell)) == 0) log_cmd_error("Can't find cell %s.\n", port_cell.c_str()); diff --git a/passes/cmds/connwrappers.cc b/passes/cmds/connwrappers.cc index 1ea48b7eb..5a15cbbaf 100644 --- a/passes/cmds/connwrappers.cc +++ b/passes/cmds/connwrappers.cc @@ -150,7 +150,7 @@ struct ConnwrappersWorker struct ConnwrappersPass : public Pass { ConnwrappersPass() : Pass("connwrappers", "match width of input-output port pairs") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -172,7 +172,7 @@ struct ConnwrappersPass : public Pass { log("The options -signed, -unsigned, and -port can be specified multiple times.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { ConnwrappersWorker worker; diff --git a/passes/cmds/copy.cc b/passes/cmds/copy.cc index fb863512b..acd2dba52 100644 --- a/passes/cmds/copy.cc +++ b/passes/cmds/copy.cc @@ -26,7 +26,7 @@ PRIVATE_NAMESPACE_BEGIN struct CopyPass : public Pass { CopyPass() : Pass("copy", "copy modules in the design") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -36,7 +36,7 @@ struct CopyPass : public Pass { log("by this command.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { if (args.size() != 3) log_cmd_error("Invalid number of arguments!\n"); diff --git a/passes/cmds/cover.cc b/passes/cmds/cover.cc index ef4f3f7d0..628ac4c5e 100644 --- a/passes/cmds/cover.cc +++ b/passes/cmds/cover.cc @@ -35,7 +35,7 @@ PRIVATE_NAMESPACE_BEGIN struct CoverPass : public Pass { CoverPass() : Pass("cover", "print code coverage counters") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -83,7 +83,7 @@ struct CoverPass : public Pass { log("Coverage counters are only available in Yosys for Linux.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { std::vector<FILE*> out_files; std::vector<std::string> patterns; @@ -98,28 +98,30 @@ struct CoverPass : public Pass { } if ((args[argidx] == "-o" || args[argidx] == "-a" || args[argidx] == "-d") && argidx+1 < args.size()) { const char *open_mode = args[argidx] == "-a" ? "a+" : "w"; - std::string filename = args[++argidx]; + const std::string &filename = args[++argidx]; + FILE *f = nullptr; if (args[argidx-1] == "-d") { #ifdef _WIN32 log_cmd_error("The 'cover -d' option is not supported on win32.\n"); #else char filename_buffer[4096]; snprintf(filename_buffer, 4096, "%s/yosys_cover_%d_XXXXXX.txt", filename.c_str(), getpid()); - filename = mkstemps(filename_buffer, 4); + f = fdopen(mkstemps(filename_buffer, 4), "w"); #endif + } else { + f = fopen(filename.c_str(), open_mode); } - FILE *f = fopen(filename.c_str(), open_mode); if (f == NULL) { for (auto f : out_files) fclose(f); - log_cmd_error("Can't create file %s.\n", args[argidx].c_str()); + log_cmd_error("Can't create file %s%s.\n", args[argidx-1] == "-d" ? "in directory " : "", args[argidx].c_str()); } out_files.push_back(f); continue; } break; } - while (argidx < args.size() && args[argidx].substr(0, 1) != "-") + while (argidx < args.size() && args[argidx].compare(0, 1, "-") != 0) patterns.push_back(args[argidx++]); extra_args(args, argidx, design); diff --git a/passes/cmds/delete.cc b/passes/cmds/delete.cc index 6d51d30e7..5822c09f8 100644 --- a/passes/cmds/delete.cc +++ b/passes/cmds/delete.cc @@ -24,7 +24,7 @@ PRIVATE_NAMESPACE_BEGIN struct DeletePass : public Pass { DeletePass() : Pass("delete", "delete objects in the design") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -40,7 +40,7 @@ struct DeletePass : public Pass { log("selected wires, thus 'deleting' module ports.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { bool flag_input = false; bool flag_output = false; @@ -107,7 +107,7 @@ struct DeletePass : public Pass { for (auto &it : module->cells_) { if (design->selected(module, it.second)) delete_cells.insert(it.second); - if ((it.second->type == "$memrd" || it.second->type == "$memwr") && + if (it.second->type.in("$memrd", "$memwr") && delete_mems.count(it.second->parameters.at("\\MEMID").decode_string()) != 0) delete_cells.insert(it.second); } diff --git a/passes/cmds/design.cc b/passes/cmds/design.cc index 490c8dde5..172addcc1 100644 --- a/passes/cmds/design.cc +++ b/passes/cmds/design.cc @@ -27,7 +27,7 @@ std::vector<RTLIL::Design*> pushed_designs; struct DesignPass : public Pass { DesignPass() : Pass("design", "save, restore and reset current design") { } - virtual ~DesignPass() { + ~DesignPass() YS_OVERRIDE { for (auto &it : saved_designs) delete it.second; saved_designs.clear(); @@ -35,7 +35,7 @@ struct DesignPass : public Pass { delete it; pushed_designs.clear(); } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -94,7 +94,7 @@ struct DesignPass : public Pass { log("between calls to 'read_verilog'. This command resets this memory.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { bool got_mode = false; bool reset_mode = false; diff --git a/passes/cmds/edgetypes.cc b/passes/cmds/edgetypes.cc index 7b75a009f..58ed6457d 100644 --- a/passes/cmds/edgetypes.cc +++ b/passes/cmds/edgetypes.cc @@ -25,7 +25,7 @@ PRIVATE_NAMESPACE_BEGIN struct EdgetypePass : public Pass { EdgetypePass() : Pass("edgetypes", "list all types of edges in selection") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -35,7 +35,7 @@ struct EdgetypePass : public Pass { log("is a 4-tuple of source and sink cell type and port name.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { diff --git a/passes/cmds/logcmd.cc b/passes/cmds/logcmd.cc index 85386f3d2..522e1089d 100644 --- a/passes/cmds/logcmd.cc +++ b/passes/cmds/logcmd.cc @@ -27,7 +27,7 @@ PRIVATE_NAMESPACE_BEGIN struct LogPass : public Pass { LogPass() : Pass("log", "print text and log files") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -52,7 +52,7 @@ struct LogPass : public Pass { log(" do not append a newline\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design*) + void execute(std::vector<std::string> args, RTLIL::Design*) YS_OVERRIDE { size_t argidx; bool to_stdout = false; diff --git a/passes/cmds/ltp.cc b/passes/cmds/ltp.cc index 42dc794ec..05701710b 100644 --- a/passes/cmds/ltp.cc +++ b/passes/cmds/ltp.cc @@ -141,7 +141,7 @@ struct LtpWorker struct LtpPass : public Pass { LtpPass() : Pass("ltp", "print longest topological path") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -154,7 +154,7 @@ struct LtpPass : public Pass { log(" automatically exclude FF cell types\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { bool noff = false; diff --git a/passes/cmds/plugin.cc b/passes/cmds/plugin.cc index 828c671de..4c16b56c4 100644 --- a/passes/cmds/plugin.cc +++ b/passes/cmds/plugin.cc @@ -23,9 +23,18 @@ # include <dlfcn.h> #endif +#ifdef WITH_PYTHON +# include <boost/algorithm/string/predicate.hpp> +# include <Python.h> +# include <boost/filesystem.hpp> +#endif + YOSYS_NAMESPACE_BEGIN std::map<std::string, void*> loaded_plugins; +#ifdef WITH_PYTHON +std::map<std::string, void*> loaded_python_plugins; +#endif std::map<std::string, std::string> loaded_plugin_aliases; #ifdef YOSYS_ENABLE_PLUGINS @@ -36,7 +45,35 @@ void load_plugin(std::string filename, std::vector<std::string> aliases) if (filename.find('/') == std::string::npos) filename = "./" + filename; + #ifdef WITH_PYTHON + if (!loaded_plugins.count(filename) && !loaded_python_plugins.count(filename)) { + #else if (!loaded_plugins.count(filename)) { + #endif + + #ifdef WITH_PYTHON + + boost::filesystem::path full_path(filename); + + if(strcmp(full_path.extension().c_str(), ".py") == 0) + { + std::string path(full_path.parent_path().c_str()); + filename = full_path.filename().c_str(); + filename = filename.substr(0,filename.size()-3); + PyRun_SimpleString(("sys.path.insert(0,\""+path+"\")").c_str()); + PyErr_Print(); + PyObject *module_p = PyImport_ImportModule(filename.c_str()); + if(module_p == NULL) + { + PyErr_Print(); + log_cmd_error("Can't load python module `%s'\n", full_path.filename().c_str()); + return; + } + loaded_python_plugins[orig_filename] = module_p; + Pass::init_register(); + } else { + #endif + void *hdl = dlopen(filename.c_str(), RTLD_LAZY|RTLD_LOCAL); if (hdl == NULL && orig_filename.find('/') == std::string::npos) hdl = dlopen((proc_share_dirname() + "plugins/" + orig_filename + ".so").c_str(), RTLD_LAZY|RTLD_LOCAL); @@ -44,6 +81,10 @@ void load_plugin(std::string filename, std::vector<std::string> aliases) log_cmd_error("Can't load module `%s': %s\n", filename.c_str(), dlerror()); loaded_plugins[orig_filename] = hdl; Pass::init_register(); + + #ifdef WITH_PYTHON + } + #endif } for (auto &alias : aliases) @@ -58,7 +99,7 @@ void load_plugin(std::string, std::vector<std::string>) struct PluginPass : public Pass { PluginPass() : Pass("plugin", "load and list loaded plugins") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -76,7 +117,7 @@ struct PluginPass : public Pass { log(" List loaded plugins\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { std::string plugin_filename; std::vector<std::string> plugin_aliases; @@ -107,7 +148,11 @@ struct PluginPass : public Pass { if (list_mode) { log("\n"); +#ifdef WITH_PYTHON + if (loaded_plugins.empty() and loaded_python_plugins.empty()) +#else if (loaded_plugins.empty()) +#endif log("No plugins loaded.\n"); else log("Loaded plugins:\n"); @@ -115,6 +160,11 @@ struct PluginPass : public Pass { for (auto &it : loaded_plugins) log(" %s\n", it.first.c_str()); +#ifdef WITH_PYTHON + for (auto &it : loaded_python_plugins) + log(" %s\n", it.first.c_str()); +#endif + if (!loaded_plugin_aliases.empty()) { log("\n"); int max_alias_len = 1; diff --git a/passes/cmds/portlist.cc b/passes/cmds/portlist.cc new file mode 100644 index 000000000..38c4a8597 --- /dev/null +++ b/passes/cmds/portlist.cc @@ -0,0 +1,93 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * + * 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 PortlistPass : public Pass { + PortlistPass() : Pass("portlist", "list (top-level) ports") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" portlist [options] [selection]\n"); + log("\n"); + log("This command lists all module ports found in the selected modules.\n"); + log("\n"); + log("If no selection is provided then it lists the ports on the top module.\n"); + log("\n"); + log(" -m\n"); + log(" print verilog blackbox module definitions instead of port lists\n"); + log("\n"); + } + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + bool m_mode = false; + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + if (args[argidx] == "-m") { + m_mode = true; + continue; + } + break; + } + + bool first_module = true; + + auto handle_module = [&](RTLIL::Module *module) { + vector<string> ports; + if (first_module) + first_module = false; + else + log("\n"); + for (auto port : module->ports) { + auto *w = module->wire(port); + ports.push_back(stringf("%s [%d:%d] %s", w->port_input ? w->port_output ? "inout" : "input" : "output", + w->upto ? w->start_offset : w->start_offset + w->width - 1, + w->upto ? w->start_offset + w->width - 1 : w->start_offset, + log_id(w))); + } + log("module %s%s\n", log_id(module), m_mode ? " (" : ""); + for (int i = 0; i < GetSize(ports); i++) + log("%s%s\n", ports[i].c_str(), m_mode && i+1 < GetSize(ports) ? "," : ""); + if (m_mode) + log(");\nendmodule\n"); + }; + + if (argidx == args.size()) + { + auto *top = design->top_module(); + if (top == nullptr) + log_cmd_error("Can't find top module in current design!\n"); + handle_module(top); + } + else + { + extra_args(args, argidx, design); + for (auto module : design->selected_modules()) + handle_module(module); + } + } +} PortlistPass; + +PRIVATE_NAMESPACE_END diff --git a/passes/cmds/qwp.cc b/passes/cmds/qwp.cc index f2dfa760e..adbe89e31 100644 --- a/passes/cmds/qwp.cc +++ b/passes/cmds/qwp.cc @@ -291,7 +291,7 @@ struct QwpWorker // gaussian elimination for (int i = 0; i < N; i++) { - if (config.verbose && ((i+1) % (N/15)) == 0) + if (config.verbose && N > 15 && ((i+1) % (N/15)) == 0) log("> Solved %d%%: %d/%d\n", (100*(i+1))/N, i+1, N); // find best row @@ -778,7 +778,7 @@ struct QwpWorker struct QwpPass : public Pass { QwpPass() : Pass("qwp", "quadratic wirelength placer") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -808,7 +808,7 @@ struct QwpPass : public Pass { log("dense matrix operations. It is only a toy-placer for small circuits.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { QwpConfig config; xorshift32_state = 123456789; diff --git a/passes/cmds/rename.cc b/passes/cmds/rename.cc index 6a002869b..9b1830b7b 100644 --- a/passes/cmds/rename.cc +++ b/passes/cmds/rename.cc @@ -24,7 +24,7 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN -static void rename_in_module(RTLIL::Module *module, std::string from_name, std::string to_name) +static void rename_in_module(RTLIL::Module *module, std::string from_name, std::string to_name, bool flag_output) { from_name = RTLIL::escape_id(from_name); to_name = RTLIL::escape_id(to_name); @@ -37,13 +37,18 @@ static void rename_in_module(RTLIL::Module *module, std::string from_name, std:: Wire *w = it.second; log("Renaming wire %s to %s in module %s.\n", log_id(w), log_id(to_name), log_id(module)); module->rename(w, to_name); - if (w->port_id) + if (w->port_id || flag_output) { + if (flag_output) + w->port_output = true; module->fixup_ports(); + } return; } for (auto &it : module->cells_) if (it.first == from_name) { + if (flag_output) + log_cmd_error("Called with -output but the specified object is a cell.\n"); log("Renaming cell %s to %s in module %s.\n", log_id(it.second), log_id(to_name), log_id(module)); module->rename(it.second, to_name); return; @@ -52,9 +57,54 @@ static void rename_in_module(RTLIL::Module *module, std::string from_name, std:: log_cmd_error("Object `%s' not found!\n", from_name.c_str()); } +static std::string derive_name_from_src(const std::string &src, int counter) +{ + std::string src_base = src.substr(0, src.find('|')); + if (src_base.empty()) + return stringf("$%d", counter); + else + return stringf("\\%s$%d", src_base.c_str(), counter); +} + +static IdString derive_name_from_wire(const RTLIL::Cell &cell) +{ + // Find output + const SigSpec *output = nullptr; + int num_outputs = 0; + for (auto &connection : cell.connections()) { + if (cell.output(connection.first)) { + output = &connection.second; + num_outputs++; + } + } + + if (num_outputs != 1) // Skip cells thad drive multiple outputs + return cell.name; + + std::string name = ""; + for (auto &chunk : output->chunks()) { + // Skip cells that drive privately named wires + if (!chunk.wire || chunk.wire->name.str()[0] == '$') + return cell.name; + + if (name != "") + name += "$"; + + name += chunk.wire->name.str(); + if (chunk.wire->width != chunk.width) { + name += "["; + if (chunk.width != 1) + name += std::to_string(chunk.offset + chunk.width) + ":"; + name += std::to_string(chunk.offset) + "]"; + } + } + + return name + cell.type.str(); +} + struct RenamePass : public Pass { RenamePass() : Pass("rename", "rename object in the design") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -64,6 +114,25 @@ struct RenamePass : public Pass { log("by this command.\n"); log("\n"); log("\n"); + log("\n"); + log(" rename -output old_name new_name\n"); + log("\n"); + log("Like above, but also make the wire an output. This will fail if the object is\n"); + log("not a wire.\n"); + log("\n"); + log("\n"); + log(" rename -src [selection]\n"); + log("\n"); + log("Assign names auto-generated from the src attribute to all selected wires and\n"); + log("cells with private names.\n"); + log("\n"); + log("\n"); + log(" rename -wire [selection]\n"); + log("\n"); + log("Assign auto-generated names based on the wires they drive to all selected\n"); + log("cells with private names. Ignores cells driving privatly named wires.\n"); + log("\n"); + log("\n"); log(" rename -enumerate [-pattern <pattern>] [selection]\n"); log("\n"); log("Assign short auto-generated names to all selected wires and cells with private\n"); @@ -71,28 +140,48 @@ struct RenamePass : public Pass { log("The character %% in the pattern is replaced with a integer number. The default\n"); log("pattern is '_%%_'.\n"); log("\n"); + log("\n"); log(" rename -hide [selection]\n"); log("\n"); log("Assign private names (the ones with $-prefix) to all selected wires and cells\n"); log("with public names. This ignores all selected ports.\n"); log("\n"); + log("\n"); log(" rename -top new_name\n"); log("\n"); log("Rename top module.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { std::string pattern_prefix = "_", pattern_suffix = "_"; + bool flag_src = false; + bool flag_wire = false; bool flag_enumerate = false; bool flag_hide = false; bool flag_top = false; + bool flag_output = false; bool got_mode = false; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { std::string arg = args[argidx]; + if (arg == "-src" && !got_mode) { + flag_src = true; + got_mode = true; + continue; + } + if (arg == "-output" && !got_mode) { + flag_output = true; + got_mode = true; + continue; + } + if (arg == "-wire" && !got_mode) { + flag_wire = true; + got_mode = true; + continue; + } if (arg == "-enumerate" && !got_mode) { flag_enumerate = true; got_mode = true; @@ -117,6 +206,57 @@ struct RenamePass : public Pass { break; } + if (flag_src) + { + extra_args(args, argidx, design); + + for (auto &mod : design->modules_) + { + int counter = 0; + + RTLIL::Module *module = mod.second; + if (!design->selected(module)) + continue; + + dict<RTLIL::IdString, RTLIL::Wire*> new_wires; + for (auto &it : module->wires_) { + if (it.first[0] == '$' && design->selected(module, it.second)) + it.second->name = derive_name_from_src(it.second->get_src_attribute(), counter++); + new_wires[it.second->name] = it.second; + } + module->wires_.swap(new_wires); + module->fixup_ports(); + + dict<RTLIL::IdString, RTLIL::Cell*> new_cells; + for (auto &it : module->cells_) { + if (it.first[0] == '$' && design->selected(module, it.second)) + it.second->name = derive_name_from_src(it.second->get_src_attribute(), counter++); + new_cells[it.second->name] = it.second; + } + module->cells_.swap(new_cells); + } + } + else + if (flag_wire) + { + extra_args(args, argidx, design); + + for (auto &mod : design->modules_) + { + RTLIL::Module *module = mod.second; + if (!design->selected(module)) + continue; + + dict<RTLIL::IdString, RTLIL::Cell*> new_cells; + for (auto &it : module->cells_) { + if (it.first[0] == '$' && design->selected(module, it.second)) + it.second->name = derive_name_from_wire(*it.second); + new_cells[it.second->name] = it.second; + } + module->cells_.swap(new_cells); + } + } + else if (flag_enumerate) { extra_args(args, argidx, design); @@ -206,10 +346,12 @@ struct RenamePass : public Pass { if (!design->selected_active_module.empty()) { if (design->modules_.count(design->selected_active_module) > 0) - rename_in_module(design->modules_.at(design->selected_active_module), from_name, to_name); + rename_in_module(design->modules_.at(design->selected_active_module), from_name, to_name, flag_output); } else { + if (flag_output) + log_cmd_error("Mode -output requires that there is an active module selected.\n"); for (auto &mod : design->modules_) { if (mod.first == from_name || RTLIL::unescape_id(mod.first) == from_name) { to_name = RTLIL::escape_id(to_name); diff --git a/passes/cmds/scatter.cc b/passes/cmds/scatter.cc index f083e1f67..7123ba9fb 100644 --- a/passes/cmds/scatter.cc +++ b/passes/cmds/scatter.cc @@ -27,7 +27,7 @@ PRIVATE_NAMESPACE_BEGIN struct ScatterPass : public Pass { ScatterPass() : Pass("scatter", "add additional intermediate nets") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -41,7 +41,7 @@ struct ScatterPass : public Pass { log("Use the opt_clean command to get rid of the additional nets.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { CellTypes ct(design); extra_args(args, 1, design); diff --git a/passes/cmds/scc.cc b/passes/cmds/scc.cc index 76363e051..99f4fbae8 100644 --- a/passes/cmds/scc.cc +++ b/passes/cmds/scc.cc @@ -218,7 +218,7 @@ struct SccWorker struct SccPass : public Pass { SccPass() : Pass("scc", "detect strongly connected components (logic loops)") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -255,7 +255,7 @@ struct SccPass : public Pass { log(" that are part of a found logic loop\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { std::map<std::string, std::string> setAttr; bool allCellTypes = false; diff --git a/passes/cmds/select.cc b/passes/cmds/select.cc index a0720797f..0f1f05ccb 100644 --- a/passes/cmds/select.cc +++ b/passes/cmds/select.cc @@ -34,7 +34,7 @@ static bool match_ids(RTLIL::IdString id, std::string pattern) { if (id == pattern) return true; - if (id.size() > 0 && id[0] == '\\' && id.substr(1) == pattern) + if (id.size() > 0 && id[0] == '\\' && id.compare(1, std::string::npos, pattern.c_str()) == 0) return true; if (patmatch(pattern.c_str(), id.c_str())) return true; @@ -124,11 +124,11 @@ static bool match_attr(const dict<RTLIL::IdString, RTLIL::Const> &attributes, st size_t pos = match_expr.find_first_of("<!=>"); if (pos != std::string::npos) { - if (match_expr.substr(pos, 2) == "!=") + if (match_expr.compare(pos, 2, "!=") == 0) return match_attr(attributes, match_expr.substr(0, pos), match_expr.substr(pos+2), '!'); - if (match_expr.substr(pos, 2) == "<=") + if (match_expr.compare(pos, 2, "<=") == 0) return match_attr(attributes, match_expr.substr(0, pos), match_expr.substr(pos+2), '['); - if (match_expr.substr(pos, 2) == ">=") + if (match_expr.compare(pos, 2, ">=") == 0) return match_attr(attributes, match_expr.substr(0, pos), match_expr.substr(pos+2), ']'); return match_attr(attributes, match_expr.substr(0, pos), match_expr.substr(pos+1), match_expr[pos]); } @@ -664,7 +664,7 @@ static void select_stmt(RTLIL::Design *design, std::string arg) } else if (arg == "%D") { if (work_stack.size() < 2) - log_cmd_error("Must have at least two elements on the stack for operator %%d.\n"); + log_cmd_error("Must have at least two elements on the stack for operator %%D.\n"); select_op_diff(design, work_stack[work_stack.size()-1], work_stack[work_stack.size()-2]); work_stack[work_stack.size()-2] = work_stack[work_stack.size()-1]; work_stack.pop_back(); @@ -693,7 +693,7 @@ static void select_stmt(RTLIL::Design *design, std::string arg) } else if (arg == "%C") { if (work_stack.size() < 1) - log_cmd_error("Must have at least one element on the stack for operator %%M.\n"); + log_cmd_error("Must have at least one element on the stack for operator %%C.\n"); select_op_module_to_cells(design, work_stack[work_stack.size()-1]); } else if (arg == "%c") { @@ -711,32 +711,32 @@ static void select_stmt(RTLIL::Design *design, std::string arg) log_cmd_error("Must have at least one element on the stack for operator %%a.\n"); select_op_alias(design, work_stack[work_stack.size()-1]); } else - if (arg == "%x" || (arg.size() > 2 && arg.substr(0, 2) == "%x" && (arg[2] == ':' || arg[2] == '*' || arg[2] == '.' || ('0' <= arg[2] && arg[2] <= '9')))) { + if (arg == "%x" || (arg.size() > 2 && arg.compare(0, 2, "%x") == 0 && (arg[2] == ':' || arg[2] == '*' || arg[2] == '.' || ('0' <= arg[2] && arg[2] <= '9')))) { if (work_stack.size() < 1) log_cmd_error("Must have at least one element on the stack for operator %%x.\n"); select_op_expand(design, arg, 'x', false); } else - if (arg == "%ci" || (arg.size() > 3 && arg.substr(0, 3) == "%ci" && (arg[3] == ':' || arg[3] == '*' || arg[3] == '.' || ('0' <= arg[3] && arg[3] <= '9')))) { + if (arg == "%ci" || (arg.size() > 3 && arg.compare(0, 3, "%ci") == 0 && (arg[3] == ':' || arg[3] == '*' || arg[3] == '.' || ('0' <= arg[3] && arg[3] <= '9')))) { if (work_stack.size() < 1) log_cmd_error("Must have at least one element on the stack for operator %%ci.\n"); select_op_expand(design, arg, 'i', false); } else - if (arg == "%co" || (arg.size() > 3 && arg.substr(0, 3) == "%co" && (arg[3] == ':' || arg[3] == '*' || arg[3] == '.' || ('0' <= arg[3] && arg[3] <= '9')))) { + if (arg == "%co" || (arg.size() > 3 && arg.compare(0, 3, "%co") == 0 && (arg[3] == ':' || arg[3] == '*' || arg[3] == '.' || ('0' <= arg[3] && arg[3] <= '9')))) { if (work_stack.size() < 1) log_cmd_error("Must have at least one element on the stack for operator %%co.\n"); select_op_expand(design, arg, 'o', false); } else - if (arg == "%xe" || (arg.size() > 3 && arg.substr(0, 3) == "%xe" && (arg[3] == ':' || arg[3] == '*' || arg[3] == '.' || ('0' <= arg[3] && arg[3] <= '9')))) { + if (arg == "%xe" || (arg.size() > 3 && arg.compare(0, 3, "%xe") == 0 && (arg[3] == ':' || arg[3] == '*' || arg[3] == '.' || ('0' <= arg[3] && arg[3] <= '9')))) { if (work_stack.size() < 1) log_cmd_error("Must have at least one element on the stack for operator %%xe.\n"); select_op_expand(design, arg, 'x', true); } else - if (arg == "%cie" || (arg.size() > 4 && arg.substr(0, 4) == "%cie" && (arg[4] == ':' || arg[4] == '*' || arg[4] == '.' || ('0' <= arg[4] && arg[4] <= '9')))) { + if (arg == "%cie" || (arg.size() > 4 && arg.compare(0, 4, "%cie") == 0 && (arg[4] == ':' || arg[4] == '*' || arg[4] == '.' || ('0' <= arg[4] && arg[4] <= '9')))) { if (work_stack.size() < 1) log_cmd_error("Must have at least one element on the stack for operator %%cie.\n"); select_op_expand(design, arg, 'i', true); } else - if (arg == "%coe" || (arg.size() > 4 && arg.substr(0, 4) == "%coe" && (arg[4] == ':' || arg[4] == '*' || arg[4] == '.' || ('0' <= arg[4] && arg[4] <= '9')))) { + if (arg == "%coe" || (arg.size() > 4 && arg.compare(0, 4, "%coe") == 0 && (arg[4] == ':' || arg[4] == '*' || arg[4] == '.' || ('0' <= arg[4] && arg[4] <= '9')))) { if (work_stack.size() < 1) log_cmd_error("Must have at least one element on the stack for operator %%coe.\n"); select_op_expand(design, arg, 'o', true); @@ -766,7 +766,7 @@ static void select_stmt(RTLIL::Design *design, std::string arg) } else { size_t pos = arg.find('/'); if (pos == std::string::npos) { - if (arg.find(':') == std::string::npos || arg.substr(0, 1) == "A") + if (arg.find(':') == std::string::npos || arg.compare(0, 1, "A") == 0) arg_mod = arg; else arg_mod = "*", arg_memb = arg; @@ -787,7 +787,7 @@ static void select_stmt(RTLIL::Design *design, std::string arg) sel.full_selection = false; for (auto &mod_it : design->modules_) { - if (arg_mod.substr(0, 2) == "A:") { + if (arg_mod.compare(0, 2, "A:") == 0) { if (!match_attr(mod_it.second->attributes, arg_mod.substr(2))) continue; } else @@ -800,27 +800,27 @@ static void select_stmt(RTLIL::Design *design, std::string arg) } RTLIL::Module *mod = mod_it.second; - if (arg_memb.substr(0, 2) == "w:") { + if (arg_memb.compare(0, 2, "w:") == 0) { for (auto &it : mod->wires_) if (match_ids(it.first, arg_memb.substr(2))) sel.selected_members[mod->name].insert(it.first); } else - if (arg_memb.substr(0, 2) == "i:") { + if (arg_memb.compare(0, 2, "i:") == 0) { for (auto &it : mod->wires_) if (it.second->port_input && match_ids(it.first, arg_memb.substr(2))) sel.selected_members[mod->name].insert(it.first); } else - if (arg_memb.substr(0, 2) == "o:") { + if (arg_memb.compare(0, 2, "o:") == 0) { for (auto &it : mod->wires_) if (it.second->port_output && match_ids(it.first, arg_memb.substr(2))) sel.selected_members[mod->name].insert(it.first); } else - if (arg_memb.substr(0, 2) == "x:") { + if (arg_memb.compare(0, 2, "x:") == 0) { for (auto &it : mod->wires_) if ((it.second->port_input || it.second->port_output) && match_ids(it.first, arg_memb.substr(2))) sel.selected_members[mod->name].insert(it.first); } else - if (arg_memb.substr(0, 2) == "s:") { + if (arg_memb.compare(0, 2, "s:") == 0) { size_t delim = arg_memb.substr(2).find(':'); if (delim == std::string::npos) { int width = atoi(arg_memb.substr(2).c_str()); @@ -837,27 +837,27 @@ static void select_stmt(RTLIL::Design *design, std::string arg) sel.selected_members[mod->name].insert(it.first); } } else - if (arg_memb.substr(0, 2) == "m:") { + if (arg_memb.compare(0, 2, "m:") == 0) { for (auto &it : mod->memories) if (match_ids(it.first, arg_memb.substr(2))) sel.selected_members[mod->name].insert(it.first); } else - if (arg_memb.substr(0, 2) == "c:") { + if (arg_memb.compare(0, 2, "c:") ==0) { for (auto &it : mod->cells_) if (match_ids(it.first, arg_memb.substr(2))) sel.selected_members[mod->name].insert(it.first); } else - if (arg_memb.substr(0, 2) == "t:") { + if (arg_memb.compare(0, 2, "t:") == 0) { for (auto &it : mod->cells_) if (match_ids(it.second->type, arg_memb.substr(2))) sel.selected_members[mod->name].insert(it.first); } else - if (arg_memb.substr(0, 2) == "p:") { + if (arg_memb.compare(0, 2, "p:") == 0) { for (auto &it : mod->processes) if (match_ids(it.first, arg_memb.substr(2))) sel.selected_members[mod->name].insert(it.first); } else - if (arg_memb.substr(0, 2) == "a:") { + if (arg_memb.compare(0, 2, "a:") == 0) { for (auto &it : mod->wires_) if (match_attr(it.second->attributes, arg_memb.substr(2))) sel.selected_members[mod->name].insert(it.first); @@ -871,12 +871,12 @@ static void select_stmt(RTLIL::Design *design, std::string arg) if (match_attr(it.second->attributes, arg_memb.substr(2))) sel.selected_members[mod->name].insert(it.first); } else - if (arg_memb.substr(0, 2) == "r:") { + if (arg_memb.compare(0, 2, "r:") == 0) { for (auto &it : mod->cells_) if (match_attr(it.second->parameters, arg_memb.substr(2))) sel.selected_members[mod->name].insert(it.first); } else { - if (arg_memb.substr(0, 2) == "n:") + if (arg_memb.compare(0, 2, "n:") == 0) arg_memb = arg_memb.substr(2); for (auto &it : mod->wires_) if (match_ids(it.first, arg_memb)) @@ -896,6 +896,29 @@ static void select_stmt(RTLIL::Design *design, std::string arg) select_filter_active_mod(design, work_stack.back()); } +static std::string describe_selection_for_assert(RTLIL::Design *design, RTLIL::Selection *sel) +{ + std::string desc = "Selection contains:\n"; + for (auto mod_it : design->modules_) + { + if (sel->selected_module(mod_it.first)) { + for (auto &it : mod_it.second->wires_) + if (sel->selected_member(mod_it.first, it.first)) + desc += stringf("%s/%s\n", id2cstr(mod_it.first), id2cstr(it.first)); + for (auto &it : mod_it.second->memories) + if (sel->selected_member(mod_it.first, it.first)) + desc += stringf("%s/%s\n", id2cstr(mod_it.first), id2cstr(it.first)); + for (auto &it : mod_it.second->cells_) + if (sel->selected_member(mod_it.first, it.first)) + desc += stringf("%s/%s\n", id2cstr(mod_it.first), id2cstr(it.first)); + for (auto &it : mod_it.second->processes) + if (sel->selected_member(mod_it.first, it.first)) + desc += stringf("%s/%s\n", id2cstr(mod_it.first), id2cstr(it.first)); + } + } + return desc; +} + PRIVATE_NAMESPACE_END YOSYS_NAMESPACE_BEGIN @@ -904,7 +927,7 @@ void handle_extra_select_args(Pass *pass, vector<string> args, size_t argidx, si { work_stack.clear(); for (; argidx < args_size; argidx++) { - if (args[argidx].substr(0, 1) == "-") { + if (args[argidx].compare(0, 1, "-") == 0) { if (pass != NULL) pass->cmd_error(args, argidx, "Unexpected option in selection arguments."); else @@ -950,7 +973,7 @@ PRIVATE_NAMESPACE_BEGIN struct SelectPass : public Pass { SelectPass() : Pass("select", "modify and view the list of selected objects") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -1167,7 +1190,7 @@ struct SelectPass : public Pass { log(" select */t:SWITCH %%x:+[GATE] */t:SWITCH %%d\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { bool add_mode = false; bool del_mode = false; @@ -1394,7 +1417,12 @@ struct SelectPass : public Pass { log_cmd_error("No selection to check.\n"); work_stack.back().optimize(design); if (!work_stack.back().empty()) - log_error("Assertion failed: selection is not empty:%s\n", sel_str.c_str()); + { + RTLIL::Selection *sel = &work_stack.back(); + sel->optimize(design); + std::string desc = describe_selection_for_assert(design, sel); + log_error("Assertion failed: selection is not empty:%s\n%s", sel_str.c_str(), desc.c_str()); + } return; } @@ -1404,7 +1432,12 @@ struct SelectPass : public Pass { log_cmd_error("No selection to check.\n"); work_stack.back().optimize(design); if (work_stack.back().empty()) - log_error("Assertion failed: selection is empty:%s\n", sel_str.c_str()); + { + RTLIL::Selection *sel = &work_stack.back(); + sel->optimize(design); + std::string desc = describe_selection_for_assert(design, sel); + log_error("Assertion failed: selection is empty:%s\n%s", sel_str.c_str(), desc.c_str()); + } return; } @@ -1431,14 +1464,23 @@ struct SelectPass : public Pass { total_count++; } if (assert_count >= 0 && assert_count != total_count) - log_error("Assertion failed: selection contains %d elements instead of the asserted %d:%s\n", - total_count, assert_count, sel_str.c_str()); + { + std::string desc = describe_selection_for_assert(design, sel); + log_error("Assertion failed: selection contains %d elements instead of the asserted %d:%s\n%s", + total_count, assert_count, sel_str.c_str(), desc.c_str()); + } if (assert_max >= 0 && assert_max < total_count) - log_error("Assertion failed: selection contains %d elements, more than the maximum number %d:%s\n", - total_count, assert_max, sel_str.c_str()); + { + std::string desc = describe_selection_for_assert(design, sel); + log_error("Assertion failed: selection contains %d elements, more than the maximum number %d:%s\n%s", + total_count, assert_max, sel_str.c_str(), desc.c_str()); + } if (assert_min >= 0 && assert_min > total_count) - log_error("Assertion failed: selection contains %d elements, less than the minimum number %d:%s\n", - total_count, assert_min, sel_str.c_str()); + { + std::string desc = describe_selection_for_assert(design, sel); + log_error("Assertion failed: selection contains %d elements, less than the minimum number %d:%s\n%s", + total_count, assert_min, sel_str.c_str(), desc.c_str()); + } return; } @@ -1470,7 +1512,7 @@ struct SelectPass : public Pass { struct CdPass : public Pass { CdPass() : Pass("cd", "a shortcut for 'select -module <name>'") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -1496,7 +1538,7 @@ struct CdPass : public Pass { log("This is just a shortcut for 'select -clear'.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { if (args.size() != 1 && args.size() != 2) log_cmd_error("Invalid number of arguments.\n"); @@ -1578,7 +1620,7 @@ static void log_matches(const char *title, Module *module, T list) struct LsPass : public Pass { LsPass() : Pass("ls", "list modules or objects in modules") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -1589,7 +1631,7 @@ struct LsPass : public Pass { log("When an active module is selected, this prints a list of objects in the module.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { size_t argidx = 1; extra_args(args, argidx, design); diff --git a/passes/cmds/setattr.cc b/passes/cmds/setattr.cc index 689e3148b..1ccfc2e86 100644 --- a/passes/cmds/setattr.cc +++ b/passes/cmds/setattr.cc @@ -34,7 +34,7 @@ struct setunset_t setunset_t(std::string set_name, std::string set_value) : name(RTLIL::escape_id(set_name)), value(), unset(false) { - if (set_value.substr(0, 1) == "\"" && set_value.substr(GetSize(set_value)-1) == "\"") { + if (set_value.compare(0, 1, "\"") == 0 && set_value.compare(GetSize(set_value)-1, std::string::npos, "\"") == 0) { value = RTLIL::Const(set_value.substr(1, GetSize(set_value)-2)); } else { RTLIL::SigSpec sig_value; @@ -56,7 +56,7 @@ static void do_setunset(dict<RTLIL::IdString, RTLIL::Const> &attrs, const std::v struct SetattrPass : public Pass { SetattrPass() : Pass("setattr", "set/unset attributes on objects") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -69,7 +69,7 @@ struct SetattrPass : public Pass { log("instead of objects within modules.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { std::vector<setunset_t> setunset_list; bool flag_mod = false; @@ -128,9 +128,48 @@ struct SetattrPass : public Pass { } } SetattrPass; +struct WbflipPass : public Pass { + WbflipPass() : Pass("wbflip", "flip the whitebox attribute") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" wbflip [selection]\n"); + log("\n"); + log("Flip the whitebox attribute on selected cells. I.e. if it's set, unset it, and\n"); + log("vice-versa. Blackbox cells are not effected by this command.\n"); + log("\n"); + } + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + std::string arg = args[argidx]; + // if (arg == "-mod") { + // flag_mod = true; + // continue; + // } + break; + } + extra_args(args, argidx, design); + + for (Module *module : design->modules()) + { + if (!design->selected(module)) + continue; + + if (module->get_bool_attribute("\\blackbox")) + continue; + + module->set_bool_attribute("\\whitebox", !module->get_bool_attribute("\\whitebox")); + } + } +} WbflipPass; + struct SetparamPass : public Pass { SetparamPass() : Pass("setparam", "set/unset parameters on objects") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -142,7 +181,7 @@ struct SetparamPass : public Pass { log("The -type option can be used to change the cell type of the selected cells.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { vector<setunset_t> setunset_list; string new_cell_type; @@ -188,7 +227,7 @@ struct SetparamPass : public Pass { struct ChparamPass : public Pass { ChparamPass() : Pass("chparam", "re-evaluate modules with new parameters") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -203,7 +242,7 @@ struct ChparamPass : public Pass { log("List the available parameters of the selected modules.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { std::vector<setunset_t> setunset_list; dict<RTLIL::IdString, RTLIL::Const> new_parameters; diff --git a/passes/cmds/setundef.cc b/passes/cmds/setundef.cc index 1cd942796..3eedc86b8 100644 --- a/passes/cmds/setundef.cc +++ b/passes/cmds/setundef.cc @@ -33,67 +33,32 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN -static RTLIL::Wire * add_wire(RTLIL::Design *design, RTLIL::Module *module, std::string name, int width, bool flag_input, bool flag_output, bool flag_global) +static RTLIL::Wire * add_wire(RTLIL::Module *module, std::string name, int width, bool flag_input, bool flag_output) { - RTLIL::Wire *wire = NULL; - name = RTLIL::escape_id(name); - - if (module->count_id(name) != 0) - { - if (module->wires_.count(name) > 0) - wire = module->wires_.at(name); - - if (wire != NULL && wire->width != width) - wire = NULL; - - if (wire != NULL && wire->port_input != flag_input) - wire = NULL; - - if (wire != NULL && wire->port_output != flag_output) - wire = NULL; - - if (wire == NULL) { - return wire; - log_cmd_error("Found incompatible object %s with same name in module %s!\n", name.c_str(), module->name.c_str()); - } - - log("Module %s already has such an object %s.\n", module->name.c_str(), name.c_str()); - } - else - { - wire = module->addWire(name, width); - wire->port_input = flag_input; - wire->port_output = flag_output; - - if (flag_input || flag_output) { - wire->port_id = module->wires_.size(); - module->fixup_ports(); - } - - log("Added wire %s to module %s.\n", name.c_str(), module->name.c_str()); - } - - if (!flag_global) - return wire; - - for (auto &it : module->cells_) - { - if (design->modules_.count(it.second->type) == 0) - continue; - - RTLIL::Module *mod = design->modules_.at(it.second->type); - if (!design->selected_whole_module(mod->name)) - continue; - if (mod->get_bool_attribute("\\blackbox")) - continue; - if (it.second->hasPort(name)) - continue; - - it.second->setPort(name, wire); - log("Added connection %s to cell %s.%s (%s).\n", name.c_str(), module->name.c_str(), it.first.c_str(), it.second->type.c_str()); - } - - return wire; + RTLIL::Wire *wire = NULL; + name = RTLIL::escape_id(name); + + if (module->count_id(name) != 0) + { + log("Module %s already has such an object %s.\n", module->name.c_str(), name.c_str()); + name += "$"; + return add_wire(module, name, width, flag_input, flag_output); + } + else + { + wire = module->addWire(name, width); + wire->port_input = flag_input; + wire->port_output = flag_output; + + if (flag_input || flag_output) { + wire->port_id = module->wires_.size(); + module->fixup_ports(); + } + + log("Added wire %s to module %s.\n", name.c_str(), module->name.c_str()); + } + + return wire; } struct SetundefWorker @@ -142,7 +107,7 @@ struct SetundefWorker struct SetundefPass : public Pass { SetundefPass() : Pass("setundef", "replace undef values with defined constants") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -172,19 +137,23 @@ struct SetundefPass : public Pass { log(" replace with $anyconst drivers (for formal)\n"); log("\n"); log(" -random <seed>\n"); - log(" replace with random bits using the specified integer als seed\n"); + log(" replace with random bits using the specified integer as seed\n"); log(" value for the random number generator.\n"); log("\n"); log(" -init\n"); log(" also create/update init values for flip-flops\n"); log("\n"); + log(" -params\n"); + log(" replace undef in cell parameters\n"); + log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { bool got_value = false; bool undriven_mode = false; bool expose_mode = false; bool init_mode = false; + bool params_mode = false; SetundefWorker worker; log_header(design, "Executing SETUNDEF pass (replace undef values with defined constants).\n"); @@ -197,7 +166,6 @@ struct SetundefPass : public Pass { continue; } if (args[argidx] == "-expose") { - got_value = true; expose_mode = true; continue; } @@ -235,6 +203,10 @@ struct SetundefPass : public Pass { init_mode = true; continue; } + if (args[argidx] == "-params") { + params_mode = true; + continue; + } if (args[argidx] == "-random" && !got_value && argidx+1 < args.size()) { got_value = true; worker.next_bit_mode = MODE_RANDOM; @@ -247,6 +219,13 @@ struct SetundefPass : public Pass { } extra_args(args, argidx, design); + if (!got_value && expose_mode) { + log("Using default as -undef with -expose.\n"); + got_value = true; + worker.next_bit_mode = MODE_UNDEF; + worker.next_bit_state = 0; + } + if (expose_mode && !undriven_mode) log_cmd_error("Option -expose must be used with option -undriven.\n"); if (!got_value) @@ -257,105 +236,121 @@ struct SetundefPass : public Pass { for (auto module : design->selected_modules()) { + if (params_mode) + { + for (auto *cell : module->selected_cells()) { + for (auto ¶meter : cell->parameters) { + for (auto &bit : parameter.second.bits) { + if (bit > RTLIL::State::S1) + bit = worker.next_bit(); + } + } + } + } + if (undriven_mode) { if (!module->processes.empty()) log_error("The 'setundef' command can't operate in -undriven mode on modules with processes. Run 'proc' first.\n"); - if (expose_mode) { - SigMap sigmap(module); - dict<SigBit, bool> wire_drivers; - pool<SigBit> used_wires; - SigPool undriven_signals; - - for (auto cell : module->cells()) - for (auto &conn : cell->connections()) { - SigSpec sig = sigmap(conn.second); - if (cell->input(conn.first)) - for (auto bit : sig) - if (bit.wire) { - used_wires.insert(bit); - } - if (cell->output(conn.first)) - for (int i = 0; i < GetSize(sig); i++) { - if (sig[i].wire) - wire_drivers[sig[i]] = true; - } - } - - for (auto wire : module->wires()) { - if (wire->port_input) { - SigSpec sig = sigmap(wire); - for (int i = 0; i < GetSize(sig); i++) - wire_drivers[sig[i]] = true; - } - if (wire->port_output) - for (auto bit : sigmap(wire)) - if (bit.wire) used_wires.insert(bit); - } - - pool<RTLIL::Wire*> undriven_wires; - for (auto bit : used_wires) { - if (!wire_drivers.count(bit)) { - undriven_wires.insert(bit.wire); - } - } - - for (auto &it : undriven_wires) - undriven_signals.add(sigmap(it)); - - for (auto &it : undriven_wires) - if (it->port_input) - undriven_signals.del(sigmap(it)); - - CellTypes ct(design); - for (auto &it : module->cells_) - for (auto &conn : it.second->connections()) - if (!ct.cell_known(it.second->type) || ct.cell_output(it.second->type, conn.first)) - undriven_signals.del(sigmap(conn.second)); - - RTLIL::SigSpec sig = undriven_signals.export_all(); - for (auto &c : sig.chunks()) { - RTLIL::Wire * wire; - if (c.wire->width == c.width) { - wire = c.wire; - wire->port_input = true; - } - else { - string name = c.wire->name.str() + "$[" + std::to_string(c.width + c.offset) + ":" + std::to_string(c.offset) + "]"; - wire = add_wire(design, module, name, c.width, true, false, false); - module->connect(RTLIL::SigSig(c, wire)); - } - log("Exposing undriven wire %s as input.\n", wire->name.c_str()); - } - module->fixup_ports(); - continue; - } - else { - SigMap sigmap(module); - SigPool undriven_signals; - - for (auto &it : module->wires_) - undriven_signals.add(sigmap(it.second)); - - for (auto &it : module->wires_) - if (it.second->port_input) - undriven_signals.del(sigmap(it.second)); - - CellTypes ct(design); - for (auto &it : module->cells_) - for (auto &conn : it.second->connections()) - if (!ct.cell_known(it.second->type) || ct.cell_output(it.second->type, conn.first)) - undriven_signals.del(sigmap(conn.second)); - - RTLIL::SigSpec sig = undriven_signals.export_all(); - for (auto &c : sig.chunks()) { - RTLIL::SigSpec bits; - for (int i = 0; i < c.width; i++) - bits.append(worker.next_bit()); - module->connect(RTLIL::SigSig(c, bits)); - } - } + if (expose_mode) + { + SigMap sigmap(module); + dict<SigBit, bool> wire_drivers; + pool<SigBit> used_wires; + SigPool undriven_signals; + + for (auto cell : module->cells()) + for (auto &conn : cell->connections()) { + SigSpec sig = sigmap(conn.second); + if (cell->input(conn.first)) + for (auto bit : sig) + if (bit.wire) + used_wires.insert(bit); + if (cell->output(conn.first)) + for (int i = 0; i < GetSize(sig); i++) + if (sig[i].wire) + wire_drivers[sig[i]] = true; + } + + for (auto wire : module->wires()) { + if (wire->port_input) { + SigSpec sig = sigmap(wire); + for (int i = 0; i < GetSize(sig); i++) + wire_drivers[sig[i]] = true; + } + if (wire->port_output) { + SigSpec sig = sigmap(wire); + for (auto bit : sig) + if (bit.wire) + used_wires.insert(bit); + } + } + + pool<RTLIL::Wire*> undriven_wires; + for (auto bit : used_wires) + if (!wire_drivers.count(bit)) + undriven_wires.insert(bit.wire); + + for (auto &it : undriven_wires) + undriven_signals.add(sigmap(it)); + + for (auto &it : undriven_wires) + if (it->port_input) + undriven_signals.del(sigmap(it)); + + CellTypes ct(design); + for (auto &it : module->cells_) + for (auto &conn : it.second->connections()) + if (!ct.cell_known(it.second->type) || ct.cell_output(it.second->type, conn.first)) + undriven_signals.del(sigmap(conn.second)); + + RTLIL::SigSpec sig = undriven_signals.export_all(); + for (auto &c : sig.chunks()) { + RTLIL::Wire * wire; + if (c.wire->width == c.width) { + wire = c.wire; + wire->port_input = true; + } else { + string name = c.wire->name.str() + "$[" + std::to_string(c.width + c.offset) + ":" + std::to_string(c.offset) + "]"; + wire = add_wire(module, name, c.width, true, false); + module->connect(RTLIL::SigSig(c, wire)); + } + log("Exposing undriven wire %s as input.\n", wire->name.c_str()); + } + module->fixup_ports(); + } + else + { + SigMap sigmap(module); + SigPool undriven_signals; + + for (auto &it : module->wires_) + undriven_signals.add(sigmap(it.second)); + + for (auto &it : module->wires_) + if (it.second->port_input) + undriven_signals.del(sigmap(it.second)); + + CellTypes ct(design); + for (auto &it : module->cells_) + for (auto &conn : it.second->connections()) + if (!ct.cell_known(it.second->type) || ct.cell_output(it.second->type, conn.first)) + undriven_signals.del(sigmap(conn.second)); + + RTLIL::SigSpec sig = undriven_signals.export_all(); + for (auto &c : sig.chunks()) { + RTLIL::SigSpec bits; + if (worker.next_bit_mode == MODE_ANYSEQ) + bits = module->Anyseq(NEW_ID, c.width); + else if (worker.next_bit_mode == MODE_ANYCONST) + bits = module->Anyconst(NEW_ID, c.width); + else + for (int i = 0; i < c.width; i++) + bits.append(worker.next_bit()); + module->connect(RTLIL::SigSig(c, bits)); + } + } } if (init_mode) @@ -398,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*, int> wire_weights; - for (auto bit : sigmap(wire)) - ffbits.erase(bit); + for (auto wire : initwires) + { + int weight = 0; - initwires.insert(wire); - } + for (auto bit : sigmap(wire)) + weight += ffbits.count(bit) ? +1 : -1; + + wire_weights[wire] = weight; + } + + initwires.sort([&](Wire *a, Wire *b) { return wire_weights.at(a) > wire_weights.at(b); }); + + 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++) - for (auto wire : module->wires()) + { + // prioritize wires that already have an init attribute + if (!ffbits.empty()) { - if (wire->name[0] == (wire_types ? '\\' : '$')) - next_wire: - continue; + for (auto wire : module->wires()) + { + if (wire->name[0] == (wire_types ? '\\' : '$')) + continue; - for (auto bit : sigmap(wire)) - if (!ffbits.count(bit)) - goto next_wire; + if (!wire->attributes.count("\\init")) + continue; - for (auto bit : sigmap(wire)) - ffbits.erase(bit); + Const &initval = wire->attributes["\\init"]; + initval.bits.resize(GetSize(wire), State::Sx); + + if (initval.is_fully_undef()) { + wire->attributes.erase("\\init"); + continue; + } - initwires.insert(wire); + for (int i = 0; i < GetSize(wire); i++) + if (initval[i] != State::Sx) + ffbits.erase(sigmap(SigBit(wire, i))); + + initwires.insert(wire); + } + + process_initwires(); } - for (auto wire : initwires) - { - Const &initval = wire->attributes["\\init"]; + // 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 (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 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/passes/cmds/show.cc b/passes/cmds/show.cc index 56e1122bf..a3e969ef1 100644 --- a/passes/cmds/show.cc +++ b/passes/cmds/show.cc @@ -26,6 +26,10 @@ # include <dirent.h> #endif +#ifdef __APPLE__ +# include <unistd.h> +#endif + #ifdef YOSYS_ENABLE_READLINE # include <readline/readline.h> #endif @@ -237,15 +241,34 @@ struct ShowWorker int idx = single_idx_count++; for (int rep, i = int(sig.chunks().size())-1; i >= 0; i -= rep) { const RTLIL::SigChunk &c = sig.chunks().at(i); - net = gen_signode_simple(c, false); - log_assert(!net.empty()); + if (!driver && c.wire == nullptr) { + RTLIL::State s1 = c.data.front(); + for (auto s2 : c.data) + if (s1 != s2) + goto not_const_stream; + net.clear(); + } else { + not_const_stream: + net = gen_signode_simple(c, false); + log_assert(!net.empty()); + } for (rep = 1; i-rep >= 0 && c == sig.chunks().at(i-rep); rep++) {} std::string repinfo = rep > 1 ? stringf("%dx ", rep) : ""; if (driver) { + log_assert(!net.empty()); label_string += stringf("<s%d> %d:%d - %s%d:%d |", i, pos, pos-c.width+1, repinfo.c_str(), c.offset+c.width-1, c.offset); net_conn_map[net].in.insert(stringf("x%d:s%d", idx, i)); net_conn_map[net].bits = rep*c.width; net_conn_map[net].color = nextColor(c, net_conn_map[net].color); + } else + if (net.empty()) { + log_assert(rep == 1); + label_string += stringf("%c -> %d:%d |", + c.data.front() == State::S0 ? '0' : + c.data.front() == State::S1 ? '1' : + c.data.front() == State::Sx ? 'X' : + c.data.front() == State::Sz ? 'Z' : '?', + pos, pos-rep*c.width+1); } else { label_string += stringf("<s%d> %s%d:%d - %d:%d |", i, repinfo.c_str(), c.offset+c.width-1, c.offset, pos, pos-rep*c.width+1); net_conn_map[net].out.insert(stringf("x%d:s%d", idx, i)); @@ -508,11 +531,11 @@ struct ShowWorker { currentColor = xorshift32(currentColor); if (wires_on_demand.count(it.first) > 0) { - if (it.second.in.size() == 1 && it.second.out.size() > 1 && it.second.in.begin()->substr(0, 1) == "p") + if (it.second.in.size() == 1 && it.second.out.size() > 1 && it.second.in.begin()->compare(0, 1, "p") == 0) it.second.out.erase(*it.second.in.begin()); if (it.second.in.size() == 1 && it.second.out.size() == 1) { std::string from = *it.second.in.begin(), to = *it.second.out.begin(); - if (from != to || from.substr(0, 1) != "p") + if (from != to || from.compare(0, 1, "p") != 0) fprintf(f, "%s:e -> %s:w [%s, %s];\n", from.c_str(), to.c_str(), nextColor(it.second.color).c_str(), widthLabel(it.second.bits).c_str()); continue; } @@ -555,7 +578,7 @@ struct ShowWorker if (!design->selected_module(module->name)) continue; if (design->selected_whole_module(module->name)) { - if (module->get_bool_attribute("\\blackbox")) { + if (module->get_blackbox_attribute()) { // log("Skipping blackbox module %s.\n", id2cstr(module->name)); continue; } else @@ -573,7 +596,7 @@ struct ShowWorker struct ShowPass : public Pass { ShowPass() : Pass("show", "generate schematics using graphviz") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -584,6 +607,7 @@ struct ShowPass : public Pass { log("\n"); log(" -viewer <viewer>\n"); log(" Run the specified command with the graphics file as parameter.\n"); + log(" On Windows, this pauses yosys until the viewer exits.\n"); log("\n"); log(" -format <format>\n"); log(" Generate a graphics file in the specified format. Use 'dot' to just\n"); @@ -622,7 +646,7 @@ struct ShowPass : public Pass { log(" assigned to each unique value of this attribute.\n"); log("\n"); log(" -width\n"); - log(" annotate busses with a label indicating the width of the bus.\n"); + log(" annotate buses with a label indicating the width of the bus.\n"); log("\n"); log(" -signed\n"); log(" mark ports (A, B) that are declared as signed (using the [AB]_SIGNED\n"); @@ -645,7 +669,7 @@ struct ShowPass : public Pass { log(" do not add the module name as graph title to the dot file\n"); log("\n"); log("When no <format> is specified, 'dot' is used. When no <format> and <viewer> is\n"); - log("specified, 'xdot' is used to display the schematic.\n"); + log("specified, 'xdot' is used to display the schematic (POSIX systems only).\n"); log("\n"); log("The generated output files are '~/.yosys_show.dot' and '~/.yosys_show.<format>',\n"); log("unless another prefix is specified using -prefix <prefix>.\n"); @@ -655,7 +679,7 @@ struct ShowPass : public Pass { log("the 'show' command is executed.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Generating Graphviz representation of design.\n"); log_push(); @@ -770,7 +794,7 @@ struct ShowPass : public Pass { if (format != "ps" && format != "dot") { int modcount = 0; for (auto &mod_it : design->modules_) { - if (mod_it.second->get_bool_attribute("\\blackbox")) + if (mod_it.second->get_blackbox_attribute()) continue; if (mod_it.second->cells_.empty() && mod_it.second->connections().empty()) continue; @@ -788,7 +812,7 @@ struct ShowPass : public Pass { if (f.fail()) log_error("Can't open lib file `%s'.\n", filename.c_str()); RTLIL::Design *lib = new RTLIL::Design; - Frontend::frontend_call(lib, &f, filename, (filename.size() > 3 && filename.substr(filename.size()-3) == ".il") ? "ilang" : "verilog"); + Frontend::frontend_call(lib, &f, filename, (filename.size() > 3 && filename.compare(filename.size()-3, std::string::npos, ".il") == 0 ? "ilang" : "verilog")); libs.push_back(lib); } @@ -817,20 +841,40 @@ struct ShowPass : public Pass { log_cmd_error("Nothing there to show.\n"); if (format != "dot" && !format.empty()) { - std::string cmd = stringf("dot -T%s '%s' > '%s.new' && mv '%s.new' '%s'", format.c_str(), dot_file.c_str(), out_file.c_str(), out_file.c_str(), out_file.c_str()); + #ifdef _WIN32 + // system()/cmd.exe does not understand single quotes on Windows. + #define DOT_CMD "dot -T%s \"%s\" > \"%s.new\" && move \"%s.new\" \"%s\"" + #else + #define DOT_CMD "dot -T%s '%s' > '%s.new' && mv '%s.new' '%s'" + #endif + std::string cmd = stringf(DOT_CMD, format.c_str(), dot_file.c_str(), out_file.c_str(), out_file.c_str(), out_file.c_str()); + #undef DOT_CMD log("Exec: %s\n", cmd.c_str()); if (run_command(cmd) != 0) log_cmd_error("Shell command failed!\n"); } if (!viewer_exe.empty()) { - std::string cmd = stringf("%s '%s' &", viewer_exe.c_str(), out_file.c_str()); + #ifdef _WIN32 + // system()/cmd.exe does not understand single quotes nor + // background tasks on Windows. So we have to pause yosys + // until the viewer exits. + #define VIEW_CMD "%s \"%s\"" + #else + #define VIEW_CMD "%s '%s' &" + #endif + std::string cmd = stringf(VIEW_CMD, viewer_exe.c_str(), out_file.c_str()); + #undef VIEW_CMD log("Exec: %s\n", cmd.c_str()); if (run_command(cmd) != 0) log_cmd_error("Shell command failed!\n"); } else if (format.empty()) { + #ifdef __APPLE__ + std::string cmd = stringf("ps -fu %d | grep -q '[ ]%s' || xdot '%s' &", getuid(), dot_file.c_str(), dot_file.c_str()); + #else std::string cmd = stringf("{ test -f '%s.pid' && fuser -s '%s.pid'; } || ( echo $$ >&3; exec xdot '%s'; ) 3> '%s.pid' &", dot_file.c_str(), dot_file.c_str(), dot_file.c_str(), dot_file.c_str()); + #endif log("Exec: %s\n", cmd.c_str()); if (run_command(cmd) != 0) log_cmd_error("Shell command failed!\n"); diff --git a/passes/cmds/splice.cc b/passes/cmds/splice.cc index 7418ec4d2..bafafca4e 100644 --- a/passes/cmds/splice.cc +++ b/passes/cmds/splice.cc @@ -247,7 +247,7 @@ struct SpliceWorker struct SplicePass : public Pass { SplicePass() : Pass("splice", "create explicit splicing cells") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -288,7 +288,7 @@ struct SplicePass : public Pass { log("by selected wires are rewired.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { bool sel_by_cell = false; bool sel_by_wire = false; diff --git a/passes/cmds/splitnets.cc b/passes/cmds/splitnets.cc index 5e37fc597..f5a1f17b3 100644 --- a/passes/cmds/splitnets.cc +++ b/passes/cmds/splitnets.cc @@ -87,7 +87,7 @@ struct SplitnetsWorker struct SplitnetsPass : public Pass { SplitnetsPass() : Pass("splitnets", "split up multi-bit nets") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -109,7 +109,7 @@ struct SplitnetsPass : public Pass { log(" and split nets so that no driver drives only part of a net.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { bool flag_ports = false; bool flag_driver = false; diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc index f1d958a1a..c8e4f3981 100644 --- a/passes/cmds/stat.cc +++ b/passes/cmds/stat.cc @@ -17,11 +17,10 @@ * */ -#include "kernel/register.h" +#include "kernel/yosys.h" #include "kernel/celltypes.h" #include "passes/techmap/libparse.h" - -#include "kernel/log.h" +#include "kernel/cost.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -37,7 +36,9 @@ struct statdata_t STAT_INT_MEMBERS #undef X double area; + string tech; + std::map<RTLIL::IdString, int> techinfo; std::map<RTLIL::IdString, int, RTLIL::sort_by_id_str> num_cells_by_type; std::set<RTLIL::IdString> unknown_cell_area; @@ -70,8 +71,10 @@ struct statdata_t #undef X } - statdata_t(RTLIL::Design *design, RTLIL::Module *mod, bool width_mode, const dict<IdString, double> &cell_area) + statdata_t(RTLIL::Design *design, RTLIL::Module *mod, bool width_mode, const dict<IdString, double> &cell_area, string techname) { + tech = techname; + #define X(_name) _name = 0; STAT_NUMERIC_MEMBERS #undef X @@ -153,7 +156,8 @@ struct statdata_t log(" Number of processes: %6d\n", num_processes); log(" Number of cells: %6d\n", num_cells); for (auto &it : num_cells_by_type) - log(" %-26s %6d\n", RTLIL::id2cstr(it.first), it.second); + if (it.second) + log(" %-26s %6d\n", RTLIL::id2cstr(it.first), it.second); if (!unknown_cell_area.empty()) { log("\n"); @@ -165,6 +169,81 @@ struct statdata_t log("\n"); log(" Chip area for %smodule '%s': %f\n", (top_mod) ? "top " : "", mod_name.c_str(), area); } + + if (tech == "xilinx") + { + int lut6_cnt = num_cells_by_type["\\LUT6"]; + int lut5_cnt = num_cells_by_type["\\LUT5"]; + int lut4_cnt = num_cells_by_type["\\LUT4"]; + int lut3_cnt = num_cells_by_type["\\LUT3"]; + int lut2_cnt = num_cells_by_type["\\LUT2"]; + int lut1_cnt = num_cells_by_type["\\LUT1"]; + int lc_cnt = 0; + + lc_cnt += lut6_cnt; + + lc_cnt += lut5_cnt; + if (lut1_cnt) { + int cnt = std::min(lut5_cnt, lut1_cnt); + lut5_cnt -= cnt; + lut1_cnt -= cnt; + } + + lc_cnt += lut4_cnt; + if (lut1_cnt) { + int cnt = std::min(lut4_cnt, lut1_cnt); + lut4_cnt -= cnt; + lut1_cnt -= cnt; + } + if (lut2_cnt) { + int cnt = std::min(lut4_cnt, lut2_cnt); + lut4_cnt -= cnt; + lut2_cnt -= cnt; + } + + lc_cnt += lut3_cnt; + if (lut1_cnt) { + int cnt = std::min(lut3_cnt, lut1_cnt); + lut3_cnt -= cnt; + lut1_cnt -= cnt; + } + if (lut2_cnt) { + int cnt = std::min(lut3_cnt, lut2_cnt); + lut3_cnt -= cnt; + lut2_cnt -= cnt; + } + if (lut3_cnt) { + int cnt = (lut3_cnt + 1) / 2; + lut3_cnt -= cnt; + } + + lc_cnt += (lut2_cnt + lut1_cnt + 1) / 2; + + log("\n"); + log(" Estimated number of LCs: %10d\n", lc_cnt); + } + + if (tech == "cmos") + { + int tran_cnt = 0; + bool tran_cnt_exact = true; + auto &gate_costs = CellCosts::cmos_gate_cost(); + + for (auto it : num_cells_by_type) { + auto ctype = it.first; + auto cnum = it.second; + + if (gate_costs.count(ctype)) + tran_cnt += cnum * gate_costs.at(ctype); + else if (ctype.in("$_DFF_P_", "$_DFF_N_")) + tran_cnt += cnum * 16; + else + tran_cnt_exact = false; + } + + log("\n"); + log(" Estimated number of transistors: %10d%s\n", tran_cnt, tran_cnt_exact ? "" : "+"); + } } }; @@ -209,7 +288,7 @@ void read_liberty_cellarea(dict<IdString, double> &cell_area, string liberty_fil struct StatPass : public Pass { StatPass() : Pass("stat", "print some statistics") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -226,12 +305,16 @@ struct StatPass : public Pass { log(" -liberty <liberty_file>\n"); log(" use cell area information from the provided liberty file\n"); log("\n"); + log(" -tech <technology>\n"); + log(" print area estemate for the specified technology. Currently supported\n"); + log(" values for <technology>: xilinx, cmos\n"); + log("\n"); log(" -width\n"); log(" annotate internal cell types with their word width.\n"); log(" e.g. $add_8 for an 8 bit wide $add cell.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Printing statistics.\n"); @@ -239,6 +322,7 @@ struct StatPass : public Pass { RTLIL::Module *top_mod = NULL; std::map<RTLIL::IdString, statdata_t> mod_stat; dict<IdString, double> cell_area; + string techname; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) @@ -253,6 +337,10 @@ struct StatPass : public Pass { read_liberty_cellarea(cell_area, liberty_file); continue; } + if (args[argidx] == "-tech" && argidx+1 < args.size()) { + techname = args[++argidx]; + continue; + } if (args[argidx] == "-top" && argidx+1 < args.size()) { if (design->modules_.count(RTLIL::escape_id(args[argidx+1])) == 0) log_cmd_error("Can't find module %s.\n", args[argidx+1].c_str()); @@ -263,13 +351,16 @@ struct StatPass : public Pass { } extra_args(args, argidx, design); + if (techname != "" && techname != "xilinx" && techname != "cmos") + log_cmd_error("Unsupported technology: '%s'\n", techname.c_str()); + for (auto mod : design->selected_modules()) { if (!top_mod && design->full_selection()) if (mod->get_bool_attribute("\\top")) top_mod = mod; - statdata_t data(design, mod, width_mode, cell_area); + statdata_t data(design, mod, width_mode, cell_area, techname); mod_stat[mod->name] = data; log("\n"); diff --git a/passes/cmds/tee.cc b/passes/cmds/tee.cc index b68c089e9..1a44bdaec 100644 --- a/passes/cmds/tee.cc +++ b/passes/cmds/tee.cc @@ -27,7 +27,7 @@ PRIVATE_NAMESPACE_BEGIN struct TeePass : public Pass { TeePass() : Pass("tee", "redirect command output to file") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -37,7 +37,7 @@ struct TeePass : public Pass { log("specified logfile(s).\n"); log("\n"); log(" -q\n"); - log(" Do not print output to the normal destination (console and/or log file)\n"); + log(" Do not print output to the normal destination (console and/or log file).\n"); log("\n"); log(" -o logfile\n"); log(" Write output to this file, truncate if exists.\n"); @@ -46,13 +46,15 @@ struct TeePass : public Pass { log(" Write output to this file, append if exists.\n"); log("\n"); log(" +INT, -INT\n"); - log(" Add/subract INT from the -v setting for this command.\n"); + log(" Add/subtract INT from the -v setting for this command.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { std::vector<FILE*> backup_log_files, files_to_close; + std::vector<std::ostream*> 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/passes/cmds/torder.cc b/passes/cmds/torder.cc index 56223610d..3c0eac8de 100644 --- a/passes/cmds/torder.cc +++ b/passes/cmds/torder.cc @@ -27,7 +27,7 @@ PRIVATE_NAMESPACE_BEGIN struct TorderPass : public Pass { TorderPass() : Pass("torder", "print cells in topological order") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -43,7 +43,7 @@ struct TorderPass : public Pass { log(" are not used in topological sorting. this option deactivates that.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { bool noautostop = false; dict<IdString, pool<IdString>> stop_db; diff --git a/passes/cmds/trace.cc b/passes/cmds/trace.cc index 1a5f873ff..cf3e46ace 100644 --- a/passes/cmds/trace.cc +++ b/passes/cmds/trace.cc @@ -25,34 +25,34 @@ PRIVATE_NAMESPACE_BEGIN struct TraceMonitor : public RTLIL::Monitor { - virtual void notify_module_add(RTLIL::Module *module) YS_OVERRIDE + void notify_module_add(RTLIL::Module *module) YS_OVERRIDE { log("#TRACE# Module add: %s\n", log_id(module)); } - virtual void notify_module_del(RTLIL::Module *module) YS_OVERRIDE + void notify_module_del(RTLIL::Module *module) YS_OVERRIDE { log("#TRACE# Module delete: %s\n", log_id(module)); } - virtual void notify_connect(RTLIL::Cell *cell, const RTLIL::IdString &port, const RTLIL::SigSpec &old_sig, RTLIL::SigSpec &sig) YS_OVERRIDE + void notify_connect(RTLIL::Cell *cell, const RTLIL::IdString &port, const RTLIL::SigSpec &old_sig, RTLIL::SigSpec &sig) YS_OVERRIDE { log("#TRACE# Cell connect: %s.%s.%s = %s (was: %s)\n", log_id(cell->module), log_id(cell), log_id(port), log_signal(sig), log_signal(old_sig)); } - virtual void notify_connect(RTLIL::Module *module, const RTLIL::SigSig &sigsig) YS_OVERRIDE + void notify_connect(RTLIL::Module *module, const RTLIL::SigSig &sigsig) YS_OVERRIDE { log("#TRACE# Connection in module %s: %s = %s\n", log_id(module), log_signal(sigsig.first), log_signal(sigsig.second)); } - virtual void notify_connect(RTLIL::Module *module, const std::vector<RTLIL::SigSig> &sigsig_vec) YS_OVERRIDE + void notify_connect(RTLIL::Module *module, const std::vector<RTLIL::SigSig> &sigsig_vec) YS_OVERRIDE { log("#TRACE# New connections in module %s:\n", log_id(module)); for (auto &sigsig : sigsig_vec) log("## %s = %s\n", log_signal(sigsig.first), log_signal(sigsig.second)); } - virtual void notify_blackout(RTLIL::Module *module) YS_OVERRIDE + void notify_blackout(RTLIL::Module *module) YS_OVERRIDE { log("#TRACE# Blackout in module %s:\n", log_id(module)); } @@ -60,7 +60,7 @@ struct TraceMonitor : public RTLIL::Monitor struct TracePass : public Pass { TracePass() : Pass("trace", "redirect command output to file") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -70,7 +70,7 @@ struct TracePass : public Pass { log("the design in real time.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) @@ -94,5 +94,38 @@ struct TracePass : public Pass { } } TracePass; -PRIVATE_NAMESPACE_END +struct DebugPass : public Pass { + DebugPass() : Pass("debug", "run command with debug log messages enabled") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" debug cmd\n"); + log("\n"); + log("Execute the specified command with debug log messages enabled\n"); + log("\n"); + } + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + // .. parse options .. + break; + } + + log_force_debug++; + + try { + std::vector<std::string> new_args(args.begin() + argidx, args.end()); + Pass::call(design, new_args); + } catch (...) { + log_force_debug--; + throw; + } + log_force_debug--; + } +} DebugPass; + +PRIVATE_NAMESPACE_END diff --git a/passes/cmds/write_file.cc b/passes/cmds/write_file.cc index 70892a945..64a762d7c 100644 --- a/passes/cmds/write_file.cc +++ b/passes/cmds/write_file.cc @@ -25,7 +25,7 @@ PRIVATE_NAMESPACE_BEGIN struct WriteFileFrontend : public Frontend { WriteFileFrontend() : Frontend("=write_file", "write a text to a file") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -44,7 +44,7 @@ struct WriteFileFrontend : public Frontend { log(" EOT\n"); log("\n"); } - virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design*) + void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design*) YS_OVERRIDE { bool append_mode = false; std::string output_filename; @@ -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/passes/equiv/Makefile.inc b/passes/equiv/Makefile.inc index dd7b3be02..27ea54b22 100644 --- a/passes/equiv/Makefile.inc +++ b/passes/equiv/Makefile.inc @@ -9,4 +9,4 @@ OBJS += passes/equiv/equiv_induct.o OBJS += passes/equiv/equiv_struct.o OBJS += passes/equiv/equiv_purge.o OBJS += passes/equiv/equiv_mark.o - +OBJS += passes/equiv/equiv_opt.o diff --git a/passes/equiv/equiv_add.cc b/passes/equiv/equiv_add.cc index 0494a724f..71599f46e 100644 --- a/passes/equiv/equiv_add.cc +++ b/passes/equiv/equiv_add.cc @@ -25,7 +25,7 @@ PRIVATE_NAMESPACE_BEGIN struct EquivAddPass : public Pass { EquivAddPass() : Pass("equiv_add", "add a $equiv cell") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -39,7 +39,7 @@ struct EquivAddPass : public Pass { log("This command adds $equiv cells for the ports of the specified cells.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, Design *design) + void execute(std::vector<std::string> args, Design *design) YS_OVERRIDE { bool try_mode = false; diff --git a/passes/equiv/equiv_induct.cc b/passes/equiv/equiv_induct.cc index c958c3de4..bcc68d6d2 100644 --- a/passes/equiv/equiv_induct.cc +++ b/passes/equiv/equiv_induct.cc @@ -162,7 +162,7 @@ struct EquivInductWorker struct EquivInductPass : public Pass { EquivInductPass() : Pass("equiv_induct", "proving $equiv cells using temporal induction") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -192,7 +192,7 @@ struct EquivInductPass : public Pass { log("after reset.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, Design *design) + void execute(std::vector<std::string> args, Design *design) YS_OVERRIDE { int success_counter = 0; bool model_undef = false; diff --git a/passes/equiv/equiv_make.cc b/passes/equiv/equiv_make.cc index b20463777..4855ce29e 100644 --- a/passes/equiv/equiv_make.cc +++ b/passes/equiv/equiv_make.cc @@ -40,6 +40,16 @@ struct EquivMakeWorker pool<SigBit> undriven_bits; SigMap assign_map; + dict<SigBit, pool<Cell*>> bit2driven; // map: bit <--> and its driven cells + + CellTypes comb_ct; + + EquivMakeWorker() + { + comb_ct.setup_internals(); + comb_ct.setup_stdcells(); + } + void read_blacklists() { for (auto fn : blacklists) @@ -278,16 +288,31 @@ struct EquivMakeWorker } } + init_bit2driven(); + + pool<Cell*> visited_cells; for (auto c : cells_list) for (auto &conn : c->connections()) if (!ct.cell_output(c->type, conn.first)) { SigSpec old_sig = assign_map(conn.second); SigSpec new_sig = rd_signal_map(old_sig); - if (old_sig != new_sig) { - log("Changing input %s of cell %s (%s): %s -> %s\n", - log_id(conn.first), log_id(c), log_id(c->type), - log_signal(old_sig), log_signal(new_sig)); - c->setPort(conn.first, new_sig); + + if(old_sig != new_sig) { + SigSpec tmp_sig = old_sig; + for (int i = 0; i < GetSize(old_sig); i++) { + SigBit old_bit = old_sig[i], new_bit = new_sig[i]; + + visited_cells.clear(); + if (check_signal_in_fanout(visited_cells, old_bit, new_bit)) + continue; + + log("Changing input %s of cell %s (%s): %s -> %s\n", + log_id(conn.first), log_id(c), log_id(c->type), + log_signal(old_bit), log_signal(new_bit)); + + tmp_sig[i] = new_bit; + } + c->setPort(conn.first, tmp_sig); } } @@ -378,6 +403,57 @@ struct EquivMakeWorker } } + void init_bit2driven() + { + for (auto cell : equiv_mod->cells()) { + if (!ct.cell_known(cell->type) && !cell->type.in("$dff", "$_DFF_P_", "$_DFF_N_", "$ff", "$_FF_")) + continue; + for (auto &conn : cell->connections()) + { + if (yosys_celltypes.cell_input(cell->type, conn.first)) + for (auto bit : assign_map(conn.second)) + { + bit2driven[bit].insert(cell); + } + } + } + } + + bool check_signal_in_fanout(pool<Cell*> & visited_cells, SigBit source_bit, SigBit target_bit) + { + if (source_bit == target_bit) + return true; + + if (bit2driven.count(source_bit) == 0) + return false; + + auto driven_cells = bit2driven.at(source_bit); + for (auto driven_cell: driven_cells) + { + bool is_comb = comb_ct.cell_known(driven_cell->type); + if (!is_comb) + continue; + + if (visited_cells.count(driven_cell) > 0) + continue; + visited_cells.insert(driven_cell); + + for (auto &conn: driven_cell->connections()) + { + if (yosys_celltypes.cell_input(driven_cell->type, conn.first)) + continue; + + for (auto bit: conn.second) { + bool is_in_fanout = check_signal_in_fanout(visited_cells, bit, target_bit); + if (is_in_fanout == true) + return true; + } + } + } + + return false; + } + void run() { copy_to_equiv(); @@ -390,7 +466,7 @@ struct EquivMakeWorker struct EquivMakePass : public Pass { EquivMakePass() : Pass("equiv_make", "prepare a circuit for equivalence checking") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -415,7 +491,7 @@ struct EquivMakePass : public Pass { log("checking problem. Use 'miter -equiv' if you want to create a miter circuit.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { EquivMakeWorker worker; worker.ct.setup(design); @@ -456,10 +532,10 @@ struct EquivMakePass : public Pass { log_cmd_error("Equiv module %s already exists.\n", args[argidx+2].c_str()); if (worker.gold_mod->has_memories() || worker.gold_mod->has_processes()) - log_cmd_error("Gold module contains memories or procresses. Run 'memory' or 'proc' respectively.\n"); + log_cmd_error("Gold module contains memories or processes. Run 'memory' or 'proc' respectively.\n"); if (worker.gate_mod->has_memories() || worker.gate_mod->has_processes()) - log_cmd_error("Gate module contains memories or procresses. Run 'memory' or 'proc' respectively.\n"); + log_cmd_error("Gate module contains memories or processes. Run 'memory' or 'proc' respectively.\n"); worker.read_blacklists(); worker.read_encfiles(); diff --git a/passes/equiv/equiv_mark.cc b/passes/equiv/equiv_mark.cc index 22c501763..135eaf145 100644 --- a/passes/equiv/equiv_mark.cc +++ b/passes/equiv/equiv_mark.cc @@ -204,7 +204,7 @@ struct EquivMarkWorker struct EquivMarkPass : public Pass { EquivMarkPass() : Pass("equiv_mark", "mark equivalence checking regions") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -216,7 +216,7 @@ struct EquivMarkPass : public Pass { log("wires and cells.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, Design *design) + void execute(std::vector<std::string> args, Design *design) YS_OVERRIDE { log_header(design, "Executing EQUIV_MARK pass.\n"); diff --git a/passes/equiv/equiv_miter.cc b/passes/equiv/equiv_miter.cc index eb2e5a171..e06f9515b 100644 --- a/passes/equiv/equiv_miter.cc +++ b/passes/equiv/equiv_miter.cc @@ -261,7 +261,7 @@ struct EquivMiterWorker struct EquivMiterPass : public Pass { EquivMiterPass() : Pass("equiv_miter", "extract miter from equiv circuit") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -282,7 +282,7 @@ struct EquivMiterPass : public Pass { log(" Create compare logic that handles undefs correctly\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { EquivMiterWorker worker; worker.ct.setup(design); diff --git a/passes/equiv/equiv_opt.cc b/passes/equiv/equiv_opt.cc new file mode 100644 index 000000000..d4c7f7953 --- /dev/null +++ b/passes/equiv/equiv_opt.cc @@ -0,0 +1,180 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2018 whitequark <whitequark@whitequark.org> + * + * 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/register.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct EquivOptPass:public ScriptPass +{ + EquivOptPass() : ScriptPass("equiv_opt", "prove equivalence for optimized circuit") { } + + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" equiv_opt [options] [command]\n"); + log("\n"); + log("This command checks circuit equivalence before and after an optimization pass.\n"); + log("\n"); + log(" -run <from_label>:<to_label>\n"); + log(" only run the commands between the labels (see below). an empty\n"); + log(" from label is synonymous to the start of the command list, and empty to\n"); + log(" label is synonymous to the end of the command list.\n"); + log("\n"); + log(" -map <filename>\n"); + log(" expand the modules in this file before proving equivalence. this is\n"); + log(" useful for handling architecture-specific primitives.\n"); + log("\n"); + log(" -assert\n"); + log(" produce an error if the circuits are not equivalent.\n"); + log("\n"); + log(" -multiclock\n"); + log(" run clk2fflogic before equivalence checking.\n"); + log("\n"); + log(" -undef\n"); + log(" enable modelling of undef states during equiv_induct.\n"); + log("\n"); + log("The following commands are executed by this verification command:\n"); + help_script(); + log("\n"); + } + + std::string command, techmap_opts; + bool assert, undef, multiclock; + + void clear_flags() YS_OVERRIDE + { + command = ""; + techmap_opts = ""; + assert = false; + undef = false; + multiclock = false; + } + + void execute(std::vector < std::string > args, RTLIL::Design * design) YS_OVERRIDE + { + string run_from, run_to; + clear_flags(); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + if (args[argidx] == "-run" && argidx + 1 < args.size()) { + size_t pos = args[argidx + 1].find(':'); + if (pos == std::string::npos) + break; + run_from = args[++argidx].substr(0, pos); + run_to = args[argidx].substr(pos + 1); + continue; + } + if (args[argidx] == "-map" && argidx + 1 < args.size()) { + techmap_opts += " -map " + args[++argidx]; + continue; + } + if (args[argidx] == "-assert") { + assert = true; + continue; + } + if (args[argidx] == "-undef") { + undef = true; + continue; + } + if (args[argidx] == "-multiclock") { + multiclock = true; + continue; + } + break; + } + + for (; argidx < args.size(); argidx++) { + if (command.empty()) { + if (args[argidx].compare(0, 1, "-") == 0) + cmd_error(args, argidx, "Unknown option."); + } else { + command += " "; + } + command += args[argidx]; + } + + if (command.empty()) + log_cmd_error("No optimization pass specified!\n"); + + if (!design->full_selection()) + log_cmd_error("This command only operates on fully selected designs!\n"); + + log_header(design, "Executing EQUIV_OPT pass.\n"); + log_push(); + + run_script(design, run_from, run_to); + + log_pop(); + } + + void script() YS_OVERRIDE + { + if (check_label("run_pass")) { + run("hierarchy -auto-top"); + run("design -save preopt"); + if (help_mode) + run("[command]"); + else + run(command); + run("design -stash postopt"); + } + + if (check_label("prepare")) { + run("design -copy-from preopt -as gold A:top"); + run("design -copy-from postopt -as gate A:top"); + } + + if ((!techmap_opts.empty() || help_mode) && check_label("techmap", "(only with -map)")) { + string opts; + if (help_mode) + opts = " -map <filename> ..."; + else + opts = techmap_opts; + run("techmap -wb -D EQUIV -autoproc" + opts); + } + + if (check_label("prove")) { + if (multiclock || help_mode) + run("clk2fflogic", "(only with -multiclock)"); + run("equiv_make gold gate equiv"); + if (help_mode) + run("equiv_induct [-undef] equiv"); + else if (undef) + run("equiv_induct -undef equiv"); + else + run("equiv_induct equiv"); + if (help_mode) + run("equiv_status [-assert] equiv"); + else if (assert) + run("equiv_status -assert equiv"); + else + run("equiv_status equiv"); + } + + if (check_label("restore")) { + run("design -load preopt"); + } + } +} EquivOptPass; + +PRIVATE_NAMESPACE_END diff --git a/passes/equiv/equiv_purge.cc b/passes/equiv/equiv_purge.cc index f8d3cd0af..18b3e7d36 100644 --- a/passes/equiv/equiv_purge.cc +++ b/passes/equiv/equiv_purge.cc @@ -176,7 +176,7 @@ struct EquivPurgeWorker struct EquivPurgePass : public Pass { EquivPurgePass() : Pass("equiv_purge", "purge equivalence checking module") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -187,7 +187,7 @@ struct EquivPurgePass : public Pass { log("ports as needed.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, Design *design) + void execute(std::vector<std::string> args, Design *design) YS_OVERRIDE { log_header(design, "Executing EQUIV_PURGE pass.\n"); diff --git a/passes/equiv/equiv_remove.cc b/passes/equiv/equiv_remove.cc index 770497a51..c5c28c7d9 100644 --- a/passes/equiv/equiv_remove.cc +++ b/passes/equiv/equiv_remove.cc @@ -24,7 +24,7 @@ PRIVATE_NAMESPACE_BEGIN struct EquivRemovePass : public Pass { EquivRemovePass() : Pass("equiv_remove", "remove $equiv cells") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -40,7 +40,7 @@ struct EquivRemovePass : public Pass { log(" keep gate circuit\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, Design *design) + void execute(std::vector<std::string> args, Design *design) YS_OVERRIDE { bool mode_gold = false; bool mode_gate = false; diff --git a/passes/equiv/equiv_simple.cc b/passes/equiv/equiv_simple.cc index e69e17ac6..c2fab26f2 100644 --- a/passes/equiv/equiv_simple.cc +++ b/passes/equiv/equiv_simple.cc @@ -273,7 +273,7 @@ struct EquivSimpleWorker struct EquivSimplePass : public Pass { EquivSimplePass() : Pass("equiv_simple", "try proving simple $equiv instances") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -298,7 +298,7 @@ struct EquivSimplePass : public Pass { log(" the max. number of time steps to be considered (default = 1)\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, Design *design) + void execute(std::vector<std::string> args, Design *design) YS_OVERRIDE { bool verbose = false, short_cones = false, model_undef = false, nogroup = false; int success_counter = 0; diff --git a/passes/equiv/equiv_status.cc b/passes/equiv/equiv_status.cc index 7b9230b35..b4a93ccf5 100644 --- a/passes/equiv/equiv_status.cc +++ b/passes/equiv/equiv_status.cc @@ -24,7 +24,7 @@ PRIVATE_NAMESPACE_BEGIN struct EquivStatusPass : public Pass { EquivStatusPass() : Pass("equiv_status", "print status of equivalent checking module") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -36,7 +36,7 @@ struct EquivStatusPass : public Pass { log(" produce an error if any unproven $equiv cell is found\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, Design *design) + void execute(std::vector<std::string> args, Design *design) YS_OVERRIDE { bool assert_mode = false; int unproven_count = 0; diff --git a/passes/equiv/equiv_struct.cc b/passes/equiv/equiv_struct.cc index c4ced6a71..6672948b9 100644 --- a/passes/equiv/equiv_struct.cc +++ b/passes/equiv/equiv_struct.cc @@ -215,9 +215,9 @@ struct EquivStructWorker if (c != nullptr) { string n = cell_name.str(); cells_type = c->type; - if (GetSize(n) > 5 && n.substr(GetSize(n)-5) == "_gold") + if (GetSize(n) > 5 && n.compare(GetSize(n)-5, std::string::npos, "_gold") == 0) gold_cells.push_back(c); - else if (GetSize(n) > 5 && n.substr(GetSize(n)-5) == "_gate") + else if (GetSize(n) > 5 && n.compare(GetSize(n)-5, std::string::npos, "_gate") == 0) gate_cells.push_back(c); else other_cells.push_back(c); @@ -283,7 +283,7 @@ struct EquivStructWorker struct EquivStructPass : public Pass { EquivStructPass() : Pass("equiv_struct", "structural equivalence checking") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -314,7 +314,7 @@ struct EquivStructPass : public Pass { log(" maximum number of iterations to run before aborting\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, Design *design) + void execute(std::vector<std::string> args, Design *design) YS_OVERRIDE { pool<IdString> fwonly_cells({ "$equiv" }); bool mode_icells = false; diff --git a/passes/fsm/fsm.cc b/passes/fsm/fsm.cc index 997558b85..c5cb338ab 100644 --- a/passes/fsm/fsm.cc +++ b/passes/fsm/fsm.cc @@ -27,7 +27,7 @@ PRIVATE_NAMESPACE_BEGIN struct FsmPass : public Pass { FsmPass() : Pass("fsm", "extract and optimize finite state machines") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -68,7 +68,7 @@ struct FsmPass : public Pass { log(" passed through to fsm_recode pass\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { bool flag_nomap = false; bool flag_norecode = false; diff --git a/passes/fsm/fsm_detect.cc b/passes/fsm/fsm_detect.cc index 9fb5446e7..5ae991b28 100644 --- a/passes/fsm/fsm_detect.cc +++ b/passes/fsm/fsm_detect.cc @@ -196,13 +196,13 @@ static void detect_fsm(RTLIL::Wire *wire) vector<string> warnings; if (is_module_port) - warnings.push_back("Forcing fsm recoding on module port might result in larger circuit.\n"); + warnings.push_back("Forcing FSM recoding on module port might result in larger circuit.\n"); if (!looks_like_good_state_reg) - warnings.push_back("Users of state reg look like fsm recoding might result in larger circuit.\n"); + warnings.push_back("Users of state reg look like FSM recoding might result in larger circuit.\n"); if (has_init_attr) - warnings.push_back("Init value on fsm state registers are ignored. Possible simulation-synthesis mismatch!"); + warnings.push_back("Initialization value on FSM state register is ignored. Possible simulation-synthesis mismatch!\n"); if (!looks_like_state_reg) warnings.push_back("Doesn't look like a proper FSM. Possible simulation-synthesis mismatch!\n"); @@ -236,7 +236,7 @@ static void detect_fsm(RTLIL::Wire *wire) log(" Users of register don't seem to benefit from recoding.\n"); if (has_init_attr) - log(" Register has an initialization value."); + log(" Register has an initialization value.\n"); if (is_self_resetting) log(" Circuit seems to be self-resetting.\n"); @@ -245,7 +245,7 @@ static void detect_fsm(RTLIL::Wire *wire) struct FsmDetectPass : public Pass { FsmDetectPass() : Pass("fsm_detect", "finding FSMs in design") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -261,7 +261,7 @@ struct FsmDetectPass : public Pass { log("'fsm_encoding' attribute to \"none\".\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing FSM_DETECT pass (finding FSMs in design).\n"); extra_args(args, 1, design); diff --git a/passes/fsm/fsm_expand.cc b/passes/fsm/fsm_expand.cc index 2c344a1c1..1610ec751 100644 --- a/passes/fsm/fsm_expand.cc +++ b/passes/fsm/fsm_expand.cc @@ -50,7 +50,7 @@ struct FsmExpand if (full_mode || cell->type == "$_MUX_") return true; - if (cell->type == "$mux" || cell->type == "$pmux") + if (cell->type.in("$mux", "$pmux")) if (cell->getPort("\\A").size() < 2) return true; @@ -265,7 +265,7 @@ struct FsmExpand struct FsmExpandPass : public Pass { FsmExpandPass() : Pass("fsm_expand", "expand FSM cells by merging logic into it") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -279,7 +279,7 @@ struct FsmExpandPass : public Pass { log("word-wide cells. Call with -full to consider all cells for merging.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { bool full_mode = false; diff --git a/passes/fsm/fsm_export.cc b/passes/fsm/fsm_export.cc index 1cbfcfae8..8eb1872f0 100644 --- a/passes/fsm/fsm_export.cc +++ b/passes/fsm/fsm_export.cc @@ -120,7 +120,7 @@ void write_kiss2(struct RTLIL::Module *module, struct RTLIL::Cell *cell, std::st */ struct FsmExportPass : public Pass { FsmExportPass() : Pass("fsm_export", "exporting FSMs to KISS2 files") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -143,7 +143,7 @@ struct FsmExportPass : public Pass { log(" use binary state encoding as state names instead of s0, s1, ...\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { dict<RTLIL::IdString, RTLIL::Const>::iterator attr_it; std::string arg; diff --git a/passes/fsm/fsm_extract.cc b/passes/fsm/fsm_extract.cc index 8a4ee3f26..a85c3bec0 100644 --- a/passes/fsm/fsm_extract.cc +++ b/passes/fsm/fsm_extract.cc @@ -168,7 +168,7 @@ undef_bit_in_next_state: ctrl_in_bit_indices[ctrl_in[i]] = i; for (auto &it : ctrl_in_bit_indices) - if (tr.ctrl_in.bits.at(it.second) == RTLIL::S1 && exclusive_ctrls.count(it.first) != 0) + if (tr.ctrl_in.bits.at(it.second) == State::S1 && exclusive_ctrls.count(it.first) != 0) for (auto &dc_bit : exclusive_ctrls.at(it.first)) if (ctrl_in_bit_indices.count(dc_bit)) tr.ctrl_in.bits.at(ctrl_in_bit_indices.at(dc_bit)) = RTLIL::State::Sa; @@ -178,7 +178,7 @@ undef_bit_in_next_state: log_state_in = fsm_data.state_table.at(state_in); if (states.count(ce.values_map(ce.assign_map(dff_in)).as_const()) == 0) { - log(" transition: %10s %s -> INVALID_STATE(%s) %s <ignored invalid transistion!>%s\n", + log(" transition: %10s %s -> INVALID_STATE(%s) %s <ignored invalid transition!>%s\n", log_signal(log_state_in), log_signal(tr.ctrl_in), log_signal(ce.values_map(ce.assign_map(dff_in))), log_signal(tr.ctrl_out), undef_bit_in_next_state_mode ? " SHORTENED" : ""); @@ -194,7 +194,7 @@ undef_bit_in_next_state: log_signal(log_state_in), log_signal(tr.ctrl_in), log_signal(fsm_data.state_table[tr.state_out]), log_signal(tr.ctrl_out)); } else { - log(" transition: %10s %s -> %10s %s <ignored undef transistion!>\n", + log(" transition: %10s %s -> %10s %s <ignored undef transition!>\n", log_signal(log_state_in), log_signal(tr.ctrl_in), log_signal(fsm_data.state_table[tr.state_out]), log_signal(tr.ctrl_out)); } @@ -216,13 +216,13 @@ undef_bit_in_next_state: ce.push(); dont_care.append(undef); ce.set(undef, constval.as_const()); - if (exclusive_ctrls.count(undef) && constval == RTLIL::S1) + if (exclusive_ctrls.count(undef) && constval == State::S1) for (auto &bit : exclusive_ctrls.at(undef)) { RTLIL::SigSpec bitval = bit; - if (ce.eval(bitval) && bitval != RTLIL::S0) + if (ce.eval(bitval) && bitval != State::S0) goto found_contradiction_1; else - ce.set(bit, RTLIL::S0); + ce.set(bit, State::S0); } find_transitions(ce, ce_nostop, fsm_data, states, state_in, ctrl_in, ctrl_out, dff_in, dont_care); found_contradiction_1: @@ -231,21 +231,21 @@ undef_bit_in_next_state: else { ce.push(), ce_nostop.push(); - ce.set(undef, RTLIL::S0); - ce_nostop.set(undef, RTLIL::S0); + ce.set(undef, State::S0); + ce_nostop.set(undef, State::S0); find_transitions(ce, ce_nostop, fsm_data, states, state_in, ctrl_in, ctrl_out, dff_in, dont_care); ce.pop(), ce_nostop.pop(); ce.push(), ce_nostop.push(); - ce.set(undef, RTLIL::S1); - ce_nostop.set(undef, RTLIL::S1); + ce.set(undef, State::S1); + ce_nostop.set(undef, State::S1); if (exclusive_ctrls.count(undef)) for (auto &bit : exclusive_ctrls.at(undef)) { RTLIL::SigSpec bitval = bit; - if ((ce.eval(bitval) || ce_nostop.eval(bitval)) && bitval != RTLIL::S0) + if ((ce.eval(bitval) || ce_nostop.eval(bitval)) && bitval != State::S0) goto found_contradiction_2; else - ce.set(bit, RTLIL::S0), ce_nostop.set(bit, RTLIL::S0); + ce.set(bit, State::S0), ce_nostop.set(bit, RTLIL::S0); } find_transitions(ce, ce_nostop, fsm_data, states, state_in, ctrl_in, ctrl_out, dff_in, dont_care); found_contradiction_2: @@ -263,8 +263,8 @@ static void extract_fsm(RTLIL::Wire *wire) RTLIL::SigSpec dff_in(RTLIL::State::Sm, wire->width); RTLIL::Const reset_state(RTLIL::State::Sx, wire->width); - RTLIL::SigSpec clk = RTLIL::S0; - RTLIL::SigSpec arst = RTLIL::S0; + RTLIL::SigSpec clk = State::S0; + RTLIL::SigSpec arst = State::S0; bool clk_polarity = true; bool arst_polarity = true; @@ -371,8 +371,8 @@ static void extract_fsm(RTLIL::Wire *wire) RTLIL::Cell *fsm_cell = module->addCell(stringf("$fsm$%s$%d", wire->name.c_str(), autoidx++), "$fsm"); fsm_cell->setPort("\\CLK", clk); fsm_cell->setPort("\\ARST", arst); - fsm_cell->parameters["\\CLK_POLARITY"] = clk_polarity ? RTLIL::S1 : RTLIL::S0; - fsm_cell->parameters["\\ARST_POLARITY"] = arst_polarity ? RTLIL::S1 : RTLIL::S0; + fsm_cell->parameters["\\CLK_POLARITY"] = clk_polarity ? State::S1 : State::S0; + fsm_cell->parameters["\\ARST_POLARITY"] = arst_polarity ? State::S1 : State::S0; fsm_cell->setPort("\\CTRL_IN", ctrl_in); fsm_cell->setPort("\\CTRL_OUT", ctrl_out); fsm_cell->parameters["\\NAME"] = RTLIL::Const(wire->name.str()); @@ -401,7 +401,7 @@ static void extract_fsm(RTLIL::Wire *wire) struct FsmExtractPass : public Pass { FsmExtractPass() : Pass("fsm_extract", "extracting FSMs in design") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -417,7 +417,7 @@ struct FsmExtractPass : public Pass { log("'opt_clean' pass to eliminate this signal.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing FSM_EXTRACT pass (extracting FSM from design).\n"); extra_args(args, 1, design); diff --git a/passes/fsm/fsm_info.cc b/passes/fsm/fsm_info.cc index 2cc1a7d53..0548259ee 100644 --- a/passes/fsm/fsm_info.cc +++ b/passes/fsm/fsm_info.cc @@ -30,7 +30,7 @@ PRIVATE_NAMESPACE_BEGIN struct FsmInfoPass : public Pass { FsmInfoPass() : Pass("fsm_info", "print information on finite state machines") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -41,7 +41,7 @@ struct FsmInfoPass : public Pass { log("pass so that this information is included in the synthesis log file.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing FSM_INFO pass (dumping all available information on FSM cells).\n"); extra_args(args, 1, design); diff --git a/passes/fsm/fsm_map.cc b/passes/fsm/fsm_map.cc index 3edaf84d2..80913fda8 100644 --- a/passes/fsm/fsm_map.cc +++ b/passes/fsm/fsm_map.cc @@ -133,7 +133,7 @@ static void implement_pattern_cache(RTLIL::Module *module, std::map<RTLIL::Const cases_vector.append(and_sig); break; case 0: - cases_vector.append(RTLIL::SigSpec(1, 1)); + cases_vector.append(State::S1); break; default: log_abort(); @@ -150,7 +150,7 @@ static void implement_pattern_cache(RTLIL::Module *module, std::map<RTLIL::Const } else if (cases_vector.size() == 1) { module->connect(RTLIL::SigSig(output, cases_vector)); } else { - module->connect(RTLIL::SigSig(output, RTLIL::SigSpec(0, 1))); + module->connect(RTLIL::SigSig(output, State::S0)); } } @@ -322,7 +322,7 @@ static void map_fsm(RTLIL::Cell *fsm_cell, RTLIL::Module *module) struct FsmMapPass : public Pass { FsmMapPass() : Pass("fsm_map", "mapping FSMs to basic logic") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -331,7 +331,7 @@ struct FsmMapPass : public Pass { log("This pass translates FSM cells to flip-flops and logic.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing FSM_MAP pass (mapping FSMs to basic logic).\n"); extra_args(args, 1, design); diff --git a/passes/fsm/fsm_opt.cc b/passes/fsm/fsm_opt.cc index 5b1da44fc..048daee55 100644 --- a/passes/fsm/fsm_opt.cc +++ b/passes/fsm/fsm_opt.cc @@ -72,7 +72,8 @@ struct FsmOpt new_transition_table.swap(fsm_data.transition_table); new_state_table.swap(fsm_data.state_table); - fsm_data.reset_state = old_to_new_state.at(fsm_data.reset_state); + if (fsm_data.reset_state != -1) + fsm_data.reset_state = old_to_new_state.at(fsm_data.reset_state); } } @@ -323,7 +324,7 @@ PRIVATE_NAMESPACE_BEGIN struct FsmOptPass : public Pass { FsmOptPass() : Pass("fsm_opt", "optimize finite state machines") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -334,7 +335,7 @@ struct FsmOptPass : public Pass { log("combination with the 'opt_clean' pass (see also 'help fsm').\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing FSM_OPT pass (simple optimizations of FSMs).\n"); extra_args(args, 1, design); diff --git a/passes/fsm/fsm_recode.cc b/passes/fsm/fsm_recode.cc index e1bde728f..fa1ff48cc 100644 --- a/passes/fsm/fsm_recode.cc +++ b/passes/fsm/fsm_recode.cc @@ -126,7 +126,7 @@ static void fsm_recode(RTLIL::Cell *cell, RTLIL::Module *module, FILE *fm_set_fs struct FsmRecodePass : public Pass { FsmRecodePass() : Pass("fsm_recode", "recoding finite state machines") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -151,7 +151,7 @@ struct FsmRecodePass : public Pass { log(" .map <old_bitpattern> <new_bitpattern>\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { FILE *fm_set_fsm_file = NULL; FILE *encfile = NULL; diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc index e61851481..d8a628448 100644 --- a/passes/hierarchy/hierarchy.cc +++ b/passes/hierarchy/hierarchy.cc @@ -2,6 +2,7 @@ * yosys -- Yosys Open SYnthesis Suite * * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * Copyright (C) 2018 Ruben Undheim <ruben.undheim@gmail.com> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -47,7 +48,7 @@ void generate(RTLIL::Design *design, const std::vector<std::string> &celltypes, RTLIL::Cell *cell = i2.second; if (design->has(cell->type)) continue; - if (cell->type.substr(0, 1) == "$" && cell->type.substr(0, 3) != "$__") + if (cell->type.begins_with("$__")) continue; for (auto &pattern : celltypes) if (patmatch(pattern.c_str(), RTLIL::unescape_id(cell->type).c_str())) @@ -139,25 +140,73 @@ void generate(RTLIL::Design *design, const std::vector<std::string> &celltypes, } } +// Return the "basic" type for an array item. +std::string basic_cell_type(const std::string celltype, int pos[3] = nullptr) { + std::string basicType = celltype; + if (celltype.compare(0, strlen("$array:"), "$array:") == 0) { + int pos_idx = celltype.find_first_of(':'); + int pos_num = celltype.find_first_of(':', pos_idx + 1); + int pos_type = celltype.find_first_of(':', pos_num + 1); + basicType = celltype.substr(pos_type + 1); + if (pos != nullptr) { + pos[0] = pos_idx; + pos[1] = pos_num; + pos[2] = pos_type; + } + } + return basicType; +} + bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check, bool flag_simcheck, std::vector<std::string> &libdirs) { bool did_something = false; std::map<RTLIL::Cell*, std::pair<int, int>> array_cells; std::string filename; + bool has_interface_ports = false; + + // If any of the ports are actually interface ports, we will always need to + // reprocess the module: + if(!module->get_bool_attribute("\\interfaces_replaced_in_module")) { + for (auto &wire : module->wires_) { + if ((wire.second->port_input || wire.second->port_output) && wire.second->get_bool_attribute("\\is_interface")) + has_interface_ports = true; + } + } + + // Always keep track of all derived interfaces available in the current module in 'interfaces_in_module': + dict<RTLIL::IdString, RTLIL::Module*> interfaces_in_module; for (auto &cell_it : module->cells_) { RTLIL::Cell *cell = cell_it.second; + if(cell->get_bool_attribute("\\is_interface")) { + RTLIL::Module *intf_module = design->modules_[cell->type]; + interfaces_in_module[cell->name] = intf_module; + } + } - if (cell->type.substr(0, 7) == "$array:") { - int pos_idx = cell->type.str().find_first_of(':'); - int pos_num = cell->type.str().find_first_of(':', pos_idx + 1); - int pos_type = cell->type.str().find_first_of(':', pos_num + 1); - int idx = atoi(cell->type.str().substr(pos_idx + 1, pos_num).c_str()); - int num = atoi(cell->type.str().substr(pos_num + 1, pos_type).c_str()); + for (auto &cell_it : module->cells_) + { + RTLIL::Cell *cell = cell_it.second; + bool has_interfaces_not_found = false; + + std::vector<RTLIL::IdString> connections_to_remove; + std::vector<RTLIL::IdString> connections_to_add_name; + std::vector<RTLIL::SigSpec> connections_to_add_signal; + + if (cell->type.begins_with("$array:")) { + int pos[3]; + basic_cell_type(cell->type.str(), pos); + int pos_idx = pos[0]; + int pos_num = pos[1]; + int pos_type = pos[2]; + int idx = atoi(cell->type.substr(pos_idx + 1, pos_num).c_str()); + int num = atoi(cell->type.substr(pos_num + 1, pos_type).c_str()); array_cells[cell] = std::pair<int, int>(idx, num); - cell->type = cell->type.str().substr(pos_type + 1); + cell->type = cell->type.substr(pos_type + 1); } + dict<RTLIL::IdString, RTLIL::Module*> interfaces_to_add_to_submodule; + dict<RTLIL::IdString, RTLIL::IdString> modports_used_in_submodule; if (design->modules_.count(cell->type) == 0) { @@ -200,11 +249,85 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check if (design->modules_.count(cell->type) == 0) log_error("File `%s' from libdir does not declare module `%s'.\n", filename.c_str(), cell->type.c_str()); did_something = true; - } else + } else { + + RTLIL::Module *mod = design->module(cell->type); + + // Go over all connections and see if any of them are SV interfaces. If they are, then add the replacements to + // some lists, so that the ports for sub-modules can be replaced further down: + for (auto &conn : cell->connections()) { + if(mod->wires_.count(conn.first) != 0 && mod->wire(conn.first)->get_bool_attribute("\\is_interface")) { // Check if the connection is present as an interface in the sub-module's port list + //const pool<string> &interface_type_pool = mod->wire(conn.first)->get_strpool_attribute("\\interface_type"); + //for (auto &d : interface_type_pool) { // TODO: Compare interface type to type in parent module (not crucially important, but good for robustness) + //} + + // Find if the sub-module has set a modport for the current interface connection: + const pool<string> &interface_modport_pool = mod->wire(conn.first)->get_strpool_attribute("\\interface_modport"); + std::string interface_modport = ""; + for (auto &d : interface_modport_pool) { + interface_modport = "\\" + d; + } + if(conn.second.bits().size() == 1 && conn.second.bits()[0].wire->get_bool_attribute("\\is_interface")) { // Check if the connected wire is a potential interface in the parent module + std::string interface_name_str = conn.second.bits()[0].wire->name.str(); + interface_name_str.replace(0,23,""); // Strip the prefix '$dummywireforinterface' from the dummy wire to get the name + interface_name_str = "\\" + interface_name_str; + RTLIL::IdString interface_name = interface_name_str; + bool not_found_interface = false; + if(module->get_bool_attribute("\\interfaces_replaced_in_module")) { // If 'interfaces' in the cell have not be been handled yet, there is no need to derive the sub-module either + // Check if the interface instance is present in module: + // Interface instances may either have the plain name or the name appended with '_inst_from_top_dummy'. + // Check for both of them here + int nexactmatch = interfaces_in_module.count(interface_name) > 0; + std::string interface_name_str2 = interface_name_str + "_inst_from_top_dummy"; + RTLIL::IdString interface_name2 = interface_name_str2; + int nmatch2 = interfaces_in_module.count(interface_name2) > 0; + if (nexactmatch > 0 || nmatch2 > 0) { + if (nexactmatch != 0) // Choose the one with the plain name if it exists + interface_name2 = interface_name; + RTLIL::Module *mod_replace_ports = interfaces_in_module.at(interface_name2); + for (auto &mod_wire : mod_replace_ports->wires_) { // Go over all wires in interface, and add replacements to lists. + std::string signal_name1 = conn.first.str() + "." + log_id(mod_wire.first); + std::string signal_name2 = interface_name.str() + "." + log_id(mod_wire.first); + connections_to_add_name.push_back(RTLIL::IdString(signal_name1)); + if(module->wires_.count(signal_name2) == 0) { + log_error("Could not find signal '%s' in '%s'\n", signal_name2.c_str(), log_id(module->name)); + } + else { + RTLIL::Wire *wire_in_parent = module->wire(signal_name2); + connections_to_add_signal.push_back(wire_in_parent); + } + } + connections_to_remove.push_back(conn.first); + interfaces_to_add_to_submodule[conn.first] = interfaces_in_module.at(interface_name2); + + // Add modports to a dict which will be passed to AstModule::derive + if (interface_modport != "") { + modports_used_in_submodule[conn.first] = interface_modport; + } + } + else not_found_interface = true; + } + else not_found_interface = true; + // If the interface instance has not already been derived in the module, we cannot complete at this stage. Set "has_interfaces_not_found" + // which will delay the expansion of this cell: + if (not_found_interface) { + // If we have already gone over all cells in this module, and the interface has still not been found - flag it as an error: + if(!(module->get_bool_attribute("\\cells_not_processed"))) { + log_warning("Could not find interface instance for `%s' in `%s'\n", log_id(interface_name), log_id(module)); + } + else { + // Only set has_interfaces_not_found if it would be possible to find them, since otherwiser we will end up in an infinite loop: + has_interfaces_not_found = true; + } + } + } + } + } + // + if (flag_check || flag_simcheck) { - RTLIL::Module *mod = design->module(cell->type); - for (auto &conn : cell->connections()) + for (auto &conn : cell->connections()) { if (conn.first[0] == '$' && '0' <= conn.first[1] && conn.first[1] <= '9') { int id = atoi(conn.first.c_str()+1); if (id <= 0 || id > GetSize(mod->ports)) @@ -213,28 +336,79 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check } else if (mod->wire(conn.first) == nullptr || mod->wire(conn.first)->port_id == 0) log_error("Module `%s' referenced in module `%s' in cell `%s' does not have a port named '%s'.\n", log_id(cell->type), log_id(module), log_id(cell), log_id(conn.first)); + } for (auto ¶m : cell->parameters) if (mod->avail_parameters.count(param.first) == 0 && param.first[0] != '$' && strchr(param.first.c_str(), '.') == NULL) log_error("Module `%s' referenced in module `%s' in cell `%s' does not have a parameter named '%s'.\n", log_id(cell->type), log_id(module), log_id(cell), log_id(param.first)); + } + } + RTLIL::Module *mod = design->modules_[cell->type]; - if (design->modules_.at(cell->type)->get_bool_attribute("\\blackbox")) { + if (design->modules_.at(cell->type)->get_blackbox_attribute()) { if (flag_simcheck) - log_error("Module `%s' referenced in module `%s' in cell `%s' is a blackbox module.\n", + log_error("Module `%s' referenced in module `%s' in cell `%s' is a blackbox/whitebox module.\n", cell->type.c_str(), module->name.c_str(), cell->name.c_str()); continue; } - if (cell->parameters.size() == 0) + // If interface instances not yet found, skip cell for now, and say we did something, so that we will return back here: + if(has_interfaces_not_found) { + did_something = true; // waiting for interfaces to be handled continue; + } - RTLIL::Module *mod = design->modules_[cell->type]; - cell->type = mod->derive(design, cell->parameters); + // Do the actual replacements of the SV interface port connection with the individual signal connections: + for(unsigned int i=0;i<connections_to_add_name.size();i++) { + cell->connections_[connections_to_add_name[i]] = connections_to_add_signal[i]; + } + // Remove the connection for the interface itself: + for(unsigned int i=0;i<connections_to_remove.size();i++) { + cell->connections_.erase(connections_to_remove[i]); + } + + // If there are no overridden parameters AND not interfaces, then we can use the existing module instance as the type + // for the cell: + if (cell->parameters.size() == 0 && (interfaces_to_add_to_submodule.size() == 0 || !(cell->get_bool_attribute("\\module_not_derived")))) { + // If the cell being processed is an the interface instance itself, go down to "handle_interface_instance:", + // so that the signals of the interface are added to the parent module. + if (mod->get_bool_attribute("\\is_interface")) { + goto handle_interface_instance; + } + continue; + } + + cell->type = mod->derive(design, cell->parameters, interfaces_to_add_to_submodule, modports_used_in_submodule); cell->parameters.clear(); did_something = true; + + handle_interface_instance: + + // We add all the signals of the interface explicitly to the parent module. This is always needed when we encounter + // an interface instance: + if (mod->get_bool_attribute("\\is_interface") && cell->get_bool_attribute("\\module_not_derived")) { + cell->set_bool_attribute("\\is_interface"); + RTLIL::Module *derived_module = design->modules_[cell->type]; + interfaces_in_module[cell->name] = derived_module; + did_something = true; + } + // We clear 'module_not_derived' such that we will not rederive the cell again (needed when there are interfaces connected to the cell) + cell->attributes.erase("\\module_not_derived"); + } + // Clear the attribute 'cells_not_processed' such that it can be known that we + // have been through all cells at least once, and that we can know whether + // to flag an error because of interface instances not found: + module->attributes.erase("\\cells_not_processed"); + + + // If any interface instances or interface ports were found in the module, we need to rederive it completely: + if ((interfaces_in_module.size() > 0 || has_interface_ports) && !module->get_bool_attribute("\\interfaces_replaced_in_module")) { + module->reprocess_module(design, interfaces_in_module); + return did_something; } + for (auto &it : array_cells) { RTLIL::Cell *cell = it.first; @@ -248,7 +422,7 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check for (auto &conn : cell->connections_) { int conn_size = conn.second.size(); RTLIL::IdString portname = conn.first; - if (portname.substr(0, 1) == "$") { + if (portname.begins_with("$")) { int port_id = atoi(portname.substr(1).c_str()); for (auto &wire_it : mod->wires_) if (wire_it.second->port_id == port_id) { @@ -277,18 +451,14 @@ void hierarchy_worker(RTLIL::Design *design, std::set<RTLIL::Module*, IdString:: if (indent == 0) log("Top module: %s\n", mod->name.c_str()); - else if (!mod->get_bool_attribute("\\blackbox")) + else if (!mod->get_blackbox_attribute()) log("Used module: %*s%s\n", indent, "", mod->name.c_str()); used.insert(mod); for (auto cell : mod->cells()) { std::string celltype = cell->type.str(); - if (celltype.substr(0, 7) == "$array:") { - int pos_idx = celltype.find_first_of(':'); - int pos_num = celltype.find_first_of(':', pos_idx + 1); - int pos_type = celltype.find_first_of(':', pos_num + 1); - celltype = celltype.substr(pos_type + 1); - } + if (celltype.compare(0, strlen("$array:"), "$array:") == 0) + celltype = basic_cell_type(celltype); if (design->module(celltype)) hierarchy_worker(design, used, design->module(celltype), indent+4); } @@ -303,10 +473,24 @@ void hierarchy_clean(RTLIL::Design *design, RTLIL::Module *top, bool purge_lib) for (auto &it : design->modules_) if (used.count(it.second) == 0) del_modules.push_back(it.second); + else { + // Now all interface ports must have been exploded, and it is hence + // safe to delete all of the remaining dummy interface ports: + pool<RTLIL::Wire*> del_wires; + for(auto &wire : it.second->wires_) { + if ((wire.second->port_input || wire.second->port_output) && wire.second->get_bool_attribute("\\is_interface")) { + del_wires.insert(wire.second); + } + } + if (del_wires.size() > 0) { + it.second->remove(del_wires); + it.second->fixup_ports(); + } + } int del_counter = 0; for (auto mod : del_modules) { - if (!purge_lib && mod->get_bool_attribute("\\blackbox")) + if (!purge_lib && mod->get_blackbox_attribute()) continue; log("Removing unused module `%s'.\n", mod->name.c_str()); design->modules_.erase(mod->name); @@ -333,17 +517,40 @@ int find_top_mod_score(Design *design, Module *module, dict<Module*, int> &db) if (db.count(module) == 0) { int score = 0; db[module] = 0; - for (auto cell : module->cells()) - if (design->module(cell->type)) - score = max(score, find_top_mod_score(design, design->module(cell->type), db) + 1); + for (auto cell : module->cells()) { + std::string celltype = cell->type.str(); + // Is this an array instance + if (celltype.compare(0, strlen("$array:"), "$array:") == 0) + celltype = basic_cell_type(celltype); + // Is this cell a module instance? + auto instModule = design->module(celltype); + // If there is no instance for this, issue a warning. + if (instModule != nullptr) { + score = max(score, find_top_mod_score(design, instModule, db) + 1); + } + } db[module] = score; } return db.at(module); } +RTLIL::Module *check_if_top_has_changed(Design *design, Module *top_mod) +{ + if(top_mod != NULL && top_mod->get_bool_attribute("\\initial_top")) + return top_mod; + else { + for (auto mod : design->modules()) { + if (mod->get_bool_attribute("\\top")) { + return mod; + } + } + } + return NULL; +} + struct HierarchyPass : public Pass { HierarchyPass() : Pass("hierarchy", "check, expand and clean up design hierarchy") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -353,15 +560,16 @@ 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"); log(" an unknown module is used as cell type.\n"); log("\n"); log(" -simcheck\n"); - log(" like -check, but also thow an error if blackbox modules are\n"); - log(" instantiated, and throw an error if the design has no top module\n"); + log(" like -check, but also throw an error if blackbox modules are\n"); + log(" instantiated, and throw an error if the design has no top module.\n"); log("\n"); log(" -purge_lib\n"); log(" by default the hierarchy command will not remove library (blackbox)\n"); @@ -374,20 +582,23 @@ struct HierarchyPass : public Pass { log("\n"); log(" -keep_positionals\n"); log(" per default this pass also converts positional arguments in cells\n"); - log(" to arguments using port names. this option disables this behavior.\n"); + log(" to arguments using port names. This option disables this behavior.\n"); log("\n"); log(" -keep_portwidths\n"); log(" per default this pass adjusts the port width on cells that are\n"); - log(" module instances when the width does not match the module port. this\n"); + 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 $assert cells. this\n"); - log(" option disables this behavior.\n"); + log(" that directly or indirectly contain one or more formal properties.\n"); + log(" This option disables this behavior.\n"); log("\n"); log(" -top <module>\n"); - log(" use the specified top module to built a design hierarchy. modules\n"); + log(" use the specified top module to build the design hierarchy. Modules\n"); log(" outside this tree (unused modules) are removed.\n"); log("\n"); log(" when the -top option is used, the 'top' attribute will be set on the\n"); @@ -397,6 +608,12 @@ struct HierarchyPass : public Pass { log(" -auto-top\n"); log(" automatically determine the top of the design hierarchy and mark it.\n"); log("\n"); + log(" -chparam name value \n"); + log(" elaborate the top module using this parameter value. Modules on which\n"); + log(" this parameter does not exist may cause a warning message to be output.\n"); + log(" This option can be specified multiple times to override multiple\n"); + log(" parameters. String values must be passed in double quotes (\").\n"); + log("\n"); log("In -generate mode this pass generates blackbox modules for the given cell\n"); log("types (wildcards supported). For this the design is searched for cells that\n"); log("match the given types and then the given port declarations are used to\n"); @@ -414,7 +631,7 @@ struct HierarchyPass : public Pass { log("in the current design.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing HIERARCHY pass (managing design hierarchy).\n"); @@ -429,9 +646,11 @@ 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<std::string> generate_cells; std::vector<generate_port_decl_t> generate_ports; + std::map<std::string, std::string> parameters; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) @@ -495,6 +714,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; @@ -506,28 +729,61 @@ struct HierarchyPass : public Pass { if (args[argidx] == "-top") { if (++argidx >= args.size()) log_cmd_error("Option -top requires an additional argument!\n"); - top_mod = design->modules_.count(RTLIL::escape_id(args[argidx])) ? design->modules_.at(RTLIL::escape_id(args[argidx])) : NULL; - if (top_mod == NULL && design->modules_.count("$abstract" + RTLIL::escape_id(args[argidx]))) { - dict<RTLIL::IdString, RTLIL::Const> empty_parameters; - design->modules_.at("$abstract" + RTLIL::escape_id(args[argidx]))->derive(design, empty_parameters); - top_mod = design->modules_.count(RTLIL::escape_id(args[argidx])) ? design->modules_.at(RTLIL::escape_id(args[argidx])) : NULL; - } - if (top_mod == NULL) - load_top_mod = args[argidx]; + load_top_mod = args[argidx]; continue; } if (args[argidx] == "-auto-top") { auto_top_mode = true; continue; } + if (args[argidx] == "-chparam" && argidx+2 < args.size()) { + const std::string &key = args[++argidx]; + const std::string &value = args[++argidx]; + auto r = parameters.emplace(key, value); + if (!r.second) { + log_warning("-chparam %s already specified: overwriting.\n", key.c_str()); + r.first->second = value; + } + continue; + } break; } extra_args(args, argidx, design, false); - if (!load_top_mod.empty()) { + if (!load_top_mod.empty()) + { + IdString top_name = RTLIL::escape_id(load_top_mod); + IdString abstract_id = "$abstract" + RTLIL::escape_id(load_top_mod); + top_mod = design->module(top_name); + + dict<RTLIL::IdString, RTLIL::Const> top_parameters; + for (auto ¶ : parameters) { + SigSpec sig_value; + if (!RTLIL::SigSpec::parse(sig_value, NULL, para.second)) + log_cmd_error("Can't decode value '%s'!\n", para.second.c_str()); + top_parameters[RTLIL::escape_id(para.first)] = sig_value.as_const(); + } + + if (top_mod == nullptr && design->module(abstract_id)) + top_mod = design->module(design->module(abstract_id)->derive(design, top_parameters)); + else if (top_mod != nullptr && !top_parameters.empty()) + top_mod = design->module(top_mod->derive(design, top_parameters)); + + if (top_mod != nullptr && top_mod->name != top_name) { + Module *m = top_mod->clone(); + m->name = top_name; + Module *old_mod = design->module(top_name); + if (old_mod) + design->remove(old_mod); + design->add(m); + top_mod = m; + } + } + + if (top_mod == nullptr && !load_top_mod.empty()) { #ifdef YOSYS_ENABLE_VERIFIC if (verific_import_pending) { - verific_import(design, load_top_mod); + verific_import(design, parameters, load_top_mod); top_mod = design->module(RTLIL::escape_id(load_top_mod)); } #endif @@ -536,7 +792,7 @@ struct HierarchyPass : public Pass { } else { #ifdef YOSYS_ENABLE_VERIFIC if (verific_import_pending) - verific_import(design); + verific_import(design, parameters); #endif } @@ -552,6 +808,30 @@ struct HierarchyPass : public Pass { if (mod_it.second->get_bool_attribute("\\top")) top_mod = mod_it.second; + if (top_mod != nullptr && top_mod->name.begins_with("$abstract")) { + IdString top_name = top_mod->name.substr(strlen("$abstract")); + + dict<RTLIL::IdString, RTLIL::Const> top_parameters; + for (auto ¶ : parameters) { + SigSpec sig_value; + if (!RTLIL::SigSpec::parse(sig_value, NULL, para.second)) + log_cmd_error("Can't decode value '%s'!\n", para.second.c_str()); + top_parameters[RTLIL::escape_id(para.first)] = sig_value.as_const(); + } + + top_mod = design->module(top_mod->derive(design, top_parameters)); + + if (top_mod != nullptr && top_mod->name != top_name) { + Module *m = top_mod->clone(); + m->name = top_name; + Module *old_mod = design->module(top_name); + if (old_mod) + design->remove(old_mod); + design->add(m); + top_mod = m; + } + } + if (top_mod == nullptr && auto_top_mode) { log_header(design, "Finding top of design hierarchy..\n"); dict<Module*, int> db; @@ -568,6 +848,14 @@ struct HierarchyPass : public Pass { if (flag_simcheck && top_mod == nullptr) log_error("Design has no top module.\n"); + if (top_mod != NULL) { + for (auto &mod_it : design->modules_) + if (mod_it.second == top_mod) + mod_it.second->attributes["\\initial_top"] = RTLIL::Const(1); + else + mod_it.second->attributes.erase("\\initial_top"); + } + bool did_something = true; while (did_something) { @@ -586,26 +874,50 @@ struct HierarchyPass : public Pass { if (expand_module(design, module, flag_check, flag_simcheck, libdirs)) did_something = true; } + + + // The top module might have changed if interface instances have been detected in it: + RTLIL::Module *tmp_top_mod = check_if_top_has_changed(design, top_mod); + if (tmp_top_mod != NULL) { + if (tmp_top_mod != top_mod){ + top_mod = tmp_top_mod; + did_something = true; + } + } + + // Delete modules marked as 'to_delete': + std::vector<RTLIL::Module *> modules_to_delete; + for(auto &mod_it : design->modules_) { + if (mod_it.second->get_bool_attribute("\\to_delete")) { + modules_to_delete.push_back(mod_it.second); + } + } + for(size_t i=0; i<modules_to_delete.size(); i++) { + design->remove(modules_to_delete[i]); + } } + if (top_mod != NULL) { log_header(design, "Analyzing design hierarchy..\n"); hierarchy_clean(design, top_mod, purge_lib); } if (top_mod != NULL) { - for (auto &mod_it : design->modules_) + for (auto &mod_it : design->modules_) { if (mod_it.second == top_mod) mod_it.second->attributes["\\top"] = RTLIL::Const(1); else mod_it.second->attributes.erase("\\top"); + mod_it.second->attributes.erase("\\initial_top"); + } } if (!nokeep_asserts) { std::map<RTLIL::Module*, bool> cache; for (auto mod : design->modules()) if (set_keep_assert(cache, mod)) { - log("Module %s directly or indirectly contains $assert cells -> setting \"keep\" attribute.\n", log_id(mod)); + log("Module %s directly or indirectly contains formal properties -> setting \"keep\" attribute.\n", log_id(mod)); mod->set_bool_attribute("\\keep"); } } @@ -658,66 +970,212 @@ struct HierarchyPass : public Pass { } } + if (!nodefaults) + { + dict<IdString, dict<IdString, Const>> 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<Module*> blackbox_derivatives; std::vector<Module*> design_modules = design->modules(); for (auto module : design_modules) - for (auto cell : module->cells()) { - Module *m = design->module(cell->type); + pool<Wire*> wand_wor_index; + dict<Wire*, SigSpec> wand_map, wor_map; + vector<SigSig> new_connections; - if (m == nullptr) - continue; + 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); + } + } - if (m->get_bool_attribute("\\blackbox") && !cell->parameters.empty()) { - IdString new_m_name = m->derive(design, cell->parameters, true); - if (new_m_name.empty()) + for (auto &conn : module->connections()) + { + SigSig new_conn; + int cursor = 0; + + for (auto c : conn.first.chunks()) + { + 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); + } + } + cursor += GetSize(c); + } + new_connections.push_back(new_conn); + } + module->new_connections(new_connections); + + for (auto cell : module->cells()) + { + if (!cell->known()) continue; - if (new_m_name != m->name) { - m = design->module(new_m_name); - blackbox_derivatives.insert(m); + + for (auto &conn : cell->connections()) + { + if (!cell->output(conn.first)) + continue; + + SigSpec new_sig; + bool update_port = false; + + for (auto c : conn.second.chunks()) + { + 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 (update_port) + cell->setPort(conn.first, new_sig); } } - for (auto &conn : cell->connections()) + for (auto w : wand_wor_index) { - Wire *w = m->wire(conn.first); + bool wand = wand_map.count(w); + SigSpec sigs = wand ? wand_map.at(w) : wor_map.at(w); + + if (GetSize(sigs) == 0) + continue; - if (w == nullptr || w->port_id == 0) + if (GetSize(w) == 1) { + if (wand) + module->addReduceAnd(NEW_ID, sigs, w); + else + module->addReduceOr(NEW_ID, sigs, w); continue; + } + + 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); + } - if (GetSize(conn.second) == 0) + for (auto cell : module->cells()) + { + Module *m = design->module(cell->type); + + if (m == nullptr) continue; - SigSpec sig = conn.second; + 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); + } + } - if (!keep_portwidths && GetSize(w) != GetSize(conn.second)) + for (auto &conn : cell->connections()) { - 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 + 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)) { - int n = GetSize(w) - GetSize(conn.second); - if (w->port_input && !w->port_output) - sig.append(Const(0, n)); + 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 - sig.append(module->addWire(NEW_ID, n)); + { + 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 (!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)); } - - 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/passes/hierarchy/submod.cc b/passes/hierarchy/submod.cc index e9ee4eef9..ec242aa1f 100644 --- a/passes/hierarchy/submod.cc +++ b/passes/hierarchy/submod.cc @@ -269,7 +269,7 @@ struct SubmodWorker struct SubmodPass : public Pass { SubmodPass() : Pass("submod", "moving part of a module to a new submodule") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -297,7 +297,7 @@ struct SubmodPass : public Pass { log("with -copy to not modify the source module.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing SUBMOD pass (moving cells to submodules as requested).\n"); log_push(); diff --git a/passes/hierarchy/uniquify.cc b/passes/hierarchy/uniquify.cc index 1da0870f6..ad3220918 100644 --- a/passes/hierarchy/uniquify.cc +++ b/passes/hierarchy/uniquify.cc @@ -24,7 +24,7 @@ PRIVATE_NAMESPACE_BEGIN struct UniquifyPass : public Pass { UniquifyPass() : Pass("uniquify", "create unique copies of modules") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -41,7 +41,7 @@ struct UniquifyPass : public Pass { log("attribute set (the 'top' module is unique implicitly).\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing UNIQUIFY pass (creating unique copies of modules).\n"); @@ -75,7 +75,7 @@ struct UniquifyPass : public Pass { if (tmod == nullptr) continue; - if (tmod->get_bool_attribute("\\blackbox")) + if (tmod->get_blackbox_attribute()) continue; if (tmod->get_bool_attribute("\\unique") && newname == tmod->name) @@ -87,6 +87,8 @@ struct UniquifyPass : public Pass { smod->name = newname; cell->type = newname; smod->set_bool_attribute("\\unique"); + if (smod->attributes.count("\\hdlname") == 0) + smod->attributes["\\hdlname"] = string(log_id(tmod->name)); design->add(smod); did_something = true; diff --git a/passes/memory/memory.cc b/passes/memory/memory.cc index 947d598be..712bc2537 100644 --- a/passes/memory/memory.cc +++ b/passes/memory/memory.cc @@ -27,7 +27,7 @@ PRIVATE_NAMESPACE_BEGIN struct MemoryPass : public Pass { MemoryPass() : Pass("memory", "translate memories to basic cells") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -48,7 +48,7 @@ struct MemoryPass : public Pass { log("or multiport memory blocks if called with the -nomap option.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { bool flag_nomap = false; bool flag_nordff = false; diff --git a/passes/memory/memory_bram.cc b/passes/memory/memory_bram.cc index a7f9cf382..aa8f94149 100644 --- a/passes/memory/memory_bram.cc +++ b/passes/memory/memory_bram.cc @@ -68,6 +68,10 @@ struct rules_t if (groups != GetSize(transp)) log_error("Bram %s variant %d has %d groups but only %d entries in 'transp'.\n", log_id(name), variant, groups, GetSize(transp)); if (groups != GetSize(clocks)) log_error("Bram %s variant %d has %d groups but only %d entries in 'clocks'.\n", log_id(name), variant, groups, GetSize(clocks)); if (groups != GetSize(clkpol)) log_error("Bram %s variant %d has %d groups but only %d entries in 'clkpol'.\n", log_id(name), variant, groups, GetSize(clkpol)); + + int group = 0; + for (auto e : enable) + if (e > dbits) log_error("Bram %s variant %d group %d has %d enable bits but only %d dbits.\n", log_id(name), variant, group, e, dbits); } vector<portinfo_t> make_portinfos() const @@ -472,8 +476,12 @@ bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram, std::vector<SigSpec> new_wr_en(GetSize(old_wr_en)); std::vector<SigSpec> new_wr_data(GetSize(old_wr_data)); std::vector<SigSpec> new_rd_data(GetSize(old_rd_data)); + std::vector<std::vector<State>> new_initdata; std::vector<int> shuffle_map; + if (cell_init) + new_initdata.resize(mem_size); + for (auto &it : en_order) { auto &bits = bits_wr_en.at(it); @@ -489,6 +497,10 @@ bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram, } for (int j = 0; j < rd_ports; j++) new_rd_data[j].append(old_rd_data[j][bits[i]]); + if (cell_init) { + for (int j = 0; j < mem_size; j++) + new_initdata[j].push_back(initdata[j][bits[i]]); + } shuffle_map.push_back(bits[i]); } @@ -499,6 +511,10 @@ bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram, } for (int j = 0; j < rd_ports; j++) new_rd_data[j].append(State::Sx); + if (cell_init) { + for (int j = 0; j < mem_size; j++) + new_initdata[j].push_back(State::Sx); + } shuffle_map.push_back(-1); } } @@ -522,10 +538,15 @@ bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram, for (int i = 0; i < rd_ports; i++) rd_data.replace(i*mem_width, new_rd_data[i]); + + if (cell_init) { + for (int i = 0; i < mem_size; i++) + initdata[i] = Const(new_initdata[i]); + } } // assign write ports - + pair<SigBit, bool> wr_clkdom; for (int cell_port_i = 0, bram_port_i = 0; cell_port_i < wr_ports; cell_port_i++) { bool clken = wr_clken[cell_port_i] == State::S1; @@ -535,7 +556,7 @@ bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram, pair<SigBit, bool> clkdom(clksig, clkpol); if (!clken) clkdom = pair<SigBit, bool>(State::S1, false); - + wr_clkdom = clkdom; log(" Write port #%d is in clock domain %s%s.\n", cell_port_i, clkdom.second ? "" : "!", clken ? log_signal(clkdom.first) : "~async~"); @@ -623,6 +644,8 @@ grow_read_ports:; pi.sig_addr = SigSpec(); pi.sig_data = SigSpec(); pi.sig_en = SigSpec(); + pi.make_outreg = false; + pi.make_transp = false; } new_portinfos.push_back(pi); if (pi.dupidx == dup_count-1) { @@ -700,7 +723,13 @@ grow_read_ports:; if (read_transp.count(pi.transp) && read_transp.at(pi.transp) != transp) { if (match.make_transp && wr_ports <= 1) { pi.make_transp = true; - enable_make_transp = true; + if (pi.clocks != 0) { + if (wr_ports == 1 && wr_clkdom != clkdom) { + log(" Bram port %c%d.%d cannot have soft transparency logic added as read and write clock domains differ.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1); + goto skip_bram_rport; + } + enable_make_transp = true; + } } else { log(" Bram port %c%d.%d has incompatible read transparency.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1); goto skip_bram_rport; @@ -719,7 +748,8 @@ grow_read_ports:; if (clken) { clock_domains[pi.clocks] = clkdom; clock_polarities[pi.clkpol] = clkdom.second; - read_transp[pi.transp] = transp; + if (!pi.make_transp) + read_transp[pi.transp] = transp; pi.sig_clock = clkdom.first; pi.sig_en = rd_en[cell_port_i]; pi.effective_clkpol = clkdom.second; @@ -895,17 +925,18 @@ grow_read_ports:; } else { SigSpec bram_dout = module->addWire(NEW_ID, bram.dbits); c->setPort(stringf("\\%sDATA", pf), bram_dout); - - if (pi.make_outreg) { + if (pi.make_outreg && pi.make_transp) { + log(" Moving output register to address for transparent port %c%d.%d.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1); + SigSpec sig_addr_q = module->addWire(NEW_ID, bram.abits); + module->addDff(NEW_ID, pi.sig_clock, sig_addr, sig_addr_q, pi.effective_clkpol); + c->setPort(stringf("\\%sADDR", pf), sig_addr_q); + } else if (pi.make_outreg) { SigSpec bram_dout_q = module->addWire(NEW_ID, bram.dbits); if (!pi.sig_en.empty()) bram_dout = module->Mux(NEW_ID, bram_dout_q, bram_dout, pi.sig_en); module->addDff(NEW_ID, pi.sig_clock, bram_dout, bram_dout_q, pi.effective_clkpol); bram_dout = bram_dout_q; - } - - if (pi.make_transp) - { + } else if (pi.make_transp) { log(" Adding extra logic for transparent port %c%d.%d.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1); SigSpec transp_en_d = module->Mux(NEW_ID, SigSpec(0, make_transp_enbits), @@ -931,6 +962,8 @@ grow_read_ports:; SigSpec addr_ok_q = addr_ok; if ((pi.clocks || pi.make_outreg) && !addr_ok.empty()) { addr_ok_q = module->addWire(NEW_ID); + if (!pi.sig_en.empty()) + addr_ok = module->Mux(NEW_ID, addr_ok_q, addr_ok, pi.sig_en); module->addDff(NEW_ID, pi.sig_clock, addr_ok, addr_ok_q, pi.effective_clkpol); } @@ -1120,7 +1153,7 @@ void handle_cell(Cell *cell, const rules_t &rules) struct MemoryBramPass : public Pass { MemoryBramPass() : Pass("memory_bram", "map memories to block rams") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -1210,7 +1243,7 @@ struct MemoryBramPass : public Pass { log("the data bits to accommodate the enable pattern of port A.\n"); log("\n"); } - virtual void execute(vector<string> args, Design *design) + void execute(vector<string> args, Design *design) YS_OVERRIDE { rules_t rules; diff --git a/passes/memory/memory_collect.cc b/passes/memory/memory_collect.cc index ab66e3fb8..6acbce62f 100644 --- a/passes/memory/memory_collect.cc +++ b/passes/memory/memory_collect.cc @@ -184,9 +184,6 @@ Cell *handle_memory(Module *module, RTLIL::Memory *memory) mem->parameters["\\OFFSET"] = Const(memory->start_offset); mem->parameters["\\SIZE"] = Const(memory->size); mem->parameters["\\ABITS"] = Const(addr_bits); - - while (GetSize(init_data) > 1 && init_data.bits.back() == State::Sx && init_data.bits[GetSize(init_data)-2] == State::Sx) - init_data.bits.pop_back(); mem->parameters["\\INIT"] = init_data; log_assert(sig_wr_clk.size() == wr_ports); @@ -197,8 +194,8 @@ Cell *handle_memory(Module *module, RTLIL::Memory *memory) log_assert(sig_wr_en.size() == wr_ports * memory->width); mem->parameters["\\WR_PORTS"] = Const(wr_ports); - mem->parameters["\\WR_CLK_ENABLE"] = wr_ports ? sig_wr_clk_enable.as_const() : Const(0, 1); - mem->parameters["\\WR_CLK_POLARITY"] = wr_ports ? sig_wr_clk_polarity.as_const() : Const(0, 1); + mem->parameters["\\WR_CLK_ENABLE"] = wr_ports ? sig_wr_clk_enable.as_const() : State::S0; + mem->parameters["\\WR_CLK_POLARITY"] = wr_ports ? sig_wr_clk_polarity.as_const() : State::S0; mem->setPort("\\WR_CLK", sig_wr_clk); mem->setPort("\\WR_ADDR", sig_wr_addr); @@ -212,9 +209,9 @@ Cell *handle_memory(Module *module, RTLIL::Memory *memory) log_assert(sig_rd_data.size() == rd_ports * memory->width); mem->parameters["\\RD_PORTS"] = Const(rd_ports); - mem->parameters["\\RD_CLK_ENABLE"] = rd_ports ? sig_rd_clk_enable.as_const() : Const(0, 1); - mem->parameters["\\RD_CLK_POLARITY"] = rd_ports ? sig_rd_clk_polarity.as_const() : Const(0, 1); - mem->parameters["\\RD_TRANSPARENT"] = rd_ports ? sig_rd_transparent.as_const() : Const(0, 1); + mem->parameters["\\RD_CLK_ENABLE"] = rd_ports ? sig_rd_clk_enable.as_const() : State::S0; + mem->parameters["\\RD_CLK_POLARITY"] = rd_ports ? sig_rd_clk_polarity.as_const() : State::S0; + mem->parameters["\\RD_TRANSPARENT"] = rd_ports ? sig_rd_transparent.as_const() : State::S0; mem->setPort("\\RD_CLK", sig_rd_clk); mem->setPort("\\RD_ADDR", sig_rd_addr); @@ -246,7 +243,7 @@ static void handle_module(Design *design, Module *module) struct MemoryCollectPass : public Pass { MemoryCollectPass() : Pass("memory_collect", "creating multi-port memory cells") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -256,7 +253,7 @@ struct MemoryCollectPass : public Pass { log("memory cells.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing MEMORY_COLLECT pass (generating $mem cells).\n"); extra_args(args, 1, design); for (auto &mod_it : design->modules_) diff --git a/passes/memory/memory_dff.cc b/passes/memory/memory_dff.cc index 6e036397d..be4b3c100 100644 --- a/passes/memory/memory_dff.cc +++ b/passes/memory/memory_dff.cc @@ -17,6 +17,7 @@ * */ +#include <algorithm> #include "kernel/yosys.h" #include "kernel/sigtools.h" @@ -41,7 +42,7 @@ struct MemoryDffWorker if (wire->attributes.count("\\init") == 0) continue; SigSpec sig = sigmap(wire); - Const initval = wire->attributes.count("\\init"); + Const initval = wire->attributes.at("\\init"); for (int i = 0; i < GetSize(sig) && i < GetSize(initval); i++) if (initval[i] == State::S0 || initval[i] == State::S1) init_bits.insert(sig[i]); @@ -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<RTLIL::SigSpec> 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); @@ -254,7 +262,7 @@ struct MemoryDffWorker mux_cells_a[sigmap(cell->getPort("\\A"))] = cell; mux_cells_b[sigmap(cell->getPort("\\B"))] = cell; } - if (cell->type == "$not" || cell->type == "$_NOT_" || (cell->type == "$logic_not" && GetSize(cell->getPort("\\A")) == 1)) { + if (cell->type.in("$not", "$_NOT_") || (cell->type == "$logic_not" && GetSize(cell->getPort("\\A")) == 1)) { SigSpec sig_a = cell->getPort("\\A"); SigSpec sig_y = cell->getPort("\\Y"); if (cell->type == "$not") @@ -283,7 +291,7 @@ struct MemoryDffWorker struct MemoryDffPass : public Pass { MemoryDffPass() : Pass("memory_dff", "merge input/output DFFs into memories") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -297,7 +305,7 @@ struct MemoryDffPass : public Pass { log(" do not merge registers on read ports\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { bool flag_wr_only = false; diff --git a/passes/memory/memory_map.cc b/passes/memory/memory_map.cc index bffeec857..65bccb5ef 100644 --- a/passes/memory/memory_map.cc +++ b/passes/memory/memory_map.cc @@ -301,7 +301,7 @@ struct MemoryMapWorker RTLIL::Wire *w = w_seladdr; - if (wr_bit != RTLIL::SigSpec(1, 1)) + if (wr_bit != State::S1) { RTLIL::Cell *c = module->addCell(genid(cell->name, "$wren", i, "", j, "", wr_offset), "$and"); c->parameters["\\A_SIGNED"] = RTLIL::Const(0); @@ -352,7 +352,7 @@ struct MemoryMapWorker struct MemoryMapPass : public Pass { MemoryMapPass() : Pass("memory_map", "translate multiport memories to basic cells") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -362,7 +362,7 @@ struct MemoryMapPass : public Pass { log("pass to word-wide DFFs and address decoders.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing MEMORY_MAP pass (converting $mem cells to logic and flip-flops).\n"); extra_args(args, 1, design); for (auto mod : design->selected_modules()) diff --git a/passes/memory/memory_memx.cc b/passes/memory/memory_memx.cc index 2b02e2490..958370164 100644 --- a/passes/memory/memory_memx.cc +++ b/passes/memory/memory_memx.cc @@ -28,7 +28,7 @@ PRIVATE_NAMESPACE_BEGIN struct MemoryMemxPass : public Pass { MemoryMemxPass() : Pass("memory_memx", "emulate vlog sim behavior for mem ports") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -38,7 +38,7 @@ struct MemoryMemxPass : public Pass { log("behavior for out-of-bounds memory reads and writes.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing MEMORY_MEMX pass (converting $mem cells to logic and flip-flops).\n"); extra_args(args, 1, design); diff --git a/passes/memory/memory_nordff.cc b/passes/memory/memory_nordff.cc index 87ab7c623..ba0361c0f 100644 --- a/passes/memory/memory_nordff.cc +++ b/passes/memory/memory_nordff.cc @@ -25,7 +25,7 @@ PRIVATE_NAMESPACE_BEGIN struct MemoryNordffPass : public Pass { MemoryNordffPass() : Pass("memory_nordff", "extract read port FFs from memories") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -35,7 +35,7 @@ struct MemoryNordffPass : public Pass { log("similar to what one would get from calling memory_dff with -nordff.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing MEMORY_NORDFF pass (extracting $dff cells from $mem).\n"); diff --git a/passes/memory/memory_share.cc b/passes/memory/memory_share.cc index ca09ac52c..eb912cfd4 100644 --- a/passes/memory/memory_share.cc +++ b/passes/memory/memory_share.cc @@ -155,7 +155,7 @@ struct MemoryShareWorker { bool ignore_data_port = false; - if (cell->type == "$mux" || cell->type == "$pmux") + if (cell->type.in("$mux", "$pmux")) { std::vector<RTLIL::SigBit> sig_a = sigmap(cell->getPort("\\A")); std::vector<RTLIL::SigBit> sig_b = sigmap(cell->getPort("\\B")); @@ -173,7 +173,7 @@ struct MemoryShareWorker continue; } - if ((cell->type == "$memwr" || cell->type == "$memrd") && + if (cell->type.in("$memwr", "$memrd") && cell->parameters.at("\\MEMID").decode_string() == memid) ignore_data_port = true; @@ -690,7 +690,7 @@ struct MemoryShareWorker sigmap_xmux.add(cell->getPort("\\Y"), sig_a); } - if (cell->type == "$mux" || cell->type == "$pmux") + if (cell->type.in("$mux", "$pmux")) { std::vector<RTLIL::SigBit> sig_y = sigmap(cell->getPort("\\Y")); for (int i = 0; i < int(sig_y.size()); i++) @@ -726,7 +726,7 @@ struct MemoryShareWorker struct MemorySharePass : public Pass { MemorySharePass() : Pass("memory_share", "consolidate memory ports") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -752,7 +752,7 @@ struct MemorySharePass : public Pass { log("optimizations) such as \"share\" and \"opt_merge\".\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing MEMORY_SHARE pass (consolidating $memrd/$memwr cells).\n"); extra_args(args, 1, design); for (auto module : design->selected_modules()) diff --git a/passes/memory/memory_unpack.cc b/passes/memory/memory_unpack.cc index a0fc31b5e..49ec66792 100644 --- a/passes/memory/memory_unpack.cc +++ b/passes/memory/memory_unpack.cc @@ -127,7 +127,7 @@ void handle_module(RTLIL::Design *design, RTLIL::Module *module) struct MemoryUnpackPass : public Pass { MemoryUnpackPass() : Pass("memory_unpack", "unpack multi-port memory cells") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -137,7 +137,7 @@ struct MemoryUnpackPass : public Pass { log("$memwr cells. It is the counterpart to the memory_collect pass.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing MEMORY_UNPACK pass (generating $memrd/$memwr cells form $mem cells).\n"); extra_args(args, 1, design); for (auto &mod_it : design->modules_) diff --git a/passes/opt/Makefile.inc b/passes/opt/Makefile.inc index 0d01e9d35..eb07e9452 100644 --- a/passes/opt/Makefile.inc +++ b/passes/opt/Makefile.inc @@ -4,6 +4,7 @@ OBJS += passes/opt/opt_merge.o OBJS += passes/opt/opt_muxtree.o OBJS += passes/opt/opt_reduce.o OBJS += passes/opt/opt_rmdff.o +OBJS += passes/opt/opt_share.o OBJS += passes/opt/opt_clean.o OBJS += passes/opt/opt_expr.o @@ -12,5 +13,7 @@ OBJS += passes/opt/share.o OBJS += passes/opt/wreduce.o 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/passes/opt/muxpack.cc b/passes/opt/muxpack.cc new file mode 100644 index 000000000..c40c02acd --- /dev/null +++ b/passes/opt/muxpack.cc @@ -0,0 +1,368 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * 2019 Eddie Hung <eddie@fpgeh.com> + * + * 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<SigBit, std::pair<SigSpec,std::vector<Const>>> sig_cmp_prev; + + ExclusiveDatabase(Module *module, const SigMap &sigmap) : module(module), sigmap(sigmap) + { + SigSpec const_sig, nonconst_sig; + SigBit y_port; + pool<Cell*> reduce_or; + for (auto cell : module->cells()) { + if (cell->type == ID($eq)) { + nonconst_sig = sigmap(cell->getPort(ID::A)); + const_sig = sigmap(cell->getPort(ID::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(ID::Y)); + } + else if (cell->type == ID($logic_not)) { + nonconst_sig = sigmap(cell->getPort(ID::A)); + const_sig = Const(State::S0, GetSize(nonconst_sig)); + y_port = sigmap(cell->getPort(ID::Y)); + } + else if (cell->type == ID($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>{const_sig.as_const()}); + } + + for (auto cell : reduce_or) { + nonconst_sig = SigSpec(); + std::vector<Const> values; + SigSpec a_port = sigmap(cell->getPort(ID::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(ID::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> 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<Cell*> remove_cells; + + dict<SigSpec, Cell*> sig_chain_next; + dict<SigSpec, Cell*> sig_chain_prev; + pool<SigBit> sigbit_with_non_chain_users; + pool<Cell*> chain_start_cells; + pool<Cell*> candidate_cells; + + ExclusiveDatabase excl_db; + + void make_sig_chain_next_prev() + { + for (auto wire : module->wires()) + { + if (wire->port_output || wire->get_bool_attribute(ID::keep)) { + for (auto bit : sigmap(wire)) + sigbit_with_non_chain_users.insert(bit); + } + } + + for (auto cell : module->cells()) + { + if (cell->type.in(ID($mux), ID($pmux)) && !cell->get_bool_attribute(ID::keep)) + { + SigSpec a_sig = sigmap(cell->getPort(ID::A)); + SigSpec b_sig; + if (cell->type == ID($mux)) + b_sig = sigmap(cell->getPort(ID::B)); + SigSpec y_sig = sigmap(cell->getPort(ID::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(ID::A)); + if (cell->type == ID($mux)) { + SigSpec b_sig = sigmap(cell->getPort(ID::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 == ID($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(ID(S))); + s_sig.append(sigmap(prev_cell->getPort(ID(S)))); + if (!excl_db.query(s_sig)) + goto start_cell; + } + + continue; + + start_cell: + chain_start_cells.insert(cell); + } + } + + vector<Cell*> create_chain(Cell *start_cell) + { + vector<Cell*> chain; + + Cell *c = start_cell; + while (c != nullptr) + { + chain.push_back(c); + + SigSpec y_sig = sigmap(c->getPort(ID::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<Cell*> &chain) + { + if (GetSize(chain) < 2) + return; + + int cursor = 0; + while (cursor < GetSize(chain)) + { + int cases = GetSize(chain) - cursor; + + Cell *first_cell = chain[cursor]; + dict<int, SigBit> 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 = ID($pmux); + SigSpec b_sig = first_cell->getPort(ID::B); + SigSpec s_sig = first_cell->getPort(ID(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(ID::Y)) == sigmap(cursor_cell->getPort(ID::A))) { + b_sig.append(cursor_cell->getPort(ID::B)); + s_sig.append(cursor_cell->getPort(ID(S))); + } + else { + log_assert(cursor_cell->type == ID($mux)); + b_sig.append(cursor_cell->getPort(ID::A)); + s_sig.append(module->LogicNot(NEW_ID, cursor_cell->getPort(ID(S)))); + } + remove_cells.insert(cursor_cell); + } + + first_cell->setPort(ID::B, b_sig); + first_cell->setPort(ID(S), s_sig); + first_cell->setParam(ID(S_WIDTH), GetSize(s_sig)); + first_cell->setPort(ID::Y, last_cell->getPort(ID::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<Cell*> 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<std::string> 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/passes/opt/opt.cc b/passes/opt/opt.cc index 021c1a03f..396819883 100644 --- a/passes/opt/opt.cc +++ b/passes/opt/opt.cc @@ -27,7 +27,7 @@ PRIVATE_NAMESPACE_BEGIN struct OptPass : public Pass { OptPass() : Pass("opt", "perform simple optimizations") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -44,7 +44,8 @@ struct OptPass : public Pass { log(" opt_muxtree\n"); log(" opt_reduce [-fine] [-full]\n"); log(" opt_merge [-share_all]\n"); - log(" opt_rmdff [-keepdc]\n"); + log(" opt_share (-full only)\n"); + log(" opt_rmdff [-keepdc] [-sat]\n"); log(" opt_clean [-purge]\n"); log(" opt_expr [-mux_undef] [-mux_bool] [-undriven] [-clkinv] [-fine] [-full] [-keepdc]\n"); log(" while <changed design>\n"); @@ -54,7 +55,7 @@ struct OptPass : public Pass { log(" do\n"); log(" opt_expr [-mux_undef] [-mux_bool] [-undriven] [-clkinv] [-fine] [-full] [-keepdc]\n"); log(" opt_merge [-share_all]\n"); - log(" opt_rmdff [-keepdc]\n"); + log(" opt_rmdff [-keepdc] [-sat]\n"); log(" opt_clean [-purge]\n"); log(" while <changed design in opt_rmdff>\n"); log("\n"); @@ -63,13 +64,14 @@ struct OptPass : public Pass { log("\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { std::string opt_clean_args; std::string opt_expr_args; std::string opt_reduce_args; std::string opt_merge_args; std::string opt_rmdff_args; + bool opt_share = false; bool fast_mode = false; log_header(design, "Executing OPT pass (performing simple optimizations).\n"); @@ -105,6 +107,7 @@ struct OptPass : public Pass { if (args[argidx] == "-full") { opt_expr_args += " -full"; opt_reduce_args += " -full"; + opt_share = true; continue; } if (args[argidx] == "-keepdc") { @@ -112,6 +115,10 @@ struct OptPass : public Pass { opt_rmdff_args += " -keepdc"; continue; } + if (args[argidx] == "-sat") { + opt_rmdff_args += " -sat"; + continue; + } if (args[argidx] == "-share_all") { opt_merge_args += " -share_all"; continue; @@ -147,6 +154,8 @@ struct OptPass : public Pass { Pass::call(design, "opt_muxtree"); Pass::call(design, "opt_reduce" + opt_reduce_args); Pass::call(design, "opt_merge" + opt_merge_args); + if (opt_share) + Pass::call(design, "opt_share"); Pass::call(design, "opt_rmdff" + opt_rmdff_args); Pass::call(design, "opt_clean" + opt_clean_args); Pass::call(design, "opt_expr" + opt_expr_args); diff --git a/passes/opt/opt_clean.cc b/passes/opt/opt_clean.cc index 25d462ada..2f69b3d4c 100644 --- a/passes/opt/opt_clean.cc +++ b/passes/opt/opt_clean.cc @@ -52,7 +52,7 @@ struct keep_cache_t return cache.at(module); cache[module] = true; - if (!module->get_bool_attribute("\\keep")) { + if (!module->get_bool_attribute(ID::keep)) { bool found_keep = false; for (auto cell : module->cells()) if (query(cell)) found_keep = true; @@ -64,7 +64,7 @@ struct keep_cache_t bool query(Cell *cell) { - if (cell->type.in("$memwr", "$meminit", "$assert", "$assume", "$live", "$fair", "$cover")) + if (cell->type.in(ID($memwr), ID($meminit), ID($assert), ID($assume), ID($live), ID($fair), ID($cover), ID($specify2), ID($specify3), ID($specrule))) return true; if (cell->has_keep_attr()) @@ -85,22 +85,34 @@ void rmunused_module_cells(Module *module, bool verbose) { SigMap sigmap(module); pool<Cell*> queue, unused; + pool<SigBit> used_raw_bits; dict<SigBit, pool<Cell*>> wire2driver; + dict<SigBit, vector<string>> driver_driver_logs; + + SigMap raw_sigmap; + for (auto &it : module->connections_) { + for (int i = 0; i < GetSize(it.second); i++) { + if (it.second[i].wire != nullptr) + raw_sigmap.add(it.first[i], it.second[i]); + } + } for (auto &it : module->cells_) { Cell *cell = it.second; for (auto &it2 : cell->connections()) { - if (!ct_all.cell_known(cell->type) || ct_all.cell_output(cell->type, it2.first)) - for (auto raw_bit : it2.second) { - if (raw_bit.wire == nullptr) - continue; - auto bit = sigmap(raw_bit); - if (bit.wire == nullptr) - log_warning("Driver-driver conflict for %s between cell %s.%s and constant %s in %s: Resolved using constant.\n", - log_signal(raw_bit), log_id(cell), log_id(it2.first), log_signal(bit), log_id(module)); - if (bit.wire != nullptr) - wire2driver[bit].insert(cell); - } + if (ct_all.cell_known(cell->type) && !ct_all.cell_output(cell->type, it2.first)) + continue; + for (auto raw_bit : it2.second) { + if (raw_bit.wire == nullptr) + continue; + auto bit = sigmap(raw_bit); + 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))); + if (bit.wire != nullptr) + wire2driver[bit].insert(cell); + } } if (keep_cache.query(cell)) queue.insert(cell); @@ -110,10 +122,12 @@ void rmunused_module_cells(Module *module, bool verbose) for (auto &it : module->wires_) { Wire *wire = it.second; - if (wire->port_output || wire->get_bool_attribute("\\keep")) { + if (wire->port_output || wire->get_bool_attribute(ID::keep)) { for (auto bit : sigmap(wire)) for (auto c : wire2driver[bit]) queue.insert(c), unused.erase(c); + for (auto raw_bit : SigSpec(wire)) + used_raw_bits.insert(raw_sigmap(raw_bit)); } } @@ -137,18 +151,34 @@ void rmunused_module_cells(Module *module, bool verbose) for (auto cell : unused) { if (verbose) - log(" removing unused `%s' cell `%s'.\n", cell->type.c_str(), cell->name.c_str()); + log_debug(" removing unused `%s' cell `%s'.\n", cell->type.c_str(), cell->name.c_str()); module->design->scratchpad_set_bool("opt.did_something", true); module->remove(cell); count_rm_cells++; } + + for (auto &it : module->cells_) { + Cell *cell = it.second; + for (auto &it2 : cell->connections()) { + if (ct_all.cell_known(cell->type) && !ct_all.cell_input(cell->type, it2.first)) + continue; + for (auto raw_bit : raw_sigmap(it2.second)) + used_raw_bits.insert(raw_bit); + } + } + + for (auto it : driver_driver_logs) { + if (used_raw_bits.count(it.first)) + for (auto msg : it.second) + log_warning("%s\n", msg.c_str()); + } } int count_nontrivial_wire_attrs(RTLIL::Wire *w) { int count = w->attributes.size(); - count -= w->attributes.count("\\src"); - count -= w->attributes.count("\\unused_bits"); + count -= w->attributes.count(ID(src)); + count -= w->attributes.count(ID(unused_bits)); return count; } @@ -192,17 +222,17 @@ bool compare_signals(RTLIL::SigBit &s1, RTLIL::SigBit &s2, SigPool ®s, SigPoo bool check_public_name(RTLIL::IdString id) { - const std::string &id_str = id.str(); - if (id_str[0] == '$') + if (id.begins_with("$")) return false; - if (id_str.substr(0, 2) == "\\_" && (id_str[id_str.size()-1] == '_' || id_str.find("_[") != std::string::npos)) + const std::string &id_str = id.str(); + if (id.begins_with("\\_") && (id.ends_with("_") || id_str.find("_[") != std::string::npos)) return false; if (id_str.find(".$") != std::string::npos) return false; return true; } -void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbose) +bool rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbose) { SigPool register_signals; SigPool connected_signals; @@ -245,11 +275,13 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos module->connections_.clear(); SigPool used_signals; + SigPool raw_used_signals; SigPool used_signals_nodrivers; for (auto &it : module->cells_) { RTLIL::Cell *cell = it.second; for (auto &it2 : cell->connections_) { assign_map.apply(it2.second); + raw_used_signals.add(it2.second); used_signals.add(it2.second); if (!ct_all.cell_output(cell->type, it2.first)) used_signals_nodrivers.add(it2.second); @@ -259,84 +291,116 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos RTLIL::Wire *wire = it.second; if (wire->port_id > 0) { RTLIL::SigSpec sig = RTLIL::SigSpec(wire); + raw_used_signals.add(sig); assign_map.apply(sig); used_signals.add(sig); if (!wire->port_input) used_signals_nodrivers.add(sig); } - if (wire->get_bool_attribute("\\keep")) { + if (wire->get_bool_attribute(ID::keep)) { RTLIL::SigSpec sig = RTLIL::SigSpec(wire); assign_map.apply(sig); used_signals.add(sig); } } - std::vector<RTLIL::Wire*> maybe_del_wires; + pool<RTLIL::Wire*> del_wires_queue; for (auto wire : module->wires()) { - if ((!purge_mode && check_public_name(wire->name)) || wire->port_id != 0 || wire->get_bool_attribute("\\keep") || wire->attributes.count("\\init")) { - RTLIL::SigSpec s1 = RTLIL::SigSpec(wire), s2 = s1; - assign_map.apply(s2); - if (!used_signals.check_any(s2) && wire->port_id == 0 && !wire->get_bool_attribute("\\keep")) { - maybe_del_wires.push_back(wire); - } else { - log_assert(GetSize(s1) == GetSize(s2)); - RTLIL::SigSig new_conn; - for (int i = 0; i < GetSize(s1); i++) - if (s1[i] != s2[i]) { - new_conn.first.append_bit(s1[i]); - new_conn.second.append_bit(s2[i]); + SigSpec s1 = SigSpec(wire), s2 = assign_map(s1); + log_assert(GetSize(s1) == GetSize(s2)); + + Const initval; + if (wire->attributes.count(ID(init))) + initval = wire->attributes.at(ID(init)); + if (GetSize(initval) != GetSize(wire)) + initval.bits.resize(GetSize(wire), State::Sx); + if (initval.is_fully_undef()) + wire->attributes.erase(ID(init)); + + if (GetSize(wire) == 0) { + // 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(ID::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) && (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 + goto delete_this_wire; + } else + if (!used_signals.check_any(s2)) { + // delete wires that aren't used by anything indirectly, even though other wires may alias it + goto delete_this_wire; + } + + if (0) + { + delete_this_wire: + del_wires_queue.insert(wire); + } + else + { + RTLIL::SigSig new_conn; + for (int i = 0; i < GetSize(s1); i++) + if (s1[i] != s2[i]) { + if (s2[i] == State::Sx && (initval[i] == State::S0 || initval[i] == State::S1)) { + s2[i] = initval[i]; + initval[i] = State::Sx; } - if (new_conn.first.size() > 0) { - used_signals.add(new_conn.first); - used_signals.add(new_conn.second); - module->connect(new_conn); + new_conn.first.append_bit(s1[i]); + new_conn.second.append_bit(s2[i]); } + if (new_conn.first.size() > 0) { + if (initval.is_fully_undef()) + wire->attributes.erase(ID(init)); + else + wire->attributes.at(ID(init)) = initval; + used_signals.add(new_conn.first); + used_signals.add(new_conn.second); + module->connect(new_conn); } - } else { - if (!used_signals.check_any(RTLIL::SigSpec(wire))) - maybe_del_wires.push_back(wire); - } - RTLIL::SigSpec sig = assign_map(RTLIL::SigSpec(wire)); - if (!used_signals_nodrivers.check_any(sig)) { - std::string unused_bits; - for (int i = 0; i < GetSize(sig); i++) { - if (sig[i].wire == NULL) - continue; - if (!used_signals_nodrivers.check(sig[i])) { - if (!unused_bits.empty()) - unused_bits += " "; - unused_bits += stringf("%d", i); + if (!used_signals_nodrivers.check_all(s2)) { + std::string unused_bits; + for (int i = 0; i < GetSize(s2); i++) { + if (s2[i].wire == NULL) + continue; + if (!used_signals_nodrivers.check(s2[i])) { + if (!unused_bits.empty()) + unused_bits += " "; + unused_bits += stringf("%d", i); + } } + if (unused_bits.empty() || wire->port_id != 0) + wire->attributes.erase(ID(unused_bits)); + else + wire->attributes[ID(unused_bits)] = RTLIL::Const(unused_bits); + } else { + wire->attributes.erase(ID(unused_bits)); } - if (unused_bits.empty() || wire->port_id != 0) - wire->attributes.erase("\\unused_bits"); - else - wire->attributes["\\unused_bits"] = RTLIL::Const(unused_bits); - } else { - wire->attributes.erase("\\unused_bits"); } } + int del_temp_wires_count = 0; + for (auto wire : del_wires_queue) { + if (ys_debug() || (check_public_name(wire->name) && verbose)) + log_debug(" removing unused non-port wire %s.\n", wire->name.c_str()); + else + del_temp_wires_count++; + } - pool<RTLIL::Wire*> del_wires; + module->remove(del_wires_queue); + count_rm_wires += GetSize(del_wires_queue); - int del_wires_count = 0; - for (auto wire : maybe_del_wires) - if (!used_signals.check_any(RTLIL::SigSpec(wire))) { - if (check_public_name(wire->name) && verbose) { - log(" removing unused non-port wire %s.\n", wire->name.c_str()); - } - del_wires.insert(wire); - del_wires_count++; - } + if (verbose && del_temp_wires_count) + log_debug(" removed %d unused temporary wires.\n", del_temp_wires_count); - module->remove(del_wires); - count_rm_wires += del_wires.size(); - - if (verbose && del_wires_count > 0) - log(" removed %d unused temporary wires.\n", del_wires_count); + return !del_wires_queue.empty(); } bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose) @@ -349,18 +413,18 @@ bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose) dict<SigBit, State> qbits; for (auto cell : module->cells()) - if (fftypes.cell_known(cell->type) && cell->hasPort("\\Q")) + if (fftypes.cell_known(cell->type) && cell->hasPort(ID(Q))) { - SigSpec sig = cell->getPort("\\Q"); + SigSpec sig = cell->getPort(ID(Q)); for (int i = 0; i < GetSize(sig); i++) { SigBit bit = sig[i]; - if (bit.wire == nullptr || bit.wire->attributes.count("\\init") == 0) + if (bit.wire == nullptr || bit.wire->attributes.count(ID(init)) == 0) continue; - Const init = bit.wire->attributes.at("\\init"); + Const init = bit.wire->attributes.at(ID(init)); if (i >= GetSize(init) || init[i] == State::Sx || init[i] == State::Sz) continue; @@ -375,10 +439,10 @@ bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose) if (!purge_mode && wire->name[0] == '\\') continue; - if (wire->attributes.count("\\init") == 0) + if (wire->attributes.count(ID(init)) == 0) continue; - Const init = wire->attributes.at("\\init"); + Const init = wire->attributes.at(ID(init)); for (int i = 0; i < GetSize(wire) && i < GetSize(init); i++) { @@ -399,9 +463,9 @@ bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose) } if (verbose) - log(" removing redundant init attribute on %s.\n", log_id(wire)); + log_debug(" removing redundant init attribute on %s.\n", log_id(wire)); - wire->attributes.erase("\\init"); + wire->attributes.erase(ID(init)); did_something = true; next_wire:; } @@ -416,33 +480,33 @@ void rmunused_module(RTLIL::Module *module, bool purge_mode, bool verbose, bool std::vector<RTLIL::Cell*> delcells; for (auto cell : module->cells()) - if (cell->type.in("$pos", "$_BUF_")) { - bool is_signed = cell->type == "$pos" && cell->getParam("\\A_SIGNED").as_bool(); - RTLIL::SigSpec a = cell->getPort("\\A"); - RTLIL::SigSpec y = cell->getPort("\\Y"); + if (cell->type.in(ID($pos), ID($_BUF_)) && !cell->has_keep_attr()) { + bool is_signed = cell->type == ID($pos) && cell->getParam(ID(A_SIGNED)).as_bool(); + RTLIL::SigSpec a = cell->getPort(ID::A); + RTLIL::SigSpec y = cell->getPort(ID::Y); a.extend_u0(GetSize(y), is_signed); module->connect(y, a); delcells.push_back(cell); } for (auto cell : delcells) { if (verbose) - log(" removing buffer cell `%s': %s = %s\n", cell->name.c_str(), - log_signal(cell->getPort("\\Y")), log_signal(cell->getPort("\\A"))); + log_debug(" removing buffer cell `%s': %s = %s\n", cell->name.c_str(), + log_signal(cell->getPort(ID::Y)), log_signal(cell->getPort(ID::A))); module->remove(cell); } if (!delcells.empty()) module->design->scratchpad_set_bool("opt.did_something", true); rmunused_module_cells(module, verbose); - rmunused_module_signals(module, purge_mode, verbose); + while (rmunused_module_signals(module, purge_mode, verbose)) { } if (rminit && rmunused_module_init(module, purge_mode, verbose)) - rmunused_module_signals(module, purge_mode, verbose); + while (rmunused_module_signals(module, purge_mode, verbose)) { } } struct OptCleanPass : public Pass { OptCleanPass() : Pass("opt_clean", "remove unused cells and wires") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -459,7 +523,7 @@ struct OptCleanPass : public Pass { log(" also remove internal nets if they have a public name\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { bool purge_mode = false; @@ -483,6 +547,9 @@ struct OptCleanPass : public Pass { ct_all.setup(design); + count_rm_cells = 0; + count_rm_wires = 0; + for (auto module : design->selected_whole_modules_warn()) { if (module->has_processes_warn()) continue; @@ -505,7 +572,7 @@ struct OptCleanPass : public Pass { struct CleanPass : public Pass { CleanPass() : Pass("clean", "remove unused cells and wires") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -520,7 +587,7 @@ struct CleanPass : public Pass { log("in -purge mode between the commands.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { bool purge_mode = false; @@ -548,9 +615,10 @@ struct CleanPass : public Pass { for (auto module : design->selected_whole_modules()) { if (module->has_processes()) continue; - rmunused_module(module, purge_mode, false, false); + rmunused_module(module, purge_mode, ys_debug(), false); } + log_suppressed(); if (count_rm_cells > 0 || count_rm_wires > 0) log("Removed %d unused cells and %d unused wires.\n", count_rm_cells, count_rm_wires); diff --git a/passes/opt/opt_demorgan.cc b/passes/opt/opt_demorgan.cc index f2af1cb93..4bc82815b 100644 --- a/passes/opt/opt_demorgan.cc +++ b/passes/opt/opt_demorgan.cc @@ -35,10 +35,10 @@ void demorgan_worker( //TODO: Add support for reduce_xor //DeMorgan of XOR is either XOR (if even number of inputs) or XNOR (if odd number) - if( (cell->type != "$reduce_and") && (cell->type != "$reduce_or") ) + if( (cell->type != ID($reduce_and)) && (cell->type != ID($reduce_or)) ) return; - auto insig = sigmap(cell->getPort("\\A")); + auto insig = sigmap(cell->getPort(ID::A)); log("Inspecting %s cell %s (%d inputs)\n", log_id(cell->type), log_id(cell->name), GetSize(insig)); int num_inverted = 0; for(int i=0; i<GetSize(insig); i++) @@ -51,7 +51,7 @@ void demorgan_worker( bool inverted = false; for(auto x : ports) { - if(x.port == "\\Y" && x.cell->type == "$_NOT_") + if(x.port == ID::Y && x.cell->type == ID($_NOT_)) { inverted = true; break; @@ -85,7 +85,7 @@ void demorgan_worker( RTLIL::Cell* srcinv = NULL; for(auto x : ports) { - if(x.port == "\\Y" && x.cell->type == "$_NOT_") + if(x.port == ID::Y && x.cell->type == ID($_NOT_)) { srcinv = x.cell; break; @@ -103,7 +103,7 @@ void demorgan_worker( //We ARE inverted - bypass it //Don't automatically delete the inverter since other stuff might still use it else - insig[i] = srcinv->getPort("\\A"); + insig[i] = srcinv->getPort(ID::A); } //Cosmetic fixup: If our input is just a scrambled version of one bus, rearrange it @@ -151,25 +151,25 @@ void demorgan_worker( } //Push the new input signal back to the reduction (after bypassing/adding inverters) - cell->setPort("\\A", insig); + cell->setPort(ID::A, insig); //Change the cell type - if(cell->type == "$reduce_and") - cell->type = "$reduce_or"; - else if(cell->type == "$reduce_or") - cell->type = "$reduce_and"; + if(cell->type == ID($reduce_and)) + cell->type = ID($reduce_or); + else if(cell->type == ID($reduce_or)) + cell->type = ID($reduce_and); //don't change XOR //Add an inverter to the output - auto inverted_output = cell->getPort("\\Y"); + auto inverted_output = cell->getPort(ID::Y); auto uninverted_output = m->addWire(NEW_ID); m->addNot(NEW_ID, RTLIL::SigSpec(uninverted_output), inverted_output); - cell->setPort("\\Y", uninverted_output); + cell->setPort(ID::Y, uninverted_output); } struct OptDemorganPass : public Pass { OptDemorganPass() : Pass("opt_demorgan", "Optimize reductions with DeMorgan equivalents") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -179,7 +179,7 @@ struct OptDemorganPass : public Pass { log("overall gate count of the circuit\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing OPT_DEMORGAN pass (push inverters through $reduce_* cells).\n"); diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc index a54a5c6b8..6cf66fb95 100644 --- a/passes/opt/opt_expr.cc +++ b/passes/opt/opt_expr.cc @@ -39,6 +39,9 @@ void replace_undriven(RTLIL::Design *design, RTLIL::Module *module) SigPool used_signals; SigPool all_signals; + dict<SigBit, pair<Wire*, State>> initbits; + pool<Wire*> revisit_initwires; + for (auto cell : module->cells()) for (auto &conn : cell->connections()) { if (!ct.cell_known(cell->type) || ct.cell_output(cell->type, conn.first)) @@ -48,9 +51,17 @@ void replace_undriven(RTLIL::Design *design, RTLIL::Module *module) } for (auto wire : module->wires()) { + if (wire->attributes.count(ID(init))) { + SigSpec sig = sigmap(wire); + Const initval = wire->attributes.at(ID(init)); + for (int i = 0; i < GetSize(initval) && i < GetSize(wire); i++) { + if (initval[i] == State::S0 || initval[i] == State::S1) + initbits[sig[i]] = make_pair(wire, initval[i]); + } + } if (wire->port_input) driven_signals.add(sigmap(wire)); - if (wire->port_output) + if (wire->port_output || wire->get_bool_attribute(ID::keep)) used_signals.add(sigmap(wire)); all_signals.add(sigmap(wire)); } @@ -67,18 +78,52 @@ void replace_undriven(RTLIL::Design *design, RTLIL::Module *module) if (sig.size() == 0) continue; - log("Setting undriven signal in %s to undef: %s\n", RTLIL::id2cstr(module->name), log_signal(c)); - module->connect(RTLIL::SigSig(c, RTLIL::SigSpec(RTLIL::State::Sx, c.width))); + Const val(RTLIL::State::Sx, GetSize(sig)); + for (int i = 0; i < GetSize(sig); i++) { + SigBit bit = sigmap(sig[i]); + auto cursor = initbits.find(bit); + if (cursor != initbits.end()) { + revisit_initwires.insert(cursor->second.first); + val[i] = cursor->second.second; + } + } + + log_debug("Setting undriven signal in %s to constant: %s = %s\n", log_id(module), log_signal(sig), log_signal(val)); + module->connect(sig, val); did_something = true; } + + if (!revisit_initwires.empty()) + { + SigMap sm2(module); + + for (auto wire : revisit_initwires) { + SigSpec sig = sm2(wire); + Const initval = wire->attributes.at(ID(init)); + for (int i = 0; i < GetSize(initval) && i < GetSize(wire); i++) { + if (SigBit(initval[i]) == sig[i]) + initval[i] = State::Sx; + } + if (initval.is_fully_undef()) { + log_debug("Removing init attribute from %s/%s.\n", log_id(module), log_id(wire)); + wire->attributes.erase(ID(init)); + did_something = true; + } else if (initval != wire->attributes.at(ID(init))) { + log_debug("Updating init attribute on %s/%s: %s\n", log_id(module), log_id(wire), log_signal(initval)); + wire->attributes[ID(init)] = initval; + did_something = true; + } + } + } } -void replace_cell(SigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell, std::string info, std::string out_port, RTLIL::SigSpec out_val) +void replace_cell(SigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell, + const std::string &info YS_ATTRIBUTE(unused), IdString out_port, RTLIL::SigSpec out_val) { RTLIL::SigSpec Y = cell->getPort(out_port); out_val.extend_u0(Y.size(), false); - log("Replacing %s cell `%s' (%s) in module `%s' with constant driver `%s = %s'.\n", + log_debug("Replacing %s cell `%s' (%s) in module `%s' with constant driver `%s = %s'.\n", cell->type.c_str(), cell->name.c_str(), info.c_str(), module->name.c_str(), log_signal(Y), log_signal(out_val)); // log_cell(cell); @@ -90,14 +135,14 @@ void replace_cell(SigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell, bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutative, SigMap &sigmap) { - std::string b_name = cell->hasPort("\\B") ? "\\B" : "\\A"; + IdString b_name = cell->hasPort(ID::B) ? ID::B : ID::A; - bool a_signed = cell->parameters.at("\\A_SIGNED").as_bool(); - bool b_signed = cell->parameters.at(b_name + "_SIGNED").as_bool(); + bool a_signed = cell->parameters.at(ID(A_SIGNED)).as_bool(); + bool b_signed = cell->parameters.at(b_name.str() + "_SIGNED").as_bool(); - RTLIL::SigSpec sig_a = sigmap(cell->getPort("\\A")); + RTLIL::SigSpec sig_a = sigmap(cell->getPort(ID::A)); RTLIL::SigSpec sig_b = sigmap(cell->getPort(b_name)); - RTLIL::SigSpec sig_y = sigmap(cell->getPort("\\Y")); + RTLIL::SigSpec sig_y = sigmap(cell->getPort(ID::Y)); sig_a.extend_u0(sig_y.size(), a_signed); sig_b.extend_u0(sig_y.size(), b_signed); @@ -112,10 +157,10 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ int group_idx = GRP_DYN; RTLIL::SigBit bit_a = bits_a[i], bit_b = bits_b[i]; - if (cell->type == "$or" && (bit_a == RTLIL::State::S1 || bit_b == RTLIL::State::S1)) + if (cell->type == ID($or) && (bit_a == RTLIL::State::S1 || bit_b == RTLIL::State::S1)) bit_a = bit_b = RTLIL::State::S1; - if (cell->type == "$and" && (bit_a == RTLIL::State::S0 || bit_b == RTLIL::State::S0)) + if (cell->type == ID($and) && (bit_a == RTLIL::State::S0 || bit_b == RTLIL::State::S0)) bit_a = bit_b = RTLIL::State::S0; if (bit_a.wire == NULL && bit_b.wire == NULL) @@ -134,7 +179,7 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ if (GetSize(grouped_bits[i]) == GetSize(bits_y)) return false; - log("Replacing %s cell `%s' in module `%s' with cells using grouped bits:\n", + log_debug("Replacing %s cell `%s' in module `%s' with cells using grouped bits:\n", log_id(cell->type), log_id(cell), log_id(module)); for (int i = 0; i < GRP_N; i++) @@ -155,28 +200,35 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ new_b.append_bit(it.first.second); } + if (cell->type.in(ID($and), ID($or)) && i == GRP_CONST_A) { + log_debug(" Direct Connection: %s (%s with %s)\n", log_signal(new_b), log_id(cell->type), log_signal(new_a)); + module->connect(new_y, new_b); + module->connect(new_conn); + continue; + } + RTLIL::Cell *c = module->addCell(NEW_ID, cell->type); - c->setPort("\\A", new_a); - c->parameters["\\A_WIDTH"] = new_a.size(); - c->parameters["\\A_SIGNED"] = false; + c->setPort(ID::A, new_a); + c->parameters[ID(A_WIDTH)] = new_a.size(); + c->parameters[ID(A_SIGNED)] = false; - if (b_name == "\\B") { - c->setPort("\\B", new_b); - c->parameters["\\B_WIDTH"] = new_b.size(); - c->parameters["\\B_SIGNED"] = false; + if (b_name == ID::B) { + c->setPort(ID::B, new_b); + c->parameters[ID(B_WIDTH)] = new_b.size(); + c->parameters[ID(B_SIGNED)] = false; } - c->setPort("\\Y", new_y); - c->parameters["\\Y_WIDTH"] = new_y->width; + c->setPort(ID::Y, new_y); + c->parameters[ID(Y_WIDTH)] = new_y->width; c->check(); module->connect(new_conn); - log(" New cell `%s': A=%s", log_id(c), log_signal(new_a)); - if (b_name == "\\B") - log(", B=%s", log_signal(new_b)); - log("\n"); + log_debug(" New cell `%s': A=%s", log_id(c), log_signal(new_a)); + if (b_name == ID::B) + log_debug(", B=%s", log_signal(new_b)); + log_debug("\n"); } cover_list("opt.opt_expr.fine.group", "$not", "$pos", "$and", "$or", "$xor", "$xnor", cell->type.str()); @@ -190,7 +242,7 @@ void handle_polarity_inv(Cell *cell, IdString port, IdString param, const SigMap { SigSpec sig = assign_map(cell->getPort(port)); if (invert_map.count(sig)) { - log("Inverting %s of %s cell `%s' in module `%s': %s -> %s\n", + log_debug("Inverting %s of %s cell `%s' in module `%s': %s -> %s\n", log_id(port), log_id(cell->type), log_id(cell), log_id(cell->module), log_signal(sig), log_signal(invert_map.at(sig))); cell->setPort(port, (invert_map.at(sig))); @@ -219,7 +271,7 @@ void handle_clkpol_celltype_swap(Cell *cell, string type1, string type2, IdStrin if (cell->type.in(type1, type2)) { SigSpec sig = assign_map(cell->getPort(port)); if (invert_map.count(sig)) { - log("Inverting %s of %s cell `%s' in module `%s': %s -> %s\n", + log_debug("Inverting %s of %s cell `%s' in module `%s': %s -> %s\n", log_id(port), log_id(cell->type), log_id(cell), log_id(cell->module), log_signal(sig), log_signal(invert_map.at(sig))); cell->setPort(port, (invert_map.at(sig))); @@ -259,6 +311,22 @@ bool is_one_or_minus_one(const Const &value, bool is_signed, bool &is_negative) return last_bit_one; } +int get_highest_hot_index(RTLIL::SigSpec signal) +{ + for (int i = GetSize(signal) - 1; i >= 0; i--) + { + if (signal[i] == RTLIL::State::S0) + continue; + + if (signal[i] == RTLIL::State::S1) + return i; + + break; + } + + return -1; +} + // if the signal has only one bit set, return the index of that bit. // otherwise return -1 int get_onehot_bit_index(RTLIL::SigSpec signal) @@ -300,11 +368,12 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons for (auto cell : module->cells()) if (design->selected(module, cell) && cell->type[0] == '$') { - if ((cell->type == "$_NOT_" || cell->type == "$not" || cell->type == "$logic_not") && - cell->getPort("\\A").size() == 1 && cell->getPort("\\Y").size() == 1) - invert_map[assign_map(cell->getPort("\\Y"))] = assign_map(cell->getPort("\\A")); - if ((cell->type == "$mux" || cell->type == "$_MUX_") && cell->getPort("\\A") == SigSpec(State::S1) && cell->getPort("\\B") == SigSpec(State::S0)) - invert_map[assign_map(cell->getPort("\\Y"))] = assign_map(cell->getPort("\\S")); + if (cell->type.in(ID($_NOT_), ID($not), ID($logic_not)) && + GetSize(cell->getPort(ID::A)) == 1 && GetSize(cell->getPort(ID::Y)) == 1) + invert_map[assign_map(cell->getPort(ID::Y))] = assign_map(cell->getPort(ID::A)); + if (cell->type.in(ID($mux), ID($_MUX_)) && + cell->getPort(ID::A) == SigSpec(State::S1) && cell->getPort(ID::B) == SigSpec(State::S0)) + invert_map[assign_map(cell->getPort(ID::Y))] = assign_map(cell->getPort(ID(S))); if (ct_combinational.cell_known(cell->type)) for (auto &conn : cell->connections()) { RTLIL::SigSpec sig = assign_map(conn.second); @@ -328,66 +397,66 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons for (auto cell : cells.sorted) { #define ACTION_DO(_p_, _s_) do { cover("opt.opt_expr.action_" S__LINE__); replace_cell(assign_map, module, cell, input.as_string(), _p_, _s_); goto next_cell; } while (0) -#define ACTION_DO_Y(_v_) ACTION_DO("\\Y", RTLIL::SigSpec(RTLIL::State::S ## _v_)) +#define ACTION_DO_Y(_v_) ACTION_DO(ID::Y, RTLIL::SigSpec(RTLIL::State::S ## _v_)) if (clkinv) { - if (cell->type.in("$dff", "$dffe", "$dffsr", "$adff", "$fsm", "$memrd", "$memwr")) - handle_polarity_inv(cell, "\\CLK", "\\CLK_POLARITY", assign_map, invert_map); + if (cell->type.in(ID($dff), ID($dffe), ID($dffsr), ID($adff), ID($fsm), ID($memrd), ID($memwr))) + handle_polarity_inv(cell, ID(CLK), ID(CLK_POLARITY), assign_map, invert_map); - if (cell->type.in("$sr", "$dffsr", "$dlatchsr")) { - handle_polarity_inv(cell, "\\SET", "\\SET_POLARITY", assign_map, invert_map); - handle_polarity_inv(cell, "\\CLR", "\\CLR_POLARITY", assign_map, invert_map); + if (cell->type.in(ID($sr), ID($dffsr), ID($dlatchsr))) { + handle_polarity_inv(cell, ID(SET), ID(SET_POLARITY), assign_map, invert_map); + handle_polarity_inv(cell, ID(CLR), ID(CLR_POLARITY), assign_map, invert_map); } - if (cell->type.in("$dffe", "$dlatch", "$dlatchsr")) - handle_polarity_inv(cell, "\\EN", "\\EN_POLARITY", assign_map, invert_map); + if (cell->type.in(ID($dffe), ID($dlatch), ID($dlatchsr))) + handle_polarity_inv(cell, ID(EN), ID(EN_POLARITY), assign_map, invert_map); - handle_clkpol_celltype_swap(cell, "$_SR_N?_", "$_SR_P?_", "\\S", assign_map, invert_map); - handle_clkpol_celltype_swap(cell, "$_SR_?N_", "$_SR_?P_", "\\R", assign_map, invert_map); + handle_clkpol_celltype_swap(cell, "$_SR_N?_", "$_SR_P?_", ID(S), assign_map, invert_map); + handle_clkpol_celltype_swap(cell, "$_SR_?N_", "$_SR_?P_", ID(R), assign_map, invert_map); - handle_clkpol_celltype_swap(cell, "$_DFF_N_", "$_DFF_P_", "\\C", assign_map, invert_map); + handle_clkpol_celltype_swap(cell, "$_DFF_N_", "$_DFF_P_", ID(C), assign_map, invert_map); - handle_clkpol_celltype_swap(cell, "$_DFFE_N?_", "$_DFFE_P?_", "\\C", assign_map, invert_map); - handle_clkpol_celltype_swap(cell, "$_DFFE_?N_", "$_DFFE_?P_", "\\E", assign_map, invert_map); + handle_clkpol_celltype_swap(cell, "$_DFFE_N?_", "$_DFFE_P?_", ID(C), assign_map, invert_map); + handle_clkpol_celltype_swap(cell, "$_DFFE_?N_", "$_DFFE_?P_", ID(E), assign_map, invert_map); - handle_clkpol_celltype_swap(cell, "$_DFF_N??_", "$_DFF_P??_", "\\C", assign_map, invert_map); - handle_clkpol_celltype_swap(cell, "$_DFF_?N?_", "$_DFF_?P?_", "\\R", assign_map, invert_map); + handle_clkpol_celltype_swap(cell, "$_DFF_N??_", "$_DFF_P??_", ID(C), assign_map, invert_map); + handle_clkpol_celltype_swap(cell, "$_DFF_?N?_", "$_DFF_?P?_", ID(R), assign_map, invert_map); - handle_clkpol_celltype_swap(cell, "$_DFFSR_N??_", "$_DFFSR_P??_", "\\C", assign_map, invert_map); - handle_clkpol_celltype_swap(cell, "$_DFFSR_?N?_", "$_DFFSR_?P?_", "\\S", assign_map, invert_map); - handle_clkpol_celltype_swap(cell, "$_DFFSR_??N_", "$_DFFSR_??P_", "\\R", assign_map, invert_map); + handle_clkpol_celltype_swap(cell, "$_DFFSR_N??_", "$_DFFSR_P??_", ID(C), assign_map, invert_map); + handle_clkpol_celltype_swap(cell, "$_DFFSR_?N?_", "$_DFFSR_?P?_", ID(S), assign_map, invert_map); + handle_clkpol_celltype_swap(cell, "$_DFFSR_??N_", "$_DFFSR_??P_", ID(R), assign_map, invert_map); - handle_clkpol_celltype_swap(cell, "$_DLATCH_N_", "$_DLATCH_P_", "\\E", assign_map, invert_map); + handle_clkpol_celltype_swap(cell, "$_DLATCH_N_", "$_DLATCH_P_", ID(E), assign_map, invert_map); - handle_clkpol_celltype_swap(cell, "$_DLATCHSR_N??_", "$_DLATCHSR_P??_", "\\E", assign_map, invert_map); - handle_clkpol_celltype_swap(cell, "$_DLATCHSR_?N?_", "$_DLATCHSR_?P?_", "\\S", assign_map, invert_map); - handle_clkpol_celltype_swap(cell, "$_DLATCHSR_??N_", "$_DLATCHSR_??P_", "\\R", assign_map, invert_map); + handle_clkpol_celltype_swap(cell, "$_DLATCHSR_N??_", "$_DLATCHSR_P??_", ID(E), assign_map, invert_map); + handle_clkpol_celltype_swap(cell, "$_DLATCHSR_?N?_", "$_DLATCHSR_?P?_", ID(S), assign_map, invert_map); + handle_clkpol_celltype_swap(cell, "$_DLATCHSR_??N_", "$_DLATCHSR_??P_", ID(R), assign_map, invert_map); } bool detect_const_and = false; bool detect_const_or = false; - if (cell->type.in("$reduce_and", "$_AND_")) + if (cell->type.in(ID($reduce_and), ID($_AND_))) detect_const_and = true; - if (cell->type.in("$and", "$logic_and") && GetSize(cell->getPort("\\A")) == 1 && GetSize(cell->getPort("\\B")) == 1 && !cell->getParam("\\A_SIGNED").as_bool()) + if (cell->type.in(ID($and), ID($logic_and)) && GetSize(cell->getPort(ID::A)) == 1 && GetSize(cell->getPort(ID::B)) == 1 && !cell->getParam(ID(A_SIGNED)).as_bool()) detect_const_and = true; - if (cell->type.in("$reduce_or", "$reduce_bool", "$_OR_")) + if (cell->type.in(ID($reduce_or), ID($reduce_bool), ID($_OR_))) detect_const_or = true; - if (cell->type.in("$or", "$logic_or") && GetSize(cell->getPort("\\A")) == 1 && GetSize(cell->getPort("\\B")) == 1 && !cell->getParam("\\A_SIGNED").as_bool()) + if (cell->type.in(ID($or), ID($logic_or)) && GetSize(cell->getPort(ID::A)) == 1 && GetSize(cell->getPort(ID::B)) == 1 && !cell->getParam(ID(A_SIGNED)).as_bool()) detect_const_or = true; if (detect_const_and || detect_const_or) { - pool<SigBit> input_bits = assign_map(cell->getPort("\\A")).to_sigbit_pool(); + pool<SigBit> input_bits = assign_map(cell->getPort(ID::A)).to_sigbit_pool(); bool found_zero = false, found_one = false, found_undef = false, found_inv = false, many_conconst = false; SigBit non_const_input = State::Sm; - if (cell->hasPort("\\B")) { - vector<SigBit> more_bits = assign_map(cell->getPort("\\B")).to_sigbit_vector(); + if (cell->hasPort(ID::B)) { + vector<SigBit> more_bits = assign_map(cell->getPort(ID::B)).to_sigbit_vector(); input_bits.insert(more_bits.begin(), more_bits.end()); } @@ -410,51 +479,50 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons if (detect_const_and && (found_zero || found_inv)) { cover("opt.opt_expr.const_and"); - replace_cell(assign_map, module, cell, "const_and", "\\Y", RTLIL::State::S0); + replace_cell(assign_map, module, cell, "const_and", ID::Y, RTLIL::State::S0); goto next_cell; } if (detect_const_or && (found_one || found_inv)) { cover("opt.opt_expr.const_or"); - replace_cell(assign_map, module, cell, "const_or", "\\Y", RTLIL::State::S1); + replace_cell(assign_map, module, cell, "const_or", ID::Y, RTLIL::State::S1); goto next_cell; } if (non_const_input != State::Sm && !found_undef) { cover("opt.opt_expr.and_or_buffer"); - replace_cell(assign_map, module, cell, "and_or_buffer", "\\Y", non_const_input); + replace_cell(assign_map, module, cell, "and_or_buffer", ID::Y, non_const_input); goto next_cell; } } - if (cell->type.in("$reduce_and", "$reduce_or", "$reduce_bool", "$reduce_xor", "$reduce_xnor", "$neg") && - GetSize(cell->getPort("\\A")) == 1 && GetSize(cell->getPort("\\Y")) == 1) + if (cell->type.in(ID($reduce_and), ID($reduce_or), ID($reduce_bool), ID($reduce_xor), ID($reduce_xnor), ID($neg)) && + GetSize(cell->getPort(ID::A)) == 1 && GetSize(cell->getPort(ID::Y)) == 1) { - if (cell->type == "$reduce_xnor") { + if (cell->type == ID($reduce_xnor)) { cover("opt.opt_expr.reduce_xnor_not"); - log("Replacing %s cell `%s' in module `%s' with $not cell.\n", + log_debug("Replacing %s cell `%s' in module `%s' with $not cell.\n", log_id(cell->type), log_id(cell->name), log_id(module)); - cell->type = "$not"; + cell->type = ID($not); + did_something = true; } else { cover("opt.opt_expr.unary_buffer"); - replace_cell(assign_map, module, cell, "unary_buffer", "\\Y", cell->getPort("\\A")); + replace_cell(assign_map, module, cell, "unary_buffer", ID::Y, cell->getPort(ID::A)); } goto next_cell; } if (do_fine) { - if (cell->type == "$not" || cell->type == "$pos" || - cell->type == "$and" || cell->type == "$or" || cell->type == "$xor" || cell->type == "$xnor") + if (cell->type.in(ID($not), ID($pos), ID($and), ID($or), ID($xor), ID($xnor))) if (group_cell_inputs(module, cell, true, assign_map)) goto next_cell; - if (cell->type == "$logic_not" || cell->type == "$logic_and" || cell->type == "$logic_or" || - cell->type == "$reduce_or" || cell->type == "$reduce_and" || cell->type == "$reduce_bool") + if (cell->type.in(ID($logic_not), ID($logic_and), ID($logic_or), ID($reduce_or), ID($reduce_and), ID($reduce_bool))) { - SigBit neutral_bit = cell->type == "$reduce_and" ? State::S1 : State::S0; + SigBit neutral_bit = cell->type == ID($reduce_and) ? State::S1 : State::S0; - RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A")); + RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID::A)); RTLIL::SigSpec new_sig_a; for (auto bit : sig_a) @@ -465,19 +533,19 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons if (GetSize(new_sig_a) < GetSize(sig_a)) { cover_list("opt.opt_expr.fine.neutral_A", "$logic_not", "$logic_and", "$logic_or", "$reduce_or", "$reduce_and", "$reduce_bool", cell->type.str()); - log("Replacing port A of %s cell `%s' in module `%s' with shorter expression: %s -> %s\n", + log_debug("Replacing port A of %s cell `%s' in module `%s' with shorter expression: %s -> %s\n", cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_sig_a)); - cell->setPort("\\A", new_sig_a); - cell->parameters.at("\\A_WIDTH") = GetSize(new_sig_a); + cell->setPort(ID::A, new_sig_a); + cell->parameters.at(ID(A_WIDTH)) = GetSize(new_sig_a); did_something = true; } } - if (cell->type == "$logic_and" || cell->type == "$logic_or") + if (cell->type.in(ID($logic_and), ID($logic_or))) { SigBit neutral_bit = State::S0; - RTLIL::SigSpec sig_b = assign_map(cell->getPort("\\B")); + RTLIL::SigSpec sig_b = assign_map(cell->getPort(ID::B)); RTLIL::SigSpec new_sig_b; for (auto bit : sig_b) @@ -488,17 +556,17 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons if (GetSize(new_sig_b) < GetSize(sig_b)) { cover_list("opt.opt_expr.fine.neutral_B", "$logic_and", "$logic_or", cell->type.str()); - log("Replacing port B of %s cell `%s' in module `%s' with shorter expression: %s -> %s\n", + log_debug("Replacing port B of %s cell `%s' in module `%s' with shorter expression: %s -> %s\n", cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_b), log_signal(new_sig_b)); - cell->setPort("\\B", new_sig_b); - cell->parameters.at("\\B_WIDTH") = GetSize(new_sig_b); + cell->setPort(ID::B, new_sig_b); + cell->parameters.at(ID(B_WIDTH)) = GetSize(new_sig_b); did_something = true; } } - if (cell->type == "$reduce_and") + if (cell->type == ID($reduce_and)) { - RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A")); + RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID::A)); RTLIL::State new_a = RTLIL::State::S1; for (auto &bit : sig_a.to_sigbit_vector()) @@ -514,17 +582,17 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons if (new_a != RTLIL::State::Sm && RTLIL::SigSpec(new_a) != sig_a) { cover("opt.opt_expr.fine.$reduce_and"); - log("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n", + log_debug("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n", cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_a)); - cell->setPort("\\A", sig_a = new_a); - cell->parameters.at("\\A_WIDTH") = 1; + cell->setPort(ID::A, sig_a = new_a); + cell->parameters.at(ID(A_WIDTH)) = 1; did_something = true; } } - if (cell->type == "$logic_not" || cell->type == "$logic_and" || cell->type == "$logic_or" || cell->type == "$reduce_or" || cell->type == "$reduce_bool") + if (cell->type.in(ID($logic_not), ID($logic_and), ID($logic_or), ID($reduce_or), ID($reduce_bool))) { - RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A")); + RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID::A)); RTLIL::State new_a = RTLIL::State::S0; for (auto &bit : sig_a.to_sigbit_vector()) @@ -540,17 +608,17 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons if (new_a != RTLIL::State::Sm && RTLIL::SigSpec(new_a) != sig_a) { cover_list("opt.opt_expr.fine.A", "$logic_not", "$logic_and", "$logic_or", "$reduce_or", "$reduce_bool", cell->type.str()); - log("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n", + log_debug("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n", cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_a)); - cell->setPort("\\A", sig_a = new_a); - cell->parameters.at("\\A_WIDTH") = 1; + cell->setPort(ID::A, sig_a = new_a); + cell->parameters.at(ID(A_WIDTH)) = 1; did_something = true; } } - if (cell->type == "$logic_and" || cell->type == "$logic_or") + if (cell->type.in(ID($logic_and), ID($logic_or))) { - RTLIL::SigSpec sig_b = assign_map(cell->getPort("\\B")); + RTLIL::SigSpec sig_b = assign_map(cell->getPort(ID::B)); RTLIL::State new_b = RTLIL::State::S0; for (auto &bit : sig_b.to_sigbit_vector()) @@ -566,25 +634,95 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons if (new_b != RTLIL::State::Sm && RTLIL::SigSpec(new_b) != sig_b) { cover_list("opt.opt_expr.fine.B", "$logic_and", "$logic_or", cell->type.str()); - log("Replacing port B of %s cell `%s' in module `%s' with constant driver: %s -> %s\n", + log_debug("Replacing port B of %s cell `%s' in module `%s' with constant driver: %s -> %s\n", cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_b), log_signal(new_b)); - cell->setPort("\\B", sig_b = new_b); - cell->parameters.at("\\B_WIDTH") = 1; + cell->setPort(ID::B, sig_b = new_b); + cell->parameters.at(ID(B_WIDTH)) = 1; + did_something = true; + } + } + + if (cell->type.in(ID($add), ID($sub))) + { + RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID::A)); + RTLIL::SigSpec sig_b = assign_map(cell->getPort(ID::B)); + RTLIL::SigSpec sig_y = cell->getPort(ID::Y); + bool sub = cell->type == ID($sub); + + int i; + for (i = 0; i < GetSize(sig_y); i++) { + if (sig_b.at(i, State::Sx) == State::S0 && sig_a.at(i, State::Sx) != State::Sx) + module->connect(sig_y[i], sig_a[i]); + else if (!sub && sig_a.at(i, State::Sx) == State::S0 && sig_b.at(i, State::Sx) != State::Sx) + module->connect(sig_y[i], sig_b[i]); + else + break; + } + if (i > 0) { + cover_list("opt.opt_expr.fine", "$add", "$sub", cell->type.str()); + cell->setPort(ID::A, sig_a.extract_end(i)); + cell->setPort(ID::B, sig_b.extract_end(i)); + cell->setPort(ID::Y, sig_y.extract_end(i)); + cell->fixup_parameters(); + did_something = true; + } + } + + if (cell->type == "$alu") + { + RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID::A)); + RTLIL::SigSpec sig_b = assign_map(cell->getPort(ID::B)); + RTLIL::SigBit sig_ci = assign_map(cell->getPort(ID(CI))); + RTLIL::SigBit sig_bi = assign_map(cell->getPort(ID(BI))); + RTLIL::SigSpec sig_x = cell->getPort(ID(X)); + RTLIL::SigSpec sig_y = cell->getPort(ID::Y); + RTLIL::SigSpec sig_co = cell->getPort(ID(CO)); + + if (sig_ci.wire || sig_bi.wire) + goto next_cell; + + bool sub = (sig_ci == State::S1 && sig_bi == State::S1); + + // If not a subtraction, yet there is a carry or B is inverted + // then no optimisation is possible as carry will not be constant + if (!sub && (sig_ci != State::S0 || sig_bi != State::S0)) + goto next_cell; + + int i; + for (i = 0; i < GetSize(sig_y); i++) { + if (sig_b.at(i, State::Sx) == State::S0 && sig_a.at(i, State::Sx) != State::Sx) { + module->connect(sig_x[i], sub ? module->Not(NEW_ID, sig_a[i]).as_bit() : sig_a[i]); + module->connect(sig_y[i], sig_a[i]); + module->connect(sig_co[i], sub ? State::S1 : State::S0); + } + else if (!sub && sig_a.at(i, State::Sx) == State::S0 && sig_b.at(i, State::Sx) != State::Sx) { + module->connect(sig_x[i], sig_b[i]); + module->connect(sig_y[i], sig_b[i]); + module->connect(sig_co[i], State::S0); + } + else + break; + } + if (i > 0) { + cover("opt.opt_expr.fine.$alu"); + cell->setPort(ID::A, sig_a.extract_end(i)); + cell->setPort(ID::B, sig_b.extract_end(i)); + cell->setPort(ID(X), sig_x.extract_end(i)); + cell->setPort(ID::Y, sig_y.extract_end(i)); + cell->setPort(ID(CO), sig_co.extract_end(i)); + cell->fixup_parameters(); did_something = true; } } } - if (cell->type == "$reduce_xor" || cell->type == "$reduce_xnor" || cell->type == "$shift" || cell->type == "$shiftx" || - cell->type == "$shl" || cell->type == "$shr" || cell->type == "$sshl" || cell->type == "$sshr" || - cell->type == "$lt" || cell->type == "$le" || cell->type == "$ge" || cell->type == "$gt" || - cell->type == "$neg" || cell->type == "$add" || cell->type == "$sub" || - cell->type == "$mul" || cell->type == "$div" || cell->type == "$mod" || cell->type == "$pow") + if (cell->type.in(ID($reduce_xor), ID($reduce_xnor), ID($shift), ID($shiftx), ID($shl), ID($shr), ID($sshl), ID($sshr), + ID($lt), ID($le), ID($ge), ID($gt), ID($neg), ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($pow))) { - RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A")); - RTLIL::SigSpec sig_b = cell->hasPort("\\B") ? assign_map(cell->getPort("\\B")) : RTLIL::SigSpec(); + RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID::A)); + RTLIL::SigSpec sig_b = cell->hasPort(ID::B) ? assign_map(cell->getPort(ID::B)) : RTLIL::SigSpec(); - if (cell->type == "$shl" || cell->type == "$shr" || cell->type == "$sshl" || cell->type == "$sshr" || cell->type == "$shift" || cell->type == "$shiftx") + if (cell->type.in(ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx))) sig_a = RTLIL::SigSpec(); for (auto &bit : sig_a.to_sigbit_vector()) @@ -599,45 +737,66 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons found_the_x_bit: cover_list("opt.opt_expr.xbit", "$reduce_xor", "$reduce_xnor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", "$lt", "$le", "$ge", "$gt", "$neg", "$add", "$sub", "$mul", "$div", "$mod", "$pow", cell->type.str()); - if (cell->type == "$reduce_xor" || cell->type == "$reduce_xnor" || - cell->type == "$lt" || cell->type == "$le" || cell->type == "$ge" || cell->type == "$gt") - replace_cell(assign_map, module, cell, "x-bit in input", "\\Y", RTLIL::State::Sx); + if (cell->type.in(ID($reduce_xor), ID($reduce_xnor), ID($lt), ID($le), ID($ge), ID($gt))) + replace_cell(assign_map, module, cell, "x-bit in input", ID::Y, RTLIL::State::Sx); else - replace_cell(assign_map, module, cell, "x-bit in input", "\\Y", RTLIL::SigSpec(RTLIL::State::Sx, cell->getPort("\\Y").size())); + replace_cell(assign_map, module, cell, "x-bit in input", ID::Y, RTLIL::SigSpec(RTLIL::State::Sx, GetSize(cell->getPort(ID::Y)))); + goto next_cell; + } + } + + if (cell->type.in(ID($shiftx), ID($shift))) { + SigSpec sig_a = assign_map(cell->getPort(ID::A)); + int width; + bool trim_x = cell->type == ID($shiftx) || !keepdc; + bool trim_0 = cell->type == ID($shift); + for (width = GetSize(sig_a); width > 1; width--) { + if ((trim_x && sig_a[width-1] == State::Sx) || + (trim_0 && sig_a[width-1] == State::S0)) + continue; + break; + } + + if (width < GetSize(sig_a)) { + cover_list("opt.opt_expr.trim", "$shiftx", "$shift", cell->type.str()); + sig_a.remove(width, GetSize(sig_a)-width); + cell->setPort(ID::A, sig_a); + cell->setParam(ID(A_WIDTH), width); + did_something = true; goto next_cell; } } - if ((cell->type == "$_NOT_" || cell->type == "$not" || cell->type == "$logic_not") && cell->getPort("\\Y").size() == 1 && - invert_map.count(assign_map(cell->getPort("\\A"))) != 0) { + if (cell->type.in(ID($_NOT_), ID($not), ID($logic_not)) && GetSize(cell->getPort(ID::Y)) == 1 && + invert_map.count(assign_map(cell->getPort(ID::A))) != 0) { cover_list("opt.opt_expr.invert.double", "$_NOT_", "$not", "$logic_not", cell->type.str()); - replace_cell(assign_map, module, cell, "double_invert", "\\Y", invert_map.at(assign_map(cell->getPort("\\A")))); + replace_cell(assign_map, module, cell, "double_invert", ID::Y, invert_map.at(assign_map(cell->getPort(ID::A)))); goto next_cell; } - if ((cell->type == "$_MUX_" || cell->type == "$mux") && invert_map.count(assign_map(cell->getPort("\\S"))) != 0) { + if (cell->type.in(ID($_MUX_), ID($mux)) && invert_map.count(assign_map(cell->getPort(ID(S)))) != 0) { cover_list("opt.opt_expr.invert.muxsel", "$_MUX_", "$mux", cell->type.str()); - log("Optimizing away select inverter for %s cell `%s' in module `%s'.\n", log_id(cell->type), log_id(cell), log_id(module)); - RTLIL::SigSpec tmp = cell->getPort("\\A"); - cell->setPort("\\A", cell->getPort("\\B")); - cell->setPort("\\B", tmp); - cell->setPort("\\S", invert_map.at(assign_map(cell->getPort("\\S")))); + log_debug("Optimizing away select inverter for %s cell `%s' in module `%s'.\n", log_id(cell->type), log_id(cell), log_id(module)); + RTLIL::SigSpec tmp = cell->getPort(ID::A); + cell->setPort(ID::A, cell->getPort(ID::B)); + cell->setPort(ID::B, tmp); + cell->setPort(ID(S), invert_map.at(assign_map(cell->getPort(ID(S))))); did_something = true; goto next_cell; } - if (cell->type == "$_NOT_") { - RTLIL::SigSpec input = cell->getPort("\\A"); + if (cell->type == ID($_NOT_)) { + RTLIL::SigSpec input = cell->getPort(ID::A); assign_map.apply(input); if (input.match("1")) ACTION_DO_Y(0); if (input.match("0")) ACTION_DO_Y(1); if (input.match("*")) ACTION_DO_Y(x); } - if (cell->type == "$_AND_") { + if (cell->type == ID($_AND_)) { RTLIL::SigSpec input; - input.append(cell->getPort("\\B")); - input.append(cell->getPort("\\A")); + input.append(cell->getPort(ID::B)); + input.append(cell->getPort(ID::A)); assign_map.apply(input); if (input.match(" 0")) ACTION_DO_Y(0); if (input.match("0 ")) ACTION_DO_Y(0); @@ -649,14 +808,14 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons if (input.match(" *")) ACTION_DO_Y(0); if (input.match("* ")) ACTION_DO_Y(0); } - if (input.match(" 1")) ACTION_DO("\\Y", input.extract(1, 1)); - if (input.match("1 ")) ACTION_DO("\\Y", input.extract(0, 1)); + if (input.match(" 1")) ACTION_DO(ID::Y, input.extract(1, 1)); + if (input.match("1 ")) ACTION_DO(ID::Y, input.extract(0, 1)); } - if (cell->type == "$_OR_") { + if (cell->type == ID($_OR_)) { RTLIL::SigSpec input; - input.append(cell->getPort("\\B")); - input.append(cell->getPort("\\A")); + input.append(cell->getPort(ID::B)); + input.append(cell->getPort(ID::A)); assign_map.apply(input); if (input.match(" 1")) ACTION_DO_Y(1); if (input.match("1 ")) ACTION_DO_Y(1); @@ -668,14 +827,14 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons if (input.match(" *")) ACTION_DO_Y(1); if (input.match("* ")) ACTION_DO_Y(1); } - if (input.match(" 0")) ACTION_DO("\\Y", input.extract(1, 1)); - if (input.match("0 ")) ACTION_DO("\\Y", input.extract(0, 1)); + if (input.match(" 0")) ACTION_DO(ID::Y, input.extract(1, 1)); + if (input.match("0 ")) ACTION_DO(ID::Y, input.extract(0, 1)); } - if (cell->type == "$_XOR_") { + if (cell->type == ID($_XOR_)) { RTLIL::SigSpec input; - input.append(cell->getPort("\\B")); - input.append(cell->getPort("\\A")); + input.append(cell->getPort(ID::B)); + input.append(cell->getPort(ID::A)); assign_map.apply(input); if (input.match("00")) ACTION_DO_Y(0); if (input.match("01")) ACTION_DO_Y(1); @@ -683,27 +842,27 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons if (input.match("11")) ACTION_DO_Y(0); if (input.match(" *")) ACTION_DO_Y(x); if (input.match("* ")) ACTION_DO_Y(x); - if (input.match(" 0")) ACTION_DO("\\Y", input.extract(1, 1)); - if (input.match("0 ")) ACTION_DO("\\Y", input.extract(0, 1)); + if (input.match(" 0")) ACTION_DO(ID::Y, input.extract(1, 1)); + if (input.match("0 ")) ACTION_DO(ID::Y, input.extract(0, 1)); } - if (cell->type == "$_MUX_") { + if (cell->type == ID($_MUX_)) { RTLIL::SigSpec input; - input.append(cell->getPort("\\S")); - input.append(cell->getPort("\\B")); - input.append(cell->getPort("\\A")); + input.append(cell->getPort(ID(S))); + input.append(cell->getPort(ID::B)); + input.append(cell->getPort(ID::A)); assign_map.apply(input); if (input.extract(2, 1) == input.extract(1, 1)) - ACTION_DO("\\Y", input.extract(2, 1)); - if (input.match(" 0")) ACTION_DO("\\Y", input.extract(2, 1)); - if (input.match(" 1")) ACTION_DO("\\Y", input.extract(1, 1)); - if (input.match("01 ")) ACTION_DO("\\Y", input.extract(0, 1)); + ACTION_DO(ID::Y, input.extract(2, 1)); + if (input.match(" 0")) ACTION_DO(ID::Y, input.extract(2, 1)); + if (input.match(" 1")) ACTION_DO(ID::Y, input.extract(1, 1)); + if (input.match("01 ")) ACTION_DO(ID::Y, input.extract(0, 1)); if (input.match("10 ")) { cover("opt.opt_expr.mux_to_inv"); - cell->type = "$_NOT_"; - cell->setPort("\\A", input.extract(0, 1)); - cell->unsetPort("\\B"); - cell->unsetPort("\\S"); + cell->type = ID($_NOT_); + cell->setPort(ID::A, input.extract(0, 1)); + cell->unsetPort(ID::B); + cell->unsetPort(ID(S)); goto next_cell; } if (input.match("11 ")) ACTION_DO_Y(1); @@ -712,38 +871,38 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons if (input.match("01*")) ACTION_DO_Y(x); if (input.match("10*")) ACTION_DO_Y(x); if (mux_undef) { - if (input.match("* ")) ACTION_DO("\\Y", input.extract(1, 1)); - if (input.match(" * ")) ACTION_DO("\\Y", input.extract(2, 1)); - if (input.match(" *")) ACTION_DO("\\Y", input.extract(2, 1)); + if (input.match("* ")) ACTION_DO(ID::Y, input.extract(1, 1)); + if (input.match(" * ")) ACTION_DO(ID::Y, input.extract(2, 1)); + if (input.match(" *")) ACTION_DO(ID::Y, input.extract(2, 1)); } } - if (cell->type == "$_TBUF_" || cell->type == "$tribuf") { - RTLIL::SigSpec input = cell->getPort(cell->type == "$_TBUF_" ? "\\E" : "\\EN"); - RTLIL::SigSpec a = cell->getPort("\\A"); + if (cell->type.in(ID($_TBUF_), ID($tribuf))) { + RTLIL::SigSpec input = cell->getPort(cell->type == ID($_TBUF_) ? ID(E) : ID(EN)); + RTLIL::SigSpec a = cell->getPort(ID::A); assign_map.apply(input); assign_map.apply(a); if (input == State::S1) - ACTION_DO("\\Y", cell->getPort("\\A")); + ACTION_DO(ID::Y, cell->getPort(ID::A)); if (input == State::S0 && !a.is_fully_undef()) { cover("opt.opt_expr.action_" S__LINE__); - log("Replacing data input of %s cell `%s' in module `%s' with constant undef.\n", + log_debug("Replacing data input of %s cell `%s' in module `%s' with constant undef.\n", cell->type.c_str(), cell->name.c_str(), module->name.c_str()); - cell->setPort("\\A", SigSpec(State::Sx, GetSize(a))); + cell->setPort(ID::A, SigSpec(State::Sx, GetSize(a))); did_something = true; goto next_cell; } } - if (cell->type == "$eq" || cell->type == "$ne" || cell->type == "$eqx" || cell->type == "$nex") + if (cell->type.in(ID($eq), ID($ne), ID($eqx), ID($nex))) { - RTLIL::SigSpec a = cell->getPort("\\A"); - RTLIL::SigSpec b = cell->getPort("\\B"); + RTLIL::SigSpec a = cell->getPort(ID::A); + RTLIL::SigSpec b = cell->getPort(ID::B); - if (cell->parameters["\\A_WIDTH"].as_int() != cell->parameters["\\B_WIDTH"].as_int()) { - int width = max(cell->parameters["\\A_WIDTH"].as_int(), cell->parameters["\\B_WIDTH"].as_int()); - a.extend_u0(width, cell->parameters["\\A_SIGNED"].as_bool() && cell->parameters["\\B_SIGNED"].as_bool()); - b.extend_u0(width, cell->parameters["\\A_SIGNED"].as_bool() && cell->parameters["\\B_SIGNED"].as_bool()); + if (cell->parameters[ID(A_WIDTH)].as_int() != cell->parameters[ID(B_WIDTH)].as_int()) { + int width = max(cell->parameters[ID(A_WIDTH)].as_int(), cell->parameters[ID(B_WIDTH)].as_int()); + a.extend_u0(width, cell->parameters[ID(A_SIGNED)].as_bool() && cell->parameters[ID(B_SIGNED)].as_bool()); + b.extend_u0(width, cell->parameters[ID(A_SIGNED)].as_bool() && cell->parameters[ID(B_SIGNED)].as_bool()); } RTLIL::SigSpec new_a, new_b; @@ -752,9 +911,9 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons for (int i = 0; i < GetSize(a); i++) { if (a[i].wire == NULL && b[i].wire == NULL && a[i] != b[i] && a[i].data <= RTLIL::State::S1 && b[i].data <= RTLIL::State::S1) { cover_list("opt.opt_expr.eqneq.isneq", "$eq", "$ne", "$eqx", "$nex", cell->type.str()); - RTLIL::SigSpec new_y = RTLIL::SigSpec((cell->type == "$eq" || cell->type == "$eqx") ? RTLIL::State::S0 : RTLIL::State::S1); - new_y.extend_u0(cell->parameters["\\Y_WIDTH"].as_int(), false); - replace_cell(assign_map, module, cell, "isneq", "\\Y", new_y); + RTLIL::SigSpec new_y = RTLIL::SigSpec(cell->type.in(ID($eq), ID($eqx)) ? RTLIL::State::S0 : RTLIL::State::S1); + new_y.extend_u0(cell->parameters[ID(Y_WIDTH)].as_int(), false); + replace_cell(assign_map, module, cell, "isneq", ID::Y, new_y); goto next_cell; } if (a[i] == b[i]) @@ -765,83 +924,87 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons if (new_a.size() == 0) { cover_list("opt.opt_expr.eqneq.empty", "$eq", "$ne", "$eqx", "$nex", cell->type.str()); - RTLIL::SigSpec new_y = RTLIL::SigSpec((cell->type == "$eq" || cell->type == "$eqx") ? RTLIL::State::S1 : RTLIL::State::S0); - new_y.extend_u0(cell->parameters["\\Y_WIDTH"].as_int(), false); - replace_cell(assign_map, module, cell, "empty", "\\Y", new_y); + RTLIL::SigSpec new_y = RTLIL::SigSpec(cell->type.in(ID($eq), ID($eqx)) ? RTLIL::State::S1 : RTLIL::State::S0); + new_y.extend_u0(cell->parameters[ID(Y_WIDTH)].as_int(), false); + replace_cell(assign_map, module, cell, "empty", ID::Y, new_y); goto next_cell; } if (new_a.size() < a.size() || new_b.size() < b.size()) { cover_list("opt.opt_expr.eqneq.resize", "$eq", "$ne", "$eqx", "$nex", cell->type.str()); - cell->setPort("\\A", new_a); - cell->setPort("\\B", new_b); - cell->parameters["\\A_WIDTH"] = new_a.size(); - cell->parameters["\\B_WIDTH"] = new_b.size(); + cell->setPort(ID::A, new_a); + cell->setPort(ID::B, new_b); + cell->parameters[ID(A_WIDTH)] = new_a.size(); + cell->parameters[ID(B_WIDTH)] = new_b.size(); } } - if ((cell->type == "$eq" || cell->type == "$ne") && cell->parameters["\\Y_WIDTH"].as_int() == 1 && - cell->parameters["\\A_WIDTH"].as_int() == 1 && cell->parameters["\\B_WIDTH"].as_int() == 1) + if (cell->type.in(ID($eq), ID($ne)) && cell->parameters[ID(Y_WIDTH)].as_int() == 1 && + cell->parameters[ID(A_WIDTH)].as_int() == 1 && cell->parameters[ID(B_WIDTH)].as_int() == 1) { - RTLIL::SigSpec a = assign_map(cell->getPort("\\A")); - RTLIL::SigSpec b = assign_map(cell->getPort("\\B")); + RTLIL::SigSpec a = assign_map(cell->getPort(ID::A)); + RTLIL::SigSpec b = assign_map(cell->getPort(ID::B)); if (a.is_fully_const() && !b.is_fully_const()) { cover_list("opt.opt_expr.eqneq.swapconst", "$eq", "$ne", cell->type.str()); - cell->setPort("\\A", b); - cell->setPort("\\B", a); + cell->setPort(ID::A, b); + cell->setPort(ID::B, a); std::swap(a, b); } if (b.is_fully_const()) { - if (b.as_bool() == (cell->type == "$eq")) { + if (b.is_fully_undef()) { RTLIL::SigSpec input = b; - ACTION_DO("\\Y", cell->getPort("\\A")); + ACTION_DO(ID::Y, Const(State::Sx, GetSize(cell->getPort(ID::Y)))); + } else + if (b.as_bool() == (cell->type == ID($eq))) { + RTLIL::SigSpec input = b; + ACTION_DO(ID::Y, cell->getPort(ID::A)); } else { cover_list("opt.opt_expr.eqneq.isnot", "$eq", "$ne", cell->type.str()); - log("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell->type), log_id(cell), log_id(module)); - cell->type = "$not"; - cell->parameters.erase("\\B_WIDTH"); - cell->parameters.erase("\\B_SIGNED"); - cell->unsetPort("\\B"); + log_debug("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell->type), log_id(cell), log_id(module)); + cell->type = ID($not); + cell->parameters.erase(ID(B_WIDTH)); + cell->parameters.erase(ID(B_SIGNED)); + cell->unsetPort(ID::B); did_something = true; } goto next_cell; } } - if ((cell->type == "$eq" || cell->type == "$ne") && - (assign_map(cell->getPort("\\A")).is_fully_zero() || assign_map(cell->getPort("\\B")).is_fully_zero())) + if (cell->type.in(ID($eq), ID($ne)) && + (assign_map(cell->getPort(ID::A)).is_fully_zero() || assign_map(cell->getPort(ID::B)).is_fully_zero())) { cover_list("opt.opt_expr.eqneq.cmpzero", "$eq", "$ne", cell->type.str()); - log("Replacing %s cell `%s' in module `%s' with %s.\n", log_id(cell->type), log_id(cell), + log_debug("Replacing %s cell `%s' in module `%s' with %s.\n", log_id(cell->type), log_id(cell), log_id(module), "$eq" ? "$logic_not" : "$reduce_bool"); - cell->type = cell->type == "$eq" ? "$logic_not" : "$reduce_bool"; - if (assign_map(cell->getPort("\\A")).is_fully_zero()) { - cell->setPort("\\A", cell->getPort("\\B")); - cell->setParam("\\A_SIGNED", cell->getParam("\\B_SIGNED")); - cell->setParam("\\A_WIDTH", cell->getParam("\\B_WIDTH")); + cell->type = cell->type == ID($eq) ? ID($logic_not) : ID($reduce_bool); + if (assign_map(cell->getPort(ID::A)).is_fully_zero()) { + cell->setPort(ID::A, cell->getPort(ID::B)); + cell->setParam(ID(A_SIGNED), cell->getParam(ID(B_SIGNED))); + cell->setParam(ID(A_WIDTH), cell->getParam(ID(B_WIDTH))); } - cell->unsetPort("\\B"); - cell->unsetParam("\\B_SIGNED"); - cell->unsetParam("\\B_WIDTH"); + cell->unsetPort(ID::B); + cell->unsetParam(ID(B_SIGNED)); + cell->unsetParam(ID(B_WIDTH)); did_something = true; goto next_cell; } - if (cell->type.in("$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx") && assign_map(cell->getPort("\\B")).is_fully_const()) + if (cell->type.in(ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx)) && assign_map(cell->getPort(ID::B)).is_fully_const()) { - bool sign_ext = cell->type == "$sshr" && cell->getParam("\\A_SIGNED").as_bool(); - int shift_bits = assign_map(cell->getPort("\\B")).as_int(cell->type.in("$shift", "$shiftx") && cell->getParam("\\B_SIGNED").as_bool()); + bool sign_ext = cell->type == ID($sshr) && cell->getParam(ID(A_SIGNED)).as_bool(); + int shift_bits = assign_map(cell->getPort(ID::B)).as_int(cell->type.in(ID($shift), ID($shiftx)) && cell->getParam(ID(B_SIGNED)).as_bool()); - if (cell->type.in("$shl", "$sshl")) + if (cell->type.in(ID($shl), ID($sshl))) shift_bits *= -1; - RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A")); - RTLIL::SigSpec sig_y(cell->type == "$shiftx" ? RTLIL::State::Sx : RTLIL::State::S0, cell->getParam("\\Y_WIDTH").as_int()); + RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID::A)); + RTLIL::SigSpec sig_y(cell->type == ID($shiftx) ? RTLIL::State::Sx : RTLIL::State::S0, cell->getParam(ID(Y_WIDTH)).as_int()); if (GetSize(sig_a) < GetSize(sig_y)) - sig_a.extend_u0(GetSize(sig_y), cell->getParam("\\A_SIGNED").as_bool()); + sig_a.extend_u0(GetSize(sig_y), cell->getParam(ID(A_SIGNED)).as_bool()); for (int i = 0; i < GetSize(sig_y); i++) { int idx = i + shift_bits; @@ -853,10 +1016,10 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons cover_list("opt.opt_expr.constshift", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", cell->type.str()); - log("Replacing %s cell `%s' (B=%s, SHR=%d) in module `%s' with fixed wiring: %s\n", - log_id(cell->type), log_id(cell), log_signal(assign_map(cell->getPort("\\B"))), shift_bits, log_id(module), log_signal(sig_y)); + log_debug("Replacing %s cell `%s' (B=%s, SHR=%d) in module `%s' with fixed wiring: %s\n", + log_id(cell->type), log_id(cell), log_signal(assign_map(cell->getPort(ID::B))), shift_bits, log_id(module), log_signal(sig_y)); - module->connect(cell->getPort("\\Y"), sig_y); + module->connect(cell->getPort(ID::Y), sig_y); module->remove(cell); did_something = true; @@ -869,41 +1032,41 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons bool identity_wrt_b = false; bool arith_inverse = false; - if (cell->type == "$add" || cell->type == "$sub" || cell->type == "$or" || cell->type == "$xor") + if (cell->type.in(ID($add), ID($sub), ID($or), ID($xor))) { - RTLIL::SigSpec a = assign_map(cell->getPort("\\A")); - RTLIL::SigSpec b = assign_map(cell->getPort("\\B")); + RTLIL::SigSpec a = assign_map(cell->getPort(ID::A)); + RTLIL::SigSpec b = assign_map(cell->getPort(ID::B)); - if (cell->type != "$sub" && a.is_fully_const() && a.as_bool() == false) + if (cell->type != ID($sub) && a.is_fully_const() && a.as_bool() == false) identity_wrt_b = true; if (b.is_fully_const() && b.as_bool() == false) identity_wrt_a = true; } - if (cell->type == "$shl" || cell->type == "$shr" || cell->type == "$sshl" || cell->type == "$sshr" || cell->type == "$shift" || cell->type == "$shiftx") + if (cell->type.in(ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx))) { - RTLIL::SigSpec b = assign_map(cell->getPort("\\B")); + RTLIL::SigSpec b = assign_map(cell->getPort(ID::B)); if (b.is_fully_const() && b.as_bool() == false) identity_wrt_a = true; } - if (cell->type == "$mul") + if (cell->type == ID($mul)) { - RTLIL::SigSpec a = assign_map(cell->getPort("\\A")); - RTLIL::SigSpec b = assign_map(cell->getPort("\\B")); + RTLIL::SigSpec a = assign_map(cell->getPort(ID::A)); + RTLIL::SigSpec b = assign_map(cell->getPort(ID::B)); - if (a.is_fully_const() && is_one_or_minus_one(a.as_const(), cell->getParam("\\A_SIGNED").as_bool(), arith_inverse)) + if (a.is_fully_const() && is_one_or_minus_one(a.as_const(), cell->getParam(ID(A_SIGNED)).as_bool(), arith_inverse)) identity_wrt_b = true; else - if (b.is_fully_const() && is_one_or_minus_one(b.as_const(), cell->getParam("\\B_SIGNED").as_bool(), arith_inverse)) + if (b.is_fully_const() && is_one_or_minus_one(b.as_const(), cell->getParam(ID(B_SIGNED)).as_bool(), arith_inverse)) identity_wrt_a = true; } - if (cell->type == "$div") + if (cell->type == ID($div)) { - RTLIL::SigSpec b = assign_map(cell->getPort("\\B")); + RTLIL::SigSpec b = assign_map(cell->getPort(ID::B)); if (b.is_fully_const() && b.size() <= 32 && b.as_int() == 1) identity_wrt_a = true; @@ -916,19 +1079,19 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons if (identity_wrt_b) cover_list("opt.opt_expr.identwrt.b", "$add", "$sub", "$or", "$xor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", "$mul", "$div", cell->type.str()); - log("Replacing %s cell `%s' in module `%s' with identity for port %c.\n", + log_debug("Replacing %s cell `%s' in module `%s' with identity for port %c.\n", cell->type.c_str(), cell->name.c_str(), module->name.c_str(), identity_wrt_a ? 'A' : 'B'); if (!identity_wrt_a) { - cell->setPort("\\A", cell->getPort("\\B")); - cell->parameters.at("\\A_WIDTH") = cell->parameters.at("\\B_WIDTH"); - cell->parameters.at("\\A_SIGNED") = cell->parameters.at("\\B_SIGNED"); + cell->setPort(ID::A, cell->getPort(ID::B)); + cell->parameters.at(ID(A_WIDTH)) = cell->parameters.at(ID(B_WIDTH)); + cell->parameters.at(ID(A_SIGNED)) = cell->parameters.at(ID(B_SIGNED)); } - cell->type = arith_inverse ? "$neg" : "$pos"; - cell->unsetPort("\\B"); - cell->parameters.erase("\\B_WIDTH"); - cell->parameters.erase("\\B_SIGNED"); + cell->type = arith_inverse ? ID($neg) : ID($pos); + cell->unsetPort(ID::B); + cell->parameters.erase(ID(B_WIDTH)); + cell->parameters.erase(ID(B_SIGNED)); cell->check(); did_something = true; @@ -936,91 +1099,91 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons } } - if (mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") && - cell->getPort("\\A") == RTLIL::SigSpec(0, 1) && cell->getPort("\\B") == RTLIL::SigSpec(1, 1)) { + if (mux_bool && cell->type.in(ID($mux), ID($_MUX_)) && + cell->getPort(ID::A) == State::S0 && cell->getPort(ID::B) == State::S1) { cover_list("opt.opt_expr.mux_bool", "$mux", "$_MUX_", cell->type.str()); - replace_cell(assign_map, module, cell, "mux_bool", "\\Y", cell->getPort("\\S")); + replace_cell(assign_map, module, cell, "mux_bool", ID::Y, cell->getPort(ID(S))); goto next_cell; } - if (mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") && - cell->getPort("\\A") == RTLIL::SigSpec(1, 1) && cell->getPort("\\B") == RTLIL::SigSpec(0, 1)) { + if (mux_bool && cell->type.in(ID($mux), ID($_MUX_)) && + cell->getPort(ID::A) == State::S1 && cell->getPort(ID::B) == State::S0) { cover_list("opt.opt_expr.mux_invert", "$mux", "$_MUX_", cell->type.str()); - log("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell->type), log_id(cell), log_id(module)); - cell->setPort("\\A", cell->getPort("\\S")); - cell->unsetPort("\\B"); - cell->unsetPort("\\S"); - if (cell->type == "$mux") { - Const width = cell->parameters["\\WIDTH"]; - cell->parameters["\\A_WIDTH"] = width; - cell->parameters["\\Y_WIDTH"] = width; - cell->parameters["\\A_SIGNED"] = 0; - cell->parameters.erase("\\WIDTH"); - cell->type = "$not"; + log_debug("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell->type), log_id(cell), log_id(module)); + cell->setPort(ID::A, cell->getPort(ID(S))); + cell->unsetPort(ID::B); + cell->unsetPort(ID(S)); + if (cell->type == ID($mux)) { + Const width = cell->parameters[ID(WIDTH)]; + cell->parameters[ID(A_WIDTH)] = width; + cell->parameters[ID(Y_WIDTH)] = width; + cell->parameters[ID(A_SIGNED)] = 0; + cell->parameters.erase(ID(WIDTH)); + cell->type = ID($not); } else - cell->type = "$_NOT_"; + cell->type = ID($_NOT_); did_something = true; goto next_cell; } - if (consume_x && mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") && cell->getPort("\\A") == RTLIL::SigSpec(0, 1)) { + if (consume_x && mux_bool && cell->type.in(ID($mux), ID($_MUX_)) && cell->getPort(ID::A) == State::S0) { cover_list("opt.opt_expr.mux_and", "$mux", "$_MUX_", cell->type.str()); - log("Replacing %s cell `%s' in module `%s' with and-gate.\n", log_id(cell->type), log_id(cell), log_id(module)); - cell->setPort("\\A", cell->getPort("\\S")); - cell->unsetPort("\\S"); - if (cell->type == "$mux") { - Const width = cell->parameters["\\WIDTH"]; - cell->parameters["\\A_WIDTH"] = width; - cell->parameters["\\B_WIDTH"] = width; - cell->parameters["\\Y_WIDTH"] = width; - cell->parameters["\\A_SIGNED"] = 0; - cell->parameters["\\B_SIGNED"] = 0; - cell->parameters.erase("\\WIDTH"); - cell->type = "$and"; + log_debug("Replacing %s cell `%s' in module `%s' with and-gate.\n", log_id(cell->type), log_id(cell), log_id(module)); + cell->setPort(ID::A, cell->getPort(ID(S))); + cell->unsetPort(ID(S)); + if (cell->type == ID($mux)) { + Const width = cell->parameters[ID(WIDTH)]; + cell->parameters[ID(A_WIDTH)] = width; + cell->parameters[ID(B_WIDTH)] = width; + cell->parameters[ID(Y_WIDTH)] = width; + cell->parameters[ID(A_SIGNED)] = 0; + cell->parameters[ID(B_SIGNED)] = 0; + cell->parameters.erase(ID(WIDTH)); + cell->type = ID($and); } else - cell->type = "$_AND_"; + cell->type = ID($_AND_); did_something = true; goto next_cell; } - if (consume_x && mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") && cell->getPort("\\B") == RTLIL::SigSpec(1, 1)) { + if (consume_x && mux_bool && cell->type.in(ID($mux), ID($_MUX_)) && cell->getPort(ID::B) == State::S1) { cover_list("opt.opt_expr.mux_or", "$mux", "$_MUX_", cell->type.str()); - log("Replacing %s cell `%s' in module `%s' with or-gate.\n", log_id(cell->type), log_id(cell), log_id(module)); - cell->setPort("\\B", cell->getPort("\\S")); - cell->unsetPort("\\S"); - if (cell->type == "$mux") { - Const width = cell->parameters["\\WIDTH"]; - cell->parameters["\\A_WIDTH"] = width; - cell->parameters["\\B_WIDTH"] = width; - cell->parameters["\\Y_WIDTH"] = width; - cell->parameters["\\A_SIGNED"] = 0; - cell->parameters["\\B_SIGNED"] = 0; - cell->parameters.erase("\\WIDTH"); - cell->type = "$or"; + log_debug("Replacing %s cell `%s' in module `%s' with or-gate.\n", log_id(cell->type), log_id(cell), log_id(module)); + cell->setPort(ID::B, cell->getPort(ID(S))); + cell->unsetPort(ID(S)); + if (cell->type == ID($mux)) { + Const width = cell->parameters[ID(WIDTH)]; + cell->parameters[ID(A_WIDTH)] = width; + cell->parameters[ID(B_WIDTH)] = width; + cell->parameters[ID(Y_WIDTH)] = width; + cell->parameters[ID(A_SIGNED)] = 0; + cell->parameters[ID(B_SIGNED)] = 0; + cell->parameters.erase(ID(WIDTH)); + cell->type = ID($or); } else - cell->type = "$_OR_"; + cell->type = ID($_OR_); did_something = true; goto next_cell; } - if (mux_undef && (cell->type == "$mux" || cell->type == "$pmux")) { + if (mux_undef && cell->type.in(ID($mux), ID($pmux))) { RTLIL::SigSpec new_a, new_b, new_s; - int width = cell->getPort("\\A").size(); - if ((cell->getPort("\\A").is_fully_undef() && cell->getPort("\\B").is_fully_undef()) || - cell->getPort("\\S").is_fully_undef()) { + int width = GetSize(cell->getPort(ID::A)); + if ((cell->getPort(ID::A).is_fully_undef() && cell->getPort(ID::B).is_fully_undef()) || + cell->getPort(ID(S)).is_fully_undef()) { cover_list("opt.opt_expr.mux_undef", "$mux", "$pmux", cell->type.str()); - replace_cell(assign_map, module, cell, "mux_undef", "\\Y", cell->getPort("\\A")); + replace_cell(assign_map, module, cell, "mux_undef", ID::Y, cell->getPort(ID::A)); goto next_cell; } - for (int i = 0; i < cell->getPort("\\S").size(); i++) { - RTLIL::SigSpec old_b = cell->getPort("\\B").extract(i*width, width); - RTLIL::SigSpec old_s = cell->getPort("\\S").extract(i, 1); + for (int i = 0; i < cell->getPort(ID(S)).size(); i++) { + RTLIL::SigSpec old_b = cell->getPort(ID::B).extract(i*width, width); + RTLIL::SigSpec old_s = cell->getPort(ID(S)).extract(i, 1); if (old_b.is_fully_undef() || old_s.is_fully_undef()) continue; new_b.append(old_b); new_s.append(old_s); } - new_a = cell->getPort("\\A"); + new_a = cell->getPort(ID::A); if (new_a.is_fully_undef() && new_s.size() > 0) { new_a = new_b.extract((new_s.size()-1)*width, width); new_b = new_b.extract(0, (new_s.size()-1)*width); @@ -1028,27 +1191,27 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons } if (new_s.size() == 0) { cover_list("opt.opt_expr.mux_empty", "$mux", "$pmux", cell->type.str()); - replace_cell(assign_map, module, cell, "mux_empty", "\\Y", new_a); + replace_cell(assign_map, module, cell, "mux_empty", ID::Y, new_a); goto next_cell; } if (new_a == RTLIL::SigSpec(RTLIL::State::S0) && new_b == RTLIL::SigSpec(RTLIL::State::S1)) { cover_list("opt.opt_expr.mux_sel01", "$mux", "$pmux", cell->type.str()); - replace_cell(assign_map, module, cell, "mux_sel01", "\\Y", new_s); + replace_cell(assign_map, module, cell, "mux_sel01", ID::Y, new_s); goto next_cell; } - if (cell->getPort("\\S").size() != new_s.size()) { + if (cell->getPort(ID(S)).size() != new_s.size()) { cover_list("opt.opt_expr.mux_reduce", "$mux", "$pmux", cell->type.str()); - log("Optimized away %d select inputs of %s cell `%s' in module `%s'.\n", - GetSize(cell->getPort("\\S")) - GetSize(new_s), log_id(cell->type), log_id(cell), log_id(module)); - cell->setPort("\\A", new_a); - cell->setPort("\\B", new_b); - cell->setPort("\\S", new_s); + log_debug("Optimized away %d select inputs of %s cell `%s' in module `%s'.\n", + GetSize(cell->getPort(ID(S))) - GetSize(new_s), log_id(cell->type), log_id(cell), log_id(module)); + cell->setPort(ID::A, new_a); + cell->setPort(ID::B, new_b); + cell->setPort(ID(S), new_s); if (new_s.size() > 1) { - cell->type = "$pmux"; - cell->parameters["\\S_WIDTH"] = new_s.size(); + cell->type = ID($pmux); + cell->parameters[ID(S_WIDTH)] = new_s.size(); } else { - cell->type = "$mux"; - cell->parameters.erase("\\S_WIDTH"); + cell->type = ID($mux); + cell->parameters.erase(ID(S_WIDTH)); } did_something = true; } @@ -1056,30 +1219,30 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons #define FOLD_1ARG_CELL(_t) \ if (cell->type == "$" #_t) { \ - RTLIL::SigSpec a = cell->getPort("\\A"); \ + RTLIL::SigSpec a = cell->getPort(ID::A); \ assign_map.apply(a); \ if (a.is_fully_const()) { \ RTLIL::Const dummy_arg(RTLIL::State::S0, 1); \ RTLIL::SigSpec y(RTLIL::const_ ## _t(a.as_const(), dummy_arg, \ - cell->parameters["\\A_SIGNED"].as_bool(), false, \ - cell->parameters["\\Y_WIDTH"].as_int())); \ + cell->parameters[ID(A_SIGNED)].as_bool(), false, \ + cell->parameters[ID(Y_WIDTH)].as_int())); \ cover("opt.opt_expr.const.$" #_t); \ - replace_cell(assign_map, module, cell, stringf("%s", log_signal(a)), "\\Y", y); \ + replace_cell(assign_map, module, cell, stringf("%s", log_signal(a)), ID::Y, y); \ goto next_cell; \ } \ } #define FOLD_2ARG_CELL(_t) \ if (cell->type == "$" #_t) { \ - RTLIL::SigSpec a = cell->getPort("\\A"); \ - RTLIL::SigSpec b = cell->getPort("\\B"); \ + RTLIL::SigSpec a = cell->getPort(ID::A); \ + RTLIL::SigSpec b = cell->getPort(ID::B); \ assign_map.apply(a), assign_map.apply(b); \ if (a.is_fully_const() && b.is_fully_const()) { \ RTLIL::SigSpec y(RTLIL::const_ ## _t(a.as_const(), b.as_const(), \ - cell->parameters["\\A_SIGNED"].as_bool(), \ - cell->parameters["\\B_SIGNED"].as_bool(), \ - cell->parameters["\\Y_WIDTH"].as_int())); \ + cell->parameters[ID(A_SIGNED)].as_bool(), \ + cell->parameters[ID(B_SIGNED)].as_bool(), \ + cell->parameters[ID(Y_WIDTH)].as_int())); \ cover("opt.opt_expr.const.$" #_t); \ - replace_cell(assign_map, module, cell, stringf("%s, %s", log_signal(a), log_signal(b)), "\\Y", y); \ + replace_cell(assign_map, module, cell, stringf("%s, %s", log_signal(a), log_signal(b)), ID::Y, y); \ goto next_cell; \ } \ } @@ -1125,25 +1288,25 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons FOLD_1ARG_CELL(neg) // be very conservative with optimizing $mux cells as we do not want to break mux trees - if (cell->type == "$mux") { - RTLIL::SigSpec input = assign_map(cell->getPort("\\S")); - RTLIL::SigSpec inA = assign_map(cell->getPort("\\A")); - RTLIL::SigSpec inB = assign_map(cell->getPort("\\B")); + if (cell->type == ID($mux)) { + RTLIL::SigSpec input = assign_map(cell->getPort(ID(S))); + RTLIL::SigSpec inA = assign_map(cell->getPort(ID::A)); + RTLIL::SigSpec inB = assign_map(cell->getPort(ID::B)); if (input.is_fully_const()) - ACTION_DO("\\Y", input.as_bool() ? cell->getPort("\\B") : cell->getPort("\\A")); + ACTION_DO(ID::Y, input.as_bool() ? cell->getPort(ID::B) : cell->getPort(ID::A)); else if (inA == inB) - ACTION_DO("\\Y", cell->getPort("\\A")); + ACTION_DO(ID::Y, cell->getPort(ID::A)); } - if (!keepdc && cell->type == "$mul") + if (!keepdc && cell->type == ID($mul)) { - bool a_signed = cell->parameters["\\A_SIGNED"].as_bool(); - bool b_signed = cell->parameters["\\B_SIGNED"].as_bool(); + bool a_signed = cell->parameters[ID(A_SIGNED)].as_bool(); + bool b_signed = cell->parameters[ID(B_SIGNED)].as_bool(); bool swapped_ab = false; - RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A")); - RTLIL::SigSpec sig_b = assign_map(cell->getPort("\\B")); - RTLIL::SigSpec sig_y = assign_map(cell->getPort("\\Y")); + RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID::A)); + RTLIL::SigSpec sig_b = assign_map(cell->getPort(ID::B)); + RTLIL::SigSpec sig_y = assign_map(cell->getPort(ID::Y)); if (sig_b.is_fully_const() && sig_b.size() <= 32) std::swap(sig_a, sig_b), std::swap(a_signed, b_signed), swapped_ab = true; @@ -1156,7 +1319,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons { cover("opt.opt_expr.mul_shift.zero"); - log("Replacing multiply-by-zero cell `%s' in module `%s' with zero-driver.\n", + log_debug("Replacing multiply-by-zero cell `%s' in module `%s' with zero-driver.\n", cell->name.c_str(), module->name.c_str()); module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size()))); @@ -1174,13 +1337,13 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons else cover("opt.opt_expr.mul_shift.unswapped"); - log("Replacing multiply-by-%d cell `%s' in module `%s' with shift-by-%d.\n", + log_debug("Replacing multiply-by-%d cell `%s' in module `%s' with shift-by-%d.\n", a_val, cell->name.c_str(), module->name.c_str(), i); if (!swapped_ab) { - cell->setPort("\\A", cell->getPort("\\B")); - cell->parameters.at("\\A_WIDTH") = cell->parameters.at("\\B_WIDTH"); - cell->parameters.at("\\A_SIGNED") = cell->parameters.at("\\B_SIGNED"); + cell->setPort(ID::A, cell->getPort(ID::B)); + cell->parameters.at(ID(A_WIDTH)) = cell->parameters.at(ID(B_WIDTH)); + cell->parameters.at(ID(A_SIGNED)) = cell->parameters.at(ID(B_SIGNED)); } std::vector<RTLIL::SigBit> new_b = RTLIL::SigSpec(i, 6); @@ -1188,10 +1351,10 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons while (GetSize(new_b) > 1 && new_b.back() == RTLIL::State::S0) new_b.pop_back(); - cell->type = "$shl"; - cell->parameters["\\B_WIDTH"] = GetSize(new_b); - cell->parameters["\\B_SIGNED"] = false; - cell->setPort("\\B", new_b); + cell->type = ID($shl); + cell->parameters[ID(B_WIDTH)] = GetSize(new_b); + cell->parameters[ID(B_SIGNED)] = false; + cell->setPort(ID::B, new_b); cell->check(); did_something = true; @@ -1200,11 +1363,11 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons } } - if (!keepdc && cell->type.in("$div", "$mod")) + if (!keepdc && cell->type.in(ID($div), ID($mod))) { - bool b_signed = cell->parameters["\\B_SIGNED"].as_bool(); - SigSpec sig_b = assign_map(cell->getPort("\\B")); - SigSpec sig_y = assign_map(cell->getPort("\\Y")); + bool b_signed = cell->parameters[ID(B_SIGNED)].as_bool(); + SigSpec sig_b = assign_map(cell->getPort(ID::B)); + SigSpec sig_y = assign_map(cell->getPort(ID::Y)); if (sig_b.is_fully_def() && sig_b.size() <= 32) { @@ -1214,7 +1377,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons { cover("opt.opt_expr.divmod_zero"); - log("Replacing divide-by-zero cell `%s' in module `%s' with undef-driver.\n", + log_debug("Replacing divide-by-zero cell `%s' in module `%s' with undef-driver.\n", cell->name.c_str(), module->name.c_str()); module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(State::Sx, sig_y.size()))); @@ -1227,11 +1390,11 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons for (int i = 1; i < (b_signed ? sig_b.size()-1 : sig_b.size()); i++) if (b_val == (1 << i)) { - if (cell->type == "$div") + if (cell->type == ID($div)) { cover("opt.opt_expr.div_shift"); - log("Replacing divide-by-%d cell `%s' in module `%s' with shift-by-%d.\n", + log_debug("Replacing divide-by-%d cell `%s' in module `%s' with shift-by-%d.\n", b_val, cell->name.c_str(), module->name.c_str(), i); std::vector<RTLIL::SigBit> new_b = RTLIL::SigSpec(i, 6); @@ -1239,17 +1402,17 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons while (GetSize(new_b) > 1 && new_b.back() == RTLIL::State::S0) new_b.pop_back(); - cell->type = "$shr"; - cell->parameters["\\B_WIDTH"] = GetSize(new_b); - cell->parameters["\\B_SIGNED"] = false; - cell->setPort("\\B", new_b); + cell->type = ID($shr); + cell->parameters[ID(B_WIDTH)] = GetSize(new_b); + cell->parameters[ID(B_SIGNED)] = false; + cell->setPort(ID::B, new_b); cell->check(); } else { cover("opt.opt_expr.mod_mask"); - log("Replacing modulo-by-%d cell `%s' in module `%s' with bitmask.\n", + log_debug("Replacing modulo-by-%d cell `%s' in module `%s' with bitmask.\n", b_val, cell->name.c_str(), module->name.c_str()); std::vector<RTLIL::SigBit> new_b = RTLIL::SigSpec(State::S1, i); @@ -1257,9 +1420,9 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons if (b_signed) new_b.push_back(State::S0); - cell->type = "$and"; - cell->parameters["\\B_WIDTH"] = GetSize(new_b); - cell->setPort("\\B", new_b); + cell->type = ID($and); + cell->parameters[ID(B_WIDTH)] = GetSize(new_b); + cell->setPort(ID::B, new_b); cell->check(); } @@ -1271,7 +1434,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons // remove redundant pairs of bits in ==, ===, !=, and !== // replace cell with const driver if inputs can't be equal - if (do_fine && cell->type.in("$eq", "$ne", "$eqx", "$nex")) + if (do_fine && cell->type.in(ID($eq), ID($ne), ID($eqx), ID($nex))) { pool<pair<SigBit, SigBit>> redundant_cache; mfp<SigBit> contradiction_cache; @@ -1279,14 +1442,14 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons contradiction_cache.promote(State::S0); contradiction_cache.promote(State::S1); - int a_width = cell->getParam("\\A_WIDTH").as_int(); - int b_width = cell->getParam("\\B_WIDTH").as_int(); + int a_width = cell->getParam(ID(A_WIDTH)).as_int(); + int b_width = cell->getParam(ID(B_WIDTH)).as_int(); - bool is_signed = cell->getParam("\\A_SIGNED").as_bool(); + bool is_signed = cell->getParam(ID(A_SIGNED)).as_bool(); int width = is_signed ? std::min(a_width, b_width) : std::max(a_width, b_width); - SigSpec sig_a = cell->getPort("\\A"); - SigSpec sig_b = cell->getPort("\\B"); + SigSpec sig_a = cell->getPort(ID::A); + SigSpec sig_b = cell->getPort(ID::B); int redundant_bits = 0; @@ -1316,10 +1479,10 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons if (contradiction_cache.find(State::S0) == contradiction_cache.find(State::S1)) { - SigSpec y_sig = cell->getPort("\\Y"); - Const y_value(cell->type.in("$eq", "$eqx") ? 0 : 1, GetSize(y_sig)); + SigSpec y_sig = cell->getPort(ID::Y); + Const y_value(cell->type.in(ID($eq), ID($eqx)) ? 0 : 1, GetSize(y_sig)); - log("Replacing cell `%s' in module `%s' with constant driver %s.\n", + log_debug("Replacing cell `%s' in module `%s' with constant driver %s.\n", log_id(cell), log_id(module), log_signal(y_value)); module->connect(y_sig, y_value); @@ -1331,131 +1494,152 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons if (redundant_bits) { - log("Removed %d redundant input bits from %s cell `%s' in module `%s'.\n", + log_debug("Removed %d redundant input bits from %s cell `%s' in module `%s'.\n", redundant_bits, log_id(cell->type), log_id(cell), log_id(module)); - cell->setPort("\\A", sig_a); - cell->setPort("\\B", sig_b); - cell->setParam("\\A_WIDTH", GetSize(sig_a)); - cell->setParam("\\B_WIDTH", GetSize(sig_b)); + cell->setPort(ID::A, sig_a); + cell->setPort(ID::B, sig_b); + cell->setParam(ID(A_WIDTH), GetSize(sig_a)); + cell->setParam(ID(B_WIDTH), GetSize(sig_b)); did_something = true; goto next_cell; } } - // replace a<0 or a>=0 with the top bit of a - if (do_fine && (cell->type == "$lt" || cell->type == "$ge" || cell->type == "$gt" || cell->type == "$le")) + // simplify comparisons + if (do_fine && cell->type.in(ID($lt), ID($ge), ID($gt), ID($le))) { - //used to decide whether the signal needs to be negated - bool is_lt = false; - - //references the variable signal in the comparison - RTLIL::SigSpec sigVar; - - //references the constant signal in the comparison - RTLIL::SigSpec sigConst; - - // note that this signal must be constant for the optimization - // to take place, but it is not checked beforehand. - // If new passes are added, this signal must be checked for const-ness - - //width of the variable port - int width; - int const_width; - - bool var_signed; - - if (cell->type == "$lt" || cell->type == "$ge") { - is_lt = cell->type == "$lt" ? 1 : 0; - sigVar = cell->getPort("\\A"); - sigConst = cell->getPort("\\B"); - width = cell->parameters["\\A_WIDTH"].as_int(); - const_width = cell->parameters["\\B_WIDTH"].as_int(); - var_signed = cell->parameters["\\A_SIGNED"].as_bool(); - } else - if (cell->type == "$gt" || cell->type == "$le") { - is_lt = cell->type == "$gt" ? 1 : 0; - sigVar = cell->getPort("\\B"); - sigConst = cell->getPort("\\A"); - width = cell->parameters["\\B_WIDTH"].as_int(); - const_width = cell->parameters["\\A_WIDTH"].as_int(); - var_signed = cell->parameters["\\B_SIGNED"].as_bool(); - } else - log_abort(); - - // replace a(signed) < 0 with the high bit of a - if (sigConst.is_fully_const() && sigConst.is_fully_zero() && var_signed == true) + IdString cmp_type = cell->type; + SigSpec var_sig = cell->getPort(ID::A); + SigSpec const_sig = cell->getPort(ID::B); + int var_width = cell->parameters[ID(A_WIDTH)].as_int(); + int const_width = cell->parameters[ID(B_WIDTH)].as_int(); + bool is_signed = cell->getParam(ID(A_SIGNED)).as_bool(); + + if (!const_sig.is_fully_const()) { - RTLIL::SigSpec a_prime(RTLIL::State::S0, cell->parameters["\\Y_WIDTH"].as_int()); - a_prime[0] = sigVar[width - 1]; - if (is_lt) { - log("Replacing %s cell `%s' (implementing X<0) with X[%d]: %s\n", - log_id(cell->type), log_id(cell), width-1, log_signal(a_prime)); - module->connect(cell->getPort("\\Y"), a_prime); - module->remove(cell); - } else { - log("Replacing %s cell `%s' (implementing X>=0) with ~X[%d]: %s\n", - log_id(cell->type), log_id(cell), width-1, log_signal(a_prime)); - module->addNot(NEW_ID, a_prime, cell->getPort("\\Y")); - module->remove(cell); - } - did_something = true; - goto next_cell; - } else - if (sigConst.is_fully_const() && sigConst.is_fully_def() && var_signed == false) + std::swap(var_sig, const_sig); + std::swap(var_width, const_width); + if (cmp_type == ID($gt)) + cmp_type = ID($lt); + else if (cmp_type == ID($lt)) + cmp_type = ID($gt); + else if (cmp_type == ID($ge)) + cmp_type = ID($le); + else if (cmp_type == ID($le)) + cmp_type = ID($ge); + } + + if (const_sig.is_fully_def() && const_sig.is_fully_const()) { - if (sigConst.is_fully_zero()) { - RTLIL::SigSpec a_prime(RTLIL::State::S0, 1); - if (is_lt) { - log("Replacing %s cell `%s' (implementing unsigned X<0) with constant false.\n", - log_id(cell->type), log_id(cell)); - a_prime[0] = RTLIL::State::S0; - } else { - log("Replacing %s cell `%s' (implementing unsigned X>=0) with constant true.\n", - log_id(cell->type), log_id(cell)); - a_prime[0] = RTLIL::State::S1; + std::string condition, replacement; + SigSpec replace_sig(State::S0, GetSize(cell->getPort(ID::Y))); + bool replace = false; + bool remove = false; + + if (!is_signed) + { /* unsigned */ + if (const_sig.is_fully_zero() && cmp_type == ID($lt)) { + condition = "unsigned X<0"; + replacement = "constant 0"; + replace_sig[0] = State::S0; + replace = true; + } + if (const_sig.is_fully_zero() && cmp_type == ID($ge)) { + condition = "unsigned X>=0"; + replacement = "constant 1"; + replace_sig[0] = State::S1; + replace = true; + } + if (const_width == var_width && const_sig.is_fully_ones() && cmp_type == ID($gt)) { + condition = "unsigned X>~0"; + replacement = "constant 0"; + replace_sig[0] = State::S0; + replace = true; + } + if (const_width == var_width && const_sig.is_fully_ones() && cmp_type == ID($le)) { + condition = "unsigned X<=~0"; + replacement = "constant 1"; + replace_sig[0] = State::S1; + replace = true; } - module->connect(cell->getPort("\\Y"), a_prime); - module->remove(cell); - did_something = true; - goto next_cell; - } - int const_bit_set = get_onehot_bit_index(sigConst); - if (const_bit_set >= 0 && const_bit_set < width) { - int bit_set = const_bit_set; - RTLIL::SigSpec a_prime(RTLIL::State::S0, width - bit_set); - for (int i = bit_set; i < width; i++) { - a_prime[i - bit_set] = sigVar[i]; + int const_bit_hot = get_onehot_bit_index(const_sig); + if (const_bit_hot >= 0 && const_bit_hot < var_width) + { + RTLIL::SigSpec var_high_sig(RTLIL::State::S0, var_width - const_bit_hot); + for (int i = const_bit_hot; i < var_width; i++) { + var_high_sig[i - const_bit_hot] = var_sig[i]; + } + + if (cmp_type == ID($lt)) + { + condition = stringf("unsigned X<%s", log_signal(const_sig)); + replacement = stringf("!X[%d:%d]", var_width - 1, const_bit_hot); + module->addLogicNot(NEW_ID, var_high_sig, cell->getPort(ID::Y)); + remove = true; + } + if (cmp_type == ID($ge)) + { + condition = stringf("unsigned X>=%s", log_signal(const_sig)); + replacement = stringf("|X[%d:%d]", var_width - 1, const_bit_hot); + module->addReduceOr(NEW_ID, var_high_sig, cell->getPort(ID::Y)); + remove = true; + } } - if (is_lt) { - log("Replacing %s cell `%s' (implementing unsigned X<%s) with !X[%d:%d]: %s.\n", - log_id(cell->type), log_id(cell), log_signal(sigConst), width - 1, bit_set, log_signal(a_prime)); - module->addLogicNot(NEW_ID, a_prime, cell->getPort("\\Y")); - } else { - log("Replacing %s cell `%s' (implementing unsigned X>=%s) with |X[%d:%d]: %s.\n", - log_id(cell->type), log_id(cell), log_signal(sigConst), width - 1, bit_set, log_signal(a_prime)); - module->addReduceOr(NEW_ID, a_prime, cell->getPort("\\Y")); + + int const_bit_set = get_highest_hot_index(const_sig); + if(const_bit_set >= var_width) + { + string cmp_name; + if (cmp_type == ID($lt) || cmp_type == ID($le)) + { + if (cmp_type == ID($lt)) cmp_name = "<"; + if (cmp_type == ID($le)) cmp_name = "<="; + condition = stringf("unsigned X[%d:0]%s%s", var_width - 1, cmp_name.c_str(), log_signal(const_sig)); + replacement = "constant 1"; + replace_sig[0] = State::S1; + replace = true; + } + if (cmp_type == ID($gt) || cmp_type == ID($ge)) + { + if (cmp_type == ID($gt)) cmp_name = ">"; + if (cmp_type == ID($ge)) cmp_name = ">="; + condition = stringf("unsigned X[%d:0]%s%s", var_width - 1, cmp_name.c_str(), log_signal(const_sig)); + replacement = "constant 0"; + replace_sig[0] = State::S0; + replace = true; + } } - module->remove(cell); - did_something = true; - goto next_cell; } - else if(const_bit_set >= width && const_bit_set >= 0){ - RTLIL::SigSpec a_prime(RTLIL::State::S0, 1); - if(is_lt){ - a_prime[0] = RTLIL::State::S1; - log("Replacing %s cell `%s' (implementing unsigned X[%d:0] < %s[%d:0]) with constant 0.\n", log_id(cell->type), log_id(cell), width-1, log_signal(sigConst),const_width-1); + else + { /* signed */ + if (const_sig.is_fully_zero() && cmp_type == ID($lt)) + { + condition = "signed X<0"; + replacement = stringf("X[%d]", var_width - 1); + replace_sig[0] = var_sig[var_width - 1]; + replace = true; } - else{ - log("Replacing %s cell `%s' (implementing unsigned X[%d:0]>= %s[%d:0]) with constant 1.\n", log_id(cell->type), log_id(cell), width-1, log_signal(sigConst),const_width-1); + if (const_sig.is_fully_zero() && cmp_type == ID($ge)) + { + condition = "signed X>=0"; + replacement = stringf("X[%d]", var_width - 1); + module->addNot(NEW_ID, var_sig[var_width - 1], cell->getPort(ID::Y)); + remove = true; } - module->connect(cell->getPort("\\Y"), a_prime); + } + + if (replace || remove) + { + log_debug("Replacing %s cell `%s' (implementing %s) with %s.\n", + log_id(cell->type), log_id(cell), condition.c_str(), replacement.c_str()); + if (replace) + module->connect(cell->getPort(ID::Y), replace_sig); module->remove(cell); did_something = true; goto next_cell; - } } } @@ -1470,14 +1654,14 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons struct OptExprPass : public Pass { OptExprPass() : Pass("opt_expr", "perform const folding and simple expression rewriting") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); log(" opt_expr [options] [selection]\n"); log("\n"); log("This pass performs const folding on internal cell types with constant inputs.\n"); - log("It also performs some simple expression rewritring.\n"); + log("It also performs some simple expression rewriting.\n"); log("\n"); log(" -mux_undef\n"); log(" remove 'undef' inputs from $mux, $pmux and $_MUX_ cells\n"); @@ -1504,7 +1688,7 @@ struct OptExprPass : public Pass { log(" replaced by 'a'. the -keepdc option disables all such optimizations.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { bool mux_undef = false; bool mux_bool = false; @@ -1555,8 +1739,14 @@ struct OptExprPass : public Pass { for (auto module : design->selected_modules()) { - if (undriven) + log("Optimizing module %s.\n", log_id(module)); + + if (undriven) { + did_something = false; replace_undriven(design, module); + if (did_something) + design->scratchpad_set_bool("opt.did_something", true); + } do { do { @@ -1566,7 +1756,11 @@ struct OptExprPass : public Pass { design->scratchpad_set_bool("opt.did_something", true); } while (did_something); replace_const_cells(design, module, true, mux_undef, mux_bool, do_fine, keepdc, clkinv); + if (did_something) + design->scratchpad_set_bool("opt.did_something", true); } while (did_something); + + log_suppressed(); } log_pop(); diff --git a/passes/opt/opt_lut.cc b/passes/opt/opt_lut.cc new file mode 100644 index 000000000..c4f278706 --- /dev/null +++ b/passes/opt/opt_lut.cc @@ -0,0 +1,595 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2018 whitequark <whitequark@whitequark.org> + * + * 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" +#include "kernel/modtools.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct OptLutWorker +{ + dict<IdString, dict<int, IdString>> &dlogic; + RTLIL::Module *module; + ModIndex index; + SigMap sigmap; + + pool<RTLIL::Cell*> luts; + dict<RTLIL::Cell*, int> luts_arity; + dict<RTLIL::Cell*, pool<RTLIL::Cell*>> luts_dlogics; + dict<RTLIL::Cell*, pool<int>> luts_dlogic_inputs; + + int eliminated_count = 0, combined_count = 0; + + bool evaluate_lut(RTLIL::Cell *lut, dict<SigBit, bool> inputs) + { + SigSpec lut_input = sigmap(lut->getPort(ID::A)); + int lut_width = lut->getParam(ID(WIDTH)).as_int(); + Const lut_table = lut->getParam(ID(LUT)); + int lut_index = 0; + + for (int i = 0; i < lut_width; i++) + { + SigBit input = sigmap(lut_input[i]); + if (inputs.count(input)) + { + lut_index |= inputs[input] << i; + } + else + { + lut_index |= SigSpec(lut_input[i]).as_bool() << i; + } + } + + return lut_table.extract(lut_index).as_bool(); + } + + void show_stats_by_arity() + { + dict<int, int> arity_counts; + dict<IdString, int> dlogic_counts; + int max_arity = 0; + + for (auto lut_arity : luts_arity) + { + max_arity = max(max_arity, lut_arity.second); + arity_counts[lut_arity.second]++; + } + + for (auto &lut_dlogics : luts_dlogics) + { + for (auto &lut_dlogic : lut_dlogics.second) + { + dlogic_counts[lut_dlogic->type]++; + } + } + + log("Number of LUTs: %8d\n", GetSize(luts)); + for (int arity = 1; arity <= max_arity; arity++) + { + if (arity_counts[arity]) + log(" %d-LUT %16d\n", arity, arity_counts[arity]); + } + for (auto &dlogic_count : dlogic_counts) + { + log(" with %-12s %4d\n", dlogic_count.first.c_str(), dlogic_count.second); + } + } + + OptLutWorker(dict<IdString, dict<int, IdString>> &dlogic, RTLIL::Module *module, int limit) : + dlogic(dlogic), module(module), index(module), sigmap(module) + { + log("Discovering LUTs.\n"); + for (auto cell : module->selected_cells()) + { + if (cell->type == ID($lut)) + { + if (cell->has_keep_attr()) + continue; + SigBit lut_output = cell->getPort(ID::Y); + if (lut_output.wire->get_bool_attribute(ID::keep)) + continue; + + int lut_width = cell->getParam(ID(WIDTH)).as_int(); + SigSpec lut_input = cell->getPort(ID::A); + int lut_arity = 0; + + log_debug("Found $lut\\WIDTH=%d cell %s.%s.\n", lut_width, log_id(module), log_id(cell)); + luts.insert(cell); + + // First, find all dedicated logic we're connected to. This results in an overapproximation + // of such connections. + pool<RTLIL::Cell*> lut_all_dlogics; + for (int i = 0; i < lut_width; i++) + { + SigBit bit = lut_input[i]; + for (auto &port : index.query_ports(bit)) + { + if (dlogic.count(port.cell->type)) + { + auto &dlogic_map = dlogic[port.cell->type]; + if (dlogic_map.count(i)) + { + if (port.port == dlogic_map[i]) + { + lut_all_dlogics.insert(port.cell); + } + } + } + } + } + + // Second, make sure that the connection to dedicated logic is legal. If it is not legal, + // it means one of the two things: + // * The connection is spurious. I.e. this is dedicated logic that will be packed + // with some other LUT, and it just happens to be connected to this LUT as well. + // * The connection is illegal. + // In either of these cases, we don't need to concern ourselves with preserving the connection + // between this LUT and this dedicated logic cell. + pool<RTLIL::Cell*> lut_legal_dlogics; + pool<int> lut_dlogic_inputs; + for (auto lut_dlogic : lut_all_dlogics) + { + auto &dlogic_map = dlogic[lut_dlogic->type]; + bool legal = true; + for (auto &dlogic_conn : dlogic_map) + { + if (lut_width <= dlogic_conn.first) + { + log_debug(" LUT has illegal connection to %s cell %s.%s.\n", lut_dlogic->type.c_str(), log_id(module), log_id(lut_dlogic)); + log_debug(" LUT input A[%d] not present.\n", dlogic_conn.first); + legal = false; + break; + } + if (sigmap(lut_input[dlogic_conn.first]) != sigmap(lut_dlogic->getPort(dlogic_conn.second))) + { + log_debug(" LUT has illegal connection to %s cell %s.%s.\n", lut_dlogic->type.c_str(), log_id(module), log_id(lut_dlogic)); + log_debug(" LUT input A[%d] (wire %s) not connected to %s port %s (wire %s).\n", dlogic_conn.first, log_signal(lut_input[dlogic_conn.first]), lut_dlogic->type.c_str(), dlogic_conn.second.c_str(), log_signal(lut_dlogic->getPort(dlogic_conn.second))); + legal = false; + break; + } + } + + if (legal) + { + log_debug(" LUT has legal connection to %s cell %s.%s.\n", lut_dlogic->type.c_str(), log_id(module), log_id(lut_dlogic)); + lut_legal_dlogics.insert(lut_dlogic); + for (auto &dlogic_conn : dlogic_map) + lut_dlogic_inputs.insert(dlogic_conn.first); + } + } + + // Third, determine LUT arity. An n-wide LUT that has k constant inputs and m inputs shared with dedicated + // logic implements an (n-k-m)-ary function. + for (int i = 0; i < lut_width; i++) + { + SigBit bit = lut_input[i]; + if (bit.wire || lut_dlogic_inputs.count(i)) + lut_arity++; + } + + log_debug(" Cell implements a %d-LUT.\n", lut_arity); + luts_arity[cell] = lut_arity; + luts_dlogics[cell] = lut_legal_dlogics; + luts_dlogic_inputs[cell] = lut_dlogic_inputs; + } + } + show_stats_by_arity(); + + log("\n"); + log("Eliminating LUTs.\n"); + pool<RTLIL::Cell*> worklist = luts; + while (worklist.size()) + { + if (limit == 0) + { + log("Limit reached.\n"); + break; + } + + auto lut = worklist.pop(); + SigSpec lut_input = sigmap(lut->getPort(ID::A)); + pool<int> &lut_dlogic_inputs = luts_dlogic_inputs[lut]; + + vector<SigBit> lut_inputs; + for (auto &bit : lut_input) + { + if (bit.wire) + lut_inputs.push_back(sigmap(bit)); + } + + bool const0_match = true; + bool const1_match = true; + vector<bool> input_matches; + for (size_t i = 0; i < lut_inputs.size(); i++) + input_matches.push_back(true); + + for (int eval = 0; eval < 1 << lut_inputs.size(); eval++) + { + dict<SigBit, bool> eval_inputs; + for (size_t i = 0; i < lut_inputs.size(); i++) + eval_inputs[lut_inputs[i]] = (eval >> i) & 1; + bool value = evaluate_lut(lut, eval_inputs); + if (value != 0) + const0_match = false; + if (value != 1) + const1_match = false; + for (size_t i = 0; i < lut_inputs.size(); i++) + { + if (value != eval_inputs[lut_inputs[i]]) + input_matches[i] = false; + } + } + + int input_match = -1; + for (size_t i = 0; i < lut_inputs.size(); i++) + if (input_matches[i]) + input_match = i; + + if (const0_match || const1_match || input_match != -1) + { + log_debug("Found redundant cell %s.%s.\n", log_id(module), log_id(lut)); + + SigBit value; + if (const0_match) + { + log_debug(" Cell evaluates constant 0.\n"); + value = State::S0; + } + if (const1_match) + { + log_debug(" Cell evaluates constant 1.\n"); + value = State::S1; + } + if (input_match != -1) { + log_debug(" Cell evaluates signal %s.\n", log_signal(lut_inputs[input_match])); + value = lut_inputs[input_match]; + } + + if (lut_dlogic_inputs.size()) + log_debug(" Not eliminating cell (connected to dedicated logic).\n"); + else + { + SigSpec lut_output = lut->getPort(ID::Y); + for (auto &port : index.query_ports(lut_output)) + { + if (port.cell != lut && luts.count(port.cell)) + worklist.insert(port.cell); + } + + module->connect(lut_output, value); + sigmap.add(lut_output, value); + + module->remove(lut); + luts.erase(lut); + luts_arity.erase(lut); + luts_dlogics.erase(lut); + luts_dlogic_inputs.erase(lut); + + eliminated_count++; + if (limit > 0) + limit--; + } + } + } + show_stats_by_arity(); + + log("\n"); + log("Combining LUTs.\n"); + worklist = luts; + while (worklist.size()) + { + if (limit == 0) + { + log("Limit reached.\n"); + break; + } + + auto lutA = worklist.pop(); + SigSpec lutA_input = sigmap(lutA->getPort(ID::A)); + SigSpec lutA_output = sigmap(lutA->getPort(ID::Y)[0]); + int lutA_width = lutA->getParam(ID(WIDTH)).as_int(); + int lutA_arity = luts_arity[lutA]; + pool<int> &lutA_dlogic_inputs = luts_dlogic_inputs[lutA]; + + auto lutA_output_ports = index.query_ports(lutA->getPort(ID::Y)); + if (lutA_output_ports.size() != 2) + continue; + + for (auto &port : lutA_output_ports) + { + if (port.cell == lutA) + continue; + + if (luts.count(port.cell)) + { + auto lutB = port.cell; + SigSpec lutB_input = sigmap(lutB->getPort(ID::A)); + SigSpec lutB_output = sigmap(lutB->getPort(ID::Y)[0]); + int lutB_width = lutB->getParam(ID(WIDTH)).as_int(); + int lutB_arity = luts_arity[lutB]; + pool<int> &lutB_dlogic_inputs = luts_dlogic_inputs[lutB]; + + log_debug("Found %s.%s (cell A) feeding %s.%s (cell B).\n", log_id(module), log_id(lutA), log_id(module), log_id(lutB)); + + if (index.query_is_output(lutA->getPort(ID::Y))) + { + log_debug(" Not combining LUTs (cascade connection feeds module output).\n"); + continue; + } + + pool<SigBit> lutA_inputs; + pool<SigBit> lutB_inputs; + for (auto &bit : lutA_input) + { + if (bit.wire) + lutA_inputs.insert(sigmap(bit)); + } + for (auto &bit : lutB_input) + { + if (bit.wire) + lutB_inputs.insert(sigmap(bit)); + } + + pool<SigBit> common_inputs; + for (auto &bit : lutA_inputs) + { + if (lutB_inputs.count(bit)) + common_inputs.insert(bit); + } + + int lutM_arity = lutA_arity + lutB_arity - 1 - common_inputs.size(); + if (lutA_dlogic_inputs.size()) + log_debug(" Cell A is a %d-LUT with %d dedicated connections. ", lutA_arity, GetSize(lutA_dlogic_inputs)); + else + log_debug(" Cell A is a %d-LUT. ", lutA_arity); + if (lutB_dlogic_inputs.size()) + log_debug("Cell B is a %d-LUT with %d dedicated connections.\n", lutB_arity, GetSize(lutB_dlogic_inputs)); + else + log_debug("Cell B is a %d-LUT.\n", lutB_arity); + log_debug(" 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; + if (lutM_arity > lutA_width) + log_debug(" Not combining LUTs into cell A (combined LUT wider than cell A).\n"); + else if (lutB_dlogic_inputs.size() > 0) + log_debug(" Not combining LUTs into cell A (cell B is connected to dedicated logic).\n"); + else if (lutB->get_bool_attribute(ID(lut_keep))) + log_debug(" Not combining LUTs into cell A (cell B has attribute \\lut_keep).\n"); + else + combine_mask |= COMBINE_A; + if (lutM_arity > lutB_width) + log_debug(" Not combining LUTs into cell B (combined LUT wider than cell B).\n"); + else if (lutA_dlogic_inputs.size() > 0) + log_debug(" Not combining LUTs into cell B (cell A is connected to dedicated logic).\n"); + else if (lutA->get_bool_attribute(ID(lut_keep))) + log_debug(" Not combining LUTs into cell B (cell A has attribute \\lut_keep).\n"); + else + combine_mask |= COMBINE_B; + + int combine = combine_mask; + if (combine == COMBINE_EITHER) + { + log_debug(" Can combine into either cell.\n"); + if (lutA_arity == 1) + { + log_debug(" Cell A is a buffer or inverter, combining into cell B.\n"); + combine = COMBINE_B; + } + else if (lutB_arity == 1) + { + log_debug(" Cell B is a buffer or inverter, combining into cell A.\n"); + combine = COMBINE_A; + } + else + { + log_debug(" Arbitrarily combining into cell A.\n"); + combine = COMBINE_A; + } + } + + RTLIL::Cell *lutM, *lutR; + pool<SigBit> lutM_inputs, lutR_inputs; + pool<int> lutM_dlogic_inputs; + if (combine == COMBINE_A) + { + log_debug(" Combining LUTs into cell A.\n"); + lutM = lutA; + lutM_inputs = lutA_inputs; + lutM_dlogic_inputs = lutA_dlogic_inputs; + lutR = lutB; + lutR_inputs = lutB_inputs; + } + else if (combine == COMBINE_B) + { + log_debug(" Combining LUTs into cell B.\n"); + lutM = lutB; + lutM_inputs = lutB_inputs; + lutM_dlogic_inputs = lutB_dlogic_inputs; + lutR = lutA; + lutR_inputs = lutA_inputs; + } + else + { + log_debug(" Cannot combine LUTs.\n"); + continue; + } + + pool<SigBit> lutR_unique; + for (auto &bit : lutR_inputs) + { + if (!common_inputs.count(bit) && bit != lutA_output) + lutR_unique.insert(bit); + } + + int lutM_width = lutM->getParam(ID(WIDTH)).as_int(); + SigSpec lutM_input = sigmap(lutM->getPort(ID::A)); + std::vector<SigBit> lutM_new_inputs; + for (int i = 0; i < lutM_width; i++) + { + bool input_unused = false; + if (sigmap(lutM_input[i]) == lutA_output) + input_unused = true; + if (!lutM_input[i].wire && !lutM_dlogic_inputs.count(i)) + input_unused = true; + + if (input_unused && lutR_unique.size()) + { + SigBit new_input = lutR_unique.pop(); + log_debug(" Connecting input %d as %s.\n", i, log_signal(new_input)); + lutM_new_inputs.push_back(new_input); + } + else if (sigmap(lutM_input[i]) == lutA_output) + { + log_debug(" Disconnecting cascade input %d.\n", i); + lutM_new_inputs.push_back(SigBit()); + } + else + { + log_debug(" Leaving input %d as %s.\n", i, log_signal(lutM_input[i])); + lutM_new_inputs.push_back(lutM_input[i]); + } + } + log_assert(lutR_unique.size() == 0); + + RTLIL::Const lutM_new_table(State::Sx, 1 << lutM_width); + for (int eval = 0; eval < 1 << lutM_width; eval++) + { + dict<SigBit, bool> eval_inputs; + for (size_t i = 0; i < lutM_new_inputs.size(); i++) + { + eval_inputs[lutM_new_inputs[i]] = (eval >> i) & 1; + } + eval_inputs[lutA_output] = evaluate_lut(lutA, eval_inputs); + lutM_new_table[eval] = (RTLIL::State) evaluate_lut(lutB, eval_inputs); + } + + log_debug(" Cell A truth table: %s.\n", lutA->getParam(ID(LUT)).as_string().c_str()); + log_debug(" Cell B truth table: %s.\n", lutB->getParam(ID(LUT)).as_string().c_str()); + log_debug(" Merged truth table: %s.\n", lutM_new_table.as_string().c_str()); + + lutM->setParam(ID(LUT), lutM_new_table); + lutM->setPort(ID::A, lutM_new_inputs); + lutM->setPort(ID::Y, lutB_output); + + luts_arity[lutM] = lutM_arity; + luts.erase(lutR); + luts_arity.erase(lutR); + lutR->module->remove(lutR); + + worklist.insert(lutM); + worklist.erase(lutR); + + combined_count++; + if (limit > 0) + limit--; + } + } + } + show_stats_by_arity(); + } +}; + +static void split(std::vector<std::string> &tokens, const std::string &text, char sep) +{ + size_t start = 0, end = 0; + while ((end = text.find(sep, start)) != std::string::npos) { + tokens.push_back(text.substr(start, end - start)); + start = end + 1; + } + tokens.push_back(text.substr(start)); +} + +struct OptLutPass : public Pass { + OptLutPass() : Pass("opt_lut", "optimize LUT cells") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" opt_lut [options] [selection]\n"); + log("\n"); + log("This pass combines cascaded $lut cells with unused inputs.\n"); + log("\n"); + log(" -dlogic <type>:<cell-port>=<LUT-input>[:<cell-port>=<LUT-input>...]\n"); + log(" preserve connections to dedicated logic cell <type> that has ports\n"); + log(" <cell-port> connected to LUT inputs <LUT-input>. this includes\n"); + log(" the case where both LUT and dedicated logic input are connected to\n"); + log(" the same constant.\n"); + log("\n"); + log(" -limit N\n"); + log(" only perform the first N combines, then stop. useful for debugging.\n"); + log("\n"); + } + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + log_header(design, "Executing OPT_LUT pass (optimize LUTs).\n"); + + dict<IdString, dict<int, IdString>> dlogic; + int limit = -1; + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + if (args[argidx] == "-dlogic" && argidx+1 < args.size()) + { + std::vector<std::string> tokens; + split(tokens, args[++argidx], ':'); + if (tokens.size() < 2) + log_cmd_error("The -dlogic option requires at least one connection.\n"); + IdString type = "\\" + tokens[0]; + for (auto it = tokens.begin() + 1; it != tokens.end(); ++it) { + std::vector<std::string> conn_tokens; + split(conn_tokens, *it, '='); + if (conn_tokens.size() != 2) + log_cmd_error("Invalid format of -dlogic signal mapping.\n"); + IdString logic_port = "\\" + conn_tokens[0]; + int lut_input = atoi(conn_tokens[1].c_str()); + dlogic[type][lut_input] = logic_port; + } + continue; + } + if (args[argidx] == "-limit" && argidx + 1 < args.size()) + { + limit = atoi(args[++argidx].c_str()); + continue; + } + break; + } + extra_args(args, argidx, design); + + int eliminated_count = 0, combined_count = 0; + for (auto module : design->selected_modules()) + { + OptLutWorker worker(dlogic, module, limit - eliminated_count - combined_count); + eliminated_count += worker.eliminated_count; + combined_count += worker.combined_count; + } + if (eliminated_count) + design->scratchpad_set_bool("opt.did_something", true); + if (combined_count) + design->scratchpad_set_bool("opt.did_something", true); + log("\n"); + log("Eliminated %d LUTs.\n", eliminated_count); + log("Combined %d LUTs.\n", combined_count); + } +} OptLutPass; + +PRIVATE_NAMESPACE_END diff --git a/passes/opt/opt_merge.cc b/passes/opt/opt_merge.cc index 2aeb514e4..aaea6159e 100644 --- a/passes/opt/opt_merge.cc +++ b/passes/opt/opt_merge.cc @@ -47,8 +47,8 @@ struct OptMergeWorker static void sort_pmux_conn(dict<RTLIL::IdString, RTLIL::SigSpec> &conn) { - SigSpec sig_s = conn.at("\\S"); - SigSpec sig_b = conn.at("\\B"); + SigSpec sig_s = conn.at(ID(S)); + SigSpec sig_b = conn.at(ID::B); int s_width = GetSize(sig_s); int width = GetSize(sig_b) / s_width; @@ -59,12 +59,12 @@ struct OptMergeWorker std::sort(sb_pairs.begin(), sb_pairs.end()); - conn["\\S"] = SigSpec(); - conn["\\B"] = SigSpec(); + conn[ID(S)] = SigSpec(); + conn[ID::B] = SigSpec(); for (auto &it : sb_pairs) { - conn["\\S"].append(it.first); - conn["\\B"].append(it.second); + conn[ID(S)].append(it.first); + conn[ID::B].append(it.second); } } @@ -94,32 +94,32 @@ struct OptMergeWorker const dict<RTLIL::IdString, RTLIL::SigSpec> *conn = &cell->connections(); dict<RTLIL::IdString, RTLIL::SigSpec> alt_conn; - if (cell->type == "$and" || cell->type == "$or" || cell->type == "$xor" || cell->type == "$xnor" || cell->type == "$add" || cell->type == "$mul" || - cell->type == "$logic_and" || cell->type == "$logic_or" || cell->type == "$_AND_" || cell->type == "$_OR_" || cell->type == "$_XOR_") { + if (cell->type.in(ID($and), ID($or), ID($xor), ID($xnor), ID($add), ID($mul), + ID($logic_and), ID($logic_or), ID($_AND_), ID($_OR_), ID($_XOR_))) { alt_conn = *conn; - if (assign_map(alt_conn.at("\\A")) < assign_map(alt_conn.at("\\B"))) { - alt_conn["\\A"] = conn->at("\\B"); - alt_conn["\\B"] = conn->at("\\A"); + if (assign_map(alt_conn.at(ID::A)) < assign_map(alt_conn.at(ID::B))) { + alt_conn[ID::A] = conn->at(ID::B); + alt_conn[ID::B] = conn->at(ID::A); } conn = &alt_conn; } else - if (cell->type == "$reduce_xor" || cell->type == "$reduce_xnor") { + if (cell->type.in(ID($reduce_xor), ID($reduce_xnor))) { alt_conn = *conn; - assign_map.apply(alt_conn.at("\\A")); - alt_conn.at("\\A").sort(); + assign_map.apply(alt_conn.at(ID::A)); + alt_conn.at(ID::A).sort(); conn = &alt_conn; } else - if (cell->type == "$reduce_and" || cell->type == "$reduce_or" || cell->type == "$reduce_bool") { + if (cell->type.in(ID($reduce_and), ID($reduce_or), ID($reduce_bool))) { alt_conn = *conn; - assign_map.apply(alt_conn.at("\\A")); - alt_conn.at("\\A").sort_and_unify(); + assign_map.apply(alt_conn.at(ID::A)); + alt_conn.at(ID::A).sort_and_unify(); conn = &alt_conn; } else - if (cell->type == "$pmux") { + if (cell->type == ID($pmux)) { alt_conn = *conn; - assign_map.apply(alt_conn.at("\\A")); - assign_map.apply(alt_conn.at("\\B")); - assign_map.apply(alt_conn.at("\\S")); + assign_map.apply(alt_conn.at(ID::A)); + assign_map.apply(alt_conn.at(ID::B)); + assign_map.apply(alt_conn.at(ID(S))); sort_pmux_conn(alt_conn); conn = &alt_conn; } @@ -189,28 +189,28 @@ struct OptMergeWorker assign_map.apply(it.second); } - if (cell1->type == "$and" || cell1->type == "$or" || cell1->type == "$xor" || cell1->type == "$xnor" || cell1->type == "$add" || cell1->type == "$mul" || - cell1->type == "$logic_and" || cell1->type == "$logic_or" || cell1->type == "$_AND_" || cell1->type == "$_OR_" || cell1->type == "$_XOR_") { - if (conn1.at("\\A") < conn1.at("\\B")) { - RTLIL::SigSpec tmp = conn1["\\A"]; - conn1["\\A"] = conn1["\\B"]; - conn1["\\B"] = tmp; + if (cell1->type == ID($and) || cell1->type == ID($or) || cell1->type == ID($xor) || cell1->type == ID($xnor) || cell1->type == ID($add) || cell1->type == ID($mul) || + cell1->type == ID($logic_and) || cell1->type == ID($logic_or) || cell1->type == ID($_AND_) || cell1->type == ID($_OR_) || cell1->type == ID($_XOR_)) { + if (conn1.at(ID::A) < conn1.at(ID::B)) { + RTLIL::SigSpec tmp = conn1[ID::A]; + conn1[ID::A] = conn1[ID::B]; + conn1[ID::B] = tmp; } - if (conn2.at("\\A") < conn2.at("\\B")) { - RTLIL::SigSpec tmp = conn2["\\A"]; - conn2["\\A"] = conn2["\\B"]; - conn2["\\B"] = tmp; + if (conn2.at(ID::A) < conn2.at(ID::B)) { + RTLIL::SigSpec tmp = conn2[ID::A]; + conn2[ID::A] = conn2[ID::B]; + conn2[ID::B] = tmp; } } else - if (cell1->type == "$reduce_xor" || cell1->type == "$reduce_xnor") { - conn1["\\A"].sort(); - conn2["\\A"].sort(); + if (cell1->type == ID($reduce_xor) || cell1->type == ID($reduce_xnor)) { + conn1[ID::A].sort(); + conn2[ID::A].sort(); } else - if (cell1->type == "$reduce_and" || cell1->type == "$reduce_or" || cell1->type == "$reduce_bool") { - conn1["\\A"].sort_and_unify(); - conn2["\\A"].sort_and_unify(); + if (cell1->type == ID($reduce_and) || cell1->type == ID($reduce_or) || cell1->type == ID($reduce_bool)) { + conn1[ID::A].sort_and_unify(); + conn2[ID::A].sort_and_unify(); } else - if (cell1->type == "$pmux") { + if (cell1->type == ID($pmux)) { sort_pmux_conn(conn1); sort_pmux_conn(conn2); } @@ -222,9 +222,9 @@ struct OptMergeWorker return true; } - if (cell1->type.substr(0, 1) == "$" && conn1.count("\\Q") != 0) { - std::vector<RTLIL::SigBit> q1 = dff_init_map(cell1->getPort("\\Q")).to_sigbit_vector(); - std::vector<RTLIL::SigBit> q2 = dff_init_map(cell2->getPort("\\Q")).to_sigbit_vector(); + if (cell1->type.begins_with("$") && conn1.count(ID(Q)) != 0) { + std::vector<RTLIL::SigBit> q1 = dff_init_map(cell1->getPort(ID(Q))).to_sigbit_vector(); + std::vector<RTLIL::SigBit> q2 = dff_init_map(cell2->getPort(ID(Q))).to_sigbit_vector(); for (size_t i = 0; i < q1.size(); i++) if ((q1.at(i).wire == NULL || q2.at(i).wire == NULL) && q1.at(i) != q2.at(i)) { lt = q1.at(i) < q2.at(i); @@ -271,24 +271,24 @@ struct OptMergeWorker ct.setup_stdcells_mem(); if (mode_nomux) { - ct.cell_types.erase("$mux"); - ct.cell_types.erase("$pmux"); + ct.cell_types.erase(ID($mux)); + ct.cell_types.erase(ID($pmux)); } - ct.cell_types.erase("$tribuf"); - ct.cell_types.erase("$_TBUF_"); - ct.cell_types.erase("$anyseq"); - ct.cell_types.erase("$anyconst"); - ct.cell_types.erase("$allseq"); - ct.cell_types.erase("$allconst"); + ct.cell_types.erase(ID($tribuf)); + ct.cell_types.erase(ID($_TBUF_)); + ct.cell_types.erase(ID($anyseq)); + ct.cell_types.erase(ID($anyconst)); + ct.cell_types.erase(ID($allseq)); + ct.cell_types.erase(ID($allconst)); log("Finding identical cells in module `%s'.\n", module->name.c_str()); assign_map.set(module); dff_init_map.set(module); for (auto &it : module->wires_) - if (it.second->attributes.count("\\init") != 0) { - Const initval = it.second->attributes.at("\\init"); + if (it.second->attributes.count(ID(init)) != 0) { + Const initval = it.second->attributes.at(ID(init)); for (int i = 0; i < GetSize(initval) && i < GetSize(it.second); i++) if (initval[i] == State::S0 || initval[i] == State::S1) dff_init_map.add(SigBit(it.second, i), initval[i]); @@ -315,17 +315,17 @@ struct OptMergeWorker { if (sharemap.count(cell) > 0) { did_something = true; - log(" Cell `%s' is identical to cell `%s'.\n", cell->name.c_str(), sharemap[cell]->name.c_str()); + log_debug(" Cell `%s' is identical to cell `%s'.\n", cell->name.c_str(), sharemap[cell]->name.c_str()); for (auto &it : cell->connections()) { if (cell->output(it.first)) { RTLIL::SigSpec other_sig = sharemap[cell]->getPort(it.first); - log(" Redirecting output %s: %s = %s\n", it.first.c_str(), + log_debug(" Redirecting output %s: %s = %s\n", it.first.c_str(), log_signal(it.second), log_signal(other_sig)); module->connect(RTLIL::SigSig(it.second, other_sig)); assign_map.add(it.second, other_sig); } } - log(" Removing %s cell `%s' from module `%s'.\n", cell->type.c_str(), cell->name.c_str(), module->name.c_str()); + log_debug(" Removing %s cell `%s' from module `%s'.\n", cell->type.c_str(), cell->name.c_str(), module->name.c_str()); #ifdef USE_CELL_HASH_CACHE cell_hash_cache.erase(cell); #endif @@ -336,12 +336,14 @@ struct OptMergeWorker } } } + + log_suppressed(); } }; struct OptMergePass : public Pass { OptMergePass() : Pass("opt_merge", "consolidate identical cells") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -357,7 +359,7 @@ struct OptMergePass : public Pass { log(" Operate on all cell types, not just built-in types.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing OPT_MERGE pass (detect identical cells).\n"); diff --git a/passes/opt/opt_muxtree.cc b/passes/opt/opt_muxtree.cc index f5ddc2af9..3c486bbcc 100644 --- a/passes/opt/opt_muxtree.cc +++ b/passes/opt/opt_muxtree.cc @@ -36,6 +36,7 @@ struct OptMuxtreeWorker RTLIL::Module *module; SigMap assign_map; int removed_count; + int glob_abort_cnt = 100000; struct bitinfo_t { bool seen_non_mux; @@ -83,12 +84,12 @@ struct OptMuxtreeWorker // .const_deactivated for (auto cell : module->cells()) { - if (cell->type == "$mux" || cell->type == "$pmux") + if (cell->type.in(ID($mux), ID($pmux))) { - RTLIL::SigSpec sig_a = cell->getPort("\\A"); - RTLIL::SigSpec sig_b = cell->getPort("\\B"); - RTLIL::SigSpec sig_s = cell->getPort("\\S"); - RTLIL::SigSpec sig_y = cell->getPort("\\Y"); + RTLIL::SigSpec sig_a = cell->getPort(ID::A); + RTLIL::SigSpec sig_b = cell->getPort(ID::B); + RTLIL::SigSpec sig_s = cell->getPort(ID(S)); + RTLIL::SigSpec sig_y = cell->getPort(ID::Y); muxinfo_t muxinfo; muxinfo.cell = cell; @@ -136,7 +137,7 @@ struct OptMuxtreeWorker } } for (auto wire : module->wires()) { - if (wire->port_output || wire->get_bool_attribute("\\keep")) + if (wire->port_output || wire->get_bool_attribute(ID::keep)) for (int idx : sig2bits(RTLIL::SigSpec(wire))) bit2info[idx].seen_non_mux = true; } @@ -180,20 +181,29 @@ struct OptMuxtreeWorker for (int mux_idx = 0; mux_idx < GetSize(root_muxes); mux_idx++) if (root_muxes.at(mux_idx)) { - log(" Root of a mux tree: %s%s\n", log_id(mux2info[mux_idx].cell), root_enable_muxes.at(mux_idx) ? " (pure)" : ""); + log_debug(" Root of a mux tree: %s%s\n", log_id(mux2info[mux_idx].cell), root_enable_muxes.at(mux_idx) ? " (pure)" : ""); root_mux_rerun.erase(mux_idx); eval_root_mux(mux_idx); + if (glob_abort_cnt == 0) { + log(" Giving up (too many iterations)\n"); + return; + } } while (!root_mux_rerun.empty()) { int mux_idx = *root_mux_rerun.begin(); - log(" Root of a mux tree: %s (rerun as non-pure)\n", log_id(mux2info[mux_idx].cell)); + log_debug(" Root of a mux tree: %s (rerun as non-pure)\n", log_id(mux2info[mux_idx].cell)); log_assert(root_enable_muxes.at(mux_idx)); root_mux_rerun.erase(mux_idx); eval_root_mux(mux_idx); + if (glob_abort_cnt == 0) { + log(" Giving up (too many iterations)\n"); + return; + } } log(" Analyzing evaluation results.\n"); + log_assert(glob_abort_cnt > 0); for (auto &mi : mux2info) { @@ -217,10 +227,10 @@ struct OptMuxtreeWorker continue; } - RTLIL::SigSpec sig_a = mi.cell->getPort("\\A"); - RTLIL::SigSpec sig_b = mi.cell->getPort("\\B"); - RTLIL::SigSpec sig_s = mi.cell->getPort("\\S"); - RTLIL::SigSpec sig_y = mi.cell->getPort("\\Y"); + RTLIL::SigSpec sig_a = mi.cell->getPort(ID::A); + RTLIL::SigSpec sig_b = mi.cell->getPort(ID::B); + RTLIL::SigSpec sig_s = mi.cell->getPort(ID(S)); + RTLIL::SigSpec sig_y = mi.cell->getPort(ID::Y); RTLIL::SigSpec sig_ports = sig_b; sig_ports.append(sig_a); @@ -245,14 +255,14 @@ struct OptMuxtreeWorker } } - mi.cell->setPort("\\A", new_sig_a); - mi.cell->setPort("\\B", new_sig_b); - mi.cell->setPort("\\S", new_sig_s); + mi.cell->setPort(ID::A, new_sig_a); + mi.cell->setPort(ID::B, new_sig_b); + mi.cell->setPort(ID(S), new_sig_s); if (GetSize(new_sig_s) == 1) { - mi.cell->type = "$mux"; - mi.cell->parameters.erase("\\S_WIDTH"); + mi.cell->type = ID($mux); + mi.cell->parameters.erase(ID(S_WIDTH)); } else { - mi.cell->parameters["\\S_WIDTH"] = RTLIL::Const(GetSize(new_sig_s)); + mi.cell->parameters[ID(S_WIDTH)] = RTLIL::Const(GetSize(new_sig_s)); } } } @@ -293,6 +303,9 @@ struct OptMuxtreeWorker void eval_mux_port(knowledge_t &knowledge, int mux_idx, int port_idx, bool do_replace_known, bool do_enable_ports, int abort_count) { + if (glob_abort_cnt == 0) + return; + muxinfo_t &muxinfo = mux2info[mux_idx]; if (do_enable_ports) @@ -315,18 +328,21 @@ struct OptMuxtreeWorker knowledge.visited_muxes[m] = true; parent_muxes.push_back(m); } - for (int m : parent_muxes) + for (int m : parent_muxes) { if (root_enable_muxes.at(m)) continue; else if (root_muxes.at(m)) { if (abort_count == 0) { root_mux_rerun.insert(m); root_enable_muxes.at(m) = true; - log(" Removing pure flag from root mux %s.\n", log_id(mux2info[m].cell)); + log_debug(" Removing pure flag from root mux %s.\n", log_id(mux2info[m].cell)); } else eval_mux(knowledge, m, false, do_enable_ports, abort_count - 1); } else eval_mux(knowledge, m, do_replace_known, do_enable_ports, abort_count); + if (glob_abort_cnt == 0) + return; + } for (int m : parent_muxes) knowledge.visited_muxes[m] = false; @@ -348,9 +364,9 @@ struct OptMuxtreeWorker int width = 0; idict<int> ctrl_bits; - if (portname == "\\B") - width = GetSize(muxinfo.cell->getPort("\\A")); - for (int bit : sig2bits(muxinfo.cell->getPort("\\S"), false)) + if (portname == ID::B) + width = GetSize(muxinfo.cell->getPort(ID::A)); + for (int bit : sig2bits(muxinfo.cell->getPort(ID(S)), false)) ctrl_bits(bit); int port_idx = 0, port_off = 0; @@ -390,12 +406,16 @@ struct OptMuxtreeWorker void eval_mux(knowledge_t &knowledge, int mux_idx, bool do_replace_known, bool do_enable_ports, int abort_count) { + if (glob_abort_cnt == 0) + return; + glob_abort_cnt--; + muxinfo_t &muxinfo = mux2info[mux_idx]; // set input ports to constants if we find known active or inactive signals if (do_replace_known) { - replace_known(knowledge, muxinfo, "\\A"); - replace_known(knowledge, muxinfo, "\\B"); + replace_known(knowledge, muxinfo, ID::A); + replace_known(knowledge, muxinfo, ID::B); } // if there is a constant activated port we just use it @@ -433,11 +453,15 @@ struct OptMuxtreeWorker if (knowledge.known_inactive.at(portinfo.ctrl_sig)) continue; eval_mux_port(knowledge, mux_idx, port_idx, do_replace_known, do_enable_ports, abort_count); + + if (glob_abort_cnt == 0) + return; } } void eval_root_mux(int mux_idx) { + log_assert(glob_abort_cnt > 0); knowledge_t knowledge; knowledge.known_inactive.resize(GetSize(bit2info)); knowledge.known_active.resize(GetSize(bit2info)); @@ -449,7 +473,7 @@ struct OptMuxtreeWorker struct OptMuxtreePass : public Pass { OptMuxtreePass() : Pass("opt_muxtree", "eliminate dead trees in multiplexer trees") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -462,7 +486,7 @@ struct OptMuxtreePass : public Pass { log("This pass only operates on completely selected modules without processes.\n"); log("\n"); } - virtual void execute(vector<std::string> args, RTLIL::Design *design) + void execute(vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing OPT_MUXTREE pass (detect dead branches in mux trees).\n"); extra_args(args, 1, design); diff --git a/passes/opt/opt_reduce.cc b/passes/opt/opt_reduce.cc index eb9d02ad5..6a8d8cabd 100644 --- a/passes/opt/opt_reduce.cc +++ b/passes/opt/opt_reduce.cc @@ -43,13 +43,13 @@ struct OptReduceWorker return; cells.erase(cell); - RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A")); + RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID::A)); pool<RTLIL::SigBit> new_sig_a_bits; for (auto &bit : sig_a.to_sigbit_set()) { if (bit == RTLIL::State::S0) { - if (cell->type == "$reduce_and") { + if (cell->type == ID($reduce_and)) { new_sig_a_bits.clear(); new_sig_a_bits.insert(RTLIL::State::S0); break; @@ -57,7 +57,7 @@ struct OptReduceWorker continue; } if (bit == RTLIL::State::S1) { - if (cell->type == "$reduce_or") { + if (cell->type == ID($reduce_or)) { new_sig_a_bits.clear(); new_sig_a_bits.insert(RTLIL::State::S1); break; @@ -73,8 +73,8 @@ struct OptReduceWorker for (auto child_cell : drivers.find(bit)) { if (child_cell->type == cell->type) { opt_reduce(cells, drivers, child_cell); - if (child_cell->getPort("\\Y")[0] == bit) { - pool<RTLIL::SigBit> child_sig_a_bits = assign_map(child_cell->getPort("\\A")).to_sigbit_pool(); + if (child_cell->getPort(ID::Y)[0] == bit) { + pool<RTLIL::SigBit> child_sig_a_bits = assign_map(child_cell->getPort(ID::A)).to_sigbit_pool(); new_sig_a_bits.insert(child_sig_a_bits.begin(), child_sig_a_bits.end()); } else new_sig_a_bits.insert(RTLIL::State::S0); @@ -87,22 +87,22 @@ struct OptReduceWorker RTLIL::SigSpec new_sig_a(new_sig_a_bits); - if (new_sig_a != sig_a || sig_a.size() != cell->getPort("\\A").size()) { + if (new_sig_a != sig_a || sig_a.size() != cell->getPort(ID::A).size()) { log(" New input vector for %s cell %s: %s\n", cell->type.c_str(), cell->name.c_str(), log_signal(new_sig_a)); did_something = true; total_count++; } - cell->setPort("\\A", new_sig_a); - cell->parameters["\\A_WIDTH"] = RTLIL::Const(new_sig_a.size()); + cell->setPort(ID::A, new_sig_a); + cell->parameters[ID(A_WIDTH)] = RTLIL::Const(new_sig_a.size()); return; } void opt_mux(RTLIL::Cell *cell) { - RTLIL::SigSpec sig_a = assign_map(cell->getPort("\\A")); - RTLIL::SigSpec sig_b = assign_map(cell->getPort("\\B")); - RTLIL::SigSpec sig_s = assign_map(cell->getPort("\\S")); + RTLIL::SigSpec sig_a = assign_map(cell->getPort(ID::A)); + RTLIL::SigSpec sig_b = assign_map(cell->getPort(ID::B)); + RTLIL::SigSpec sig_s = assign_map(cell->getPort(ID(S))); RTLIL::SigSpec new_sig_b, new_sig_s; pool<RTLIL::SigSpec> handled_sig; @@ -123,15 +123,15 @@ struct OptReduceWorker if (this_s.size() > 1) { - RTLIL::Cell *reduce_or_cell = module->addCell(NEW_ID, "$reduce_or"); - reduce_or_cell->setPort("\\A", this_s); - reduce_or_cell->parameters["\\A_SIGNED"] = RTLIL::Const(0); - reduce_or_cell->parameters["\\A_WIDTH"] = RTLIL::Const(this_s.size()); - reduce_or_cell->parameters["\\Y_WIDTH"] = RTLIL::Const(1); + RTLIL::Cell *reduce_or_cell = module->addCell(NEW_ID, ID($reduce_or)); + reduce_or_cell->setPort(ID::A, this_s); + reduce_or_cell->parameters[ID(A_SIGNED)] = RTLIL::Const(0); + reduce_or_cell->parameters[ID(A_WIDTH)] = RTLIL::Const(this_s.size()); + reduce_or_cell->parameters[ID(Y_WIDTH)] = RTLIL::Const(1); RTLIL::Wire *reduce_or_wire = module->addWire(NEW_ID); this_s = RTLIL::SigSpec(reduce_or_wire); - reduce_or_cell->setPort("\\Y", this_s); + reduce_or_cell->setPort(ID::Y, this_s); } new_sig_b.append(this_b); @@ -147,28 +147,28 @@ struct OptReduceWorker if (new_sig_s.size() == 0) { - module->connect(RTLIL::SigSig(cell->getPort("\\Y"), cell->getPort("\\A"))); - assign_map.add(cell->getPort("\\Y"), cell->getPort("\\A")); + module->connect(RTLIL::SigSig(cell->getPort(ID::Y), cell->getPort(ID::A))); + assign_map.add(cell->getPort(ID::Y), cell->getPort(ID::A)); module->remove(cell); } else { - cell->setPort("\\B", new_sig_b); - cell->setPort("\\S", new_sig_s); + cell->setPort(ID::B, new_sig_b); + cell->setPort(ID(S), new_sig_s); if (new_sig_s.size() > 1) { - cell->parameters["\\S_WIDTH"] = RTLIL::Const(new_sig_s.size()); + cell->parameters[ID(S_WIDTH)] = RTLIL::Const(new_sig_s.size()); } else { - cell->type = "$mux"; - cell->parameters.erase("\\S_WIDTH"); + cell->type = ID($mux); + cell->parameters.erase(ID(S_WIDTH)); } } } void opt_mux_bits(RTLIL::Cell *cell) { - std::vector<RTLIL::SigBit> sig_a = assign_map(cell->getPort("\\A")).to_sigbit_vector(); - std::vector<RTLIL::SigBit> sig_b = assign_map(cell->getPort("\\B")).to_sigbit_vector(); - std::vector<RTLIL::SigBit> sig_y = assign_map(cell->getPort("\\Y")).to_sigbit_vector(); + std::vector<RTLIL::SigBit> sig_a = assign_map(cell->getPort(ID::A)).to_sigbit_vector(); + std::vector<RTLIL::SigBit> sig_b = assign_map(cell->getPort(ID::B)).to_sigbit_vector(); + std::vector<RTLIL::SigBit> sig_y = assign_map(cell->getPort(ID::Y)).to_sigbit_vector(); std::vector<RTLIL::SigBit> new_sig_y; RTLIL::SigSig old_sig_conn; @@ -209,29 +209,29 @@ struct OptReduceWorker if (new_sig_y.size() != sig_y.size()) { log(" Consolidated identical input bits for %s cell %s:\n", cell->type.c_str(), cell->name.c_str()); - log(" Old ports: A=%s, B=%s, Y=%s\n", log_signal(cell->getPort("\\A")), - log_signal(cell->getPort("\\B")), log_signal(cell->getPort("\\Y"))); + log(" Old ports: A=%s, B=%s, Y=%s\n", log_signal(cell->getPort(ID::A)), + log_signal(cell->getPort(ID::B)), log_signal(cell->getPort(ID::Y))); - cell->setPort("\\A", RTLIL::SigSpec()); + cell->setPort(ID::A, RTLIL::SigSpec()); for (auto &in_tuple : consolidated_in_tuples) { - RTLIL::SigSpec new_a = cell->getPort("\\A"); + RTLIL::SigSpec new_a = cell->getPort(ID::A); new_a.append(in_tuple.at(0)); - cell->setPort("\\A", new_a); + cell->setPort(ID::A, new_a); } - cell->setPort("\\B", RTLIL::SigSpec()); - for (int i = 1; i <= cell->getPort("\\S").size(); i++) + cell->setPort(ID::B, RTLIL::SigSpec()); + for (int i = 1; i <= cell->getPort(ID(S)).size(); i++) for (auto &in_tuple : consolidated_in_tuples) { - RTLIL::SigSpec new_b = cell->getPort("\\B"); + RTLIL::SigSpec new_b = cell->getPort(ID::B); new_b.append(in_tuple.at(i)); - cell->setPort("\\B", new_b); + cell->setPort(ID::B, new_b); } - cell->parameters["\\WIDTH"] = RTLIL::Const(new_sig_y.size()); - cell->setPort("\\Y", new_sig_y); + cell->parameters[ID(WIDTH)] = RTLIL::Const(new_sig_y.size()); + cell->setPort(ID::Y, new_sig_y); - log(" New ports: A=%s, B=%s, Y=%s\n", log_signal(cell->getPort("\\A")), - log_signal(cell->getPort("\\B")), log_signal(cell->getPort("\\Y"))); + log(" New ports: A=%s, B=%s, Y=%s\n", log_signal(cell->getPort(ID::A)), + log_signal(cell->getPort(ID::B)), log_signal(cell->getPort(ID::Y))); log(" New connections: %s = %s\n", log_signal(old_sig_conn.first), log_signal(old_sig_conn.second)); module->connect(old_sig_conn); @@ -253,15 +253,15 @@ struct OptReduceWorker SigPool mem_wren_sigs; for (auto &cell_it : module->cells_) { RTLIL::Cell *cell = cell_it.second; - if (cell->type == "$mem") - mem_wren_sigs.add(assign_map(cell->getPort("\\WR_EN"))); - if (cell->type == "$memwr") - mem_wren_sigs.add(assign_map(cell->getPort("\\EN"))); + if (cell->type == ID($mem)) + mem_wren_sigs.add(assign_map(cell->getPort(ID(WR_EN)))); + if (cell->type == ID($memwr)) + mem_wren_sigs.add(assign_map(cell->getPort(ID(EN)))); } for (auto &cell_it : module->cells_) { RTLIL::Cell *cell = cell_it.second; - if (cell->type == "$dff" && mem_wren_sigs.check_any(assign_map(cell->getPort("\\Q")))) - mem_wren_sigs.add(assign_map(cell->getPort("\\D"))); + if (cell->type == ID($dff) && mem_wren_sigs.check_any(assign_map(cell->getPort(ID(Q))))) + mem_wren_sigs.add(assign_map(cell->getPort(ID(D)))); } bool keep_expanding_mem_wren_sigs = true; @@ -269,12 +269,12 @@ struct OptReduceWorker keep_expanding_mem_wren_sigs = false; for (auto &cell_it : module->cells_) { RTLIL::Cell *cell = cell_it.second; - if (cell->type == "$mux" && mem_wren_sigs.check_any(assign_map(cell->getPort("\\Y")))) { - if (!mem_wren_sigs.check_all(assign_map(cell->getPort("\\A"))) || - !mem_wren_sigs.check_all(assign_map(cell->getPort("\\B")))) + if (cell->type == ID($mux) && mem_wren_sigs.check_any(assign_map(cell->getPort(ID::Y)))) { + if (!mem_wren_sigs.check_all(assign_map(cell->getPort(ID::A))) || + !mem_wren_sigs.check_all(assign_map(cell->getPort(ID::B)))) keep_expanding_mem_wren_sigs = true; - mem_wren_sigs.add(assign_map(cell->getPort("\\A"))); - mem_wren_sigs.add(assign_map(cell->getPort("\\B"))); + mem_wren_sigs.add(assign_map(cell->getPort(ID::A))); + mem_wren_sigs.add(assign_map(cell->getPort(ID::B))); } } } @@ -286,7 +286,7 @@ struct OptReduceWorker // merge trees of reduce_* cells to one single cell and unify input vectors // (only handle reduce_and and reduce_or for various reasons) - const char *type_list[] = { "$reduce_or", "$reduce_and" }; + const IdString type_list[] = { ID($reduce_or), ID($reduce_and) }; for (auto type : type_list) { SigSet<RTLIL::Cell*> drivers; @@ -296,7 +296,7 @@ struct OptReduceWorker RTLIL::Cell *cell = cell_it.second; if (cell->type != type || !design->selected(module, cell)) continue; - drivers.insert(assign_map(cell->getPort("\\Y")), cell); + drivers.insert(assign_map(cell->getPort(ID::Y)), cell); cells.insert(cell); } @@ -311,14 +311,14 @@ struct OptReduceWorker std::vector<RTLIL::Cell*> cells; for (auto &it : module->cells_) - if ((it.second->type == "$mux" || it.second->type == "$pmux") && design->selected(module, it.second)) + if ((it.second->type == ID($mux) || it.second->type == ID($pmux)) && design->selected(module, it.second)) cells.push_back(it.second); for (auto cell : cells) { // this optimization is to aggressive for most coarse-grain applications. // but we always want it for multiplexers driving write enable ports. - if (do_fine || mem_wren_sigs.check_any(assign_map(cell->getPort("\\Y")))) + if (do_fine || mem_wren_sigs.check_any(assign_map(cell->getPort(ID::Y)))) opt_mux_bits(cell); opt_mux(cell); @@ -329,7 +329,7 @@ struct OptReduceWorker struct OptReducePass : public Pass { OptReducePass() : Pass("opt_reduce", "simplify large MUXes and AND/OR gates") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -350,7 +350,7 @@ struct OptReducePass : public Pass { log(" alias for -fine\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { bool do_fine = false; diff --git a/passes/opt/opt_rmdff.cc b/passes/opt/opt_rmdff.cc index b5edb357b..0bf74098a 100644 --- a/passes/opt/opt_rmdff.cc +++ b/passes/opt/opt_rmdff.cc @@ -17,26 +17,31 @@ * */ +#include "kernel/log.h" #include "kernel/register.h" +#include "kernel/rtlil.h" +#include "kernel/satgen.h" #include "kernel/sigtools.h" -#include "kernel/log.h" -#include <stdlib.h> #include <stdio.h> +#include <stdlib.h> USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN SigMap assign_map, dff_init_map; SigSet<RTLIL::Cell*> mux_drivers; +dict<SigBit, RTLIL::Cell*> bit2driver; dict<SigBit, pool<SigBit>> init_attributes; + bool keepdc; +bool sat; void remove_init_attr(SigSpec sig) { for (auto bit : assign_map(sig)) if (init_attributes.count(bit)) for (auto wbit : init_attributes.at(bit)) - wbit.wire->attributes.at("\\init")[wbit.offset] = State::Sx; + wbit.wire->attributes.at(ID(init))[wbit.offset] = State::Sx; } bool handle_dffsr(RTLIL::Module *mod, RTLIL::Cell *cell) @@ -44,39 +49,39 @@ bool handle_dffsr(RTLIL::Module *mod, RTLIL::Cell *cell) SigSpec sig_set, sig_clr; State pol_set, pol_clr; - if (cell->hasPort("\\S")) - sig_set = cell->getPort("\\S"); + if (cell->hasPort(ID(S))) + sig_set = cell->getPort(ID(S)); - if (cell->hasPort("\\R")) - sig_clr = cell->getPort("\\R"); + if (cell->hasPort(ID(R))) + sig_clr = cell->getPort(ID(R)); - if (cell->hasPort("\\SET")) - sig_set = cell->getPort("\\SET"); + if (cell->hasPort(ID(SET))) + sig_set = cell->getPort(ID(SET)); - if (cell->hasPort("\\CLR")) - sig_clr = cell->getPort("\\CLR"); + if (cell->hasPort(ID(CLR))) + sig_clr = cell->getPort(ID(CLR)); log_assert(GetSize(sig_set) == GetSize(sig_clr)); - if (cell->type.substr(0,8) == "$_DFFSR_") { + if (cell->type.begins_with("$_DFFSR_")) { pol_set = cell->type[9] == 'P' ? State::S1 : State::S0; pol_clr = cell->type[10] == 'P' ? State::S1 : State::S0; } else - if (cell->type.substr(0,11) == "$_DLATCHSR_") { + if (cell->type.begins_with("$_DLATCHSR_")) { pol_set = cell->type[12] == 'P' ? State::S1 : State::S0; pol_clr = cell->type[13] == 'P' ? State::S1 : State::S0; } else - if (cell->type == "$dffsr" || cell->type == "$dlatchsr") { - pol_set = cell->parameters["\\SET_POLARITY"].as_bool() ? State::S1 : State::S0; - pol_clr = cell->parameters["\\CLR_POLARITY"].as_bool() ? State::S1 : State::S0; + if (cell->type.in(ID($dffsr), ID($dlatchsr))) { + pol_set = cell->parameters[ID(SET_POLARITY)].as_bool() ? State::S1 : State::S0; + pol_clr = cell->parameters[ID(CLR_POLARITY)].as_bool() ? State::S1 : State::S0; } else log_abort(); State npol_set = pol_set == State::S0 ? State::S1 : State::S0; State npol_clr = pol_clr == State::S0 ? State::S1 : State::S0; - SigSpec sig_d = cell->getPort("\\D"); - SigSpec sig_q = cell->getPort("\\Q"); + SigSpec sig_d = cell->getPort(ID(D)); + SigSpec sig_q = cell->getPort(ID(Q)); bool did_something = false; bool proper_sr = false; @@ -132,20 +137,20 @@ bool handle_dffsr(RTLIL::Module *mod, RTLIL::Cell *cell) return true; } - if (cell->type == "$dffsr" || cell->type == "$dlatchsr") + if (cell->type.in(ID($dffsr), ID($dlatchsr))) { - cell->setParam("\\WIDTH", GetSize(sig_d)); - cell->setPort("\\SET", sig_set); - cell->setPort("\\CLR", sig_clr); - cell->setPort("\\D", sig_d); - cell->setPort("\\Q", sig_q); + cell->setParam(ID(WIDTH), GetSize(sig_d)); + cell->setPort(ID(SET), sig_set); + cell->setPort(ID(CLR), sig_clr); + cell->setPort(ID(D), sig_d); + cell->setPort(ID(Q), sig_q); } else { - cell->setPort("\\S", sig_set); - cell->setPort("\\R", sig_clr); - cell->setPort("\\D", sig_d); - cell->setPort("\\Q", sig_q); + cell->setPort(ID(S), sig_set); + cell->setPort(ID(R), sig_clr); + cell->setPort(ID(D), sig_d); + cell->setPort(ID(Q), sig_q); } if (proper_sr) @@ -154,49 +159,48 @@ bool handle_dffsr(RTLIL::Module *mod, RTLIL::Cell *cell) if (used_pol_set && used_pol_clr && pol_set != pol_clr) return did_something; - if (cell->type == "$dlatchsr") + if (cell->type == ID($dlatchsr)) return did_something; State unified_pol = used_pol_set ? pol_set : pol_clr; - if (cell->type == "$dffsr") + if (cell->type == ID($dffsr)) { if (hasreset) { log("Converting %s (%s) to %s in module %s.\n", log_id(cell), log_id(cell->type), "$adff", log_id(mod)); - cell->type = "$adff"; - cell->setParam("\\ARST_POLARITY", unified_pol); - cell->setParam("\\ARST_VALUE", reset_val); - cell->setPort("\\ARST", sig_reset); + cell->type = ID($adff); + cell->setParam(ID(ARST_POLARITY), unified_pol); + cell->setParam(ID(ARST_VALUE), reset_val); + cell->setPort(ID(ARST), sig_reset); - cell->unsetParam("\\SET_POLARITY"); - cell->unsetParam("\\CLR_POLARITY"); - cell->unsetPort("\\SET"); - cell->unsetPort("\\CLR"); - - return true; + cell->unsetParam(ID(SET_POLARITY)); + cell->unsetParam(ID(CLR_POLARITY)); + cell->unsetPort(ID(SET)); + cell->unsetPort(ID(CLR)); } else { log("Converting %s (%s) to %s in module %s.\n", log_id(cell), log_id(cell->type), "$dff", log_id(mod)); - cell->type = "$dff"; - cell->unsetParam("\\SET_POLARITY"); - cell->unsetParam("\\CLR_POLARITY"); - cell->unsetPort("\\SET"); - cell->unsetPort("\\CLR"); - - return true; + cell->type = ID($dff); + cell->unsetParam(ID(SET_POLARITY)); + cell->unsetParam(ID(CLR_POLARITY)); + cell->unsetPort(ID(SET)); + cell->unsetPort(ID(CLR)); } + + return true; } - else + + if (!hasreset) { IdString new_type; - if (cell->type.substr(0,8) == "$_DFFSR_") + if (cell->type.begins_with("$_DFFSR_")) new_type = stringf("$_DFF_%c_", cell->type[8]); - else if (cell->type.substr(0,11) == "$_DLATCHSR_") + else if (cell->type.begins_with("$_DLATCHSR_")) new_type = stringf("$_DLATCH_%c_", cell->type[11]); else log_abort(); @@ -204,11 +208,13 @@ bool handle_dffsr(RTLIL::Module *mod, RTLIL::Cell *cell) log("Converting %s (%s) to %s in module %s.\n", log_id(cell), log_id(cell->type), log_id(new_type), log_id(mod)); cell->type = new_type; - cell->unsetPort("\\S"); - cell->unsetPort("\\R"); + cell->unsetPort(ID(S)); + cell->unsetPort(ID(R)); - return did_something; + return true; } + + return did_something; } bool handle_dlatch(RTLIL::Module *mod, RTLIL::Cell *dlatch) @@ -216,18 +222,18 @@ bool handle_dlatch(RTLIL::Module *mod, RTLIL::Cell *dlatch) SigSpec sig_e; State on_state, off_state; - if (dlatch->type == "$dlatch") { - sig_e = assign_map(dlatch->getPort("\\EN")); - on_state = dlatch->getParam("\\EN_POLARITY").as_bool() ? State::S1 : State::S0; - off_state = dlatch->getParam("\\EN_POLARITY").as_bool() ? State::S0 : State::S1; + if (dlatch->type == ID($dlatch)) { + sig_e = assign_map(dlatch->getPort(ID(EN))); + on_state = dlatch->getParam(ID(EN_POLARITY)).as_bool() ? State::S1 : State::S0; + off_state = dlatch->getParam(ID(EN_POLARITY)).as_bool() ? State::S0 : State::S1; } else - if (dlatch->type == "$_DLATCH_P_") { - sig_e = assign_map(dlatch->getPort("\\E")); + if (dlatch->type == ID($_DLATCH_P_)) { + sig_e = assign_map(dlatch->getPort(ID(E))); on_state = State::S1; off_state = State::S0; } else - if (dlatch->type == "$_DLATCH_N_") { - sig_e = assign_map(dlatch->getPort("\\E")); + if (dlatch->type == ID($_DLATCH_N_)) { + sig_e = assign_map(dlatch->getPort(ID(E))); on_state = State::S0; off_state = State::S1; } else @@ -236,15 +242,15 @@ bool handle_dlatch(RTLIL::Module *mod, RTLIL::Cell *dlatch) if (sig_e == off_state) { RTLIL::Const val_init; - for (auto bit : dff_init_map(dlatch->getPort("\\Q"))) + for (auto bit : dff_init_map(dlatch->getPort(ID(Q)))) val_init.bits.push_back(bit.wire == NULL ? bit.data : State::Sx); - mod->connect(dlatch->getPort("\\Q"), val_init); + mod->connect(dlatch->getPort(ID(Q)), val_init); goto delete_dlatch; } if (sig_e == on_state) { - mod->connect(dlatch->getPort("\\Q"), dlatch->getPort("\\D")); + mod->connect(dlatch->getPort(ID(Q)), dlatch->getPort(ID(D))); goto delete_dlatch; } @@ -252,56 +258,74 @@ bool handle_dlatch(RTLIL::Module *mod, RTLIL::Cell *dlatch) delete_dlatch: log("Removing %s (%s) from module %s.\n", log_id(dlatch), log_id(dlatch->type), log_id(mod)); - remove_init_attr(dlatch->getPort("\\Q")); + remove_init_attr(dlatch->getPort(ID(Q))); mod->remove(dlatch); return true; } 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"); - sig_q = dff->getPort("\\Q"); + if (dff->type == ID($_FF_)) { + sig_d = dff->getPort(ID(D)); + sig_q = dff->getPort(ID(Q)); } - else if (dff->type == "$_DFF_N_" || dff->type == "$_DFF_P_") { - sig_d = dff->getPort("\\D"); - sig_q = dff->getPort("\\Q"); - sig_c = dff->getPort("\\C"); - val_cp = RTLIL::Const(dff->type == "$_DFF_P_", 1); + else if (dff->type == ID($_DFF_N_) || dff->type == ID($_DFF_P_)) { + sig_d = dff->getPort(ID(D)); + sig_q = dff->getPort(ID(Q)); + sig_c = dff->getPort(ID(C)); + val_cp = RTLIL::Const(dff->type == ID($_DFF_P_), 1); } - else if (dff->type.substr(0,6) == "$_DFF_" && dff->type.substr(9) == "_" && + else if (dff->type.begins_with("$_DFF_") && dff->type.compare(9, 1, "_") == 0 && (dff->type[6] == 'N' || dff->type[6] == 'P') && (dff->type[7] == 'N' || dff->type[7] == 'P') && (dff->type[8] == '0' || dff->type[8] == '1')) { - sig_d = dff->getPort("\\D"); - sig_q = dff->getPort("\\Q"); - sig_c = dff->getPort("\\C"); - sig_r = dff->getPort("\\R"); + sig_d = dff->getPort(ID(D)); + sig_q = dff->getPort(ID(Q)); + sig_c = dff->getPort(ID(C)); + sig_r = dff->getPort(ID(R)); val_cp = RTLIL::Const(dff->type[6] == 'P', 1); val_rp = RTLIL::Const(dff->type[7] == 'P', 1); val_rv = RTLIL::Const(dff->type[8] == '1', 1); } - else if (dff->type == "$ff") { - sig_d = dff->getPort("\\D"); - sig_q = dff->getPort("\\Q"); + else if (dff->type.begins_with("$_DFFE_") && dff->type.compare(9, 1, "_") == 0 && + (dff->type[7] == 'N' || dff->type[7] == 'P') && + (dff->type[8] == 'N' || dff->type[8] == 'P')) { + sig_d = dff->getPort(ID(D)); + sig_q = dff->getPort(ID(Q)); + sig_c = dff->getPort(ID(C)); + sig_e = dff->getPort(ID(E)); + val_cp = RTLIL::Const(dff->type[7] == 'P', 1); + val_ep = RTLIL::Const(dff->type[8] == 'P', 1); + } + else if (dff->type == ID($ff)) { + sig_d = dff->getPort(ID(D)); + sig_q = dff->getPort(ID(Q)); } - else if (dff->type == "$dff") { - 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); + else if (dff->type == ID($dff)) { + sig_d = dff->getPort(ID(D)); + sig_q = dff->getPort(ID(Q)); + sig_c = dff->getPort(ID(CLK)); + val_cp = RTLIL::Const(dff->parameters[ID(CLK_POLARITY)].as_bool(), 1); } - else if (dff->type == "$adff") { - sig_d = dff->getPort("\\D"); - sig_q = dff->getPort("\\Q"); - sig_c = dff->getPort("\\CLK"); - sig_r = dff->getPort("\\ARST"); - val_cp = RTLIL::Const(dff->parameters["\\CLK_POLARITY"].as_bool(), 1); - val_rp = RTLIL::Const(dff->parameters["\\ARST_POLARITY"].as_bool(), 1); - val_rv = dff->parameters["\\ARST_VALUE"]; + else if (dff->type == ID($dffe)) { + sig_e = dff->getPort(ID(EN)); + sig_d = dff->getPort(ID(D)); + sig_q = dff->getPort(ID(Q)); + sig_c = dff->getPort(ID(CLK)); + val_cp = RTLIL::Const(dff->parameters[ID(CLK_POLARITY)].as_bool(), 1); + val_ep = RTLIL::Const(dff->parameters[ID(EN_POLARITY)].as_bool(), 1); + } + else if (dff->type == ID($adff)) { + sig_d = dff->getPort(ID(D)); + sig_q = dff->getPort(ID(Q)); + sig_c = dff->getPort(ID(CLK)); + sig_r = dff->getPort(ID(ARST)); + val_cp = RTLIL::Const(dff->parameters[ID(CLK_POLARITY)].as_bool(), 1); + val_rp = RTLIL::Const(dff->parameters[ID(ARST_POLARITY)].as_bool(), 1); + val_rv = dff->parameters[ID(ARST_VALUE)]; } else log_abort(); @@ -319,12 +343,12 @@ bool handle_dff(RTLIL::Module *mod, RTLIL::Cell *dff) val_init.bits.push_back(bit.wire == NULL ? bit.data : RTLIL::State::Sx); } - if (dff->type.in("$ff", "$dff") && mux_drivers.has(sig_d)) { + if (dff->type.in(ID($ff), ID($dff)) && mux_drivers.has(sig_d)) { std::set<RTLIL::Cell*> muxes; mux_drivers.find(sig_d, muxes); for (auto mux : muxes) { - RTLIL::SigSpec sig_a = assign_map(mux->getPort("\\A")); - RTLIL::SigSpec sig_b = assign_map(mux->getPort("\\B")); + RTLIL::SigSpec sig_a = assign_map(mux->getPort(ID::A)); + RTLIL::SigSpec sig_b = assign_map(mux->getPort(ID::B)); if (sig_a == sig_q && sig_b.is_fully_const() && (!has_init || val_init == sig_b.as_const())) { mod->connect(sig_q, sig_b); goto delete_dff; @@ -336,85 +360,207 @@ 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; } log("Removing unused reset from %s (%s) from module %s.\n", log_id(dff), log_id(dff->type), log_id(mod)); - if (dff->type == "$adff") { - dff->type = "$dff"; - dff->unsetPort("\\ARST"); - dff->unsetParam("\\ARST_POLARITY"); - dff->unsetParam("\\ARST_VALUE"); + if (dff->type == ID($adff)) { + dff->type = ID($dff); + dff->unsetPort(ID(ARST)); + dff->unsetParam(ID(ARST_POLARITY)); + dff->unsetParam(ID(ARST_VALUE)); return true; } - log_assert(dff->type.substr(0,6) == "$_DFF_"); + log_assert(dff->type.begins_with("$_DFF_")); dff->type = stringf("$_DFF_%c_", + dff->type[6]); - dff->unsetPort("\\R"); + dff->unsetPort(ID(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 == ID($dffe)) { + dff->type = ID($dff); + dff->unsetPort(ID(EN)); + dff->unsetParam(ID(EN_POLARITY)); + return true; + } + + log_assert(dff->type.begins_with("$_DFFE_")); + dff->type = stringf("$_DFF_%c_", + dff->type[7]); + dff->unsetPort(ID(E)); } + if (sat && has_init && (!sig_r.size() || val_init == val_rv)) + { + bool removed_sigbits = false; + + ezSatPtr ez; + SatGen satgen(ez.get(), &assign_map); + pool<Cell*> sat_cells; + + std::function<void(Cell*)> sat_import_cell = [&](Cell *c) { + if (!sat_cells.insert(c).second) + return; + if (!satgen.importCell(c)) + return; + for (auto &conn : c->connections()) { + if (!c->input(conn.first)) + continue; + for (auto bit : assign_map(conn.second)) + if (bit2driver.count(bit)) + sat_import_cell(bit2driver.at(bit)); + } + }; + + // For each register bit, try to prove that it cannot change from the initial value. If so, remove it + for (int position = 0; position < GetSize(sig_d); position += 1) { + RTLIL::SigBit q_sigbit = sig_q[position]; + RTLIL::SigBit d_sigbit = sig_d[position]; + + if ((!q_sigbit.wire) || (!d_sigbit.wire)) + continue; + + if (!bit2driver.count(d_sigbit)) + continue; + + sat_import_cell(bit2driver.at(d_sigbit)); + + RTLIL::State sigbit_init_val = val_init[position]; + if (sigbit_init_val != State::S0 && sigbit_init_val != State::S1) + continue; + + int init_sat_pi = satgen.importSigSpec(sigbit_init_val).front(); + int q_sat_pi = satgen.importSigBit(q_sigbit); + int d_sat_pi = satgen.importSigBit(d_sigbit); + + // Try to find out whether the register bit can change under some circumstances + bool counter_example_found = ez->solve(ez->IFF(q_sat_pi, init_sat_pi), ez->NOT(ez->IFF(d_sat_pi, init_sat_pi))); + + // If the register bit cannot change, we can replace it with a constant + if (!counter_example_found) + { + log("Setting constant %d-bit at position %d on %s (%s) from module %s.\n", sigbit_init_val ? 1 : 0, + position, log_id(dff), log_id(dff->type), log_id(mod)); + + SigSpec tmp = dff->getPort(ID(D)); + tmp[position] = sigbit_init_val; + dff->setPort(ID(D), tmp); + + removed_sigbits = true; + } + } + + if (removed_sigbits) { + handle_dff(mod, dff); + return true; + } + } + + return false; delete_dff: log("Removing %s (%s) from module %s.\n", log_id(dff), log_id(dff->type), log_id(mod)); - remove_init_attr(dff->getPort("\\Q")); + remove_init_attr(dff->getPort(ID(Q))); mod->remove(dff); + + for (auto &entry : bit2driver) + if (entry.second == dff) + bit2driver.erase(entry.first); + return true; } struct OptRmdffPass : public Pass { OptRmdffPass() : Pass("opt_rmdff", "remove DFFs with constant inputs") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); - log(" opt_rmdff [-keepdc] [selection]\n"); + log(" opt_rmdff [-keepdc] [-sat] [selection]\n"); log("\n"); log("This pass identifies flip-flops with constant inputs and replaces them with\n"); log("a constant driver.\n"); log("\n"); + log(" -sat\n"); + log(" additionally invoke SAT solver to detect and remove flip-flops (with \n"); + log(" non-constant inputs) that can also be replaced with a constant driver\n"); + log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { int total_count = 0, total_initdrv = 0; log_header(design, "Executing OPT_RMDFF pass (remove dff with constant values).\n"); keepdc = false; + sat = false; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { @@ -422,24 +568,28 @@ struct OptRmdffPass : public Pass { keepdc = true; continue; } + if (args[argidx] == "-sat") { + sat = true; + continue; + } break; } extra_args(args, argidx, design); - for (auto module : design->selected_modules()) - { + for (auto module : design->selected_modules()) { pool<SigBit> driven_bits; dict<SigBit, State> init_bits; assign_map.set(module); dff_init_map.set(module); mux_drivers.clear(); + bit2driver.clear(); init_attributes.clear(); for (auto wire : module->wires()) { - if (wire->attributes.count("\\init") != 0) { - Const initval = wire->attributes.at("\\init"); + if (wire->attributes.count(ID(init)) != 0) { + Const initval = wire->attributes.at(ID(init)); for (int i = 0; i < GetSize(initval) && i < GetSize(wire); i++) if (initval[i] == State::S0 || initval[i] == State::S1) dff_init_map.add(SigBit(wire, i), initval[i]); @@ -458,40 +608,45 @@ struct OptRmdffPass : public Pass { driven_bits.insert(bit); } } - mux_drivers.clear(); std::vector<RTLIL::IdString> dff_list; std::vector<RTLIL::IdString> dffsr_list; std::vector<RTLIL::IdString> dlatch_list; for (auto cell : module->cells()) { - for (auto &conn : cell->connections()) - if (cell->output(conn.first) || !cell->known()) - for (auto bit : assign_map(conn.second)) + for (auto &conn : cell->connections()) { + bool is_output = cell->output(conn.first); + if (is_output || !cell->known()) + for (auto bit : assign_map(conn.second)) { + if (is_output) + bit2driver[bit] = cell; driven_bits.insert(bit); + } + } - if (cell->type == "$mux" || cell->type == "$pmux") { - if (cell->getPort("\\A").size() == cell->getPort("\\B").size()) - mux_drivers.insert(assign_map(cell->getPort("\\Y")), cell); + if (cell->type.in(ID($mux), ID($pmux))) { + if (cell->getPort(ID::A).size() == cell->getPort(ID::B).size()) + mux_drivers.insert(assign_map(cell->getPort(ID::Y)), cell); continue; } if (!design->selected(module, cell)) continue; - if (cell->type.in("$_DFFSR_NNN_", "$_DFFSR_NNP_", "$_DFFSR_NPN_", "$_DFFSR_NPP_", - "$_DFFSR_PNN_", "$_DFFSR_PNP_", "$_DFFSR_PPN_", "$_DFFSR_PPP_", "$dffsr", - "$_DLATCHSR_NNN_", "$_DLATCHSR_NNP_", "$_DLATCHSR_NPN_", "$_DLATCHSR_NPP_", - "$_DLATCHSR_PNN_", "$_DLATCHSR_PNP_", "$_DLATCHSR_PPN_", "$_DLATCHSR_PPP_", "$dlatchsr")) + if (cell->type.in(ID($_DFFSR_NNN_), ID($_DFFSR_NNP_), ID($_DFFSR_NPN_), ID($_DFFSR_NPP_), + ID($_DFFSR_PNN_), ID($_DFFSR_PNP_), ID($_DFFSR_PPN_), ID($_DFFSR_PPP_), ID($dffsr), + ID($_DLATCHSR_NNN_), ID($_DLATCHSR_NNP_), ID($_DLATCHSR_NPN_), ID($_DLATCHSR_NPP_), + ID($_DLATCHSR_PNN_), ID($_DLATCHSR_PNP_), ID($_DLATCHSR_PPN_), ID($_DLATCHSR_PPP_), ID($dlatchsr))) dffsr_list.push_back(cell->name); - 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")) + if (cell->type.in(ID($_FF_), ID($_DFF_N_), ID($_DFF_P_), + ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_), + ID($_DFF_PN0_), ID($_DFF_PN1_), ID($_DFF_PP0_), ID($_DFF_PP1_), + ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_), + ID($ff), ID($dff), ID($dffe), ID($adff))) dff_list.push_back(cell->name); - if (cell->type.in("$dlatch", "$_DLATCH_P_", "$_DLATCH_N_")) + if (cell->type.in(ID($dlatch), ID($_DLATCH_P_), ID($_DLATCH_N_))) dlatch_list.push_back(cell->name); } @@ -539,6 +694,7 @@ struct OptRmdffPass : public Pass { assign_map.clear(); mux_drivers.clear(); + bit2driver.clear(); init_attributes.clear(); if (total_count || total_initdrv) diff --git a/passes/opt/opt_share.cc b/passes/opt/opt_share.cc new file mode 100644 index 000000000..2c456705c --- /dev/null +++ b/passes/opt/opt_share.cc @@ -0,0 +1,650 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * 2019 Bogdan Vukobratovic <bogdan.vukobratovic@gmail.com> + * + * 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/log.h" +#include "kernel/register.h" +#include "kernel/rtlil.h" +#include "kernel/sigtools.h" +#include <algorithm> + +#include <stdio.h> +#include <stdlib.h> + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +SigMap assign_map; + +struct OpMuxConn { + RTLIL::SigSpec sig; + RTLIL::Cell *mux; + RTLIL::Cell *op; + int mux_port_id; + int mux_port_offset; + int op_outsig_offset; + + bool operator<(const OpMuxConn &other) const + { + if (mux != other.mux) + return mux < other.mux; + + if (mux_port_id != other.mux_port_id) + return mux_port_id < other.mux_port_id; + + return mux_port_offset < other.mux_port_offset; + } +}; + +// Helper class to track additiona information about a SigSpec, like whether it is signed and the semantics of the port it is connected to +struct ExtSigSpec { + RTLIL::SigSpec sig; + RTLIL::SigSpec sign; + bool is_signed; + RTLIL::IdString semantics; + + ExtSigSpec() {} + + ExtSigSpec(RTLIL::SigSpec s, RTLIL::SigSpec sign = RTLIL::Const(0, 1), bool is_signed = false, RTLIL::IdString semantics = RTLIL::IdString()) : sig(s), sign(sign), is_signed(is_signed), semantics(semantics) {} + + bool empty() const { return sig.empty(); } + + bool operator<(const ExtSigSpec &other) const + { + if (sig != other.sig) + return sig < other.sig; + + if (sign != other.sign) + return sign < other.sign; + + if (is_signed != other.is_signed) + return is_signed < other.is_signed; + + return semantics < other.semantics; + } + + bool operator==(const RTLIL::SigSpec &other) const { return (sign != RTLIL::Const(0, 1)) ? false : sig == other; } + bool operator==(const ExtSigSpec &other) const { return is_signed == other.is_signed && sign == other.sign && sig == other.sig && semantics == other.semantics; } +}; + +#define BITWISE_OPS ID($_AND_), ID($_NAND_), ID($_OR_), ID($_NOR_), ID($_XOR_), ID($_XNOR_), ID($_ANDNOT_), ID($_ORNOT_), ID($and), ID($or), ID($xor), ID($xnor) + +#define REDUCTION_OPS ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_xnor), ID($reduce_bool), ID($reduce_nand) + +#define LOGICAL_OPS ID($logic_and), ID($logic_or) + +#define SHIFT_OPS ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx) + +#define RELATIONAL_OPS ID($lt), ID($le), ID($eq), ID($ne), ID($eqx), ID($nex), ID($ge), ID($gt) + +bool cell_supported(RTLIL::Cell *cell) +{ + if (cell->type.in(ID($alu))) { + RTLIL::SigSpec sig_bi = cell->getPort(ID(BI)); + RTLIL::SigSpec sig_ci = cell->getPort(ID(CI)); + + if (sig_bi.is_fully_const() && sig_ci.is_fully_const() && sig_bi == sig_ci) + return true; + } else if (cell->type.in(LOGICAL_OPS, SHIFT_OPS, BITWISE_OPS, RELATIONAL_OPS, ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($concat))) { + return true; + } + + return false; +} + +std::map<IdString, IdString> mergeable_type_map; + +bool mergeable(RTLIL::Cell *a, RTLIL::Cell *b) +{ + if (mergeable_type_map.empty()) { + mergeable_type_map.insert({ID($sub), ID($add)}); + } + auto a_type = a->type; + if (mergeable_type_map.count(a_type)) + a_type = mergeable_type_map.at(a_type); + + auto b_type = b->type; + if (mergeable_type_map.count(b_type)) + b_type = mergeable_type_map.at(b_type); + + return a_type == b_type; +} + +RTLIL::IdString decode_port_semantics(RTLIL::Cell *cell, RTLIL::IdString port_name) +{ + if (cell->type.in(ID($lt), ID($le), ID($ge), ID($gt), ID($div), ID($mod), ID($concat), SHIFT_OPS) && port_name == ID::B) + return port_name; + + return ""; +} + +RTLIL::SigSpec decode_port_sign(RTLIL::Cell *cell, RTLIL::IdString port_name) { + + if (cell->type == ID($alu) && port_name == ID::B) + return cell->getPort(ID(BI)); + else if (cell->type == ID($sub) && port_name == ID::B) + return RTLIL::Const(1, 1); + + return RTLIL::Const(0, 1); +} + +bool decode_port_signed(RTLIL::Cell *cell, RTLIL::IdString port_name) +{ + if (cell->type.in(BITWISE_OPS, LOGICAL_OPS)) + return false; + + if (cell->hasParam(port_name.str() + "_SIGNED")) + return cell->getParam(port_name.str() + "_SIGNED").as_bool(); + + return false; +} + +ExtSigSpec decode_port(RTLIL::Cell *cell, RTLIL::IdString port_name, SigMap *sigmap) +{ + auto sig = (*sigmap)(cell->getPort(port_name)); + + RTLIL::SigSpec sign = decode_port_sign(cell, port_name); + RTLIL::IdString semantics = decode_port_semantics(cell, port_name); + + bool is_signed = decode_port_signed(cell, port_name); + + return ExtSigSpec(sig, sign, is_signed, semantics); +} + +void merge_operators(RTLIL::Module *module, RTLIL::Cell *mux, const std::vector<OpMuxConn> &ports, const ExtSigSpec &operand) +{ + std::vector<ExtSigSpec> muxed_operands; + int max_width = 0; + for (const auto& p : ports) { + auto op = p.op; + + RTLIL::IdString muxed_port_name = ID::A; + if (decode_port(op, ID::A, &assign_map) == operand) + muxed_port_name = ID::B; + + auto operand = decode_port(op, muxed_port_name, &assign_map); + if (operand.sig.size() > max_width) + max_width = operand.sig.size(); + + muxed_operands.push_back(operand); + } + + auto shared_op = ports[0].op; + + if (std::any_of(muxed_operands.begin(), muxed_operands.end(), [&](ExtSigSpec &op) { return op.sign != muxed_operands[0].sign; })) + max_width = std::max(max_width, shared_op->getParam(ID(Y_WIDTH)).as_int()); + + + for (auto &operand : muxed_operands) + operand.sig.extend_u0(max_width, operand.is_signed); + + for (const auto& p : ports) { + auto op = p.op; + if (op == shared_op) + continue; + module->remove(op); + } + + for (auto &muxed_op : muxed_operands) + if (muxed_op.sign != muxed_operands[0].sign) + muxed_op = ExtSigSpec(module->Neg(NEW_ID, muxed_op.sig, muxed_op.is_signed)); + + RTLIL::SigSpec mux_y = mux->getPort(ID::Y); + RTLIL::SigSpec mux_a = mux->getPort(ID::A); + RTLIL::SigSpec mux_b = mux->getPort(ID::B); + RTLIL::SigSpec mux_s = mux->getPort(ID(S)); + + RTLIL::SigSpec shared_pmux_a = RTLIL::Const(RTLIL::State::Sx, max_width); + RTLIL::SigSpec shared_pmux_b; + RTLIL::SigSpec shared_pmux_s; + + int conn_width = ports[0].sig.size(); + int conn_offset = ports[0].mux_port_offset; + + shared_op->setPort(ID::Y, shared_op->getPort(ID::Y).extract(0, conn_width)); + + if (mux->type == ID($pmux)) { + shared_pmux_s = RTLIL::SigSpec(); + + for (const auto &p : ports) { + shared_pmux_s.append(mux_s[p.mux_port_id]); + mux_b.replace(p.mux_port_id * mux_a.size() + conn_offset, shared_op->getPort(ID::Y)); + } + } else { + shared_pmux_s = RTLIL::SigSpec{mux_s, module->Not(NEW_ID, mux_s)}; + mux_a.replace(conn_offset, shared_op->getPort(ID::Y)); + mux_b.replace(conn_offset, shared_op->getPort(ID::Y)); + } + + mux->setPort(ID::A, mux_a); + mux->setPort(ID::B, mux_b); + mux->setPort(ID::Y, mux_y); + mux->setPort(ID(S), mux_s); + + for (const auto &op : muxed_operands) + shared_pmux_b.append(op.sig); + + auto mux_to_oper = module->Pmux(NEW_ID, shared_pmux_a, shared_pmux_b, shared_pmux_s); + + if (shared_op->type.in(ID($alu))) { + RTLIL::SigSpec alu_x = shared_op->getPort(ID(X)); + RTLIL::SigSpec alu_co = shared_op->getPort(ID(CO)); + + shared_op->setPort(ID(X), alu_x.extract(0, conn_width)); + shared_op->setPort(ID(CO), alu_co.extract(0, conn_width)); + } + + shared_op->setParam(ID(Y_WIDTH), conn_width); + + if (decode_port(shared_op, ID::A, &assign_map) == operand) { + shared_op->setPort(ID::B, mux_to_oper); + shared_op->setParam(ID(B_WIDTH), max_width); + } else { + shared_op->setPort(ID::A, mux_to_oper); + shared_op->setParam(ID(A_WIDTH), max_width); + } +} + +typedef struct { + RTLIL::Cell *mux; + std::vector<OpMuxConn> ports; + ExtSigSpec shared_operand; +} merged_op_t; + + +template <typename T> void remove_val(std::vector<T> &v, const std::vector<T> &vals) +{ + auto val_iter = vals.rbegin(); + for (auto i = v.rbegin(); i != v.rend(); ++i) + if ((val_iter != vals.rend()) && (*i == *val_iter)) { + v.erase(i.base() - 1); + ++val_iter; + } +} + +void check_muxed_operands(std::vector<const OpMuxConn *> &ports, const ExtSigSpec &shared_operand) +{ + auto it = ports.begin(); + ExtSigSpec seed; + + while (it != ports.end()) { + auto p = *it; + auto op = p->op; + + RTLIL::IdString muxed_port_name = ID::A; + if (decode_port(op, ID::A, &assign_map) == shared_operand) { + muxed_port_name = ID::B; + } + + auto operand = decode_port(op, muxed_port_name, &assign_map); + + if (seed.empty()) + seed = operand; + + if (operand.is_signed != seed.is_signed) { + ports.erase(it); + } else { + ++it; + } + } +} + +ExtSigSpec find_shared_operand(const OpMuxConn* seed, std::vector<const OpMuxConn *> &ports, const std::map<ExtSigSpec, std::set<RTLIL::Cell *>> &operand_to_users) +{ + std::set<RTLIL::Cell *> ops_using_operand; + std::set<RTLIL::Cell *> ops_set; + for(const auto& p: ports) + ops_set.insert(p->op); + + ExtSigSpec oper; + + auto op_a = seed->op; + + for (RTLIL::IdString port_name : {ID::A, ID::B}) { + oper = decode_port(op_a, port_name, &assign_map); + auto operand_users = operand_to_users.at(oper); + + if (operand_users.size() == 1) + continue; + + ops_using_operand.clear(); + for (auto mux_ops: ops_set) + if (operand_users.count(mux_ops)) + ops_using_operand.insert(mux_ops); + + if (ops_using_operand.size() > 1) { + ports.erase(std::remove_if(ports.begin(), ports.end(), [&](const OpMuxConn *p) { return !ops_using_operand.count(p->op); }), + ports.end()); + return oper; + } + } + + return ExtSigSpec(); +} + +dict<RTLIL::SigSpec, OpMuxConn> find_valid_op_mux_conns(RTLIL::Module *module, dict<RTLIL::SigBit, RTLIL::SigSpec> &op_outbit_to_outsig, + dict<RTLIL::SigSpec, RTLIL::Cell *> outsig_to_operator, + dict<RTLIL::SigBit, RTLIL::SigSpec> &op_aux_to_outsig) +{ + dict<RTLIL::SigSpec, int> op_outsig_user_track; + dict<RTLIL::SigSpec, OpMuxConn> op_mux_conn_map; + + std::function<void(RTLIL::SigSpec)> remove_outsig = [&](RTLIL::SigSpec outsig) { + for (auto op_outbit : outsig) + op_outbit_to_outsig.erase(op_outbit); + + if (op_mux_conn_map.count(outsig)) + op_mux_conn_map.erase(outsig); + }; + + std::function<void(RTLIL::SigBit)> remove_outsig_from_aux_bit = [&](RTLIL::SigBit auxbit) { + auto aux_outsig = op_aux_to_outsig.at(auxbit); + auto op = outsig_to_operator.at(aux_outsig); + auto op_outsig = assign_map(op->getPort(ID::Y)); + remove_outsig(op_outsig); + + for (auto aux_outbit : aux_outsig) + op_aux_to_outsig.erase(aux_outbit); + }; + + std::function<void(RTLIL::Cell *)> find_op_mux_conns = [&](RTLIL::Cell *mux) { + RTLIL::SigSpec sig; + int mux_port_size; + + if (mux->type.in(ID($mux), ID($_MUX_))) { + mux_port_size = mux->getPort(ID::A).size(); + sig = RTLIL::SigSpec{mux->getPort(ID::B), mux->getPort(ID::A)}; + } else { + mux_port_size = mux->getPort(ID::A).size(); + sig = mux->getPort(ID::B); + } + + auto mux_insig = assign_map(sig); + + for (int i = 0; i < mux_insig.size(); ++i) { + if (op_aux_to_outsig.count(mux_insig[i])) { + remove_outsig_from_aux_bit(mux_insig[i]); + continue; + } + + if (!op_outbit_to_outsig.count(mux_insig[i])) + continue; + + auto op_outsig = op_outbit_to_outsig.at(mux_insig[i]); + + if (op_mux_conn_map.count(op_outsig)) { + remove_outsig(op_outsig); + continue; + } + + int mux_port_id = i / mux_port_size; + int mux_port_offset = i % mux_port_size; + + int op_outsig_offset; + for (op_outsig_offset = 0; op_outsig[op_outsig_offset] != mux_insig[i]; ++op_outsig_offset) + ; + + int j = op_outsig_offset; + do { + if (!op_outbit_to_outsig.count(mux_insig[i])) + break; + + if (op_outbit_to_outsig.at(mux_insig[i]) != op_outsig) + break; + + ++i; + ++j; + } while ((i / mux_port_size == mux_port_id) && (j < op_outsig.size())); + + int op_conn_width = j - op_outsig_offset; + OpMuxConn inp = { + op_outsig.extract(op_outsig_offset, op_conn_width), + mux, + outsig_to_operator.at(op_outsig), + mux_port_id, + mux_port_offset, + op_outsig_offset, + }; + + op_mux_conn_map[op_outsig] = inp; + + --i; + } + }; + + std::function<void(RTLIL::SigSpec)> remove_connected_ops = [&](RTLIL::SigSpec sig) { + auto mux_insig = assign_map(sig); + for (auto outbit : mux_insig) { + if (op_aux_to_outsig.count(outbit)) { + remove_outsig_from_aux_bit(outbit); + continue; + } + + if (!op_outbit_to_outsig.count(outbit)) + continue; + + remove_outsig(op_outbit_to_outsig.at(outbit)); + } + }; + + for (auto cell : module->cells()) { + if (cell->type.in(ID($mux), ID($_MUX_), ID($pmux))) { + remove_connected_ops(cell->getPort(ID(S))); + find_op_mux_conns(cell); + } else { + for (auto &conn : cell->connections()) + if (cell->input(conn.first)) + remove_connected_ops(conn.second); + } + } + + for (auto w : module->wires()) { + if (!w->port_output) + continue; + + remove_connected_ops(w); + } + + return op_mux_conn_map; +} + +struct OptSharePass : public Pass { + OptSharePass() : Pass("opt_share", "merge mutually exclusive cells of the same type that share an input signal") {} + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" opt_share [selection]\n"); + log("\n"); + + log("This pass identifies mutually exclusive cells of the same type that:\n"); + log(" (a) share an input signal,\n"); + log(" (b) drive the same $mux, $_MUX_, or $pmux multiplexing cell,\n"); + log("\n"); + log("allowing the cell to be merged and the multiplexer to be moved from\n"); + log("multiplexing its output to multiplexing the non-shared input signals.\n"); + log("\n"); + } + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + + log_header(design, "Executing OPT_SHARE pass.\n"); + + extra_args(args, 1, design); + for (auto module : design->selected_modules()) { + assign_map.clear(); + assign_map.set(module); + + std::map<ExtSigSpec, std::set<RTLIL::Cell *>> operand_to_users; + dict<RTLIL::SigSpec, RTLIL::Cell *> outsig_to_operator; + dict<RTLIL::SigBit, RTLIL::SigSpec> op_outbit_to_outsig; + dict<RTLIL::SigBit, RTLIL::SigSpec> op_aux_to_outsig; + bool any_shared_operands = false; + std::vector<ExtSigSpec> op_insigs; + + for (auto cell : module->cells()) { + if (!cell_supported(cell)) + continue; + + if (cell->type == ID($alu)) { + for (RTLIL::IdString port_name : {ID(X), ID(CO)}) { + auto mux_insig = assign_map(cell->getPort(port_name)); + outsig_to_operator[mux_insig] = cell; + for (auto outbit : mux_insig) + op_aux_to_outsig[outbit] = mux_insig; + } + } + + auto mux_insig = assign_map(cell->getPort(ID::Y)); + outsig_to_operator[mux_insig] = cell; + for (auto outbit : mux_insig) + op_outbit_to_outsig[outbit] = mux_insig; + + for (RTLIL::IdString port_name : {ID::A, ID::B}) { + auto op_insig = decode_port(cell, port_name, &assign_map); + op_insigs.push_back(op_insig); + operand_to_users[op_insig].insert(cell); + if (operand_to_users[op_insig].size() > 1) + any_shared_operands = true; + } + } + + if (!any_shared_operands) + continue; + + // Operator outputs need to be exclusively connected to the $mux inputs in order to be mergeable. Hence we count to + // how many points are operator output bits connected. + dict<RTLIL::SigSpec, OpMuxConn> op_mux_conn_map = + find_valid_op_mux_conns(module, op_outbit_to_outsig, outsig_to_operator, op_aux_to_outsig); + + // Group op connections connected to same ports of the same $mux. Sort them in ascending order of their port offset + dict<RTLIL::Cell*, std::vector<std::set<OpMuxConn>>> mux_port_op_conns; + for (auto& val: op_mux_conn_map) { + OpMuxConn p = val.second; + auto& mux_port_conns = mux_port_op_conns[p.mux]; + + if (mux_port_conns.size() == 0) { + int mux_port_num; + + if (p.mux->type.in(ID($mux), ID($_MUX_))) + mux_port_num = 2; + else + mux_port_num = p.mux->getPort(ID(S)).size(); + + mux_port_conns.resize(mux_port_num); + } + + mux_port_conns[p.mux_port_id].insert(p); + } + + std::vector<merged_op_t> merged_ops; + for (auto& val: mux_port_op_conns) { + + RTLIL::Cell* cell = val.first; + auto &mux_port_conns = val.second; + + const OpMuxConn *seed = NULL; + + // Look through the bits of the $mux inputs and see which of them are connected to the operator + // results. Operator results can be concatenated with other signals before led to the $mux. + while (true) { + + // Remove either the merged ports from the last iteration or the seed that failed to yield a merger + if (seed != NULL) { + mux_port_conns[seed->mux_port_id].erase(*seed); + seed = NULL; + } + + // For a new merger, find the seed op connection that starts at lowest port offset among port connections + for (auto &port_conns : mux_port_conns) { + if (!port_conns.size()) + continue; + + const OpMuxConn *next_p = &(*port_conns.begin()); + + if ((seed == NULL) || (seed->mux_port_offset > next_p->mux_port_offset)) + seed = next_p; + } + + // Cannot find the seed -> nothing to do for this $mux anymore + if (seed == NULL) + break; + + // Find all other op connections that start from the same port offset, and whose ops can be merged with the seed op + std::vector<const OpMuxConn *> mergeable_conns; + for (auto &port_conns : mux_port_conns) { + if (!port_conns.size()) + continue; + + const OpMuxConn *next_p = &(*port_conns.begin()); + + if ((next_p->op_outsig_offset == seed->op_outsig_offset) && + (next_p->mux_port_offset == seed->mux_port_offset) && mergeable(next_p->op, seed->op) && + next_p->sig.size() == seed->sig.size()) + mergeable_conns.push_back(next_p); + } + + // We need at least two mergeable connections for the merger + if (mergeable_conns.size() < 2) + continue; + + // Filter mergeable connections whose ops share an operand with seed connection's op + auto shared_operand = find_shared_operand(seed, mergeable_conns, operand_to_users); + + if (shared_operand.empty()) + continue; + + check_muxed_operands(mergeable_conns, shared_operand); + + if (mergeable_conns.size() < 2) + continue; + + // Remember the combination for the merger + std::vector<OpMuxConn> merged_ports; + for (auto p : mergeable_conns) { + merged_ports.push_back(*p); + mux_port_conns[p->mux_port_id].erase(*p); + } + + seed = NULL; + + merged_ops.push_back(merged_op_t{cell, merged_ports, shared_operand}); + + design->scratchpad_set_bool("opt.did_something", true); + } + + } + + for (auto &shared : merged_ops) { + log(" Found cells that share an operand and can be merged by moving the %s %s in front " + "of " + "them:\n", + log_id(shared.mux->type), log_id(shared.mux)); + for (const auto& op : shared.ports) + log(" %s\n", log_id(op.op)); + log("\n"); + + merge_operators(module, shared.mux, shared.ports, shared.shared_operand); + } + } + } + +} OptSharePass; + +PRIVATE_NAMESPACE_END diff --git a/passes/opt/pmux2shiftx.cc b/passes/opt/pmux2shiftx.cc new file mode 100644 index 000000000..92b5794ac --- /dev/null +++ b/passes/opt/pmux2shiftx.cc @@ -0,0 +1,860 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * + * 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 OnehotDatabase +{ + Module *module; + const SigMap &sigmap; + bool verbose = false; + bool initialized = false; + + pool<SigBit> init_ones; + dict<SigSpec, pool<SigSpec>> sig_sources_db; + dict<SigSpec, bool> sig_onehot_cache; + pool<SigSpec> recursion_guard; + + OnehotDatabase(Module *module, const SigMap &sigmap) : module(module), sigmap(sigmap) + { + } + + void initialize() + { + log_assert(!initialized); + initialized = true; + + for (auto wire : module->wires()) + { + auto it = wire->attributes.find(ID(init)); + if (it == wire->attributes.end()) + continue; + + auto &val = it->second; + int width = std::max(GetSize(wire), GetSize(val)); + + for (int i = 0; i < width; i++) + if (val[i] == State::S1) + init_ones.insert(sigmap(SigBit(wire, i))); + } + + for (auto cell : module->cells()) + { + vector<SigSpec> inputs; + SigSpec output; + + if (cell->type.in(ID($adff), ID($dff), ID($dffe), ID($dlatch), ID($ff))) + { + output = cell->getPort(ID(Q)); + if (cell->type == ID($adff)) + inputs.push_back(cell->getParam(ID(ARST_VALUE))); + inputs.push_back(cell->getPort(ID(D))); + } + + if (cell->type.in(ID($mux), ID($pmux))) + { + output = cell->getPort(ID::Y); + inputs.push_back(cell->getPort(ID::A)); + SigSpec B = cell->getPort(ID::B); + for (int i = 0; i < GetSize(B); i += GetSize(output)) + inputs.push_back(B.extract(i, GetSize(output))); + } + + if (!output.empty()) + { + output = sigmap(output); + auto &srcs = sig_sources_db[output]; + for (auto src : inputs) { + while (!src.empty() && src[GetSize(src)-1] == State::S0) + src.remove(GetSize(src)-1); + srcs.insert(sigmap(src)); + } + } + } + } + + void query_worker(const SigSpec &sig, bool &retval, bool &cache, int indent) + { + if (verbose) + log("%*s %s\n", indent, "", log_signal(sig)); + log_assert(retval); + + if (recursion_guard.count(sig)) { + if (verbose) + log("%*s - recursion\n", indent, ""); + cache = false; + return; + } + + auto it = sig_onehot_cache.find(sig); + if (it != sig_onehot_cache.end()) { + if (verbose) + log("%*s - cached (%s)\n", indent, "", it->second ? "true" : "false"); + if (!it->second) + retval = false; + return; + } + + bool found_init_ones = false; + for (auto bit : sig) { + if (init_ones.count(bit)) { + if (found_init_ones) { + if (verbose) + log("%*s - non-onehot init value\n", indent, ""); + retval = false; + break; + } + found_init_ones = true; + } + } + + if (retval) + { + if (sig.is_fully_const()) + { + bool found_ones = false; + for (auto bit : sig) { + if (bit == State::S1) { + if (found_ones) { + if (verbose) + log("%*s - non-onehot constant\n", indent, ""); + retval = false; + break; + } + found_ones = true; + } + } + } + else + { + auto srcs = sig_sources_db.find(sig); + if (srcs == sig_sources_db.end()) { + if (verbose) + log("%*s - no sources for non-const signal\n", indent, ""); + retval = false; + } else { + for (auto &src : srcs->second) { + bool child_cache = true; + recursion_guard.insert(sig); + query_worker(src, retval, child_cache, indent+4); + recursion_guard.erase(sig); + if (!child_cache) + cache = false; + if (!retval) + break; + } + } + } + } + + // it is always safe to cache a negative result + if (cache || !retval) + sig_onehot_cache[sig] = retval; + } + + bool query(const SigSpec &sig) + { + bool retval = true; + bool cache = true; + + if (verbose) + log("** ONEHOT QUERY START (%s)\n", log_signal(sig)); + + if (!initialized) + initialize(); + + query_worker(sig, retval, cache, 3); + + if (verbose) + log("** ONEHOT QUERY RESULT = %s\n", retval ? "true" : "false"); + + // it is always safe to cache the root result of a query + if (!cache) + sig_onehot_cache[sig] = retval; + + return retval; + } +}; + +struct Pmux2ShiftxPass : public Pass { + Pmux2ShiftxPass() : Pass("pmux2shiftx", "transform $pmux cells to $shiftx cells") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" pmux2shiftx [options] [selection]\n"); + log("\n"); + log("This pass transforms $pmux cells to $shiftx cells.\n"); + log("\n"); + log(" -v, -vv\n"); + log(" verbose output\n"); + log("\n"); + log(" -min_density <percentage>\n"); + log(" specifies the minimum density for the shifter\n"); + log(" default: 50\n"); + log("\n"); + log(" -min_choices <int>\n"); + log(" specified the minimum number of choices for a control signal\n"); + log(" default: 3\n"); + log("\n"); + log(" -onehot ignore|pmux|shiftx\n"); + 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<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + int min_density = 50; + int min_choices = 3; + bool allow_onehot = false; + bool optimize_onehot = true; + bool verbose = false; + bool verbose_onehot = false; + bool norange = false; + + log_header(design, "Executing PMUX2SHIFTX pass.\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + if (args[argidx] == "-min_density" && argidx+1 < args.size()) { + min_density = atoi(args[++argidx].c_str()); + continue; + } + if (args[argidx] == "-min_choices" && argidx+1 < args.size()) { + min_choices = atoi(args[++argidx].c_str()); + continue; + } + if (args[argidx] == "-onehot" && argidx+1 < args.size() && args[argidx+1] == "ignore") { + argidx++; + allow_onehot = false; + optimize_onehot = false; + continue; + } + if (args[argidx] == "-onehot" && argidx+1 < args.size() && args[argidx+1] == "pmux") { + argidx++; + allow_onehot = false; + optimize_onehot = true; + continue; + } + if (args[argidx] == "-onehot" && argidx+1 < args.size() && args[argidx+1] == "shiftx") { + argidx++; + allow_onehot = true; + optimize_onehot = false; + continue; + } + if (args[argidx] == "-v") { + verbose = true; + continue; + } + if (args[argidx] == "-vv") { + verbose = true; + verbose_onehot = true; + continue; + } + if (args[argidx] == "-norange") { + norange = true; + continue; + } + break; + } + extra_args(args, argidx, design); + + for (auto module : design->selected_modules()) + { + SigMap sigmap(module); + OnehotDatabase onehot_db(module, sigmap); + onehot_db.verbose = verbose_onehot; + + dict<SigBit, pair<SigSpec, Const>> eqdb; + + for (auto cell : module->cells()) + { + if (cell->type == ID($eq)) + { + dict<SigBit, State> bits; + + SigSpec A = sigmap(cell->getPort(ID::A)); + SigSpec B = sigmap(cell->getPort(ID::B)); + + int a_width = cell->getParam(ID(A_WIDTH)).as_int(); + int b_width = cell->getParam(ID(B_WIDTH)).as_int(); + + if (a_width < b_width) { + bool a_signed = cell->getParam(ID(A_SIGNED)).as_int(); + A.extend_u0(b_width, a_signed); + } + + if (b_width < a_width) { + bool b_signed = cell->getParam(ID(B_SIGNED)).as_int(); + B.extend_u0(a_width, b_signed); + } + + for (int i = 0; i < GetSize(A); i++) { + SigBit a_bit = A[i], b_bit = B[i]; + if (b_bit.wire && !a_bit.wire) { + std::swap(a_bit, b_bit); + } + if (!a_bit.wire || b_bit.wire) + goto next_cell; + if (bits.count(a_bit)) + goto next_cell; + bits[a_bit] = b_bit.data; + } + + if (GetSize(bits) > 20) + goto next_cell; + + bits.sort(); + pair<SigSpec, Const> entry; + + for (auto it : bits) { + entry.first.append_bit(it.first); + entry.second.bits.push_back(it.second); + } + + eqdb[sigmap(cell->getPort(ID::Y)[0])] = entry; + goto next_cell; + } + + if (cell->type == ID($logic_not)) + { + dict<SigBit, State> bits; + + SigSpec A = sigmap(cell->getPort(ID::A)); + + for (int i = 0; i < GetSize(A); i++) + bits[A[i]] = State::S0; + + bits.sort(); + pair<SigSpec, Const> entry; + + for (auto it : bits) { + entry.first.append_bit(it.first); + entry.second.bits.push_back(it.second); + } + + eqdb[sigmap(cell->getPort(ID::Y)[0])] = entry; + goto next_cell; + } + next_cell:; + } + + for (auto cell : module->selected_cells()) + { + if (cell->type != ID($pmux)) + continue; + + string src = cell->get_src_attribute(); + int width = cell->getParam(ID(WIDTH)).as_int(); + int width_bits = ceil_log2(width); + int extwidth = width; + + while (extwidth & (extwidth-1)) + extwidth++; + + dict<SigSpec, pool<int>> seldb; + + SigSpec A = cell->getPort(ID::A); + SigSpec B = cell->getPort(ID::B); + SigSpec S = sigmap(cell->getPort(ID(S))); + for (int i = 0; i < GetSize(S); i++) + { + if (!eqdb.count(S[i])) + continue; + + auto &entry = eqdb.at(S[i]); + seldb[entry.first].insert(i); + } + + if (seldb.empty()) + continue; + + bool printed_pmux_header = false; + + if (verbose) { + printed_pmux_header = true; + log("Inspecting $pmux cell %s/%s.\n", log_id(module), log_id(cell)); + log(" data width: %d (next power-of-2 = %d, log2 = %d)\n", width, extwidth, width_bits); + } + + SigSpec updated_S = cell->getPort(ID(S)); + SigSpec updated_B = cell->getPort(ID::B); + + while (!seldb.empty()) + { + // pick the largest entry in seldb + SigSpec sig = seldb.begin()->first; + for (auto &it : seldb) { + if (GetSize(sig) < GetSize(it.first)) + sig = it.first; + else if (GetSize(seldb.at(sig)) < GetSize(it.second)) + sig = it.first; + } + + // find the relevant choices + bool is_onehot = GetSize(sig) > 2; + dict<Const, int> choices; + for (int i : seldb.at(sig)) { + Const val = eqdb.at(S[i]).second; + int onebits = 0; + for (auto b : val.bits) + if (b == State::S1) + onebits++; + if (onebits > 1) + is_onehot = false; + choices[val] = i; + } + + bool full_pmux = GetSize(choices) == GetSize(S); + + // TBD: also find choices that are using signals that are subsets of the bits in "sig" + + if (!verbose) + { + if (is_onehot && !allow_onehot && !optimize_onehot) { + seldb.erase(sig); + continue; + } + + if (GetSize(choices) < min_choices) { + seldb.erase(sig); + continue; + } + } + + if (!printed_pmux_header) { + printed_pmux_header = true; + log("Inspecting $pmux cell %s/%s.\n", log_id(module), log_id(cell)); + log(" data width: %d (next power-of-2 = %d, log2 = %d)\n", width, extwidth, width_bits); + } + + log(" checking ctrl signal %s\n", log_signal(sig)); + + auto print_choices = [&]() { + log(" table of choices:\n"); + for (auto &it : choices) + log(" %3d: %s: %s\n", it.second, log_signal(it.first), + log_signal(B.extract(it.second*width, width))); + }; + + if (verbose) + { + if (is_onehot && !allow_onehot && !optimize_onehot) { + print_choices(); + log(" ignoring one-hot encoding.\n"); + seldb.erase(sig); + continue; + } + + if (GetSize(choices) < min_choices) { + print_choices(); + log(" insufficient choices.\n"); + seldb.erase(sig); + continue; + } + } + + if (is_onehot && optimize_onehot) + { + print_choices(); + if (!onehot_db.query(sig)) + { + log(" failed to detect onehot driver. do not optimize.\n"); + } + else + { + log(" optimizing one-hot encoding.\n"); + for (auto &it : choices) + { + const Const &val = it.first; + int index = -1; + + for (int i = 0; i < GetSize(val); i++) + if (val[i] == State::S1) { + log_assert(index < 0); + index = i; + } + + if (index < 0) { + log(" %3d: zero encoding.\n", it.second); + continue; + } + + SigBit new_ctrl = sig[index]; + log(" %3d: new crtl signal is %s.\n", it.second, log_signal(new_ctrl)); + updated_S[it.second] = new_ctrl; + } + } + seldb.erase(sig); + continue; + } + + // find the best permutation + vector<int> perm_new_from_old(GetSize(sig)); + Const perm_xormask(State::S0, GetSize(sig)); + { + vector<int> values(GetSize(choices)); + vector<bool> used_src_columns(GetSize(sig)); + vector<vector<bool>> columns(GetSize(sig), vector<bool>(GetSize(values))); + + for (int i = 0; i < GetSize(choices); i++) { + Const val = choices.element(i)->first; + for (int k = 0; k < GetSize(val); k++) + if (val[k] == State::S1) + columns[k][i] = true; + } + + for (int dst_col = GetSize(sig)-1; dst_col >= 0; dst_col--) + { + int best_src_col = -1; + bool best_inv = false; + int best_maxval = 0; + int best_delta = 0; + + // find best src column for this dst column + for (int src_col = 0; src_col < GetSize(sig); src_col++) + { + if (used_src_columns[src_col]) + continue; + + int this_maxval = 0; + int this_minval = 1 << 30; + + int this_inv_maxval = 0; + int this_inv_minval = 1 << 30; + + for (int i = 0; i < GetSize(values); i++) + { + int val = values[i]; + int inv_val = val; + + if (columns[src_col][i]) + val |= 1 << dst_col; + else + inv_val |= 1 << dst_col; + + this_maxval = std::max(this_maxval, val); + this_minval = std::min(this_minval, val); + + this_inv_maxval = std::max(this_inv_maxval, inv_val); + this_inv_minval = std::min(this_inv_minval, inv_val); + } + + int this_delta = this_maxval - this_minval; + int this_inv_delta = this_maxval - this_minval; + bool this_inv = false; + + 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; + + if (this_inv) { + this_delta = this_inv_delta; + this_maxval = this_inv_maxval; + this_minval = this_inv_minval; + } + + bool this_is_better = false; + + if (best_src_col < 0) + this_is_better = true; + 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; + else + this_is_better = sig[best_src_col] < sig[src_col]; + + if (this_is_better) { + best_src_col = src_col; + best_inv = this_inv; + best_maxval = this_maxval; + best_delta = this_delta; + } + } + + used_src_columns[best_src_col] = true; + perm_new_from_old[dst_col] = best_src_col; + perm_xormask[dst_col] = best_inv ? State::S1 : State::S0; + } + } + + // permutated sig + SigSpec perm_sig(State::S0, GetSize(sig)); + for (int i = 0; i < GetSize(sig); i++) + perm_sig[i] = sig[perm_new_from_old[i]]; + + log(" best permutation: %s\n", log_signal(perm_sig)); + log(" best xor mask: %s\n", log_signal(perm_xormask)); + + // permutated choices + int min_choice = 1 << 30; + int max_choice = -1; + dict<Const, int> perm_choices; + + for (auto &it : choices) + { + Const &old_c = it.first; + Const new_c(State::S0, GetSize(old_c)); + + for (int i = 0; i < GetSize(old_c); i++) + new_c[i] = old_c[perm_new_from_old[i]]; + + Const new_c_before_xor = new_c; + new_c = const_xor(new_c, perm_xormask, false, false, GetSize(new_c)); + + perm_choices[new_c] = it.second; + + min_choice = std::min(min_choice, new_c.as_int()); + max_choice = std::max(max_choice, new_c.as_int()); + + log(" %3d: %s -> %s -> %s: %s\n", it.second, log_signal(old_c), log_signal(new_c_before_xor), + log_signal(new_c), log_signal(B.extract(it.second*width, width))); + } + + int range_density = 100*GetSize(choices) / (max_choice-min_choice+1); + int absolute_density = 100*GetSize(choices) / (max_choice+1); + + log(" choices: %d\n", GetSize(choices)); + log(" min choice: %d\n", min_choice); + log(" max choice: %d\n", max_choice); + log(" range density: %d%%\n", range_density); + log(" absolute density: %d%%\n", absolute_density); + + if (full_pmux) { + int full_density = 100*GetSize(choices) / (1 << GetSize(sig)); + log(" full density: %d%%\n", full_density); + if (full_density < min_density) { + full_pmux = false; + } else { + min_choice = 0; + max_choice = (1 << GetSize(sig))-1; + log(" update to full case.\n"); + log(" new min choice: %d\n", min_choice); + log(" new max choice: %d\n", max_choice); + } + } + + bool full_case = (min_choice == 0) && (max_choice == (1 << GetSize(sig))-1) && (full_pmux || max_choice+1 == GetSize(choices)); + log(" full case: %s\n", full_case ? "true" : "false"); + + // check density percentages + Const offset(State::S0, GetSize(sig)); + if (!norange && absolute_density < min_density && range_density >= min_density) + { + offset = Const(min_choice, GetSize(sig)); + log(" offset: %s\n", log_signal(offset)); + + min_choice -= offset.as_int(); + max_choice -= offset.as_int(); + + dict<Const, int> new_perm_choices; + for (auto &it : perm_choices) + new_perm_choices[const_sub(it.first, offset, false, false, GetSize(sig))] = it.second; + perm_choices.swap(new_perm_choices); + } else + if (absolute_density < min_density) { + log(" insufficient density.\n"); + seldb.erase(sig); + continue; + } + + // creat cmp signal + SigSpec cmp = perm_sig; + if (perm_xormask.as_bool()) + cmp = module->Xor(NEW_ID, cmp, perm_xormask, false, src); + if (offset.as_bool()) + cmp = module->Sub(NEW_ID, cmp, offset, false, src); + + // create enable signal + SigBit en = State::S1; + if (!full_case) { + Const enable_mask(State::S0, max_choice+1); + for (auto &it : perm_choices) + enable_mask[it.first.as_int()] = State::S1; + en = module->addWire(NEW_ID); + module->addShift(NEW_ID, enable_mask, cmp, en, false, src); + } + + // create data signal + SigSpec data(State::Sx, (max_choice+1)*extwidth); + if (full_pmux) { + for (int i = 0; i <= max_choice; i++) + data.replace(i*extwidth, A); + } + for (auto &it : perm_choices) { + int position = it.first.as_int()*extwidth; + int data_index = it.second; + data.replace(position, B.extract(data_index*width, width)); + updated_S[data_index] = State::S0; + updated_B.replace(data_index*width, SigSpec(State::Sx, width)); + } + + // create shiftx cell + SigSpec shifted_cmp = {cmp, SigSpec(State::S0, width_bits)}; + SigSpec outsig = module->addWire(NEW_ID, width); + Cell *c = module->addShiftx(NEW_ID, data, shifted_cmp, outsig, false, src); + updated_S.append(en); + updated_B.append(outsig); + log(" created $shiftx cell %s.\n", log_id(c)); + + // remove this sig and continue with the next block + seldb.erase(sig); + } + + // update $pmux cell + cell->setPort(ID(S), updated_S); + cell->setPort(ID::B, updated_B); + cell->setParam(ID(S_WIDTH), GetSize(updated_S)); + } + } + } +} Pmux2ShiftxPass; + +struct OnehotPass : public Pass { + OnehotPass() : Pass("onehot", "optimize $eq cells for onehot signals") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" onehot [options] [selection]\n"); + log("\n"); + log("This pass optimizes $eq cells that compare one-hot signals against constants\n"); + log("\n"); + log(" -v, -vv\n"); + log(" verbose output\n"); + log("\n"); + } + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + bool verbose = false; + bool verbose_onehot = false; + + log_header(design, "Executing ONEHOT pass.\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + if (args[argidx] == "-v") { + verbose = true; + continue; + } + if (args[argidx] == "-vv") { + verbose = true; + verbose_onehot = true; + continue; + } + break; + } + extra_args(args, argidx, design); + + for (auto module : design->selected_modules()) + { + SigMap sigmap(module); + OnehotDatabase onehot_db(module, sigmap); + onehot_db.verbose = verbose_onehot; + + for (auto cell : module->selected_cells()) + { + if (cell->type != ID($eq)) + continue; + + SigSpec A = sigmap(cell->getPort(ID::A)); + SigSpec B = sigmap(cell->getPort(ID::B)); + + int a_width = cell->getParam(ID(A_WIDTH)).as_int(); + int b_width = cell->getParam(ID(B_WIDTH)).as_int(); + + if (a_width < b_width) { + bool a_signed = cell->getParam(ID(A_SIGNED)).as_int(); + A.extend_u0(b_width, a_signed); + } + + if (b_width < a_width) { + bool b_signed = cell->getParam(ID(B_SIGNED)).as_int(); + B.extend_u0(a_width, b_signed); + } + + if (A.is_fully_const()) + std::swap(A, B); + + if (!B.is_fully_const()) + continue; + + if (verbose) + log("Checking $eq(%s, %s) cell %s/%s.\n", log_signal(A), log_signal(B), log_id(module), log_id(cell)); + + if (!onehot_db.query(A)) { + if (verbose) + log(" onehot driver test on %s failed.\n", log_signal(A)); + continue; + } + + int index = -1; + bool not_onehot = false; + + for (int i = 0; i < GetSize(B); i++) { + if (B[i] != State::S1) + continue; + if (index >= 0) + not_onehot = true; + index = i; + } + + if (index < 0) { + if (verbose) + log(" not optimizing the zero pattern.\n"); + continue; + } + + SigSpec Y = cell->getPort(ID::Y); + + if (not_onehot) + { + if (verbose) + log(" replacing with constant 0 driver.\n"); + else + log("Replacing one-hot $eq(%s, %s) cell %s/%s with constant 0 driver.\n", log_signal(A), log_signal(B), log_id(module), log_id(cell)); + module->connect(Y, SigSpec(1, GetSize(Y))); + } + else + { + SigSpec sig = A[index]; + if (verbose) + log(" replacing with signal %s.\n", log_signal(sig)); + else + log("Replacing one-hot $eq(%s, %s) cell %s/%s with signal %s.\n",log_signal(A), log_signal(B), log_id(module), log_id(cell), log_signal(sig)); + sig.extend_u0(GetSize(Y)); + module->connect(Y, sig); + } + + module->remove(cell); + } + } + } +} OnehotPass; + +PRIVATE_NAMESPACE_END diff --git a/passes/opt/rmports.cc b/passes/opt/rmports.cc index 756be7473..32363dd68 100644 --- a/passes/opt/rmports.cc +++ b/passes/opt/rmports.cc @@ -28,7 +28,7 @@ PRIVATE_NAMESPACE_BEGIN struct RmportsPassPass : public Pass { RmportsPassPass() : Pass("rmports", "remove module ports with no connections") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -39,7 +39,7 @@ struct RmportsPassPass : public Pass { log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing RMPORTS pass (remove ports with no connections).\n"); @@ -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; i<module->ports.size(); i++) diff --git a/passes/opt/share.cc b/passes/opt/share.cc index 22914eaa7..92ce3fd11 100644 --- a/passes/opt/share.cc +++ b/passes/opt/share.cc @@ -89,8 +89,8 @@ struct ShareWorker queue_bits.clear(); for (auto &pbit : portbits) { - if (pbit.cell->type == "$mux" || pbit.cell->type == "$pmux") { - pool<RTLIL::SigBit> bits = modwalker.sigmap(pbit.cell->getPort("\\S")).to_sigbit_pool(); + if (pbit.cell->type == ID($mux) || pbit.cell->type == ID($pmux)) { + pool<RTLIL::SigBit> bits = modwalker.sigmap(pbit.cell->getPort(ID(S))).to_sigbit_pool(); terminal_bits.insert(bits.begin(), bits.end()); queue_bits.insert(bits.begin(), bits.end()); visited_cells.insert(pbit.cell); @@ -128,7 +128,7 @@ struct ShareWorker static int bits_macc(RTLIL::Cell *c) { Macc m(c); - int width = GetSize(c->getPort("\\Y")); + int width = GetSize(c->getPort(ID::Y)); return bits_macc(m, width); } @@ -242,7 +242,7 @@ struct ShareWorker { Macc m1(c1), m2(c2), supermacc; - int w1 = GetSize(c1->getPort("\\Y")), w2 = GetSize(c2->getPort("\\Y")); + int w1 = GetSize(c1->getPort(ID::Y)), w2 = GetSize(c2->getPort(ID::Y)); int width = max(w1, w2); m1.optimize(w1); @@ -328,11 +328,11 @@ struct ShareWorker { RTLIL::SigSpec sig_y = module->addWire(NEW_ID, width); - supercell_aux->insert(module->addPos(NEW_ID, sig_y, c1->getPort("\\Y"))); - supercell_aux->insert(module->addPos(NEW_ID, sig_y, c2->getPort("\\Y"))); + supercell_aux->insert(module->addPos(NEW_ID, sig_y, c1->getPort(ID::Y))); + supercell_aux->insert(module->addPos(NEW_ID, sig_y, c2->getPort(ID::Y))); - supercell->setParam("\\Y_WIDTH", width); - supercell->setPort("\\Y", sig_y); + supercell->setParam(ID(Y_WIDTH), width); + supercell->setPort(ID::Y, sig_y); supermacc.optimize(width); supermacc.to_cell(supercell); @@ -368,22 +368,22 @@ struct ShareWorker continue; } - if (cell->type == "$memrd") { - if (cell->parameters.at("\\CLK_ENABLE").as_bool()) + if (cell->type == ID($memrd)) { + if (cell->parameters.at(ID(CLK_ENABLE)).as_bool()) continue; - if (config.opt_aggressive || !modwalker.sigmap(cell->getPort("\\ADDR")).is_fully_const()) + if (config.opt_aggressive || !modwalker.sigmap(cell->getPort(ID(ADDR))).is_fully_const()) shareable_cells.insert(cell); continue; } - if (cell->type == "$mul" || cell->type == "$div" || cell->type == "$mod") { - if (config.opt_aggressive || cell->parameters.at("\\Y_WIDTH").as_int() >= 4) + if (cell->type.in(ID($mul), ID($div), ID($mod))) { + if (config.opt_aggressive || cell->parameters.at(ID(Y_WIDTH)).as_int() >= 4) shareable_cells.insert(cell); continue; } - if (cell->type == "$shl" || cell->type == "$shr" || cell->type == "$sshl" || cell->type == "$sshr") { - if (config.opt_aggressive || cell->parameters.at("\\Y_WIDTH").as_int() >= 8) + if (cell->type.in(ID($shl), ID($shr), ID($sshl), ID($sshr))) { + if (config.opt_aggressive || cell->parameters.at(ID(Y_WIDTH)).as_int() >= 8) shareable_cells.insert(cell); continue; } @@ -401,9 +401,9 @@ struct ShareWorker if (c1->type != c2->type) return false; - if (c1->type == "$memrd") + if (c1->type == ID($memrd)) { - if (c1->parameters.at("\\MEMID").decode_string() != c2->parameters.at("\\MEMID").decode_string()) + if (c1->parameters.at(ID(MEMID)).decode_string() != c2->parameters.at(ID(MEMID)).decode_string()) return false; return true; @@ -413,11 +413,11 @@ struct ShareWorker { if (!config.opt_aggressive) { - int a1_width = c1->parameters.at("\\A_WIDTH").as_int(); - int y1_width = c1->parameters.at("\\Y_WIDTH").as_int(); + int a1_width = c1->parameters.at(ID(A_WIDTH)).as_int(); + int y1_width = c1->parameters.at(ID(Y_WIDTH)).as_int(); - int a2_width = c2->parameters.at("\\A_WIDTH").as_int(); - int y2_width = c2->parameters.at("\\Y_WIDTH").as_int(); + int a2_width = c2->parameters.at(ID(A_WIDTH)).as_int(); + int y2_width = c2->parameters.at(ID(Y_WIDTH)).as_int(); if (max(a1_width, a2_width) > 2 * min(a1_width, a2_width)) return false; if (max(y1_width, y2_width) > 2 * min(y1_width, y2_width)) return false; @@ -426,17 +426,17 @@ struct ShareWorker return true; } - if (config.generic_bin_ops.count(c1->type) || c1->type == "$alu") + if (config.generic_bin_ops.count(c1->type) || c1->type == ID($alu)) { if (!config.opt_aggressive) { - int a1_width = c1->parameters.at("\\A_WIDTH").as_int(); - int b1_width = c1->parameters.at("\\B_WIDTH").as_int(); - int y1_width = c1->parameters.at("\\Y_WIDTH").as_int(); + int a1_width = c1->parameters.at(ID(A_WIDTH)).as_int(); + int b1_width = c1->parameters.at(ID(B_WIDTH)).as_int(); + int y1_width = c1->parameters.at(ID(Y_WIDTH)).as_int(); - int a2_width = c2->parameters.at("\\A_WIDTH").as_int(); - int b2_width = c2->parameters.at("\\B_WIDTH").as_int(); - int y2_width = c2->parameters.at("\\Y_WIDTH").as_int(); + int a2_width = c2->parameters.at(ID(A_WIDTH)).as_int(); + int b2_width = c2->parameters.at(ID(B_WIDTH)).as_int(); + int y2_width = c2->parameters.at(ID(Y_WIDTH)).as_int(); if (max(a1_width, a2_width) > 2 * min(a1_width, a2_width)) return false; if (max(b1_width, b2_width) > 2 * min(b1_width, b2_width)) return false; @@ -450,13 +450,13 @@ struct ShareWorker { if (!config.opt_aggressive) { - int a1_width = c1->parameters.at("\\A_WIDTH").as_int(); - int b1_width = c1->parameters.at("\\B_WIDTH").as_int(); - int y1_width = c1->parameters.at("\\Y_WIDTH").as_int(); + int a1_width = c1->parameters.at(ID(A_WIDTH)).as_int(); + int b1_width = c1->parameters.at(ID(B_WIDTH)).as_int(); + int y1_width = c1->parameters.at(ID(Y_WIDTH)).as_int(); - int a2_width = c2->parameters.at("\\A_WIDTH").as_int(); - int b2_width = c2->parameters.at("\\B_WIDTH").as_int(); - int y2_width = c2->parameters.at("\\Y_WIDTH").as_int(); + int a2_width = c2->parameters.at(ID(A_WIDTH)).as_int(); + int b2_width = c2->parameters.at(ID(B_WIDTH)).as_int(); + int y2_width = c2->parameters.at(ID(Y_WIDTH)).as_int(); int min1_width = min(a1_width, b1_width); int max1_width = max(a1_width, b1_width); @@ -472,7 +472,7 @@ struct ShareWorker return true; } - if (c1->type == "$macc") + if (c1->type == ID($macc)) { if (!config.opt_aggressive) if (share_macc(c1, c2) > 2 * min(bits_macc(c1), bits_macc(c2))) return false; @@ -510,27 +510,27 @@ struct ShareWorker if (config.generic_uni_ops.count(c1->type)) { - if (c1->parameters.at("\\A_SIGNED").as_bool() != c2->parameters.at("\\A_SIGNED").as_bool()) + if (c1->parameters.at(ID(A_SIGNED)).as_bool() != c2->parameters.at(ID(A_SIGNED)).as_bool()) { - RTLIL::Cell *unsigned_cell = c1->parameters.at("\\A_SIGNED").as_bool() ? c2 : c1; - if (unsigned_cell->getPort("\\A").to_sigbit_vector().back() != RTLIL::State::S0) { - unsigned_cell->parameters.at("\\A_WIDTH") = unsigned_cell->parameters.at("\\A_WIDTH").as_int() + 1; - RTLIL::SigSpec new_a = unsigned_cell->getPort("\\A"); + RTLIL::Cell *unsigned_cell = c1->parameters.at(ID(A_SIGNED)).as_bool() ? c2 : c1; + if (unsigned_cell->getPort(ID::A).to_sigbit_vector().back() != RTLIL::State::S0) { + unsigned_cell->parameters.at(ID(A_WIDTH)) = unsigned_cell->parameters.at(ID(A_WIDTH)).as_int() + 1; + RTLIL::SigSpec new_a = unsigned_cell->getPort(ID::A); new_a.append_bit(RTLIL::State::S0); - unsigned_cell->setPort("\\A", new_a); + unsigned_cell->setPort(ID::A, new_a); } - unsigned_cell->parameters.at("\\A_SIGNED") = true; + unsigned_cell->parameters.at(ID(A_SIGNED)) = true; unsigned_cell->check(); } - bool a_signed = c1->parameters.at("\\A_SIGNED").as_bool(); - log_assert(a_signed == c2->parameters.at("\\A_SIGNED").as_bool()); + bool a_signed = c1->parameters.at(ID(A_SIGNED)).as_bool(); + log_assert(a_signed == c2->parameters.at(ID(A_SIGNED)).as_bool()); - RTLIL::SigSpec a1 = c1->getPort("\\A"); - RTLIL::SigSpec y1 = c1->getPort("\\Y"); + RTLIL::SigSpec a1 = c1->getPort(ID::A); + RTLIL::SigSpec y1 = c1->getPort(ID::Y); - RTLIL::SigSpec a2 = c2->getPort("\\A"); - RTLIL::SigSpec y2 = c2->getPort("\\Y"); + RTLIL::SigSpec a2 = c2->getPort(ID::A); + RTLIL::SigSpec y2 = c2->getPort(ID::Y); int a_width = max(a1.size(), a2.size()); int y_width = max(y1.size(), y2.size()); @@ -544,11 +544,11 @@ struct ShareWorker RTLIL::Wire *y = module->addWire(NEW_ID, y_width); RTLIL::Cell *supercell = module->addCell(NEW_ID, c1->type); - supercell->parameters["\\A_SIGNED"] = a_signed; - supercell->parameters["\\A_WIDTH"] = a_width; - supercell->parameters["\\Y_WIDTH"] = y_width; - supercell->setPort("\\A", a); - supercell->setPort("\\Y", y); + supercell->parameters[ID(A_SIGNED)] = a_signed; + supercell->parameters[ID(A_WIDTH)] = a_width; + supercell->parameters[ID(Y_WIDTH)] = y_width; + supercell->setPort(ID::A, a); + supercell->setPort(ID::Y, y); supercell_aux.insert(module->addPos(NEW_ID, y, y1)); supercell_aux.insert(module->addPos(NEW_ID, y, y2)); @@ -557,54 +557,54 @@ struct ShareWorker return supercell; } - if (config.generic_bin_ops.count(c1->type) || config.generic_cbin_ops.count(c1->type) || c1->type == "$alu") + if (config.generic_bin_ops.count(c1->type) || config.generic_cbin_ops.count(c1->type) || c1->type == ID($alu)) { bool modified_src_cells = false; if (config.generic_cbin_ops.count(c1->type)) { - int score_unflipped = max(c1->parameters.at("\\A_WIDTH").as_int(), c2->parameters.at("\\A_WIDTH").as_int()) + - max(c1->parameters.at("\\B_WIDTH").as_int(), c2->parameters.at("\\B_WIDTH").as_int()); + int score_unflipped = max(c1->parameters.at(ID(A_WIDTH)).as_int(), c2->parameters.at(ID(A_WIDTH)).as_int()) + + max(c1->parameters.at(ID(B_WIDTH)).as_int(), c2->parameters.at(ID(B_WIDTH)).as_int()); - int score_flipped = max(c1->parameters.at("\\A_WIDTH").as_int(), c2->parameters.at("\\B_WIDTH").as_int()) + - max(c1->parameters.at("\\B_WIDTH").as_int(), c2->parameters.at("\\A_WIDTH").as_int()); + int score_flipped = max(c1->parameters.at(ID(A_WIDTH)).as_int(), c2->parameters.at(ID(B_WIDTH)).as_int()) + + max(c1->parameters.at(ID(B_WIDTH)).as_int(), c2->parameters.at(ID(A_WIDTH)).as_int()); if (score_flipped < score_unflipped) { - RTLIL::SigSpec tmp = c2->getPort("\\A"); - c2->setPort("\\A", c2->getPort("\\B")); - c2->setPort("\\B", tmp); + RTLIL::SigSpec tmp = c2->getPort(ID::A); + c2->setPort(ID::A, c2->getPort(ID::B)); + c2->setPort(ID::B, tmp); - std::swap(c2->parameters.at("\\A_WIDTH"), c2->parameters.at("\\B_WIDTH")); - std::swap(c2->parameters.at("\\A_SIGNED"), c2->parameters.at("\\B_SIGNED")); + std::swap(c2->parameters.at(ID(A_WIDTH)), c2->parameters.at(ID(B_WIDTH))); + std::swap(c2->parameters.at(ID(A_SIGNED)), c2->parameters.at(ID(B_SIGNED))); modified_src_cells = true; } } - if (c1->parameters.at("\\A_SIGNED").as_bool() != c2->parameters.at("\\A_SIGNED").as_bool()) + if (c1->parameters.at(ID(A_SIGNED)).as_bool() != c2->parameters.at(ID(A_SIGNED)).as_bool()) { - RTLIL::Cell *unsigned_cell = c1->parameters.at("\\A_SIGNED").as_bool() ? c2 : c1; - if (unsigned_cell->getPort("\\A").to_sigbit_vector().back() != RTLIL::State::S0) { - unsigned_cell->parameters.at("\\A_WIDTH") = unsigned_cell->parameters.at("\\A_WIDTH").as_int() + 1; - RTLIL::SigSpec new_a = unsigned_cell->getPort("\\A"); + RTLIL::Cell *unsigned_cell = c1->parameters.at(ID(A_SIGNED)).as_bool() ? c2 : c1; + if (unsigned_cell->getPort(ID::A).to_sigbit_vector().back() != RTLIL::State::S0) { + unsigned_cell->parameters.at(ID(A_WIDTH)) = unsigned_cell->parameters.at(ID(A_WIDTH)).as_int() + 1; + RTLIL::SigSpec new_a = unsigned_cell->getPort(ID::A); new_a.append_bit(RTLIL::State::S0); - unsigned_cell->setPort("\\A", new_a); + unsigned_cell->setPort(ID::A, new_a); } - unsigned_cell->parameters.at("\\A_SIGNED") = true; + unsigned_cell->parameters.at(ID(A_SIGNED)) = true; modified_src_cells = true; } - if (c1->parameters.at("\\B_SIGNED").as_bool() != c2->parameters.at("\\B_SIGNED").as_bool()) + if (c1->parameters.at(ID(B_SIGNED)).as_bool() != c2->parameters.at(ID(B_SIGNED)).as_bool()) { - RTLIL::Cell *unsigned_cell = c1->parameters.at("\\B_SIGNED").as_bool() ? c2 : c1; - if (unsigned_cell->getPort("\\B").to_sigbit_vector().back() != RTLIL::State::S0) { - unsigned_cell->parameters.at("\\B_WIDTH") = unsigned_cell->parameters.at("\\B_WIDTH").as_int() + 1; - RTLIL::SigSpec new_b = unsigned_cell->getPort("\\B"); + RTLIL::Cell *unsigned_cell = c1->parameters.at(ID(B_SIGNED)).as_bool() ? c2 : c1; + if (unsigned_cell->getPort(ID::B).to_sigbit_vector().back() != RTLIL::State::S0) { + unsigned_cell->parameters.at(ID(B_WIDTH)) = unsigned_cell->parameters.at(ID(B_WIDTH)).as_int() + 1; + RTLIL::SigSpec new_b = unsigned_cell->getPort(ID::B); new_b.append_bit(RTLIL::State::S0); - unsigned_cell->setPort("\\B", new_b); + unsigned_cell->setPort(ID::B, new_b); } - unsigned_cell->parameters.at("\\B_SIGNED") = true; + unsigned_cell->parameters.at(ID(B_SIGNED)) = true; modified_src_cells = true; } @@ -613,28 +613,28 @@ struct ShareWorker c2->check(); } - bool a_signed = c1->parameters.at("\\A_SIGNED").as_bool(); - bool b_signed = c1->parameters.at("\\B_SIGNED").as_bool(); + bool a_signed = c1->parameters.at(ID(A_SIGNED)).as_bool(); + bool b_signed = c1->parameters.at(ID(B_SIGNED)).as_bool(); - log_assert(a_signed == c2->parameters.at("\\A_SIGNED").as_bool()); - log_assert(b_signed == c2->parameters.at("\\B_SIGNED").as_bool()); + log_assert(a_signed == c2->parameters.at(ID(A_SIGNED)).as_bool()); + log_assert(b_signed == c2->parameters.at(ID(B_SIGNED)).as_bool()); - if (c1->type == "$shl" || c1->type == "$shr" || c1->type == "$sshl" || c1->type == "$sshr") + if (c1->type == ID($shl) || c1->type == ID($shr) || c1->type == ID($sshl) || c1->type == ID($sshr)) b_signed = false; - RTLIL::SigSpec a1 = c1->getPort("\\A"); - RTLIL::SigSpec b1 = c1->getPort("\\B"); - RTLIL::SigSpec y1 = c1->getPort("\\Y"); + RTLIL::SigSpec a1 = c1->getPort(ID::A); + RTLIL::SigSpec b1 = c1->getPort(ID::B); + RTLIL::SigSpec y1 = c1->getPort(ID::Y); - RTLIL::SigSpec a2 = c2->getPort("\\A"); - RTLIL::SigSpec b2 = c2->getPort("\\B"); - RTLIL::SigSpec y2 = c2->getPort("\\Y"); + RTLIL::SigSpec a2 = c2->getPort(ID::A); + RTLIL::SigSpec b2 = c2->getPort(ID::B); + RTLIL::SigSpec y2 = c2->getPort(ID::Y); int a_width = max(a1.size(), a2.size()); int b_width = max(b1.size(), b2.size()); int y_width = max(y1.size(), y2.size()); - if (c1->type == "$shr" && a_signed) + if (c1->type == ID($shr) && a_signed) { a_width = max(y_width, a_width); @@ -660,43 +660,43 @@ struct ShareWorker supercell_aux.insert(module->addMux(NEW_ID, b2, b1, act, b)); RTLIL::Wire *y = module->addWire(NEW_ID, y_width); - RTLIL::Wire *x = c1->type == "$alu" ? module->addWire(NEW_ID, y_width) : nullptr; - RTLIL::Wire *co = c1->type == "$alu" ? module->addWire(NEW_ID, y_width) : nullptr; + RTLIL::Wire *x = c1->type == ID($alu) ? module->addWire(NEW_ID, y_width) : nullptr; + RTLIL::Wire *co = c1->type == ID($alu) ? module->addWire(NEW_ID, y_width) : nullptr; RTLIL::Cell *supercell = module->addCell(NEW_ID, c1->type); - supercell->parameters["\\A_SIGNED"] = a_signed; - supercell->parameters["\\B_SIGNED"] = b_signed; - supercell->parameters["\\A_WIDTH"] = a_width; - supercell->parameters["\\B_WIDTH"] = b_width; - supercell->parameters["\\Y_WIDTH"] = y_width; - supercell->setPort("\\A", a); - supercell->setPort("\\B", b); - supercell->setPort("\\Y", y); - if (c1->type == "$alu") { + supercell->parameters[ID(A_SIGNED)] = a_signed; + supercell->parameters[ID(B_SIGNED)] = b_signed; + supercell->parameters[ID(A_WIDTH)] = a_width; + supercell->parameters[ID(B_WIDTH)] = b_width; + supercell->parameters[ID(Y_WIDTH)] = y_width; + supercell->setPort(ID::A, a); + supercell->setPort(ID::B, b); + supercell->setPort(ID::Y, y); + if (c1->type == ID($alu)) { RTLIL::Wire *ci = module->addWire(NEW_ID), *bi = module->addWire(NEW_ID); - supercell_aux.insert(module->addMux(NEW_ID, c2->getPort("\\CI"), c1->getPort("\\CI"), act, ci)); - supercell_aux.insert(module->addMux(NEW_ID, c2->getPort("\\BI"), c1->getPort("\\BI"), act, bi)); - supercell->setPort("\\CI", ci); - supercell->setPort("\\BI", bi); - supercell->setPort("\\CO", co); - supercell->setPort("\\X", x); + supercell_aux.insert(module->addMux(NEW_ID, c2->getPort(ID(CI)), c1->getPort(ID(CI)), act, ci)); + supercell_aux.insert(module->addMux(NEW_ID, c2->getPort(ID(BI)), c1->getPort(ID(BI)), act, bi)); + supercell->setPort(ID(CI), ci); + supercell->setPort(ID(BI), bi); + supercell->setPort(ID(CO), co); + supercell->setPort(ID(X), x); } supercell->check(); supercell_aux.insert(module->addPos(NEW_ID, y, y1)); supercell_aux.insert(module->addPos(NEW_ID, y, y2)); - if (c1->type == "$alu") { - supercell_aux.insert(module->addPos(NEW_ID, co, c1->getPort("\\CO"))); - supercell_aux.insert(module->addPos(NEW_ID, co, c2->getPort("\\CO"))); - supercell_aux.insert(module->addPos(NEW_ID, x, c1->getPort("\\X"))); - supercell_aux.insert(module->addPos(NEW_ID, x, c2->getPort("\\X"))); + if (c1->type == ID($alu)) { + supercell_aux.insert(module->addPos(NEW_ID, co, c1->getPort(ID(CO)))); + supercell_aux.insert(module->addPos(NEW_ID, co, c2->getPort(ID(CO)))); + supercell_aux.insert(module->addPos(NEW_ID, x, c1->getPort(ID(X)))); + supercell_aux.insert(module->addPos(NEW_ID, x, c2->getPort(ID(X)))); } supercell_aux.insert(supercell); return supercell; } - if (c1->type == "$macc") + if (c1->type == ID($macc)) { RTLIL::Cell *supercell = module->addCell(NEW_ID, c1->type); supercell_aux.insert(supercell); @@ -705,14 +705,18 @@ struct ShareWorker return supercell; } - if (c1->type == "$memrd") + if (c1->type == ID($memrd)) { RTLIL::Cell *supercell = module->addCell(NEW_ID, c1); - RTLIL::SigSpec addr1 = c1->getPort("\\ADDR"); - RTLIL::SigSpec addr2 = c2->getPort("\\ADDR"); - if (addr1 != addr2) - supercell->setPort("\\ADDR", module->Mux(NEW_ID, addr2, addr1, act)); - supercell_aux.insert(module->addPos(NEW_ID, supercell->getPort("\\DATA"), c2->getPort("\\DATA"))); + RTLIL::SigSpec addr1 = c1->getPort(ID(ADDR)); + RTLIL::SigSpec addr2 = c2->getPort(ID(ADDR)); + if (GetSize(addr1) < GetSize(addr2)) + addr1.extend_u0(GetSize(addr2)); + else + addr2.extend_u0(GetSize(addr1)); + supercell->setPort(ID(ADDR), addr1 != addr2 ? module->Mux(NEW_ID, addr2, addr1, act) : addr1); + supercell->parameters[ID(ABITS)] = RTLIL::Const(GetSize(addr1)); + supercell_aux.insert(module->addPos(NEW_ID, supercell->getPort(ID(DATA)), c2->getPort(ID(DATA)))); supercell_aux.insert(supercell); return supercell; } @@ -743,8 +747,8 @@ struct ShareWorker modwalker.get_consumers(pbits, modwalker.cell_outputs[cell]); for (auto &bit : pbits) { - if ((bit.cell->type == "$mux" || bit.cell->type == "$pmux") && bit.port == "\\S") - forbidden_controls_cache[cell].insert(bit.cell->getPort("\\S").extract(bit.offset, 1)); + if ((bit.cell->type == ID($mux) || bit.cell->type == ID($pmux)) && bit.port == ID(S)) + forbidden_controls_cache[cell].insert(bit.cell->getPort(ID(S)).extract(bit.offset, 1)); consumer_cells.insert(bit.cell); } @@ -870,7 +874,7 @@ struct ShareWorker } for (auto &pbit : modwalker.signal_consumers[bit]) { log_assert(fwd_ct.cell_known(pbit.cell->type)); - if ((pbit.cell->type == "$mux" || pbit.cell->type == "$pmux") && (pbit.port == "\\A" || pbit.port == "\\B")) + if ((pbit.cell->type == ID($mux) || pbit.cell->type == ID($pmux)) && (pbit.port == ID::A || pbit.port == ID::B)) driven_data_muxes.insert(pbit.cell); else driven_cells.insert(pbit.cell); @@ -886,10 +890,10 @@ struct ShareWorker bool used_in_a = false; std::set<int> used_in_b_parts; - int width = c->parameters.at("\\WIDTH").as_int(); - std::vector<RTLIL::SigBit> sig_a = modwalker.sigmap(c->getPort("\\A")); - std::vector<RTLIL::SigBit> sig_b = modwalker.sigmap(c->getPort("\\B")); - std::vector<RTLIL::SigBit> sig_s = modwalker.sigmap(c->getPort("\\S")); + int width = c->parameters.at(ID(WIDTH)).as_int(); + std::vector<RTLIL::SigBit> sig_a = modwalker.sigmap(c->getPort(ID::A)); + std::vector<RTLIL::SigBit> sig_b = modwalker.sigmap(c->getPort(ID::B)); + std::vector<RTLIL::SigBit> sig_s = modwalker.sigmap(c->getPort(ID(S))); for (auto &bit : sig_a) if (cell_out_bits.count(bit)) @@ -1128,14 +1132,14 @@ struct ShareWorker fwd_ct.setup_internals(); cone_ct.setup_internals(); - cone_ct.cell_types.erase("$mul"); - cone_ct.cell_types.erase("$mod"); - cone_ct.cell_types.erase("$div"); - cone_ct.cell_types.erase("$pow"); - cone_ct.cell_types.erase("$shl"); - cone_ct.cell_types.erase("$shr"); - cone_ct.cell_types.erase("$sshl"); - cone_ct.cell_types.erase("$sshr"); + cone_ct.cell_types.erase(ID($mul)); + cone_ct.cell_types.erase(ID($mod)); + cone_ct.cell_types.erase(ID($div)); + cone_ct.cell_types.erase(ID($pow)); + cone_ct.cell_types.erase(ID($shl)); + cone_ct.cell_types.erase(ID($shr)); + cone_ct.cell_types.erase(ID($sshl)); + cone_ct.cell_types.erase(ID($sshr)); modwalker.setup(design, module); @@ -1149,9 +1153,9 @@ struct ShareWorker GetSize(shareable_cells), log_id(module)); for (auto cell : module->cells()) - if (cell->type == "$pmux") - for (auto bit : cell->getPort("\\S")) - for (auto other_bit : cell->getPort("\\S")) + if (cell->type == ID($pmux)) + for (auto bit : cell->getPort(ID(S))) + for (auto other_bit : cell->getPort(ID(S))) if (bit < other_bit) exclusive_ctrls.push_back(std::pair<RTLIL::SigBit, RTLIL::SigBit>(bit, other_bit)); @@ -1421,7 +1425,7 @@ struct ShareWorker struct SharePass : public Pass { SharePass() : Pass("share", "perform sat-based resource sharing") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -1453,7 +1457,7 @@ struct SharePass : public Pass { log(" Only perform the first N merges, then stop. This is useful for debugging.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { ShareWorkerConfig config; @@ -1462,43 +1466,43 @@ struct SharePass : public Pass { config.opt_aggressive = false; config.opt_fast = false; - config.generic_uni_ops.insert("$not"); - // config.generic_uni_ops.insert("$pos"); - config.generic_uni_ops.insert("$neg"); - - config.generic_cbin_ops.insert("$and"); - config.generic_cbin_ops.insert("$or"); - config.generic_cbin_ops.insert("$xor"); - config.generic_cbin_ops.insert("$xnor"); - - config.generic_bin_ops.insert("$shl"); - config.generic_bin_ops.insert("$shr"); - config.generic_bin_ops.insert("$sshl"); - config.generic_bin_ops.insert("$sshr"); - - config.generic_bin_ops.insert("$lt"); - config.generic_bin_ops.insert("$le"); - config.generic_bin_ops.insert("$eq"); - config.generic_bin_ops.insert("$ne"); - config.generic_bin_ops.insert("$eqx"); - config.generic_bin_ops.insert("$nex"); - config.generic_bin_ops.insert("$ge"); - config.generic_bin_ops.insert("$gt"); - - config.generic_cbin_ops.insert("$add"); - config.generic_cbin_ops.insert("$mul"); - - config.generic_bin_ops.insert("$sub"); - config.generic_bin_ops.insert("$div"); - config.generic_bin_ops.insert("$mod"); - // config.generic_bin_ops.insert("$pow"); - - config.generic_uni_ops.insert("$logic_not"); - config.generic_cbin_ops.insert("$logic_and"); - config.generic_cbin_ops.insert("$logic_or"); - - config.generic_other_ops.insert("$alu"); - config.generic_other_ops.insert("$macc"); + config.generic_uni_ops.insert(ID($not)); + // config.generic_uni_ops.insert(ID($pos)); + config.generic_uni_ops.insert(ID($neg)); + + config.generic_cbin_ops.insert(ID($and)); + config.generic_cbin_ops.insert(ID($or)); + config.generic_cbin_ops.insert(ID($xor)); + config.generic_cbin_ops.insert(ID($xnor)); + + config.generic_bin_ops.insert(ID($shl)); + config.generic_bin_ops.insert(ID($shr)); + config.generic_bin_ops.insert(ID($sshl)); + config.generic_bin_ops.insert(ID($sshr)); + + config.generic_bin_ops.insert(ID($lt)); + config.generic_bin_ops.insert(ID($le)); + config.generic_bin_ops.insert(ID($eq)); + config.generic_bin_ops.insert(ID($ne)); + config.generic_bin_ops.insert(ID($eqx)); + config.generic_bin_ops.insert(ID($nex)); + config.generic_bin_ops.insert(ID($ge)); + config.generic_bin_ops.insert(ID($gt)); + + config.generic_cbin_ops.insert(ID($add)); + config.generic_cbin_ops.insert(ID($mul)); + + config.generic_bin_ops.insert(ID($sub)); + config.generic_bin_ops.insert(ID($div)); + config.generic_bin_ops.insert(ID($mod)); + // config.generic_bin_ops.insert(ID($pow)); + + config.generic_uni_ops.insert(ID($logic_not)); + config.generic_cbin_ops.insert(ID($logic_and)); + config.generic_cbin_ops.insert(ID($logic_or)); + + config.generic_other_ops.insert(ID($alu)); + config.generic_other_ops.insert(ID($macc)); log_header(design, "Executing SHARE pass (SAT-based resource sharing).\n"); diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc index 07503fbb3..c02c355cb 100644 --- a/passes/opt/wreduce.cc +++ b/passes/opt/wreduce.cc @@ -22,23 +22,24 @@ #include "kernel/modtools.h" USING_YOSYS_NAMESPACE -using namespace RTLIL; PRIVATE_NAMESPACE_BEGIN struct WreduceConfig { pool<IdString> supported_cell_types; + bool keepdc = false; WreduceConfig() { supported_cell_types = pool<IdString>({ - "$not", "$pos", "$neg", - "$and", "$or", "$xor", "$xnor", - "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", - "$lt", "$le", "$eq", "$ne", "$eqx", "$nex", "$ge", "$gt", - "$add", "$sub", "$mul", // "$div", "$mod", "$pow", - "$mux", "$pmux" + ID($not), ID($pos), ID($neg), + ID($and), ID($or), ID($xor), ID($xnor), + ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx), + ID($lt), ID($le), ID($eq), ID($ne), ID($eqx), ID($nex), ID($ge), ID($gt), + ID($add), ID($sub), ID($mul), // ID($div), ID($mod), ID($pow), + ID($mux), ID($pmux), + ID($dff), ID($adff) }); } }; @@ -52,6 +53,8 @@ struct WreduceWorker std::set<Cell*, IdString::compare_ptr_by_name<Cell>> work_queue_cells; std::set<SigBit> work_queue_bits; pool<SigBit> keep_bits; + dict<SigBit, State> init_bits; + pool<SigBit> remove_init_bits; WreduceWorker(WreduceConfig *config, Module *module) : config(config), module(module), mi(module) { } @@ -60,10 +63,10 @@ struct WreduceWorker { // Reduce size of MUX if inputs agree on a value for a bit or a output bit is unused - SigSpec sig_a = mi.sigmap(cell->getPort("\\A")); - SigSpec sig_b = mi.sigmap(cell->getPort("\\B")); - SigSpec sig_s = mi.sigmap(cell->getPort("\\S")); - SigSpec sig_y = mi.sigmap(cell->getPort("\\Y")); + SigSpec sig_a = mi.sigmap(cell->getPort(ID::A)); + SigSpec sig_b = mi.sigmap(cell->getPort(ID::B)); + SigSpec sig_s = mi.sigmap(cell->getPort(ID(S))); + SigSpec sig_y = mi.sigmap(cell->getPort(ID::Y)); std::vector<SigBit> bits_removed; if (sig_y.has_const()) @@ -73,15 +76,15 @@ struct WreduceWorker { auto info = mi.query(sig_y[i]); if (!info->is_output && GetSize(info->ports) <= 1 && !keep_bits.count(mi.sigmap(sig_y[i]))) { - bits_removed.push_back(Sx); + bits_removed.push_back(State::Sx); continue; } SigBit ref = sig_a[i]; for (int k = 0; k < GetSize(sig_s); k++) { - if (ref != Sx && sig_b[k*GetSize(sig_a) + i] != Sx && ref != sig_b[k*GetSize(sig_a) + i]) + if ((config->keepdc || (ref != State::Sx && sig_b[k*GetSize(sig_a) + i] != State::Sx)) && ref != sig_b[k*GetSize(sig_a) + i]) goto no_match_ab; - if (sig_b[k*GetSize(sig_a) + i] != Sx) + if (sig_b[k*GetSize(sig_a) + i] != State::Sx) ref = sig_b[k*GetSize(sig_a) + i]; } if (0) @@ -126,20 +129,107 @@ struct WreduceWorker for (auto bit : new_work_queue_bits) work_queue_bits.insert(bit); - cell->setPort("\\A", new_sig_a); - cell->setPort("\\B", new_sig_b); - cell->setPort("\\Y", new_sig_y); + cell->setPort(ID::A, new_sig_a); + cell->setPort(ID::B, new_sig_b); + cell->setPort(ID::Y, new_sig_y); cell->fixup_parameters(); module->connect(sig_y.extract(n_kept, n_removed), sig_removed); } + void run_cell_dff(Cell *cell) + { + // Reduce size of FF if inputs are just sign/zero extended or output bit is not used + + SigSpec sig_d = mi.sigmap(cell->getPort(ID(D))); + SigSpec sig_q = mi.sigmap(cell->getPort(ID(Q))); + Const initval; + + int width_before = GetSize(sig_q); + + if (width_before == 0) + return; + + bool zero_ext = sig_d[GetSize(sig_d)-1] == State::S0; + bool sign_ext = !zero_ext; + + for (int i = 0; i < GetSize(sig_q); i++) { + SigBit bit = sig_q[i]; + if (init_bits.count(bit)) + initval.bits.push_back(init_bits.at(bit)); + else + initval.bits.push_back(State::Sx); + } + + for (int i = GetSize(sig_q)-1; i >= 0; i--) + { + if (zero_ext && sig_d[i] == State::S0 && (initval[i] == State::S0 || initval[i] == State::Sx)) { + module->connect(sig_q[i], State::S0); + remove_init_bits.insert(sig_q[i]); + sig_d.remove(i); + sig_q.remove(i); + continue; + } + + if (sign_ext && i > 0 && sig_d[i] == sig_d[i-1] && initval[i] == initval[i-1]) { + module->connect(sig_q[i], sig_q[i-1]); + remove_init_bits.insert(sig_q[i]); + sig_d.remove(i); + sig_q.remove(i); + continue; + } + + auto info = mi.query(sig_q[i]); + if (info == nullptr) + return; + if (!info->is_output && GetSize(info->ports) == 1 && !keep_bits.count(mi.sigmap(sig_q[i]))) { + remove_init_bits.insert(sig_q[i]); + sig_d.remove(i); + sig_q.remove(i); + zero_ext = false; + sign_ext = false; + continue; + } + + break; + } + + if (width_before == GetSize(sig_q)) + return; + + if (GetSize(sig_q) == 0) { + log("Removed cell %s.%s (%s).\n", log_id(module), log_id(cell), log_id(cell->type)); + module->remove(cell); + return; + } + + log("Removed top %d bits (of %d) from FF cell %s.%s (%s).\n", width_before - GetSize(sig_q), width_before, + log_id(module), log_id(cell), log_id(cell->type)); + + for (auto bit : sig_d) + work_queue_bits.insert(bit); + + for (auto bit : sig_q) + work_queue_bits.insert(bit); + + // Narrow ARST_VALUE parameter to new size. + if (cell->parameters.count(ID(ARST_VALUE))) { + Const arst_value = cell->getParam(ID(ARST_VALUE)); + arst_value.bits.resize(GetSize(sig_q)); + cell->setParam(ID(ARST_VALUE), arst_value); + } + + cell->setPort(ID(D), sig_d); + cell->setPort(ID(Q), sig_q); + cell->fixup_parameters(); + } + void run_reduce_inport(Cell *cell, char port, int max_port_size, bool &port_signed, bool &did_something) { port_signed = cell->getParam(stringf("\\%c_SIGNED", port)).as_bool(); SigSpec sig = mi.sigmap(cell->getPort(stringf("\\%c", port))); - if (port == 'B' && cell->type.in("$shl", "$shr", "$sshl", "$sshr")) + if (port == 'B' && cell->type.in(ID($shl), ID($shr), ID($sshl), ID($sshr))) port_signed = false; int bits_removed = 0; @@ -154,7 +244,7 @@ struct WreduceWorker while (GetSize(sig) > 1 && sig[GetSize(sig)-1] == sig[GetSize(sig)-2]) work_queue_bits.insert(sig[GetSize(sig)-1]), sig.remove(GetSize(sig)-1), bits_removed++; } else { - while (GetSize(sig) > 1 && sig[GetSize(sig)-1] == S0) + while (GetSize(sig) > 1 && sig[GetSize(sig)-1] == State::S0) work_queue_bits.insert(sig[GetSize(sig)-1]), sig.remove(GetSize(sig)-1), bits_removed++; } @@ -173,10 +263,13 @@ struct WreduceWorker if (!cell->type.in(config->supported_cell_types)) return; - if (cell->type.in("$mux", "$pmux")) + if (cell->type.in(ID($mux), ID($pmux))) return run_cell_mux(cell); - SigSpec sig = mi.sigmap(cell->getPort("\\Y")); + if (cell->type.in(ID($dff), ID($adff))) + return run_cell_dff(cell); + + SigSpec sig = mi.sigmap(cell->getPort(ID::Y)); if (sig.has_const()) return; @@ -184,10 +277,10 @@ struct WreduceWorker // Reduce size of ports A and B based on constant input bits and size of output port - int max_port_a_size = cell->hasPort("\\A") ? GetSize(cell->getPort("\\A")) : -1; - int max_port_b_size = cell->hasPort("\\B") ? GetSize(cell->getPort("\\B")) : -1; + int max_port_a_size = cell->hasPort(ID::A) ? GetSize(cell->getPort(ID::A)) : -1; + int max_port_b_size = cell->hasPort(ID::B) ? GetSize(cell->getPort(ID::B)) : -1; - if (cell->type.in("$not", "$pos", "$neg", "$and", "$or", "$xor", "$add", "$sub")) { + if (cell->type.in(ID($not), ID($pos), ID($neg), ID($and), ID($or), ID($xor), ID($add), ID($sub))) { max_port_a_size = min(max_port_a_size, GetSize(sig)); max_port_b_size = min(max_port_b_size, GetSize(sig)); } @@ -195,32 +288,32 @@ struct WreduceWorker bool port_a_signed = false; bool port_b_signed = false; - if (max_port_a_size >= 0 && cell->type != "$shiftx") + if (max_port_a_size >= 0 && cell->type != ID($shiftx)) run_reduce_inport(cell, 'A', max_port_a_size, port_a_signed, did_something); if (max_port_b_size >= 0) run_reduce_inport(cell, 'B', max_port_b_size, port_b_signed, did_something); - if (cell->hasPort("\\A") && cell->hasPort("\\B") && port_a_signed && port_b_signed) { - SigSpec sig_a = mi.sigmap(cell->getPort("\\A")), sig_b = mi.sigmap(cell->getPort("\\B")); + if (cell->hasPort(ID::A) && cell->hasPort(ID::B) && port_a_signed && port_b_signed) { + SigSpec sig_a = mi.sigmap(cell->getPort(ID::A)), sig_b = mi.sigmap(cell->getPort(ID::B)); if (GetSize(sig_a) > 0 && sig_a[GetSize(sig_a)-1] == State::S0 && GetSize(sig_b) > 0 && sig_b[GetSize(sig_b)-1] == State::S0) { log("Converting cell %s.%s (%s) from signed to unsigned.\n", log_id(module), log_id(cell), log_id(cell->type)); - cell->setParam("\\A_SIGNED", 0); - cell->setParam("\\B_SIGNED", 0); + cell->setParam(ID(A_SIGNED), 0); + cell->setParam(ID(B_SIGNED), 0); port_a_signed = false; port_b_signed = false; did_something = true; } } - if (cell->hasPort("\\A") && !cell->hasPort("\\B") && port_a_signed) { - SigSpec sig_a = mi.sigmap(cell->getPort("\\A")); + if (cell->hasPort(ID::A) && !cell->hasPort(ID::B) && port_a_signed) { + SigSpec sig_a = mi.sigmap(cell->getPort(ID::A)); if (GetSize(sig_a) > 0 && sig_a[GetSize(sig_a)-1] == State::S0) { log("Converting cell %s.%s (%s) from signed to unsigned.\n", log_id(module), log_id(cell), log_id(cell->type)); - cell->setParam("\\A_SIGNED", 0); + cell->setParam(ID(A_SIGNED), 0); port_a_signed = false; did_something = true; } @@ -230,13 +323,16 @@ struct WreduceWorker // Reduce size of port Y based on sizes for A and B and unused bits in Y int bits_removed = 0; - if (port_a_signed && cell->type == "$shr") { + if (port_a_signed && cell->type == ID($shr)) { // do not reduce size of output on $shr cells with signed A inputs } else { while (GetSize(sig) > 0) { - auto info = mi.query(sig[GetSize(sig)-1]); + auto bit = sig[GetSize(sig)-1]; + if (keep_bits.count(bit)) + break; + auto info = mi.query(bit); if (info->is_output || GetSize(info->ports) > 1) break; @@ -245,24 +341,24 @@ struct WreduceWorker } } - if (cell->type.in("$pos", "$add", "$mul", "$and", "$or", "$xor")) + if (cell->type.in(ID($pos), ID($add), ID($mul), ID($and), ID($or), ID($xor), ID($sub))) { - bool is_signed = cell->getParam("\\A_SIGNED").as_bool(); + bool is_signed = cell->getParam(ID(A_SIGNED)).as_bool() || cell->type == ID($sub); int a_size = 0, b_size = 0; - if (cell->hasPort("\\A")) a_size = GetSize(cell->getPort("\\A")); - if (cell->hasPort("\\B")) b_size = GetSize(cell->getPort("\\B")); + if (cell->hasPort(ID::A)) a_size = GetSize(cell->getPort(ID::A)); + if (cell->hasPort(ID::B)) b_size = GetSize(cell->getPort(ID::B)); int max_y_size = max(a_size, b_size); - if (cell->type == "$add") + if (cell->type.in(ID($add), ID($sub))) max_y_size++; - if (cell->type == "$mul") + if (cell->type == ID($mul)) max_y_size = a_size + b_size; while (GetSize(sig) > 1 && GetSize(sig) > max_y_size) { - module->connect(sig[GetSize(sig)-1], is_signed ? sig[GetSize(sig)-2] : S0); + module->connect(sig[GetSize(sig)-1], is_signed ? sig[GetSize(sig)-2] : State::S0); sig.remove(GetSize(sig)-1); bits_removed++; } @@ -277,7 +373,7 @@ struct WreduceWorker if (bits_removed) { log("Removed top %d bits (of %d) from port Y of cell %s.%s (%s).\n", bits_removed, GetSize(sig) + bits_removed, log_id(module), log_id(cell), log_id(cell->type)); - cell->setPort("\\Y", sig); + cell->setPort(ID::Y, sig); did_something = true; } @@ -290,17 +386,28 @@ struct WreduceWorker static int count_nontrivial_wire_attrs(RTLIL::Wire *w) { int count = w->attributes.size(); - count -= w->attributes.count("\\src"); - count -= w->attributes.count("\\unused_bits"); + count -= w->attributes.count(ID(src)); + count -= w->attributes.count(ID(unused_bits)); return count; } void run() { - for (auto w : module->wires()) - if (w->get_bool_attribute("\\keep")) + // create a copy as mi.sigmap will be updated as we process the module + SigMap init_attr_sigmap = mi.sigmap; + + for (auto w : module->wires()) { + if (w->get_bool_attribute(ID::keep)) for (auto bit : mi.sigmap(w)) keep_bits.insert(bit); + if (w->attributes.count(ID(init))) { + Const initval = w->attributes.at(ID(init)); + SigSpec initsig = init_attr_sigmap(w); + int width = std::min(GetSize(initval), GetSize(initsig)); + for (int i = 0; i < width; i++) + init_bits[initsig[i]] = initval[i]; + } + } for (auto c : module->selected_cells()) work_queue_cells.insert(c); @@ -348,12 +455,28 @@ struct WreduceWorker module->connect(nw, SigSpec(w).extract(0, GetSize(nw))); module->swap_names(w, nw); } + + if (!remove_init_bits.empty()) { + for (auto w : module->wires()) { + if (w->attributes.count(ID(init))) { + Const initval = w->attributes.at(ID(init)); + Const new_initval(State::Sx, GetSize(w)); + SigSpec initsig = init_attr_sigmap(w); + int width = std::min(GetSize(initval), GetSize(initsig)); + for (int i = 0; i < width; i++) { + if (!remove_init_bits.count(initsig[i])) + new_initval[i] = initval[i]; + } + w->attributes.at(ID(init)) = new_initval; + } + } + } } }; struct WreducePass : public Pass { WreducePass() : Pass("wreduce", "reduce the word size of operations if possible") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -372,8 +495,11 @@ struct WreducePass : public Pass { log(" Do not change the width of memory address ports. Use this options in\n"); log(" flows that use the 'memory_memx' pass.\n"); log("\n"); + log(" -keepdc\n"); + log(" Do not optimize explicit don't-care values.\n"); + log("\n"); } - virtual void execute(std::vector<std::string> args, Design *design) + void execute(std::vector<std::string> args, Design *design) YS_OVERRIDE { WreduceConfig config; bool opt_memx = false; @@ -386,6 +512,10 @@ struct WreducePass : public Pass { opt_memx = true; continue; } + if (args[argidx] == "-keepdc") { + config.keepdc = true; + continue; + } break; } extra_args(args, argidx, design); @@ -397,30 +527,66 @@ struct WreducePass : public Pass { for (auto c : module->selected_cells()) { - if (c->type.in("$reduce_and", "$reduce_or", "$reduce_xor", "$reduce_xnor", "$reduce_bool", - "$lt", "$le", "$eq", "$ne", "$eqx", "$nex", "$ge", "$gt", - "$logic_not", "$logic_and", "$logic_or") && GetSize(c->getPort("\\Y")) > 1) { - SigSpec sig = c->getPort("\\Y"); + if (c->type.in(ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_xnor), ID($reduce_bool), + ID($lt), ID($le), ID($eq), ID($ne), ID($eqx), ID($nex), ID($ge), ID($gt), + ID($logic_not), ID($logic_and), ID($logic_or)) && GetSize(c->getPort(ID::Y)) > 1) { + SigSpec sig = c->getPort(ID::Y); if (!sig.has_const()) { - c->setPort("\\Y", sig[0]); - c->setParam("\\Y_WIDTH", 1); + c->setPort(ID::Y, sig[0]); + c->setParam(ID(Y_WIDTH), 1); sig.remove(0); module->connect(sig, Const(0, GetSize(sig))); } } - if (!opt_memx && c->type.in("$memrd", "$memwr", "$meminit")) { - IdString memid = c->getParam("\\MEMID").decode_string(); + + if (c->type.in(ID($div), ID($mod), ID($pow))) + { + SigSpec A = c->getPort(ID::A); + int original_a_width = GetSize(A); + if (c->getParam(ID(A_SIGNED)).as_bool()) { + while (GetSize(A) > 1 && A[GetSize(A)-1] == State::S0 && A[GetSize(A)-2] == State::S0) + A.remove(GetSize(A)-1, 1); + } else { + while (GetSize(A) > 0 && A[GetSize(A)-1] == State::S0) + A.remove(GetSize(A)-1, 1); + } + if (original_a_width != GetSize(A)) { + log("Removed top %d bits (of %d) from port A of cell %s.%s (%s).\n", + original_a_width-GetSize(A), original_a_width, log_id(module), log_id(c), log_id(c->type)); + c->setPort(ID::A, A); + c->setParam(ID(A_WIDTH), GetSize(A)); + } + + SigSpec B = c->getPort(ID::B); + int original_b_width = GetSize(B); + if (c->getParam(ID(B_SIGNED)).as_bool()) { + while (GetSize(B) > 1 && B[GetSize(B)-1] == State::S0 && B[GetSize(B)-2] == State::S0) + B.remove(GetSize(B)-1, 1); + } else { + while (GetSize(B) > 0 && B[GetSize(B)-1] == State::S0) + B.remove(GetSize(B)-1, 1); + } + if (original_b_width != GetSize(B)) { + log("Removed top %d bits (of %d) from port B of cell %s.%s (%s).\n", + original_b_width-GetSize(B), original_b_width, log_id(module), log_id(c), log_id(c->type)); + c->setPort(ID::B, B); + c->setParam(ID(B_WIDTH), GetSize(B)); + } + } + + if (!opt_memx && c->type.in(ID($memrd), ID($memwr), ID($meminit))) { + IdString memid = c->getParam(ID(MEMID)).decode_string(); RTLIL::Memory *mem = module->memories.at(memid); if (mem->start_offset >= 0) { - int cur_addrbits = c->getParam("\\ABITS").as_int(); + int cur_addrbits = c->getParam(ID(ABITS)).as_int(); int max_addrbits = ceil_log2(mem->start_offset + mem->size); if (cur_addrbits > max_addrbits) { log("Removed top %d address bits (of %d) from memory %s port %s.%s (%s).\n", cur_addrbits-max_addrbits, cur_addrbits, - c->type == "$memrd" ? "read" : c->type == "$memwr" ? "write" : "init", + c->type == ID($memrd) ? "read" : c->type == ID($memwr) ? "write" : "init", log_id(module), log_id(c), log_id(memid)); - c->setParam("\\ABITS", max_addrbits); - c->setPort("\\ADDR", c->getPort("\\ADDR").extract(0, max_addrbits)); + c->setParam(ID(ABITS), max_addrbits); + c->setPort(ID(ADDR), c->getPort(ID(ADDR)).extract(0, max_addrbits)); } } } diff --git a/passes/pmgen/.gitignore b/passes/pmgen/.gitignore new file mode 100644 index 000000000..6b319b8c3 --- /dev/null +++ b/passes/pmgen/.gitignore @@ -0,0 +1 @@ +/*_pm.h
\ No newline at end of file diff --git a/passes/pmgen/Makefile.inc b/passes/pmgen/Makefile.inc new file mode 100644 index 000000000..98691d0fe --- /dev/null +++ b/passes/pmgen/Makefile.inc @@ -0,0 +1,39 @@ +%_pm.h: passes/pmgen/pmgen.py %.pmg + $(P) mkdir -p passes/pmgen && python3 $< -o $@ -p $(subst _pm.h,,$(notdir $@)) $(filter-out $<,$^) + +# -------------------------------------- + +OBJS += passes/pmgen/test_pmgen.o +passes/pmgen/test_pmgen.o: passes/pmgen/test_pmgen_pm.h passes/pmgen/ice40_dsp_pm.h passes/pmgen/peepopt_pm.h passes/pmgen/xilinx_srl_pm.h +$(eval $(call add_extra_objs,passes/pmgen/test_pmgen_pm.h)) + +# -------------------------------------- + +OBJS += passes/pmgen/ice40_dsp.o +passes/pmgen/ice40_dsp.o: passes/pmgen/ice40_dsp_pm.h +$(eval $(call add_extra_objs,passes/pmgen/ice40_dsp_pm.h)) + +# -------------------------------------- + +OBJS += passes/pmgen/ice40_wrapcarry.o +passes/pmgen/ice40_wrapcarry.o: passes/pmgen/ice40_wrapcarry_pm.h +$(eval $(call add_extra_objs,passes/pmgen/ice40_wrapcarry_pm.h)) + +# -------------------------------------- + +OBJS += passes/pmgen/peepopt.o +passes/pmgen/peepopt.o: passes/pmgen/peepopt_pm.h +$(eval $(call add_extra_objs,passes/pmgen/peepopt_pm.h)) + +PEEPOPT_PATTERN = passes/pmgen/peepopt_shiftmul.pmg +PEEPOPT_PATTERN += passes/pmgen/peepopt_muldiv.pmg +PEEPOPT_PATTERN += passes/pmgen/peepopt_dffmux.pmg + +passes/pmgen/peepopt_pm.h: passes/pmgen/pmgen.py $(PEEPOPT_PATTERN) + $(P) mkdir -p passes/pmgen && python3 $< -o $@ -p peepopt $(filter-out $<,$^) + +# -------------------------------------- + +OBJS += passes/pmgen/xilinx_srl.o +passes/pmgen/xilinx_srl.o: passes/pmgen/xilinx_srl_pm.h +$(eval $(call add_extra_objs,passes/pmgen/xilinx_srl_pm.h)) diff --git a/passes/pmgen/README.md b/passes/pmgen/README.md new file mode 100644 index 000000000..2f5b8d0b2 --- /dev/null +++ b/passes/pmgen/README.md @@ -0,0 +1,384 @@ +Pattern Matcher Generator +========================= + +The program `pmgen.py` reads a `.pmg` (Pattern Matcher Generator) file and +writes a header-only C++ library that implements that pattern matcher. + +The "patterns" in this context are subgraphs in a Yosys RTLIL netlist. + +The algorithm used in the generated pattern matcher is a simple recursive +search with backtracking. It is left to the author of the `.pmg` file to +determine an efficient cell order for the search that allows for maximum +use of indices and early backtracking. + + +API of Generated Matcher +======================== + +When `pmgen.py` reads a `foobar.pmg` file, it writes `foobar_pm.h` containing +a class `foobar_pm`. That class is instantiated with an RTLIL module and a +list of cells from that module: + + foobar_pm pm(module, module->selected_cells()); + +The caller must make sure that none of the cells in the 2nd argument are +deleted for as long as the patter matcher instance is used. + +At any time it is possible to disable cells, preventing them from showing +up in any future matches: + + pm.blacklist(some_cell); + +The `.run_<pattern_name>(callback_function)` method searches for all matches +for the pattern`<pattern_name>` and calls the callback function for each found +match: + + pm.run_foobar([&](){ + log("found matching 'foo' cell: %s\n", log_id(pm.st.foo)); + log(" with 'bar' cell: %s\n", log_id(pm.st.bar)); + }); + +The `.pmg` file declares matcher state variables that are accessible via the +`.st_<pattern_name>.<state_name>` members. (The `.st_<pattern_name>` member is +of type `foobar_pm::state_<pattern_name>_t`.) + +Similarly the `.pmg` file declares user data variables that become members of +`.ud_<pattern_name>`, a struct of type `foobar_pm::udata_<pattern_name>_t`. + +There are three versions of the `run_<pattern_name>()` method: Without callback, +callback without arguments, and callback with reference to `pm`. All versions +of the `run_<pattern_name>()` method return the number of found matches. + + +The .pmg File Format +==================== + +The `.pmg` file format is a simple line-based file format. For the most part +lines consist of whitespace-separated tokens. + +Lines in `.pmg` files starting with `//` are comments. + +Declaring a pattern +------------------- + +A `.pmg` file contains one or more patterns. Each pattern starts with a line +with the `pattern` keyword followed by the name of the pattern. + +Declaring state variables +------------------------- + +One or more state variables can be declared using the `state` statement, +followed by a C++ type in angle brackets, followed by a whitespace separated +list of variable names. For example: + + state <bool> flag1 flag2 happy big + state <SigSpec> sigA sigB sigY + +State variables are automatically managed by the generated backtracking algorithm +and saved and restored as needed. + +They are automatically initialized to the default constructed value of their type +when `.run_<pattern_name>(callback_function)` is called. + +Declaring udata variables +------------------------- + +Udata (user-data) variables can be used for example to configure the matcher or +the callback function used to perform actions on found matches. + +There is no automatic management of udata variables. For this reason it is +recommended that the user-supplied matcher code treats them as read-only +variables. + +They are declared like state variables, just using the `udata` statement: + + udata <int> min_data_width max_data_width + udata <IdString> data_port_name + +They are automatically initialized to the default constructed value of their type +when the pattern matcher object is constructed. + +Embedded C++ code +----------------- + +Many statements in a `.pmg` file contain C++ code. However, there are some +slight additions to regular C++/Yosys/RTLIL code that make it a bit easier to +write matchers: + +- Identifiers starting with a dollar sign or backslash are automatically + converted to special IdString variables that are initialized when the + matcher object is constructed. + +- The `port(<cell>, <portname>)` function is a handy alias for + `sigmap(<cell>->getPort(<portname>))`. + +- Similarly `param(<cell>, <paramname>)` looks up a parameter on a cell. + +- The function `nusers(<sigspec>)` returns the number of different cells + connected to any of the given signal bits, plus one if any of the signal + bits is also a primary input or primary output. + +- In `code..endcode` blocks there exist `accept`, `reject`, `branch`, + `finish`, and `subpattern` statements. + +- In `index` statements there is a special `===` operator for the index + lookup. + +Matching cells +-------------- + +Cells are matched using `match..endmatch` blocks. For example: + + match mul + if ff + select mul->type == $mul + select nusers(port(mul, \Y) == 2 + index <SigSpec> port(mul, \Y) === port(ff, \D) + filter some_weird_function(mul) < other_weird_function(ff) + optional + endmatch + +A `match` block starts with `match <statevar>` and implicitly generates +a state variable `<statevar>` of type `RTLIL::Cell*`. + +All statements in the match block are optional. (An empty match block +would simply match each and every cell in the module.) + +The `if <expression>` statement makes the match block conditional. If +`<expression>` evaluates to `false` then the match block will be ignored +and the corresponding state variable is set to `nullptr`. In our example +we only try to match the `mul` cell if the `ff` state variable points +to a cell. (Presumably `ff` is provided by a prior `match` block.) + +The `select` lines are evaluated once for each cell when the matcher is +initialized. A `match` block will only consider cells for which all `select` +expressions evaluated to `true`. Note that the state variable corresponding to +the match (in the example `mul`) is the only state variable that may be used +in `select` lines. + +Index lines are using the `index <type> expr1 === expr2` syntax. `expr1` is +evaluated during matcher initialization and the same restrictions apply as for +`select` expressions. `expr2` is evaluated when the match is calulated. It is a +function of any state variables assigned to by previous blocks. Both expression +are converted to the given type and compared for equality. Only cells for which +all `index` statements in the block pass are considered by the match. + +Note that `select` and `index` are fast operations. Thus `select` and `index` +should be used whenever possible to create efficient matchers. + +Finally, `filter <expression>` narrows down the remaining list of cells. For +performance reasons `filter` statements should only be used for things that +can't be done using `select` and `index`. + +The `optional` statement marks optional matches. That is, the matcher will also +explore the case where `mul` is set to `nullptr`. Without the `optional` +statement a match may only be assigned nullptr when one of the `if` expressions +evaluates to `false`. + +The `semioptional` statement marks matches that must match if at least one +matching cell exists, but if no matching cell exists it is set to `nullptr`. + +Slices and choices +------------------ + +Cell matches can contain "slices" and "choices". Slices can be used to +create matches for different sections of a cell. For example: + + state <int> pmux_slice + + match pmux + select pmux->type == $pmux + slice idx GetSize(port(pmux, \S)) + index <SigBit> port(pmux, \S)[idx] === port(eq, \Y) + set pmux_slice idx + endmatch + +The first argument to `slice` is the local variable name used to identify the +slice. The second argument is the number of slices that should be created for +this cell. The `set` statement can be used to copy that index into a state +variable so that later matches and/or code blocks can refer to it. + +A similar mechanism is "choices", where a list of options is given as +second argument, and the matcher will iterate over those options: + + state <SigSpec> foo bar + state <IdString> eq_ab eq_ba + + match eq + select eq->type == $eq + choice <IdString> AB {\A, \B} + define <IdString> BA (AB == \A ? \B : \A) + index <SigSpec> port(eq, AB) === foo + index <SigSpec> port(eq, BA) === bar + set eq_ab AB + set eq_ba BA + generate + +Notice how `define` can be used to define additional local variables similar +to the loop variables defined by `slice` and `choice`. + +Additional code +--------------- + +Interleaved with `match..endmatch` blocks there may be `code..endcode` blocks. +Such a block starts with the keyword `code` followed by a list of state variables +that the block may modify. For example: + + code addAB sigS + if (addA) { + addAB = addA; + sigS = port(addA, \B); + } + if (addB) { + addAB = addB; + sigS = port(addB, \A); + } + endcode + +The special keyword `reject` can be used to reject the current state and +backtrack. For example: + + code + if (ffA && ffB) { + if (port(ffA, \CLK) != port(ffB, \CLK)) + reject; + if (param(ffA, \CLK_POLARITY) != param(ffB, \CLK_POLARITY)) + reject; + } + endcode + +Similarly, the special keyword `accept` can be used to accept the current +state. (`accept` will not backtrack. This means it continues with the current +branch and may accept a larger match later.) + +The special keyword `branch` can be used to explore different cases. Note that +each code block has an implicit `branch` at the end. So most use-cases of the +`branch` keyword need to end the block with `reject` to avoid the implicit +branch at the end. For example: + + state <int> mode + + code mode + for (mode = 0; mode < 8; mode++) + branch; + reject; + endcode + +But in some cases it is more natural to utilize the implicit branch statement: + + state <IdString> portAB + + code portAB + portAB = \A; + branch; + portAB = \B; + endcode + +There is an implicit `code..endcode` block at the end of each (sub)pattern +that just rejects. + +A `code..finally..endcode` block executes the code after `finally` during +back-tracking. This is useful for maintaining user data state or printing +debug messages. For example: + + udata <vector<Cell*>> stack + + code + stack.push_back(addAB); + ... + finally + stack.pop_back(); + endcode + +`accept` and `finish` statements can be used inside the `finally` section, +but not `reject`, `branch`, or `subpattern`. + +Declaring a subpattern +---------------------- + +A subpattern starts with a line containing the `subpattern` keyword followed +by the name of the subpattern. Subpatterns can be called from a `code` block +using a `subpattern(<subpattern_name>);` C statement. + +Arguments may be passed to subpattern via state variables. The `subpattern` +line must be followed by a `arg <arg1> <arg2> ...` line that lists the +state variables used to pass arguments. + + state <IdString> foobar_type + state <bool> foobar_state + + code foobar_type foobar_state + foobar_state = false; + foobar_type = $add; + subpattern(foo); + foobar_type = $sub; + subpattern(bar); + endcode + + subpattern foo + arg foobar_type foobar_state + + match addsub + index <IdString> addsub->type === foobar_type + ... + endmatch + + code + if (foobar_state) { + subpattern(tail); + } else { + foobar_state = true; + subpattern(bar); + } + endcode + + subpattern bar + arg foobar_type foobar_state + + match addsub + index <IdString> addsub->type === foobar_type + ... + endmatch + + code + if (foobar_state) { + subpattern(tail); + } else { + foobar_state = true; + subpattern(foo); + } + endcode + + subpattern tail + ... + +Subpatterns can be called recursively. + +If a `subpattern` statement is preceded by a `fallthrough` statement, this is +equivalent to calling the subpattern at the end of the preceding block. + +Generate Blocks +--------------- + +Match blocks may contain an optional `generate` section that is used for automatic +test-case generation. For example: + + match mul + ... + generate 10 0 + SigSpec Y = port(ff, \D); + SigSpec A = module->addWire(NEW_ID, GetSize(Y) - rng(GetSize(Y)/2)); + SigSpec B = module->addWire(NEW_ID, GetSize(Y) - rng(GetSize(Y)/2)); + module->addMul(NEW_ID, A, B, Y, rng(2)); + endmatch + +The expression `rng(n)` returns a non-negative integer less than `n`. + +The first argument to `generate` is the chance of this generate block being +executed when the match block did not match anything, in percent. + +The second argument to `generate` is the chance of this generate block being +executed when the match block did match something, in percent. + +The special statement `finish` can be used within generate blocks to terminate +the current pattern matcher run. diff --git a/passes/pmgen/ice40_dsp.cc b/passes/pmgen/ice40_dsp.cc new file mode 100644 index 000000000..16bfe537f --- /dev/null +++ b/passes/pmgen/ice40_dsp.cc @@ -0,0 +1,235 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * + * 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 + +#include "passes/pmgen/ice40_dsp_pm.h" + +void create_ice40_dsp(ice40_dsp_pm &pm) +{ + auto &st = pm.st_ice40_dsp; + +#if 0 + log("\n"); + log("ffA: %s\n", log_id(st.ffA, "--")); + log("ffB: %s\n", log_id(st.ffB, "--")); + log("mul: %s\n", log_id(st.mul, "--")); + log("ffY: %s\n", log_id(st.ffY, "--")); + log("addAB: %s\n", log_id(st.addAB, "--")); + log("muxAB: %s\n", log_id(st.muxAB, "--")); + log("ffS: %s\n", log_id(st.ffS, "--")); +#endif + + log("Checking %s.%s for iCE40 DSP inference.\n", log_id(pm.module), log_id(st.mul)); + + if (GetSize(st.sigA) > 16) { + log(" input A (%s) is too large (%d > 16).\n", log_signal(st.sigA), GetSize(st.sigA)); + return; + } + + if (GetSize(st.sigB) > 16) { + log(" input B (%s) is too large (%d > 16).\n", log_signal(st.sigB), GetSize(st.sigB)); + return; + } + + if (GetSize(st.sigS) > 32) { + log(" accumulator (%s) is too large (%d > 32).\n", log_signal(st.sigS), GetSize(st.sigS)); + return; + } + + if (GetSize(st.sigY) > 32) { + log(" output (%s) is too large (%d > 32).\n", log_signal(st.sigY), GetSize(st.sigY)); + return; + } + + bool mul_signed = st.mul->getParam("\\A_SIGNED").as_bool(); + + log(" replacing $mul with SB_MAC16 cell.\n"); + + Cell *cell = pm.module->addCell(NEW_ID, "\\SB_MAC16"); + pm.module->swap_names(cell, st.mul); + + // SB_MAC16 Input Interface + + SigSpec A = st.sigA; + A.extend_u0(16, mul_signed); + + SigSpec B = st.sigB; + B.extend_u0(16, mul_signed); + + SigSpec CD; + if (st.muxA) + CD = st.muxA->getPort("\\B"); + if (st.muxB) + CD = st.muxB->getPort("\\A"); + CD.extend_u0(32, mul_signed); + + cell->setPort("\\A", A); + cell->setPort("\\B", B); + cell->setPort("\\C", CD.extract(0, 16)); + cell->setPort("\\D", CD.extract(16, 16)); + + cell->setParam("\\A_REG", st.ffA ? State::S1 : State::S0); + cell->setParam("\\B_REG", st.ffB ? State::S1 : State::S0); + + cell->setPort("\\AHOLD", State::S0); + cell->setPort("\\BHOLD", State::S0); + cell->setPort("\\CHOLD", State::S0); + cell->setPort("\\DHOLD", State::S0); + + cell->setPort("\\IRSTTOP", State::S0); + cell->setPort("\\IRSTBOT", State::S0); + + if (st.clock_vld) + { + cell->setPort("\\CLK", st.clock); + cell->setPort("\\CE", State::S1); + cell->setParam("\\NEG_TRIGGER", st.clock_pol ? State::S0 : State::S1); + + log(" clock: %s (%s)", log_signal(st.clock), st.clock_pol ? "posedge" : "negedge"); + + if (st.ffA) + log(" ffA:%s", log_id(st.ffA)); + + if (st.ffB) + log(" ffB:%s", log_id(st.ffB)); + + if (st.ffY) + log(" ffY:%s", log_id(st.ffY)); + + if (st.ffS) + log(" ffS:%s", log_id(st.ffS)); + + log("\n"); + } + else + { + cell->setPort("\\CLK", State::S0); + cell->setPort("\\CE", State::S0); + cell->setParam("\\NEG_TRIGGER", State::S0); + } + + // SB_MAC16 Cascade Interface + + cell->setPort("\\SIGNEXTIN", State::Sx); + cell->setPort("\\SIGNEXTOUT", pm.module->addWire(NEW_ID)); + + cell->setPort("\\CI", State::Sx); + cell->setPort("\\CO", pm.module->addWire(NEW_ID)); + + cell->setPort("\\ACCUMCI", State::Sx); + cell->setPort("\\ACCUMCO", pm.module->addWire(NEW_ID)); + + // SB_MAC16 Output Interface + + SigSpec O = st.ffS ? st.sigS : st.sigY; + if (GetSize(O) < 32) + O.append(pm.module->addWire(NEW_ID, 32-GetSize(O))); + + cell->setPort("\\O", O); + + if (st.addAB) { + log(" accumulator %s (%s)\n", log_id(st.addAB), log_id(st.addAB->type)); + cell->setPort("\\ADDSUBTOP", st.addAB->type == "$add" ? State::S0 : State::S1); + cell->setPort("\\ADDSUBBOT", st.addAB->type == "$add" ? State::S0 : State::S1); + } else { + cell->setPort("\\ADDSUBTOP", State::S0); + cell->setPort("\\ADDSUBBOT", State::S0); + } + + cell->setPort("\\ORSTTOP", State::S0); + cell->setPort("\\ORSTBOT", State::S0); + + cell->setPort("\\OHOLDTOP", State::S0); + cell->setPort("\\OHOLDBOT", State::S0); + + SigSpec acc_reset = State::S0; + if (st.muxA) + acc_reset = st.muxA->getPort("\\S"); + if (st.muxB) + acc_reset = pm.module->Not(NEW_ID, st.muxB->getPort("\\S")); + + cell->setPort("\\OLOADTOP", acc_reset); + cell->setPort("\\OLOADBOT", acc_reset); + + // SB_MAC16 Remaining Parameters + + cell->setParam("\\C_REG", State::S0); + cell->setParam("\\D_REG", State::S0); + + cell->setParam("\\TOP_8x8_MULT_REG", st.ffY ? State::S1 : State::S0); + cell->setParam("\\BOT_8x8_MULT_REG", st.ffY ? State::S1 : State::S0); + cell->setParam("\\PIPELINE_16x16_MULT_REG1", st.ffY ? State::S1 : State::S0); + cell->setParam("\\PIPELINE_16x16_MULT_REG2", State::S0); + + cell->setParam("\\TOPOUTPUT_SELECT", Const(st.ffS ? 1 : 3, 2)); + cell->setParam("\\TOPADDSUB_LOWERINPUT", Const(2, 2)); + cell->setParam("\\TOPADDSUB_UPPERINPUT", State::S0); + cell->setParam("\\TOPADDSUB_CARRYSELECT", Const(3, 2)); + + cell->setParam("\\BOTOUTPUT_SELECT", Const(st.ffS ? 1 : 3, 2)); + cell->setParam("\\BOTADDSUB_LOWERINPUT", Const(2, 2)); + cell->setParam("\\BOTADDSUB_UPPERINPUT", State::S0); + cell->setParam("\\BOTADDSUB_CARRYSELECT", Const(0, 2)); + + cell->setParam("\\MODE_8x8", State::S0); + cell->setParam("\\A_SIGNED", mul_signed ? State::S1 : State::S0); + cell->setParam("\\B_SIGNED", mul_signed ? State::S1 : State::S0); + + pm.autoremove(st.mul); + pm.autoremove(st.ffY); + pm.autoremove(st.ffS); +} + +struct Ice40DspPass : public Pass { + Ice40DspPass() : Pass("ice40_dsp", "iCE40: map multipliers") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" ice40_dsp [options] [selection]\n"); + log("\n"); + log("Map multipliers and multiply-accumulate blocks to iCE40 DSP resources.\n"); + log("\n"); + } + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + log_header(design, "Executing ICE40_DSP pass (map multipliers).\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + // if (args[argidx] == "-singleton") { + // singleton_mode = true; + // continue; + // } + break; + } + extra_args(args, argidx, design); + + for (auto module : design->selected_modules()) + ice40_dsp_pm(module, module->selected_cells()).run_ice40_dsp(create_ice40_dsp); + } +} Ice40DspPass; + +PRIVATE_NAMESPACE_END diff --git a/passes/pmgen/ice40_dsp.pmg b/passes/pmgen/ice40_dsp.pmg new file mode 100644 index 000000000..7003092bb --- /dev/null +++ b/passes/pmgen/ice40_dsp.pmg @@ -0,0 +1,163 @@ +pattern ice40_dsp + +state <SigBit> clock +state <bool> clock_pol clock_vld +state <SigSpec> sigA sigB sigY sigS +state <Cell*> addAB muxAB + +match mul + select mul->type.in($mul) + select GetSize(mul->getPort(\A)) + GetSize(mul->getPort(\B)) > 10 + select GetSize(mul->getPort(\Y)) > 10 +endmatch + +match ffA + select ffA->type.in($dff) + // select nusers(port(ffA, \Q)) == 2 + index <SigSpec> port(ffA, \Q) === port(mul, \A) + optional +endmatch + +code sigA clock clock_pol clock_vld + sigA = port(mul, \A); + + if (ffA) { + sigA = port(ffA, \D); + + clock = port(ffA, \CLK).as_bit(); + clock_pol = param(ffA, \CLK_POLARITY).as_bool(); + clock_vld = true; + } +endcode + +match ffB + select ffB->type.in($dff) + // select nusers(port(ffB, \Q)) == 2 + index <SigSpec> port(ffB, \Q) === port(mul, \B) + optional +endmatch + +code sigB clock clock_pol clock_vld + sigB = port(mul, \B); + + if (ffB) { + sigB = port(ffB, \D); + SigBit c = port(ffB, \CLK).as_bit(); + bool cp = param(ffB, \CLK_POLARITY).as_bool(); + + if (clock_vld && (c != clock || cp != clock_pol)) + reject; + + clock = c; + clock_pol = cp; + clock_vld = true; + } +endcode + +match ffY + select ffY->type.in($dff) + select nusers(port(ffY, \D)) == 2 + index <SigSpec> port(ffY, \D) === port(mul, \Y) + optional +endmatch + +code sigY clock clock_pol clock_vld + sigY = port(mul, \Y); + + if (ffY) { + sigY = port(ffY, \Q); + SigBit c = port(ffY, \CLK).as_bit(); + bool cp = param(ffY, \CLK_POLARITY).as_bool(); + + if (clock_vld && (c != clock || cp != clock_pol)) + reject; + + clock = c; + clock_pol = cp; + clock_vld = true; + } +endcode + +match addA + select addA->type.in($add) + select nusers(port(addA, \A)) == 2 + index <SigSpec> port(addA, \A) === sigY + optional +endmatch + +match addB + if !addA + select addB->type.in($add, $sub) + select nusers(port(addB, \B)) == 2 + index <SigSpec> port(addB, \B) === sigY + optional +endmatch + +code addAB sigS + if (addA) { + addAB = addA; + sigS = port(addA, \B); + } + if (addB) { + addAB = addB; + sigS = port(addB, \A); + } + if (addAB) { + int natural_mul_width = GetSize(sigA) + GetSize(sigB); + int actual_mul_width = GetSize(sigY); + int actual_acc_width = GetSize(sigS); + + if ((actual_acc_width > actual_mul_width) && (natural_mul_width > actual_mul_width)) + reject; + if ((actual_acc_width != actual_mul_width) && (param(mul, \A_SIGNED).as_bool() != param(addAB, \A_SIGNED).as_bool())) + reject; + } +endcode + +match muxA + if addAB + select muxA->type.in($mux) + select nusers(port(muxA, \A)) == 2 + index <SigSpec> port(muxA, \A) === port(addAB, \Y) + optional +endmatch + +match muxB + if addAB + if !muxA + select muxB->type.in($mux) + select nusers(port(muxB, \B)) == 2 + index <SigSpec> port(muxB, \B) === port(addAB, \Y) + optional +endmatch + +code muxAB + muxAB = addAB; + if (muxA) + muxAB = muxA; + if (muxB) + muxAB = muxB; +endcode + +match ffS + if muxAB + select ffS->type.in($dff) + select nusers(port(ffS, \D)) == 2 + index <SigSpec> port(ffS, \D) === port(muxAB, \Y) + index <SigSpec> port(ffS, \Q) === sigS +endmatch + +code clock clock_pol clock_vld + if (ffS) { + SigBit c = port(ffS, \CLK).as_bit(); + bool cp = param(ffS, \CLK_POLARITY).as_bool(); + + if (clock_vld && (c != clock || cp != clock_pol)) + reject; + + clock = c; + clock_pol = cp; + clock_vld = true; + } + accept; +endcode diff --git a/passes/pmgen/ice40_wrapcarry.cc b/passes/pmgen/ice40_wrapcarry.cc new file mode 100644 index 000000000..69ef3cd82 --- /dev/null +++ b/passes/pmgen/ice40_wrapcarry.cc @@ -0,0 +1,90 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * + * 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 + +#include "passes/pmgen/ice40_wrapcarry_pm.h" + +void create_ice40_wrapcarry(ice40_wrapcarry_pm &pm) +{ + auto &st = pm.st_ice40_wrapcarry; + +#if 0 + log("\n"); + log("carry: %s\n", log_id(st.carry, "--")); + log("lut: %s\n", log_id(st.lut, "--")); +#endif + + log(" replacing SB_LUT + SB_CARRY with $__ICE40_CARRY_WRAPPER cell.\n"); + + Cell *cell = pm.module->addCell(NEW_ID, "$__ICE40_CARRY_WRAPPER"); + pm.module->swap_names(cell, st.carry); + + cell->setPort("\\A", st.carry->getPort("\\I0")); + cell->setPort("\\B", st.carry->getPort("\\I1")); + cell->setPort("\\CI", st.carry->getPort("\\CI")); + cell->setPort("\\CO", st.carry->getPort("\\CO")); + + cell->setPort("\\I0", st.lut->getPort("\\I0")); + cell->setPort("\\I3", st.lut->getPort("\\I3")); + cell->setPort("\\O", st.lut->getPort("\\O")); + cell->setParam("\\LUT", st.lut->getParam("\\LUT_INIT")); + + pm.autoremove(st.carry); + pm.autoremove(st.lut); +} + +struct Ice40WrapCarryPass : public Pass { + Ice40WrapCarryPass() : Pass("ice40_wrapcarry", "iCE40: wrap carries") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" ice40_wrapcarry [selection]\n"); + log("\n"); + log("Wrap manually instantiated SB_CARRY cells, along with their associated SB_LUTs,\n"); + log("into an internal $__ICE40_CARRY_WRAPPER cell for preservation across technology\n"); + log("mapping."); + log("\n"); + } + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + log_header(design, "Executing ICE40_WRAPCARRY pass (wrap carries).\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + // if (args[argidx] == "-singleton") { + // singleton_mode = true; + // continue; + // } + break; + } + extra_args(args, argidx, design); + + for (auto module : design->selected_modules()) + ice40_wrapcarry_pm(module, module->selected_cells()).run_ice40_wrapcarry(create_ice40_wrapcarry); + } +} Ice40WrapCarryPass; + +PRIVATE_NAMESPACE_END diff --git a/passes/pmgen/ice40_wrapcarry.pmg b/passes/pmgen/ice40_wrapcarry.pmg new file mode 100644 index 000000000..9e64c7467 --- /dev/null +++ b/passes/pmgen/ice40_wrapcarry.pmg @@ -0,0 +1,11 @@ +pattern ice40_wrapcarry + +match carry + select carry->type.in(\SB_CARRY) +endmatch + +match lut + select lut->type.in(\SB_LUT4) + index <SigSpec> port(lut, \I1) === port(carry, \I0) + index <SigSpec> port(lut, \I2) === port(carry, \I1) +endmatch diff --git a/passes/pmgen/peepopt.cc b/passes/pmgen/peepopt.cc new file mode 100644 index 000000000..72b02127a --- /dev/null +++ b/passes/pmgen/peepopt.cc @@ -0,0 +1,69 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * + * 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 + +bool did_something; + +#include "passes/pmgen/peepopt_pm.h" + +struct PeepoptPass : public Pass { + PeepoptPass() : Pass("peepopt", "collection of peephole optimizers") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" peepopt [options] [selection]\n"); + log("\n"); + log("This pass applies a collection of peephole optimizers to the current design.\n"); + log("\n"); + } + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + log_header(design, "Executing PEEPOPT pass (run peephole optimizers).\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + // if (args[argidx] == "-singleton") { + // singleton_mode = true; + // continue; + // } + break; + } + extra_args(args, argidx, design); + + for (auto module : design->selected_modules()) { + did_something = true; + while (did_something) { + did_something = false; + peepopt_pm pm(module, module->selected_cells()); + pm.run_shiftmul(); + pm.run_muldiv(); + pm.run_dffmux(); + } + } + } +} PeepoptPass; + +PRIVATE_NAMESPACE_END diff --git a/passes/pmgen/peepopt_dffmux.pmg b/passes/pmgen/peepopt_dffmux.pmg new file mode 100644 index 000000000..c88a52226 --- /dev/null +++ b/passes/pmgen/peepopt_dffmux.pmg @@ -0,0 +1,113 @@ +pattern dffmux + +state <IdString> cemuxAB rstmuxBA +state <SigSpec> sigD + +match dff + select dff->type == $dff + select GetSize(port(dff, \D)) > 1 +endmatch + +match rstmux + select rstmux->type == $mux + select GetSize(port(rstmux, \Y)) > 1 + index <SigSpec> port(rstmux, \Y) === port(dff, \D) + choice <IdString> BA {\B, \A} + select port(rstmux, BA).is_fully_const() + set rstmuxBA BA + optional +endmatch + +code sigD + if (rstmux) + sigD = port(rstmux, rstmuxBA == \B ? \A : \B); + else + sigD = port(dff, \D); +endcode + +match cemux + select cemux->type == $mux + select GetSize(port(cemux, \Y)) > 1 + index <SigSpec> port(cemux, \Y) === sigD + choice <IdString> AB {\A, \B} + index <SigSpec> port(cemux, AB) === port(dff, \Q) + set cemuxAB AB +endmatch + +code + SigSpec D = port(cemux, cemuxAB == \A ? \B : \A); + SigSpec Q = port(dff, \Q); + Const rst; + if (rstmux) + rst = port(rstmux, rstmuxBA).as_const(); + int width = GetSize(D); + + SigSpec &ceA = cemux->connections_.at(\A); + SigSpec &ceB = cemux->connections_.at(\B); + SigSpec &ceY = cemux->connections_.at(\Y); + SigSpec &dffD = dff->connections_.at(\D); + SigSpec &dffQ = dff->connections_.at(\Q); + + if (D[width-1] == D[width-2]) { + did_something = true; + + SigBit sign = D[width-1]; + bool is_signed = sign.wire; + int i; + for (i = width-1; i >= 2; i--) { + if (!is_signed) { + module->connect(Q[i], sign); + if (D[i-1] != sign || (rst.size() && rst[i-1] != rst[width-1])) + break; + } + else { + module->connect(Q[i], Q[i-1]); + if (D[i-2] != sign || (rst.size() && rst[i-1] != rst[width-1])) + break; + } + } + + ceA.remove(i, width-i); + ceB.remove(i, width-i); + ceY.remove(i, width-i); + cemux->fixup_parameters(); + dffD.remove(i, width-i); + dffQ.remove(i, width-i); + dff->fixup_parameters(); + + log("dffcemux pattern in %s: dff=%s, cemux=%s; removed top %d bits.\n", log_id(module), log_id(dff), log_id(cemux), width-i); + accept; + } + else { + int count = 0; + for (int i = width-1; i >= 0; i--) { + if (D[i].wire) + continue; + Wire *w = Q[i].wire; + auto it = w->attributes.find(\init); + State init; + if (it != w->attributes.end()) + init = it->second[Q[i].offset]; + else + init = State::Sx; + + if (init == State::Sx || init == D[i].data) { + count++; + module->connect(Q[i], D[i]); + ceA.remove(i); + ceB.remove(i); + ceY.remove(i); + dffD.remove(i); + dffQ.remove(i); + } + } + if (count > 0) { + did_something = true; + cemux->fixup_parameters(); + dff->fixup_parameters(); + log("dffcemux pattern in %s: dff=%s, cemux=%s; removed %d constant bits.\n", log_id(module), log_id(dff), log_id(cemux), count); + } + + accept; + } +endcode diff --git a/passes/pmgen/peepopt_muldiv.pmg b/passes/pmgen/peepopt_muldiv.pmg new file mode 100644 index 000000000..7cad759d0 --- /dev/null +++ b/passes/pmgen/peepopt_muldiv.pmg @@ -0,0 +1,36 @@ +pattern muldiv + +state <SigSpec> t x y + +match mul + select mul->type == $mul + select GetSize(port(mul, \A)) + GetSize(port(mul, \B)) <= GetSize(port(mul, \Y)) +endmatch + +code t x y + t = port(mul, \Y); + x = port(mul, \A); + y = port(mul, \B); + branch; + std::swap(x, y); +endcode + +match div + select div->type.in($div) + index <SigSpec> port(div, \A) === t + index <SigSpec> port(div, \B) === x +endmatch + +code + SigSpec div_y = port(div, \Y); + SigSpec val_y = y; + + if (GetSize(div_y) != GetSize(val_y)) + val_y.extend_u0(GetSize(div_y), param(div, \A_SIGNED).as_bool()); + + did_something = true; + log("muldiv pattern in %s: mul=%s, div=%s\n", log_id(module), log_id(mul), log_id(div)); + module->connect(div_y, val_y); + autoremove(div); + accept; +endcode diff --git a/passes/pmgen/peepopt_shiftmul.pmg b/passes/pmgen/peepopt_shiftmul.pmg new file mode 100644 index 000000000..d4748ae19 --- /dev/null +++ b/passes/pmgen/peepopt_shiftmul.pmg @@ -0,0 +1,96 @@ +pattern shiftmul +// +// Optimize mul+shift pairs that result from expressions such as foo[s*W+:W] +// + +state <SigSpec> shamt + +match shift + select shift->type.in($shift, $shiftx, $shr) +endmatch + +code shamt + shamt = port(shift, \B); + if (shamt.empty()) + reject; + if (shamt[GetSize(shamt)-1] == State::S0) { + do { + shamt.remove(GetSize(shamt)-1); + if (shamt.empty()) + reject; + } while (shamt[GetSize(shamt)-1] == State::S0); + } else + if (shift->type.in($shift, $shiftx) && param(shift, \B_SIGNED).as_bool()) { + reject; + } + if (GetSize(shamt) > 20) + reject; +endcode + +match mul + select mul->type.in($mul) + select port(mul, \A).is_fully_const() || port(mul, \B).is_fully_const() + index <SigSpec> port(mul, \Y) === shamt +endmatch + +code +{ + IdString const_factor_port = port(mul, \A).is_fully_const() ? \A : \B; + IdString const_factor_signed = const_factor_port == \A ? \A_SIGNED : \B_SIGNED; + Const const_factor_cnst = port(mul, const_factor_port).as_const(); + int const_factor = const_factor_cnst.as_int(); + + if (GetSize(const_factor_cnst) == 0) + reject; + + if (const_factor_cnst.bits[GetSize(const_factor_cnst)-1] != State::S0 && + param(mul, const_factor_signed).as_bool()) + reject; + + if (GetSize(const_factor_cnst) > 20) + reject; + + 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 = 1 << factor_bits; + SigSpec padding(State::Sx, new_const_factor-const_factor); + SigSpec old_a = port(shift, \A), new_a; + int trunc = 0; + + if (GetSize(old_a) % const_factor != 0) { + trunc = const_factor - GetSize(old_a) % const_factor; + old_a.append(SigSpec(State::Sx, trunc)); + } + + for (int i = 0; i*const_factor < GetSize(old_a); i++) { + SigSpec slice = old_a.extract(i*const_factor, const_factor); + new_a.append(slice); + new_a.append(padding); + } + + if (trunc > 0) + new_a.remove(GetSize(new_a)-trunc, trunc); + + SigSpec new_b = {mul_din, SigSpec(State::S0, factor_bits)}; + if (param(shift, \B_SIGNED).as_bool()) + new_b.append(State::S0); + + shift->setPort(\A, new_a); + shift->setParam(\A_WIDTH, GetSize(new_a)); + shift->setPort(\B, new_b); + shift->setParam(\B_WIDTH, GetSize(new_b)); + + blacklist(shift); + accept; +} +endcode diff --git a/passes/pmgen/pmgen.py b/passes/pmgen/pmgen.py new file mode 100644 index 000000000..573722d68 --- /dev/null +++ b/passes/pmgen/pmgen.py @@ -0,0 +1,774 @@ +#!/usr/bin/env python3 + +import re +import sys +import pprint +import getopt + +pp = pprint.PrettyPrinter(indent=4) + +prefix = None +pmgfiles = list() +outfile = None +debug = False +genhdr = False + +opts, args = getopt.getopt(sys.argv[1:], "p:o:dg") + +for o, a in opts: + if o == "-p": + prefix = a + elif o == "-o": + outfile = a + elif o == "-d": + debug = True + elif o == "-g": + genhdr = True + +if outfile is None: + outfile = "/dev/stdout" + +for a in args: + assert a.endswith(".pmg") + if prefix is None and len(args) == 1: + prefix = a[0:-4] + prefix = prefix.split('/')[-1] + pmgfiles.append(a) + +assert prefix is not None + +current_pattern = None +current_subpattern = None +patterns = dict() +subpatterns = dict() +subpattern_args = dict() +state_types = dict() +udata_types = dict() +blocks = list() +ids = dict() + +def rewrite_cpp(s): + t = list() + i = 0 + while i < len(s): + if s[i] in ("'", '"') and i + 1 < len(s): + j = i + 1 + while j + 1 < len(s) and s[j] != s[i]: + if s[j] == '\\' and j + 1 < len(s): + j += 1 + j += 1 + t.append(s[i:j+1]) + i = j + 1 + continue + + if s[i] in ('$', '\\') and i + 1 < len(s): + j = i + 1 + while True: + if j == len(s): + j -= 1 + break + if ord('a') <= ord(s[j]) <= ord('z'): + j += 1 + continue + if ord('A') <= ord(s[j]) <= ord('Z'): + j += 1 + continue + if ord('0') <= ord(s[j]) <= ord('9'): + j += 1 + continue + if s[j] == '_': + j += 1 + continue + j -= 1 + break + + n = s[i:j+1] + i = j + 1 + + if n[0] == '$': + v = "id_d_" + n[1:] + else: + v = "id_b_" + n[1:] + + if v not in ids: + ids[v] = n + else: + assert ids[v] == n + + t.append(v) + continue + + if s[i] == "\t": + t.append(" ") + else: + t.append(s[i]) + + i += 1 + + return "".join(t) + +def process_pmgfile(f, filename): + linenr = 0 + global current_pattern + global current_subpattern + while True: + linenr += 1 + line = f.readline() + if line == "": break + line = line.strip() + + cmd = line.split() + if len(cmd) == 0 or cmd[0].startswith("//"): continue + cmd = cmd[0] + + if cmd == "pattern": + if current_pattern is not None: + block = dict() + block["type"] = "final" + block["pattern"] = (current_pattern, current_subpattern) + blocks.append(block) + line = line.split() + assert len(line) == 2 + assert line[1] not in patterns + current_pattern = line[1] + current_subpattern = "" + patterns[current_pattern] = len(blocks) + subpatterns[(current_pattern, current_subpattern)] = len(blocks) + subpattern_args[(current_pattern, current_subpattern)] = list() + state_types[current_pattern] = dict() + udata_types[current_pattern] = dict() + continue + + assert current_pattern is not None + + if cmd == "fallthrough": + block = dict() + block["type"] = "fallthrough" + blocks.append(block) + line = line.split() + assert len(line) == 1 + continue + + if cmd == "subpattern": + if len(blocks) == 0 or blocks[-1]["type"] != "fallthrough": + block = dict() + block["type"] = "final" + block["pattern"] = (current_pattern, current_subpattern) + blocks.append(block) + elif len(blocks) and blocks[-1]["type"] == "fallthrough": + del blocks[-1] + line = line.split() + assert len(line) == 2 + current_subpattern = line[1] + subpattern_args[(current_pattern, current_subpattern)] = list() + assert (current_pattern, current_subpattern) not in subpatterns + subpatterns[(current_pattern, current_subpattern)] = len(blocks) + continue + + if cmd == "arg": + line = line.split() + assert len(line) > 1 + subpattern_args[(current_pattern, current_subpattern)] += line[1:] + continue + + if cmd == "state": + m = re.match(r"^state\s+<(.*?)>\s+(([A-Za-z_][A-Za-z_0-9]*\s+)*[A-Za-z_][A-Za-z_0-9]*)\s*$", line) + assert m + type_str = m.group(1) + states_str = m.group(2) + for s in re.split(r"\s+", states_str): + assert s not in state_types[current_pattern] + state_types[current_pattern][s] = type_str + continue + + if cmd == "udata": + m = re.match(r"^udata\s+<(.*?)>\s+(([A-Za-z_][A-Za-z_0-9]*\s+)*[A-Za-z_][A-Za-z_0-9]*)\s*$", line) + assert m + type_str = m.group(1) + udatas_str = m.group(2) + for s in re.split(r"\s+", udatas_str): + assert s not in udata_types[current_pattern] + udata_types[current_pattern][s] = type_str + continue + + if cmd == "match": + block = dict() + block["type"] = "match" + block["src"] = "%s:%d" % (filename, linenr) + block["pattern"] = (current_pattern, current_subpattern) + + block["genargs"] = None + block["gencode"] = None + + line = line.split() + assert len(line) == 2 + assert (line[1] not in state_types[current_pattern]) or (state_types[current_pattern][line[1]] == "Cell*") + block["cell"] = line[1] + state_types[current_pattern][line[1]] = "Cell*"; + + block["if"] = list() + block["setup"] = list() + block["index"] = list() + block["filter"] = list() + block["sets"] = list() + block["optional"] = False + block["semioptional"] = False + + while True: + linenr += 1 + l = f.readline() + assert l != "" + a = l.split() + if len(a) == 0 or a[0].startswith("//"): continue + if a[0] == "endmatch": break + + if a[0] == "if": + b = l.lstrip()[2:] + block["if"].append(rewrite_cpp(b.strip())) + continue + + if a[0] == "select": + b = l.lstrip()[6:] + block["setup"].append(("select", rewrite_cpp(b.strip()))) + continue + + if a[0] == "slice": + m = re.match(r"^\s*slice\s+(\S+)\s+(.*?)\s*$", l) + block["setup"].append(("slice", m.group(1), rewrite_cpp(m.group(2)))) + continue + + if a[0] == "choice": + m = re.match(r"^\s*choice\s+<(.*?)>\s+(\S+)\s+(.*?)\s*$", l) + block["setup"].append(("choice", m.group(1), m.group(2), rewrite_cpp(m.group(3)))) + continue + + if a[0] == "define": + m = re.match(r"^\s*define\s+<(.*?)>\s+(\S+)\s+(.*?)\s*$", l) + block["setup"].append(("define", m.group(1), m.group(2), rewrite_cpp(m.group(3)))) + continue + + if a[0] == "index": + m = re.match(r"^\s*index\s+<(.*?)>\s+(.*?)\s*===\s*(.*?)\s*$", l) + assert m + block["index"].append((m.group(1), rewrite_cpp(m.group(2)), rewrite_cpp(m.group(3)))) + continue + + if a[0] == "filter": + b = l.lstrip()[6:] + block["filter"].append(rewrite_cpp(b.strip())) + continue + + if a[0] == "set": + m = re.match(r"^\s*set\s+(\S+)\s+(.*?)\s*$", l) + block["sets"].append((m.group(1), rewrite_cpp(m.group(2)))) + continue + + if a[0] == "optional": + block["optional"] = True + continue + + if a[0] == "semioptional": + block["semioptional"] = True + continue + + if a[0] == "generate": + block["genargs"] = list([int(s) for s in a[1:]]) + if len(block["genargs"]) == 0: block["genargs"].append(100) + if len(block["genargs"]) == 1: block["genargs"].append(0) + assert len(block["genargs"]) == 2 + block["gencode"] = list() + while True: + linenr += 1 + l = f.readline() + assert l != "" + a = l.split() + if len(a) == 1 and a[0] == "endmatch": break + block["gencode"].append(rewrite_cpp(l.rstrip())) + break + + assert False + + if block["optional"]: + assert not block["semioptional"] + + blocks.append(block) + continue + + if cmd == "code": + block = dict() + block["type"] = "code" + block["src"] = "%s:%d" % (filename, linenr) + block["pattern"] = (current_pattern, current_subpattern) + + block["code"] = list() + block["fcode"] = list() + block["states"] = set() + + for s in line.split()[1:]: + assert s in state_types[current_pattern] + block["states"].add(s) + + codetype = "code" + + while True: + linenr += 1 + l = f.readline() + assert l != "" + a = l.split() + if len(a) == 0: continue + if a[0] == "endcode": break + + if a[0] == "finally": + codetype = "fcode" + continue + + block[codetype].append(rewrite_cpp(l.rstrip())) + + blocks.append(block) + continue + + assert False + +for fn in pmgfiles: + with open(fn, "r") as f: + process_pmgfile(f, fn) + +if current_pattern is not None: + block = dict() + block["type"] = "final" + block["pattern"] = (current_pattern, current_subpattern) + blocks.append(block) + +current_pattern = None +current_subpattern = None + +if debug: + pp.pprint(blocks) + +with open(outfile, "w") as f: + for fn in pmgfiles: + print("// Generated by pmgen.py from {}".format(fn), file=f) + print("", file=f) + + if genhdr: + print("#include \"kernel/yosys.h\"", file=f) + print("#include \"kernel/sigtools.h\"", file=f) + print("", file=f) + print("YOSYS_NAMESPACE_BEGIN", file=f) + print("", file=f) + + print("struct {}_pm {{".format(prefix), file=f) + print(" Module *module;", file=f) + print(" SigMap sigmap;", file=f) + print(" std::function<void()> on_accept;", file=f) + print(" bool generate_mode;", file=f) + print(" int accept_cnt;", file=f) + print("", file=f) + + print(" uint32_t rngseed;", file=f) + print(" int rng(unsigned int n) {", file=f) + print(" rngseed ^= rngseed << 13;", file=f) + print(" rngseed ^= rngseed >> 17;", file=f) + print(" rngseed ^= rngseed << 5;", file=f) + print(" return rngseed % n;", file=f) + print(" }", file=f) + print("", file=f) + + for index in range(len(blocks)): + block = blocks[index] + if block["type"] == "match": + index_types = list() + for entry in block["index"]: + index_types.append(entry[0]) + value_types = ["Cell*"] + for entry in block["setup"]: + if entry[0] == "slice": + value_types.append("int") + if entry[0] == "choice": + value_types.append(entry[1]) + if entry[0] == "define": + value_types.append(entry[1]) + print(" typedef std::tuple<{}> index_{}_key_type;".format(", ".join(index_types), index), file=f) + print(" typedef std::tuple<{}> index_{}_value_type;".format(", ".join(value_types), index), file=f) + print(" dict<index_{}_key_type, vector<index_{}_value_type>> index_{};".format(index, index, index), file=f) + print(" dict<SigBit, pool<Cell*>> sigusers;", file=f) + print(" pool<Cell*> blacklist_cells;", file=f) + print(" pool<Cell*> autoremove_cells;", file=f) + print(" dict<Cell*,int> rollback_cache;", file=f) + print(" int rollback;", file=f) + print("", file=f) + + for current_pattern in sorted(patterns.keys()): + print(" struct state_{}_t {{".format(current_pattern), file=f) + for s, t in sorted(state_types[current_pattern].items()): + print(" {} {};".format(t, s), file=f) + print(" }} st_{};".format(current_pattern), file=f) + print("", file=f) + + print(" struct udata_{}_t {{".format(current_pattern), file=f) + for s, t in sorted(udata_types[current_pattern].items()): + print(" {} {};".format(t, s), file=f) + print(" }} ud_{};".format(current_pattern), file=f) + print("", file=f) + current_pattern = None + + for v, n in sorted(ids.items()): + if n[0] == "\\": + print(" IdString {}{{\"\\{}\"}};".format(v, n), file=f) + else: + print(" IdString {}{{\"{}\"}};".format(v, n), file=f) + print("", file=f) + + print(" void add_siguser(const SigSpec &sig, Cell *cell) {", file=f) + print(" for (auto bit : sigmap(sig)) {", file=f) + print(" if (bit.wire == nullptr) continue;", file=f) + print(" sigusers[bit].insert(cell);", file=f) + print(" }", file=f) + print(" }", file=f) + print("", file=f) + + print(" void blacklist(Cell *cell) {", file=f) + print(" if (cell != nullptr && blacklist_cells.insert(cell).second) {", file=f) + print(" auto ptr = rollback_cache.find(cell);", file=f) + print(" if (ptr == rollback_cache.end()) return;", file=f) + print(" int rb = ptr->second;", file=f) + print(" if (rollback == 0 || rollback > rb)", file=f) + print(" rollback = rb;", file=f) + print(" }", file=f) + print(" }", file=f) + print("", file=f) + + print(" void autoremove(Cell *cell) {", file=f) + print(" if (cell != nullptr) {", file=f) + print(" autoremove_cells.insert(cell);", file=f) + print(" blacklist(cell);", file=f) + print(" }", file=f) + print(" }", file=f) + print("", file=f) + + current_pattern = None + + print(" SigSpec port(Cell *cell, IdString portname) {", file=f) + print(" return sigmap(cell->getPort(portname));", file=f) + print(" }", file=f) + print("", file=f) + + print(" Const param(Cell *cell, IdString paramname) {", file=f) + print(" return cell->getParam(paramname);", file=f) + print(" }", file=f) + print("", file=f) + + print(" int nusers(const SigSpec &sig) {", file=f) + print(" pool<Cell*> users;", file=f) + print(" for (auto bit : sigmap(sig))", file=f) + print(" for (auto user : sigusers[bit])", file=f) + print(" users.insert(user);", file=f) + print(" return GetSize(users);", file=f) + print(" }", file=f) + print("", file=f) + + print(" {}_pm(Module *module, const vector<Cell*> &cells) :".format(prefix), file=f) + print(" module(module), sigmap(module), generate_mode(false), rngseed(12345678) {", file=f) + for current_pattern in sorted(patterns.keys()): + for s, t in sorted(udata_types[current_pattern].items()): + if t.endswith("*"): + print(" ud_{}.{} = nullptr;".format(current_pattern,s), file=f) + else: + print(" ud_{}.{} = {}();".format(current_pattern, s, t), file=f) + current_pattern = None + print(" for (auto port : module->ports)", file=f) + print(" add_siguser(module->wire(port), nullptr);", file=f) + print(" for (auto cell : module->cells())", file=f) + print(" for (auto &conn : cell->connections())", file=f) + print(" add_siguser(conn.second, cell);", file=f) + print(" for (auto cell : cells) {", file=f) + + for index in range(len(blocks)): + block = blocks[index] + if block["type"] == "match": + print(" do {", file=f) + print(" Cell *{} = cell;".format(block["cell"]), file=f) + print(" index_{}_value_type value;".format(index), file=f) + print(" std::get<0>(value) = cell;", file=f) + loopcnt = 0 + valueidx = 1 + for item in block["setup"]: + if item[0] == "select": + print(" if (!({})) continue;".format(item[1]), file=f) + if item[0] == "slice": + print(" int &{} = std::get<{}>(value);".format(item[1], valueidx), file=f) + print(" for ({} = 0; {} < {}; {}++) {{".format(item[1], item[1], item[2], item[1]), file=f) + valueidx += 1 + loopcnt += 1 + if item[0] == "choice": + print(" vector<{}> _pmg_choices_{} = {};".format(item[1], item[2], item[3]), file=f) + print(" for (const {} &{} : _pmg_choices_{}) {{".format(item[1], item[2], item[2]), file=f) + print(" std::get<{}>(value) = {};".format(valueidx, item[2]), file=f) + valueidx += 1 + loopcnt += 1 + if item[0] == "define": + print(" {} &{} = std::get<{}>(value);".format(item[1], item[2], valueidx), file=f) + print(" {} = {};".format(item[2], item[3]), file=f) + valueidx += 1 + print(" index_{}_key_type key;".format(index), file=f) + for field, entry in enumerate(block["index"]): + print(" std::get<{}>(key) = {};".format(field, entry[1]), file=f) + print(" index_{}[key].push_back(value);".format(index), file=f) + for i in range(loopcnt): + print(" }", file=f) + print(" } while (0);", file=f) + + print(" }", file=f) + print(" }", file=f) + print("", file=f) + + print(" ~{}_pm() {{".format(prefix), file=f) + print(" for (auto cell : autoremove_cells)", file=f) + print(" module->remove(cell);", file=f) + print(" }", file=f) + print("", file=f) + + for current_pattern in sorted(patterns.keys()): + print(" int run_{}(std::function<void()> on_accept_f) {{".format(current_pattern), file=f) + print(" accept_cnt = 0;", file=f) + print(" on_accept = on_accept_f;", file=f) + print(" rollback = 0;", file=f) + for s, t in sorted(state_types[current_pattern].items()): + if t.endswith("*"): + print(" st_{}.{} = nullptr;".format(current_pattern, s), file=f) + else: + print(" st_{}.{} = {}();".format(current_pattern, s, t), file=f) + print(" block_{}(1);".format(patterns[current_pattern]), file=f) + print(" log_assert(rollback_cache.empty());", file=f) + print(" return accept_cnt;", file=f) + print(" }", file=f) + print("", file=f) + print(" int run_{}(std::function<void({}_pm&)> on_accept_f) {{".format(current_pattern, prefix), file=f) + print(" return run_{}([&](){{on_accept_f(*this);}});".format(current_pattern), file=f) + print(" }", file=f) + print("", file=f) + print(" int run_{}() {{".format(current_pattern), file=f) + print(" return run_{}([](){{}});".format(current_pattern, current_pattern), file=f) + print(" }", file=f) + print("", file=f) + + if len(subpatterns): + for p, s in sorted(subpatterns.keys()): + print(" void block_subpattern_{}_{}(int recursion) {{ block_{}(recursion); }}".format(p, s, subpatterns[(p, s)]), file=f) + print("", file=f) + + current_pattern = None + current_subpattern = None + + for index in range(len(blocks)): + block = blocks[index] + + if block["type"] in ("match", "code"): + print(" // {}".format(block["src"]), file=f) + + print(" void block_{}(int recursion YS_ATTRIBUTE(unused)) {{".format(index), file=f) + current_pattern, current_subpattern = block["pattern"] + + if block["type"] == "final": + print(" }", file=f) + if index+1 != len(blocks): + print("", file=f) + continue + + const_st = set() + nonconst_st = set() + restore_st = set() + + for s in subpattern_args[(current_pattern, current_subpattern)]: + const_st.add(s) + + for i in range(subpatterns[(current_pattern, current_subpattern)], index): + if blocks[i]["type"] == "code": + for s in blocks[i]["states"]: + const_st.add(s) + elif blocks[i]["type"] == "match": + const_st.add(blocks[i]["cell"]) + for item in blocks[i]["sets"]: + const_st.add(item[0]) + else: + assert False + + if block["type"] == "code": + for s in block["states"]: + if s in const_st: + const_st.remove(s) + restore_st.add(s) + nonconst_st.add(s) + elif block["type"] == "match": + s = block["cell"] + assert s not in const_st + nonconst_st.add(s) + for item in block["sets"]: + if item[0] in const_st: + const_st.remove(item[0]) + nonconst_st.add(item[0]) + else: + assert False + + for s in sorted(const_st): + t = state_types[current_pattern][s] + if t.endswith("*"): + print(" {} const &{} YS_ATTRIBUTE(unused) = st_{}.{};".format(t, s, current_pattern, s), file=f) + else: + print(" const {} &{} YS_ATTRIBUTE(unused) = st_{}.{};".format(t, s, current_pattern, s), file=f) + + for s in sorted(nonconst_st): + t = state_types[current_pattern][s] + print(" {} &{} YS_ATTRIBUTE(unused) = st_{}.{};".format(t, s, current_pattern, s), file=f) + + for u in sorted(udata_types[current_pattern].keys()): + t = udata_types[current_pattern][u] + print(" {} &{} YS_ATTRIBUTE(unused) = ud_{}.{};".format(t, u, current_pattern, u), file=f) + + if len(restore_st): + print("", file=f) + for s in sorted(restore_st): + t = state_types[current_pattern][s] + print(" {} _pmg_backup_{} = {};".format(t, s, s), file=f) + + if block["type"] == "code": + print("", file=f) + print("#define reject do { goto rollback_label; } while(0)", file=f) + print("#define accept do { accept_cnt++; on_accept(); if (rollback) goto rollback_label; } while(0)", file=f) + print("#define finish do { rollback = -1; goto rollback_label; } while(0)", file=f) + print("#define branch do {{ block_{}(recursion+1); if (rollback) goto rollback_label; }} while(0)".format(index+1), file=f) + print("#define subpattern(pattern_name) do {{ block_subpattern_{}_ ## pattern_name (recursion+1); if (rollback) goto rollback_label; }} while(0)".format(current_pattern), file=f) + + for line in block["code"]: + print(" " + line, file=f) + + print("", file=f) + print(" block_{}(recursion+1);".format(index+1), file=f) + + print("#undef reject", file=f) + print("#undef accept", file=f) + print("#undef finish", file=f) + print("#undef branch", file=f) + print("#undef subpattern", file=f) + + print("", file=f) + print("rollback_label:", file=f) + print(" YS_ATTRIBUTE(unused);", file=f) + + if len(block["fcode"]): + print("#define accept do { accept_cnt++; on_accept(); } while(0)", file=f) + print("#define finish do { rollback = -1; goto finish_label; } while(0)", file=f) + for line in block["fcode"]: + print(" " + line, file=f) + print("finish_label:", file=f) + print(" YS_ATTRIBUTE(unused);", file=f) + print("#undef accept", file=f) + print("#undef finish", file=f) + + if len(restore_st) or len(nonconst_st): + print("", file=f) + for s in sorted(restore_st): + t = state_types[current_pattern][s] + print(" {} = _pmg_backup_{};".format(s, s), file=f) + for s in sorted(nonconst_st): + if s not in restore_st: + t = state_types[current_pattern][s] + if t.endswith("*"): + print(" {} = nullptr;".format(s), file=f) + else: + print(" {} = {}();".format(s, t), file=f) + + elif block["type"] == "match": + assert len(restore_st) == 0 + + print(" Cell* _pmg_backup_{} = {};".format(block["cell"], block["cell"]), file=f) + + if len(block["if"]): + for expr in block["if"]: + print("", file=f) + print(" if (!({})) {{".format(expr), file=f) + print(" {} = nullptr;".format(block["cell"]), file=f) + print(" block_{}(recursion+1);".format(index+1), file=f) + print(" {} = _pmg_backup_{};".format(block["cell"], block["cell"]), file=f) + print(" return;", file=f) + print(" }", file=f) + + print("", file=f) + print(" index_{}_key_type key;".format(index), file=f) + for field, entry in enumerate(block["index"]): + print(" std::get<{}>(key) = {};".format(field, entry[2]), file=f) + print(" auto cells_ptr = index_{}.find(key);".format(index), file=f) + + if block["semioptional"] or block["genargs"] is not None: + print(" bool found_any_match = false;", file=f) + + print("", file=f) + print(" if (cells_ptr != index_{}.end()) {{".format(index), file=f) + print(" const vector<index_{}_value_type> &cells = cells_ptr->second;".format(index), file=f) + print(" for (int _pmg_idx = 0; _pmg_idx < GetSize(cells); _pmg_idx++) {", file=f) + print(" {} = std::get<0>(cells[_pmg_idx]);".format(block["cell"]), file=f) + valueidx = 1 + for item in block["setup"]: + if item[0] == "slice": + print(" const int &{} YS_ATTRIBUTE(unused) = std::get<{}>(cells[_pmg_idx]);".format(item[1], valueidx), file=f) + valueidx += 1 + if item[0] == "choice": + print(" const {} &{} YS_ATTRIBUTE(unused) = std::get<{}>(cells[_pmg_idx]);".format(item[1], item[2], valueidx), file=f) + valueidx += 1 + if item[0] == "define": + print(" const {} &{} YS_ATTRIBUTE(unused) = std::get<{}>(cells[_pmg_idx]);".format(item[1], item[2], valueidx), file=f) + valueidx += 1 + print(" if (blacklist_cells.count({})) continue;".format(block["cell"]), file=f) + for expr in block["filter"]: + print(" if (!({})) continue;".format(expr), file=f) + if block["semioptional"] or block["genargs"] is not None: + print(" found_any_match = true;", file=f) + for item in block["sets"]: + print(" auto _pmg_backup_{} = {};".format(item[0], item[0]), file=f) + print(" {} = {};".format(item[0], item[1]), file=f) + print(" auto rollback_ptr = rollback_cache.insert(make_pair(std::get<0>(cells[_pmg_idx]), recursion));", file=f) + print(" block_{}(recursion+1);".format(index+1), file=f) + for item in block["sets"]: + print(" {} = _pmg_backup_{};".format(item[0], item[0]), file=f) + print(" if (rollback_ptr.second)", file=f) + print(" rollback_cache.erase(rollback_ptr.first);", file=f) + print(" if (rollback) {", file=f) + print(" if (rollback != recursion) {{".format(index+1), file=f) + print(" {} = _pmg_backup_{};".format(block["cell"], block["cell"]), file=f) + print(" return;", file=f) + print(" }", file=f) + print(" rollback = 0;", file=f) + print(" }", file=f) + print(" }", file=f) + print(" }", file=f) + + print("", file=f) + print(" {} = nullptr;".format(block["cell"]), file=f) + + if block["optional"]: + print(" block_{}(recursion+1);".format(index+1), file=f) + + if block["semioptional"]: + print(" if (!found_any_match) block_{}(recursion+1);".format(index+1), file=f) + + print(" {} = _pmg_backup_{};".format(block["cell"], block["cell"]), file=f) + + if block["genargs"] is not None: + print("#define finish do { rollback = -1; return; } while(0)", file=f) + print(" if (generate_mode && rng(100) < (found_any_match ? {} : {})) {{".format(block["genargs"][1], block["genargs"][0]), file=f) + for line in block["gencode"]: + print(" " + line, file=f) + print(" }", file=f) + print("#undef finish", file=f) + else: + assert False + + current_pattern = None + print(" }", file=f) + print("", file=f) + + print("};", file=f) + + if genhdr: + print("", file=f) + print("YOSYS_NAMESPACE_END", file=f) diff --git a/passes/pmgen/test_pmgen.cc b/passes/pmgen/test_pmgen.cc new file mode 100644 index 000000000..4f3eec935 --- /dev/null +++ b/passes/pmgen/test_pmgen.cc @@ -0,0 +1,385 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * + * 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 + +// for peepopt_pm +bool did_something; + +#include "passes/pmgen/test_pmgen_pm.h" +#include "passes/pmgen/ice40_dsp_pm.h" +#include "passes/pmgen/xilinx_srl_pm.h" +#include "passes/pmgen/peepopt_pm.h" + +void reduce_chain(test_pmgen_pm &pm) +{ + auto &st = pm.st_reduce; + auto &ud = pm.ud_reduce; + + if (ud.longest_chain.empty()) + return; + + log("Found chain of length %d (%s):\n", GetSize(ud.longest_chain), log_id(st.first->type)); + + SigSpec A; + SigSpec Y = ud.longest_chain.front().first->getPort(ID(Y)); + auto last_cell = ud.longest_chain.back().first; + + for (auto it : ud.longest_chain) { + auto cell = it.first; + if (cell == last_cell) { + A.append(cell->getPort(ID(A))); + A.append(cell->getPort(ID(B))); + } else { + A.append(cell->getPort(it.second == ID(A) ? ID(B) : ID(A))); + } + log(" %s\n", log_id(cell)); + pm.autoremove(cell); + } + + Cell *c; + + if (last_cell->type == ID($_AND_)) + c = pm.module->addReduceAnd(NEW_ID, A, Y); + else if (last_cell->type == ID($_OR_)) + c = pm.module->addReduceOr(NEW_ID, A, Y); + else if (last_cell->type == ID($_XOR_)) + c = pm.module->addReduceXor(NEW_ID, A, Y); + else + log_abort(); + + log(" -> %s (%s)\n", log_id(c), log_id(c->type)); +} + +void reduce_tree(test_pmgen_pm &pm) +{ + auto &st = pm.st_reduce; + auto &ud = pm.ud_reduce; + + if (ud.longest_chain.empty()) + return; + + SigSpec A = ud.leaves; + SigSpec Y = st.first->getPort(ID(Y)); + pm.autoremove(st.first); + + log("Found %s tree with %d leaves for %s (%s).\n", log_id(st.first->type), + GetSize(A), log_signal(Y), log_id(st.first)); + + Cell *c; + + if (st.first->type == ID($_AND_)) + c = pm.module->addReduceAnd(NEW_ID, A, Y); + else if (st.first->type == ID($_OR_)) + c = pm.module->addReduceOr(NEW_ID, A, Y); + else if (st.first->type == ID($_XOR_)) + c = pm.module->addReduceXor(NEW_ID, A, Y); + else + log_abort(); + + log(" -> %s (%s)\n", log_id(c), log_id(c->type)); +} + +void opt_eqpmux(test_pmgen_pm &pm) +{ + auto &st = pm.st_eqpmux; + + SigSpec Y = st.pmux->getPort(ID::Y); + int width = GetSize(Y); + + SigSpec EQ = st.pmux->getPort(ID::B).extract(st.pmux_slice_eq*width, width); + SigSpec NE = st.pmux->getPort(ID::B).extract(st.pmux_slice_ne*width, width); + + log("Found eqpmux circuit driving %s (eq=%s, ne=%s, pmux=%s).\n", + log_signal(Y), log_id(st.eq), log_id(st.ne), log_id(st.pmux)); + + pm.autoremove(st.pmux); + Cell *c = pm.module->addMux(NEW_ID, NE, EQ, st.eq->getPort(ID::Y), Y); + log(" -> %s (%s)\n", log_id(c), log_id(c->type)); +} + +#define GENERATE_PATTERN(pmclass, pattern) \ + generate_pattern<pmclass>([](pmclass &pm, std::function<void()> f){ return pm.run_ ## pattern(f); }, #pmclass, #pattern, design) + +void pmtest_addports(Module *module) +{ + pool<SigBit> driven_bits, used_bits; + SigMap sigmap(module); + int icnt = 0, ocnt = 0; + + for (auto cell : module->cells()) + for (auto conn : cell->connections()) + { + if (cell->input(conn.first)) + for (auto bit : sigmap(conn.second)) + used_bits.insert(bit); + if (cell->output(conn.first)) + for (auto bit : sigmap(conn.second)) + driven_bits.insert(bit); + } + + for (auto wire : vector<Wire*>(module->wires())) + { + SigSpec ibits, obits; + for (auto bit : sigmap(wire)) { + if (!used_bits.count(bit)) + obits.append(bit); + if (!driven_bits.count(bit)) + ibits.append(bit); + } + if (!ibits.empty()) { + Wire *w = module->addWire(stringf("\\i%d", icnt++), GetSize(ibits)); + w->port_input = true; + module->connect(ibits, w); + } + if (!obits.empty()) { + Wire *w = module->addWire(stringf("\\o%d", ocnt++), GetSize(obits)); + w->port_output = true; + module->connect(w, obits); + } + } + + module->fixup_ports(); +} + +template <class pm> +void generate_pattern(std::function<void(pm&,std::function<void()>)> run, const char *pmclass, const char *pattern, Design *design) +{ + log("Generating \"%s\" patterns for pattern matcher \"%s\".\n", pattern, pmclass); + + int modcnt = 0; + int maxmodcnt = 100; + int maxsubcnt = 4; + int timeout = 0; + vector<Module*> mods; + + while (modcnt < maxmodcnt) + { + int submodcnt = 0, itercnt = 0, cellcnt = 0; + Module *mod = design->addModule(NEW_ID); + + while (modcnt < maxmodcnt && submodcnt < maxsubcnt && itercnt++ < 1000) + { + if (timeout++ > 10000) + log_error("pmgen generator is stuck: 10000 iterations with no matching module generated.\n"); + + pm matcher(mod, mod->cells()); + + matcher.rng(1); + matcher.rngseed += modcnt; + matcher.rng(1); + matcher.rngseed += submodcnt; + matcher.rng(1); + matcher.rngseed += itercnt; + matcher.rng(1); + matcher.rngseed += cellcnt; + matcher.rng(1); + + if (GetSize(mod->cells()) != cellcnt) + { + bool found_match = false; + run(matcher, [&](){ found_match = true; }); + cellcnt = GetSize(mod->cells()); + + if (found_match) { + Module *m = design->addModule(stringf("\\pmtest_%s_%s_%05d", + pmclass, pattern, modcnt++)); + log("Creating module %s with %d cells.\n", log_id(m), cellcnt); + mod->cloneInto(m); + pmtest_addports(m); + mods.push_back(m); + submodcnt++; + timeout = 0; + } + } + + matcher.generate_mode = true; + run(matcher, [](){}); + } + + if (submodcnt && maxsubcnt < (1 << 16)) + maxsubcnt *= 2; + + design->remove(mod); + } + + Module *m = design->addModule(stringf("\\pmtest_%s_%s", pmclass, pattern)); + log("Creating module %s with %d cells.\n", log_id(m), GetSize(mods)); + for (auto mod : mods) { + Cell *c = m->addCell(mod->name, mod->name); + for (auto port : mod->ports) { + Wire *w = m->addWire(NEW_ID, GetSize(mod->wire(port))); + c->setPort(port, w); + } + } + pmtest_addports(m); +} + +struct TestPmgenPass : public Pass { + TestPmgenPass() : Pass("test_pmgen", "test pass for pmgen") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" test_pmgen -reduce_chain [options] [selection]\n"); + log("\n"); + log("Demo for recursive pmgen patterns. Map chains of AND/OR/XOR to $reduce_*.\n"); + log("\n"); + + log("\n"); + log(" test_pmgen -reduce_tree [options] [selection]\n"); + log("\n"); + log("Demo for recursive pmgen patterns. Map trees of AND/OR/XOR to $reduce_*.\n"); + log("\n"); + + log("\n"); + log(" test_pmgen -eqpmux [options] [selection]\n"); + log("\n"); + log("Demo for recursive pmgen patterns. Optimize EQ/NE/PMUX circuits.\n"); + log("\n"); + + log("\n"); + log(" test_pmgen -generate [options] <pattern_name>\n"); + log("\n"); + log("Create modules that match the specified pattern.\n"); + log("\n"); + } + + void execute_reduce_chain(std::vector<std::string> args, RTLIL::Design *design) + { + log_header(design, "Executing TEST_PMGEN pass (-reduce_chain).\n"); + + size_t argidx; + for (argidx = 2; argidx < args.size(); argidx++) + { + // if (args[argidx] == "-singleton") { + // singleton_mode = true; + // continue; + // } + break; + } + extra_args(args, argidx, design); + + for (auto module : design->selected_modules()) + while (test_pmgen_pm(module, module->selected_cells()).run_reduce(reduce_chain)) {} + } + + void execute_reduce_tree(std::vector<std::string> args, RTLIL::Design *design) + { + log_header(design, "Executing TEST_PMGEN pass (-reduce_tree).\n"); + + size_t argidx; + for (argidx = 2; argidx < args.size(); argidx++) + { + // if (args[argidx] == "-singleton") { + // singleton_mode = true; + // continue; + // } + break; + } + extra_args(args, argidx, design); + + for (auto module : design->selected_modules()) + test_pmgen_pm(module, module->selected_cells()).run_reduce(reduce_tree); + } + + void execute_eqpmux(std::vector<std::string> args, RTLIL::Design *design) + { + log_header(design, "Executing TEST_PMGEN pass (-eqpmux).\n"); + + size_t argidx; + for (argidx = 2; argidx < args.size(); argidx++) + { + // if (args[argidx] == "-singleton") { + // singleton_mode = true; + // continue; + // } + break; + } + extra_args(args, argidx, design); + + for (auto module : design->selected_modules()) + test_pmgen_pm(module, module->selected_cells()).run_eqpmux(opt_eqpmux); + } + + void execute_generate(std::vector<std::string> args, RTLIL::Design *design) + { + log_header(design, "Executing TEST_PMGEN pass (-generate).\n"); + + size_t argidx; + for (argidx = 2; argidx < args.size(); argidx++) + { + // if (args[argidx] == "-singleton") { + // singleton_mode = true; + // continue; + // } + break; + } + + if (argidx+1 != args.size()) + log_cmd_error("Expected exactly one pattern.\n"); + + string pattern = args[argidx]; + + if (pattern == "reduce") + return GENERATE_PATTERN(test_pmgen_pm, reduce); + + if (pattern == "eqpmux") + return GENERATE_PATTERN(test_pmgen_pm, eqpmux); + + if (pattern == "ice40_dsp") + return GENERATE_PATTERN(ice40_dsp_pm, ice40_dsp); + + if (pattern == "xilinx_srl.fixed") + return GENERATE_PATTERN(xilinx_srl_pm, fixed); + if (pattern == "xilinx_srl.variable") + return GENERATE_PATTERN(xilinx_srl_pm, variable); + + if (pattern == "peepopt-muldiv") + return GENERATE_PATTERN(peepopt_pm, muldiv); + + if (pattern == "peepopt-shiftmul") + return GENERATE_PATTERN(peepopt_pm, shiftmul); + + log_cmd_error("Unknown pattern: %s\n", pattern.c_str()); + } + + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + if (GetSize(args) > 1) + { + if (args[1] == "-reduce_chain") + return execute_reduce_chain(args, design); + if (args[1] == "-reduce_tree") + return execute_reduce_tree(args, design); + if (args[1] == "-eqpmux") + return execute_eqpmux(args, design); + if (args[1] == "-generate") + return execute_generate(args, design); + } + help(); + log_cmd_error("Missing or unsupported mode parameter.\n"); + } +} TestPmgenPass; + +PRIVATE_NAMESPACE_END diff --git a/passes/pmgen/test_pmgen.pmg b/passes/pmgen/test_pmgen.pmg new file mode 100644 index 000000000..287ed97d8 --- /dev/null +++ b/passes/pmgen/test_pmgen.pmg @@ -0,0 +1,189 @@ +pattern reduce + +state <IdString> portname +udata <vector<pair<Cell*, IdString>>> chain longest_chain +udata <pool<Cell*>> non_first_cells +udata <SigSpec> leaves + +code + non_first_cells.clear(); + subpattern(setup); +endcode + +match first + select first->type.in($_AND_, $_OR_, $_XOR_) + filter !non_first_cells.count(first) +generate + SigSpec A = module->addWire(NEW_ID); + SigSpec B = module->addWire(NEW_ID); + SigSpec Y = module->addWire(NEW_ID); + switch (rng(3)) + { + case 0: + module->addAndGate(NEW_ID, A, B, Y); + break; + case 1: + module->addOrGate(NEW_ID, A, B, Y); + break; + case 2: + module->addXorGate(NEW_ID, A, B, Y); + break; + } +endmatch + +code + leaves = SigSpec(); + longest_chain.clear(); + chain.push_back(make_pair(first, \A)); + subpattern(tail); + chain.back().second = \B; + subpattern(tail); +finally + chain.pop_back(); + log_assert(chain.empty()); + if (GetSize(longest_chain) > 1) + accept; +endcode + +// ------------------------------------------------------------------ + +subpattern setup + +match first + select first->type.in($_AND_, $_OR_, $_XOR_) +endmatch + +code portname + portname = \A; + branch; + portname = \B; +endcode + +match next + select next->type.in($_AND_, $_OR_, $_XOR_) + select nusers(port(next, \Y)) == 2 + index <IdString> next->type === first->type + index <SigSpec> port(next, \Y) === port(first, portname) +endmatch + +code + non_first_cells.insert(next); +endcode + +// ------------------------------------------------------------------ + +subpattern tail +arg first + +match next + semioptional + select next->type.in($_AND_, $_OR_, $_XOR_) + select nusers(port(next, \Y)) == 2 + index <IdString> next->type === chain.back().first->type + index <SigSpec> port(next, \Y) === port(chain.back().first, chain.back().second) +generate 10 + SigSpec A = module->addWire(NEW_ID); + SigSpec B = module->addWire(NEW_ID); + SigSpec Y = port(chain.back().first, chain.back().second); + Cell *c = module->addAndGate(NEW_ID, A, B, Y); + c->type = chain.back().first->type; +endmatch + +code + if (next) { + chain.push_back(make_pair(next, \A)); + subpattern(tail); + chain.back().second = \B; + subpattern(tail); + } else { + if (GetSize(chain) > GetSize(longest_chain)) + longest_chain = chain; + leaves.append(port(chain.back().first, chain.back().second)); + } +finally + if (next) + chain.pop_back(); +endcode + +// ================================================================== + +pattern eqpmux + +state <bool> eq_ne_signed +state <SigSpec> eq_inA eq_inB +state <int> pmux_slice_eq pmux_slice_ne + +match eq + select eq->type == $eq + choice <IdString> AB {\A, \B} + define <IdString> BA AB == \A ? \B : \A + set eq_inA port(eq, \A) + set eq_inB port(eq, \B) + set eq_ne_signed param(eq, \A_SIGNED).as_bool() +generate 100 10 + SigSpec A = module->addWire(NEW_ID, rng(7)+1); + SigSpec B = module->addWire(NEW_ID, rng(7)+1); + SigSpec Y = module->addWire(NEW_ID); + module->addEq(NEW_ID, A, B, Y, rng(2)); +endmatch + +match pmux + select pmux->type == $pmux + slice idx GetSize(port(pmux, \S)) + index <SigBit> port(pmux, \S)[idx] === port(eq, \Y) + set pmux_slice_eq idx +generate 100 10 + int width = rng(7) + 1; + int numsel = rng(4) + 1; + int idx = rng(numsel); + + SigSpec A = module->addWire(NEW_ID, width); + SigSpec Y = module->addWire(NEW_ID, width); + + SigSpec B, S; + for (int i = 0; i < numsel; i++) { + B.append(module->addWire(NEW_ID, width)); + S.append(i == idx ? port(eq, \Y) : module->addWire(NEW_ID)); + } + + module->addPmux(NEW_ID, A, B, S, Y); +endmatch + +match ne + select ne->type == $ne + choice <IdString> AB {\A, \B} + define <IdString> BA (AB == \A ? \B : \A) + index <SigSpec> port(ne, AB) === eq_inA + index <SigSpec> port(ne, BA) === eq_inB + index <int> param(ne, \A_SIGNED).as_bool() === eq_ne_signed +generate 100 10 + SigSpec A = eq_inA, B = eq_inB, Y; + if (rng(2)) { + std::swap(A, B); + } + if (rng(2)) { + for (auto bit : port(pmux, \S)) { + if (nusers(bit) < 2) + Y.append(bit); + } + if (GetSize(Y)) + Y = Y[rng(GetSize(Y))]; + else + Y = module->addWire(NEW_ID); + } else { + Y = module->addWire(NEW_ID); + } + module->addNe(NEW_ID, A, B, Y, rng(2)); +endmatch + +match pmux2 + select pmux2->type == $pmux + slice idx GetSize(port(pmux2, \S)) + index <Cell*> pmux2 === pmux + index <SigBit> port(pmux2, \S)[idx] === port(ne, \Y) + set pmux_slice_ne idx +endmatch + +code + accept; +endcode diff --git a/passes/pmgen/xilinx_srl.cc b/passes/pmgen/xilinx_srl.cc new file mode 100644 index 000000000..3d264e8d4 --- /dev/null +++ b/passes/pmgen/xilinx_srl.cc @@ -0,0 +1,258 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * (C) 2019 Eddie Hung <eddie@fpgeh.com> + * + * 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 + +#include "passes/pmgen/xilinx_srl_pm.h" + +void run_fixed(xilinx_srl_pm &pm) +{ + auto &st = pm.st_fixed; + auto &ud = pm.ud_fixed; + log("Found fixed chain of length %d (%s):\n", GetSize(ud.longest_chain), log_id(st.first->type)); + + SigSpec initval; + for (auto cell : ud.longest_chain) { + log_debug(" %s\n", log_id(cell)); + if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_), ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_))) { + SigBit Q = cell->getPort(ID(Q)); + log_assert(Q.wire); + auto it = Q.wire->attributes.find(ID(init)); + if (it != Q.wire->attributes.end()) { + auto &i = it->second[Q.offset]; + initval.append(i); + i = State::Sx; + } + else + initval.append(State::Sx); + } + else if (cell->type.in(ID(FDRE), ID(FDRE_1))) { + if (cell->parameters.at(ID(INIT), State::S0).as_bool()) + initval.append(State::S1); + else + initval.append(State::S0); + } + else + log_abort(); + pm.autoremove(cell); + } + + auto first_cell = ud.longest_chain.back(); + auto last_cell = ud.longest_chain.front(); + Cell *c = pm.module->addCell(NEW_ID, ID($__XILINX_SHREG_)); + pm.module->swap_names(c, first_cell); + + if (first_cell->type.in(ID($_DFF_N_), ID($_DFF_P_), ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_), ID(FDRE), ID(FDRE_1))) { + c->setParam(ID(DEPTH), GetSize(ud.longest_chain)); + c->setParam(ID(INIT), initval.as_const()); + if (first_cell->type.in(ID($_DFF_P_), ID($_DFFE_PN_), ID($_DFFE_PP_))) + c->setParam(ID(CLKPOL), 1); + else if (first_cell->type.in(ID($_DFF_N_), ID($DFFE_NN_), ID($_DFFE_NP_), ID(FDRE_1))) + c->setParam(ID(CLKPOL), 0); + else if (first_cell->type.in(ID(FDRE))) { + if (!first_cell->parameters.at(ID(IS_C_INVERTED), State::S0).as_bool()) + c->setParam(ID(CLKPOL), 1); + else + c->setParam(ID(CLKPOL), 0); + } + else + log_abort(); + if (first_cell->type.in(ID($_DFFE_NP_), ID($_DFFE_PP_))) + c->setParam(ID(ENPOL), 1); + else if (first_cell->type.in(ID($_DFFE_NN_), ID($_DFFE_PN_))) + c->setParam(ID(ENPOL), 0); + else + c->setParam(ID(ENPOL), 2); + + c->setPort(ID(C), first_cell->getPort(ID(C))); + c->setPort(ID(D), first_cell->getPort(ID(D))); + c->setPort(ID(Q), last_cell->getPort(ID(Q))); + c->setPort(ID(L), GetSize(ud.longest_chain)-1); + if (first_cell->type.in(ID($_DFF_N_), ID($_DFF_P_))) + c->setPort(ID(E), State::S1); + else if (first_cell->type.in(ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_))) + c->setPort(ID(E), first_cell->getPort(ID(E))); + else if (first_cell->type.in(ID(FDRE), ID(FDRE_1))) + c->setPort(ID(E), first_cell->getPort(ID(CE))); + else + log_abort(); + } + else + log_abort(); + + log(" -> %s (%s)\n", log_id(c), log_id(c->type)); +} + +void run_variable(xilinx_srl_pm &pm) +{ + auto &st = pm.st_variable; + auto &ud = pm.ud_variable; + + log("Found variable chain of length %d (%s):\n", GetSize(ud.chain), log_id(st.first->type)); + + SigSpec initval; + for (const auto &i : ud.chain) { + auto cell = i.first; + auto slice = i.second; + log_debug(" %s\n", log_id(cell)); + if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_), ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_), ID($dff), ID($dffe))) { + SigBit Q = cell->getPort(ID(Q))[slice]; + log_assert(Q.wire); + auto it = Q.wire->attributes.find(ID(init)); + if (it != Q.wire->attributes.end()) { + auto &i = it->second[Q.offset]; + initval.append(i); + i = State::Sx; + } + else + initval.append(State::Sx); + } + else + log_abort(); + } + pm.autoremove(st.shiftx); + + auto first_cell = ud.chain.back().first; + auto first_slice = ud.chain.back().second; + + Cell *c = pm.module->addCell(NEW_ID, ID($__XILINX_SHREG_)); + pm.module->swap_names(c, first_cell); + + if (first_cell->type.in(ID($_DFF_N_), ID($_DFF_P_), ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_), ID($dff), ID($dffe))) { + c->setParam(ID(DEPTH), GetSize(ud.chain)); + c->setParam(ID(INIT), initval.as_const()); + Const clkpol, enpol; + if (first_cell->type.in(ID($_DFF_P_), ID($_DFFE_PN_), ID($_DFFE_PP_))) + clkpol = 1; + else if (first_cell->type.in(ID($_DFF_N_), ID($DFFE_NN_), ID($_DFFE_NP_))) + clkpol = 0; + else if (first_cell->type.in(ID($dff), ID($dffe))) + clkpol = first_cell->getParam(ID(CLK_POLARITY)); + else + log_abort(); + if (first_cell->type.in(ID($_DFFE_NP_), ID($_DFFE_PP_))) + enpol = 1; + else if (first_cell->type.in(ID($_DFFE_NN_), ID($_DFFE_PN_))) + enpol = 0; + else if (first_cell->type.in(ID($dffe))) + enpol = first_cell->getParam(ID(EN_POLARITY)); + else + enpol = 2; + c->setParam(ID(CLKPOL), clkpol); + c->setParam(ID(ENPOL), enpol); + + if (first_cell->type.in(ID($_DFF_N_), ID($_DFF_P_), ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_))) + c->setPort(ID(C), first_cell->getPort(ID(C))); + else if (first_cell->type.in(ID($dff), ID($dffe))) + c->setPort(ID(C), first_cell->getPort(ID(CLK))); + else + log_abort(); + c->setPort(ID(D), first_cell->getPort(ID(D))[first_slice]); + c->setPort(ID(Q), st.shiftx->getPort(ID(Y))); + c->setPort(ID(L), st.shiftx->getPort(ID(B))); + if (first_cell->type.in(ID($_DFF_N_), ID($_DFF_P_), ID($dff))) + c->setPort(ID(E), State::S1); + else if (first_cell->type.in(ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_))) + c->setPort(ID(E), first_cell->getPort(ID(E))); + else if (first_cell->type.in(ID($dffe))) + c->setPort(ID(E), first_cell->getPort(ID(EN))); + else + log_abort(); + } + else + log_abort(); + + log(" -> %s (%s)\n", log_id(c), log_id(c->type)); +} + +struct XilinxSrlPass : public Pass { + XilinxSrlPass() : Pass("xilinx_srl", "Xilinx shift register extraction") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" xilinx_srl [options] [selection]\n"); + log("\n"); + log("This pass converts chains of built-in flops (bit-level: $_DFF_[NP]_, $_DFFE_*\n"); + log("and word-level: $dff, $dffe) as well as Xilinx flops (FDRE, FDRE_1) into a\n"); + log("$__XILINX_SHREG cell. Chains must be of the same cell type, clock, clock polarity,\n"); + log("enable, and enable polarity (where relevant).\n"); + log("Flops with resets cannot be mapped to Xilinx devices and will not be inferred."); + log("\n"); + log(" -minlen N\n"); + log(" min length of shift register (default = 3)\n"); + log("\n"); + log(" -fixed\n"); + log(" infer fixed-length shift registers.\n"); + log("\n"); + log(" -variable\n"); + log(" infer variable-length shift registers (i.e. fixed-length shifts where\n"); + log(" each element also fans-out to a $shiftx cell).\n"); + log("\n"); + } + + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + log_header(design, "Executing XILINX_SRL pass (Xilinx shift register extraction).\n"); + + bool fixed = false; + bool variable = false; + int minlen = 3; + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + if (args[argidx] == "-minlen" && argidx+1 < args.size()) { + minlen = atoi(args[++argidx].c_str()); + continue; + } + if (args[argidx] == "-fixed") { + fixed = true; + continue; + } + if (args[argidx] == "-variable") { + variable = true; + continue; + } + break; + } + extra_args(args, argidx, design); + + if (!fixed && !variable) + log_cmd_error("'-fixed' and/or '-variable' must be specified.\n"); + + for (auto module : design->selected_modules()) { + auto pm = xilinx_srl_pm(module, module->selected_cells()); + pm.ud_fixed.minlen = minlen; + pm.ud_variable.minlen = minlen; + + if (fixed) + pm.run_fixed(run_fixed); + if (variable) + pm.run_variable(run_variable); + } + } +} XilinxSrlPass; + +PRIVATE_NAMESPACE_END diff --git a/passes/pmgen/xilinx_srl.pmg b/passes/pmgen/xilinx_srl.pmg new file mode 100644 index 000000000..b18119b87 --- /dev/null +++ b/passes/pmgen/xilinx_srl.pmg @@ -0,0 +1,326 @@ +pattern fixed + +state <IdString> clk_port en_port +udata <vector<Cell*>> chain longest_chain +udata <pool<Cell*>> non_first_cells +udata <int> minlen + +code + non_first_cells.clear(); + subpattern(setup); +endcode + +match first + select first->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_, \FDRE, \FDRE_1) + select !first->has_keep_attr() + select !first->type.in(\FDRE) || !first->parameters.at(\IS_R_INVERTED, State::S0).as_bool() + select !first->type.in(\FDRE) || !first->parameters.at(\IS_D_INVERTED, State::S0).as_bool() + select !first->type.in(\FDRE, \FDRE_1) || first->connections_.at(\R, State::S0).is_fully_zero() + filter !non_first_cells.count(first) +generate + SigSpec C = module->addWire(NEW_ID); + SigSpec D = module->addWire(NEW_ID); + SigSpec Q = module->addWire(NEW_ID); + auto r = rng(8); + Cell* cell; + switch (r) + { + case 0: + case 1: + cell = module->addCell(NEW_ID, \FDRE); + cell->setPort(\C, C); + cell->setPort(\D, D); + cell->setPort(\Q, Q); + cell->setPort(\CE, module->addWire(NEW_ID)); + if (r & 1) + cell->setPort(\R, module->addWire(NEW_ID)); + else { + if (rng(2) == 0) + cell->setPort(\R, State::S0); + } + break; + case 2: + case 3: + cell = module->addDffGate(NEW_ID, C, D, Q, r & 1); + break; + case 4: + case 5: + case 6: + case 7: + cell = module->addDffeGate(NEW_ID, C, module->addWire(NEW_ID), D, Q, r & 1, r & 2); + break; + default: log_abort(); + } +endmatch + +code clk_port en_port + if (first->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_, \FDRE, \FDRE_1)) + clk_port = \C; + else log_abort(); + if (first->type.in($_DFF_N_, $_DFF_P_)) + en_port = IdString(); + else if (first->type.in($_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_)) + en_port = \E; + else if (first->type.in(\FDRE, \FDRE_1)) + en_port = \CE; + else log_abort(); + + longest_chain.clear(); + chain.push_back(first); + subpattern(tail); +finally + chain.pop_back(); + log_assert(chain.empty()); + if (GetSize(longest_chain) >= minlen) + accept; +endcode + +// ------------------------------------------------------------------ + +subpattern setup +arg clk_port +arg en_port + +match first + select first->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_, \FDRE, \FDRE_1) + select !first->has_keep_attr() + select !first->type.in(\FDRE) || !first->parameters.at(\IS_R_INVERTED, State::S0).as_bool() + select !first->type.in(\FDRE) || !first->parameters.at(\IS_D_INVERTED, State::S0).as_bool() + select !first->type.in(\FDRE, \FDRE_1) || first->connections_.at(\R, State::S0).is_fully_zero() +endmatch + +code clk_port en_port + if (first->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_, \FDRE, \FDRE_1)) + clk_port = \C; + else log_abort(); + if (first->type.in($_DFF_N_, $_DFF_P_)) + en_port = IdString(); + else if (first->type.in($_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_)) + en_port = \E; + else if (first->type.in(\FDRE, \FDRE_1)) + en_port = \CE; + else log_abort(); +endcode + +match next + select next->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_, \FDRE, \FDRE_1) + select !next->has_keep_attr() + select port(next, \D)[0].wire && !port(next, \D)[0].wire->get_bool_attribute(\keep) + select nusers(port(next, \Q)) == 2 + index <IdString> next->type === first->type + index <SigBit> port(next, \Q) === port(first, \D) + filter port(next, clk_port) == port(first, clk_port) + filter en_port == IdString() || port(next, en_port) == port(first, en_port) + filter !first->type.in(\FDRE) || next->parameters.at(\IS_C_INVERTED, State::S0).as_bool() == first->parameters.at(\IS_C_INVERTED, State::S0).as_bool() + filter !first->type.in(\FDRE) || next->parameters.at(\IS_D_INVERTED, State::S0).as_bool() == first->parameters.at(\IS_D_INVERTED, State::S0).as_bool() + filter !first->type.in(\FDRE) || next->parameters.at(\IS_R_INVERTED, State::S0).as_bool() == first->parameters.at(\IS_R_INVERTED, State::S0).as_bool() + filter !first->type.in(\FDRE, \FDRE_1) || next->connections_.at(\R, State::S0).is_fully_zero() +endmatch + +code + non_first_cells.insert(next); +endcode + +// ------------------------------------------------------------------ + +subpattern tail +arg first +arg clk_port +arg en_port + +match next + semioptional + select next->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_, \FDRE, \FDRE_1) + select !next->has_keep_attr() + select port(next, \D)[0].wire && !port(next, \D)[0].wire->get_bool_attribute(\keep) + select nusers(port(next, \Q)) == 2 + index <IdString> next->type === chain.back()->type + index <SigBit> port(next, \Q) === port(chain.back(), \D) + filter port(next, clk_port) == port(first, clk_port) + filter en_port == IdString() || port(next, en_port) == port(first, en_port) + filter !first->type.in(\FDRE) || next->parameters.at(\IS_C_INVERTED, State::S0).as_bool() == first->parameters.at(\IS_C_INVERTED, State::S0).as_bool() + filter !first->type.in(\FDRE) || next->parameters.at(\IS_D_INVERTED, State::S0).as_bool() == first->parameters.at(\IS_D_INVERTED, State::S0).as_bool() + filter !first->type.in(\FDRE) || next->parameters.at(\IS_R_INVERTED, State::S0).as_bool() == first->parameters.at(\IS_R_INVERTED, State::S0).as_bool() + filter !first->type.in(\FDRE, \FDRE_1) || next->connections_.at(\R, State::S0).is_fully_zero() +generate + Cell *cell = module->addCell(NEW_ID, chain.back()->type); + cell->setPort(\C, chain.back()->getPort(\C)); + cell->setPort(\D, module->addWire(NEW_ID)); + cell->setPort(\Q, chain.back()->getPort(\D)); + if (cell->type == \FDRE) { + if (rng(2) == 0) + cell->setPort(\R, chain.back()->connections_.at(\R, State::S0)); + cell->setPort(\CE, chain.back()->getPort(\CE)); + } + else if (cell->type.begins_with("$_DFFE_")) + cell->setPort(\E, chain.back()->getPort(\E)); +endmatch + +code + if (next) { + chain.push_back(next); + subpattern(tail); + } else { + if (GetSize(chain) > GetSize(longest_chain)) + longest_chain = chain; + } +finally + if (next) + chain.pop_back(); +endcode + +// ----------- + +pattern variable + +state <IdString> clk_port en_port +state <int> shiftx_width +state <int> slice +udata <int> minlen +udata <vector<pair<Cell*,int>>> chain +udata <pool<SigBit>> chain_bits + +code + chain_bits.clear(); +endcode + +match shiftx + select shiftx->type.in($shiftx) + select !shiftx->has_keep_attr() + select param(shiftx, \Y_WIDTH).as_int() == 1 + filter param(shiftx, \A_WIDTH).as_int() >= minlen +generate + minlen = 3; + module->addShiftx(NEW_ID, module->addWire(NEW_ID, rng(6)+minlen), module->addWire(NEW_ID, 3), module->addWire(NEW_ID)); +endmatch + +code shiftx_width + shiftx_width = param(shiftx, \A_WIDTH).as_int(); +endcode + +match first + select first->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_, $dff, $dffe) + select !first->has_keep_attr() + select port(first, \Q)[0].wire && !port(first, \Q)[0].wire->get_bool_attribute(\keep) + slice idx GetSize(port(first, \Q)) + select nusers(port(first, \Q)[idx]) <= 2 + index <SigBit> port(first, \Q)[idx] === port(shiftx, \A)[shiftx_width-1] + set slice idx +generate + SigSpec C = module->addWire(NEW_ID); + auto WIDTH = rng(3)+1; + SigSpec D = module->addWire(NEW_ID, WIDTH); + SigSpec Q = module->addWire(NEW_ID, WIDTH); + auto r = rng(8); + Cell *cell = nullptr; + switch (r) + { + case 0: + case 1: + cell = module->addDff(NEW_ID, C, D, Q, r & 1); + break; + case 2: + case 3: + case 4: + case 5: + //cell = module->addDffe(NEW_ID, C, module->addWire(NEW_ID), D, Q, r & 1, r & 4); + //break; + case 6: + case 7: + WIDTH = 1; + cell = module->addDffGate(NEW_ID, C, D[0], Q[0], r & 1); + break; + default: log_abort(); + } + shiftx->connections_.at(\A)[shiftx_width-1] = port(cell, \Q)[rng(WIDTH)]; +endmatch + +code clk_port en_port + if (first->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_)) + clk_port = \C; + else if (first->type.in($dff, $dffe)) + clk_port = \CLK; + else log_abort(); + if (first->type.in($_DFF_N_, $_DFF_P_, $dff)) + en_port = IdString(); + else if (first->type.in($_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_)) + en_port = \E; + else if (first->type.in($dffe)) + en_port = \EN; + else log_abort(); + + chain_bits.insert(port(first, \Q)[slice]); + chain.emplace_back(first, slice); + subpattern(tail); +finally + if (GetSize(chain) == shiftx_width) + accept; + chain.clear(); +endcode + +// ------------------------------------------------------------------ + +subpattern tail +arg first +arg shiftx +arg shiftx_width +arg slice +arg clk_port +arg en_port + +match next + semioptional + select next->type.in($_DFF_N_, $_DFF_P_, $_DFFE_NN_, $_DFFE_NP_, $_DFFE_PN_, $_DFFE_PP_, $dff, $dffe) + select !next->has_keep_attr() + select port(next, \D)[0].wire && !port(next, \D)[0].wire->get_bool_attribute(\keep) + slice idx GetSize(port(next, \Q)) + select nusers(port(next, \Q)[idx]) <= 3 + index <IdString> next->type === chain.back().first->type + index <SigBit> port(next, \Q)[idx] === port(chain.back().first, \D)[chain.back().second] + index <SigBit> port(next, \Q)[idx] === port(shiftx, \A)[shiftx_width-1-GetSize(chain)] + filter port(next, clk_port) == port(first, clk_port) + filter en_port == IdString() || port(next, en_port) == port(first, en_port) + filter !next->type.in($dff, $dffe) || param(next, \CLK_POLARITY).as_bool() == param(first, \CLK_POLARITY).as_bool() + filter !next->type.in($dffe) || param(next, \EN_POLARITY).as_bool() == param(first, \EN_POLARITY).as_bool() + filter !chain_bits.count(port(next, \D)[idx]) + set slice idx +generate + if (GetSize(chain) < shiftx_width) { + auto back = chain.back().first; + auto slice = chain.back().second; + if (back->type.in($dff, $dffe)) { + auto WIDTH = GetSize(port(back, \D)); + if (rng(2) == 0 && slice < WIDTH-1) { + auto new_slice = slice + rng(WIDTH-1-slice); + back->connections_.at(\D)[slice] = port(back, \Q)[new_slice]; + } + else { + auto D = module->addWire(NEW_ID, WIDTH); + if (back->type == $dff) + module->addDff(NEW_ID, port(back, \CLK), D, port(back, \D), param(back, \CLK_POLARITY).as_bool()); + else if (back->type == $dffe) + module->addDffe(NEW_ID, port(back, \CLK), port(back, \EN), D, port(back, \D), param(back, \CLK_POLARITY).as_bool(), param(back, \EN_POLARITY).as_bool()); + else + log_abort(); + } + } + else if (back->type.begins_with("$_DFF_")) { + Cell *cell = module->addCell(NEW_ID, back->type); + cell->setPort(\C, back->getPort(\C)); + cell->setPort(\D, module->addWire(NEW_ID)); + cell->setPort(\Q, back->getPort(\D)); + } + else + log_abort(); + shiftx->connections_.at(\A)[shiftx_width-1-GetSize(chain)] = port(back, \D)[slice]; + } +endmatch + +code + if (next) { + chain_bits.insert(port(next, \Q)[slice]); + chain.emplace_back(next, slice); + if (GetSize(chain) < shiftx_width) + subpattern(tail); + } +endcode diff --git a/passes/proc/Makefile.inc b/passes/proc/Makefile.inc index 397fe46a1..4b56979f8 100644 --- a/passes/proc/Makefile.inc +++ b/passes/proc/Makefile.inc @@ -1,5 +1,6 @@ OBJS += passes/proc/proc.o +OBJS += passes/proc/proc_prune.o OBJS += passes/proc/proc_clean.o OBJS += passes/proc/proc_rmdead.o OBJS += passes/proc/proc_init.o @@ -7,4 +8,3 @@ OBJS += passes/proc/proc_arst.o OBJS += passes/proc/proc_mux.o OBJS += passes/proc/proc_dlatch.o OBJS += passes/proc/proc_dff.o - diff --git a/passes/proc/proc.cc b/passes/proc/proc.cc index d5366f266..a5b4a3112 100644 --- a/passes/proc/proc.cc +++ b/passes/proc/proc.cc @@ -27,7 +27,7 @@ PRIVATE_NAMESPACE_BEGIN struct ProcPass : public Pass { ProcPass() : Pass("proc", "translate processes to netlists") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -37,6 +37,7 @@ struct ProcPass : public Pass { log("\n"); log(" proc_clean\n"); log(" proc_rmdead\n"); + log(" proc_prune\n"); log(" proc_init\n"); log(" proc_arst\n"); log(" proc_mux\n"); @@ -57,7 +58,7 @@ struct ProcPass : public Pass { log(" executed in -ifx mode.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { std::string global_arst; bool ifxmode = false; @@ -83,6 +84,7 @@ struct ProcPass : public Pass { Pass::call(design, "proc_clean"); if (!ifxmode) Pass::call(design, "proc_rmdead"); + Pass::call(design, "proc_prune"); Pass::call(design, "proc_init"); if (global_arst.empty()) Pass::call(design, "proc_arst"); diff --git a/passes/proc/proc_arst.cc b/passes/proc/proc_arst.cc index 216b00ddd..c606deb88 100644 --- a/passes/proc/proc_arst.cc +++ b/passes/proc/proc_arst.cc @@ -55,7 +55,7 @@ bool check_signal(RTLIL::Module *mod, RTLIL::SigSpec signal, RTLIL::SigSpec ref, return check_signal(mod, cell->getPort("\\A"), ref, polarity); } - if ((cell->type == "$eq" || cell->type == "$eqx") && cell->getPort("\\Y") == signal) { + if (cell->type.in("$eq", "$eqx") && cell->getPort("\\Y") == signal) { if (cell->getPort("\\A").is_fully_const()) { if (!cell->getPort("\\A").as_bool()) polarity = !polarity; @@ -68,7 +68,7 @@ bool check_signal(RTLIL::Module *mod, RTLIL::SigSpec signal, RTLIL::SigSpec ref, } } - if ((cell->type == "$ne" || cell->type == "$nex") && cell->getPort("\\Y") == signal) { + if (cell->type.in("$ne", "$nex") && cell->getPort("\\Y") == signal) { if (cell->getPort("\\A").is_fully_const()) { if (cell->getPort("\\A").as_bool()) polarity = !polarity; @@ -172,7 +172,7 @@ restart_proc_arst: sync->type = sync->type == RTLIL::SyncType::STp ? RTLIL::SyncType::ST1 : RTLIL::SyncType::ST0; } for (auto &action : sync->actions) { - RTLIL::SigSpec rspec = action.second; + RTLIL::SigSpec rspec = assign_map(action.second); RTLIL::SigSpec rval = RTLIL::SigSpec(RTLIL::State::Sm, rspec.size()); for (int i = 0; i < GetSize(rspec); i++) if (rspec[i].wire == NULL) @@ -203,7 +203,7 @@ restart_proc_arst: struct ProcArstPass : public Pass { ProcArstPass() : Pass("proc_arst", "detect asynchronous resets") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -221,7 +221,7 @@ struct ProcArstPass : public Pass { log(" in the 'init' attribute on the net.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { std::string global_arst; bool global_arst_neg = false; diff --git a/passes/proc/proc_clean.cc b/passes/proc/proc_clean.cc index 7dbabc211..114c6ab03 100644 --- a/passes/proc/proc_clean.cc +++ b/passes/proc/proc_clean.cc @@ -69,26 +69,49 @@ void proc_clean_switch(RTLIL::SwitchRule *sw, RTLIL::CaseRule *parent, bool &did did_something = true; for (auto &action : sw->cases[0]->actions) parent->actions.push_back(action); - for (auto sw2 : sw->cases[0]->switches) - parent->switches.push_back(sw2); + parent->switches.insert(parent->switches.begin(), sw->cases[0]->switches.begin(), sw->cases[0]->switches.end()); sw->cases[0]->switches.clear(); delete sw->cases[0]; sw->cases.clear(); } else { - bool all_cases_are_empty = true; - for (auto cs : sw->cases) { - if (cs->actions.size() != 0 || cs->switches.size() != 0) - all_cases_are_empty = false; + bool all_fully_def = true; + for (auto cs : sw->cases) + { if (max_depth != 0) proc_clean_case(cs, did_something, count, max_depth-1); + int size = 0; + for (auto cmp : cs->compare) + { + size += cmp.size(); + if (!cmp.is_fully_def()) + all_fully_def = false; + } + if (sw->signal.size() != size) + all_fully_def = false; } - if (all_cases_are_empty) { - did_something = true; - for (auto cs : sw->cases) - delete cs; - sw->cases.clear(); + if (all_fully_def) + { + for (auto cs = sw->cases.begin(); cs != sw->cases.end();) + { + if ((*cs)->empty()) + { + did_something = true; + delete *cs; + cs = sw->cases.erase(cs); + } + else ++cs; + } + } + else + { + while (!sw->cases.empty() && sw->cases.back()->empty()) + { + did_something = true; + delete sw->cases.back(); + sw->cases.pop_back(); + } } } } @@ -106,7 +129,7 @@ void proc_clean_case(RTLIL::CaseRule *cs, bool &did_something, int &count, int m } for (size_t i = 0; i < cs->switches.size(); i++) { RTLIL::SwitchRule *sw = cs->switches[i]; - if (sw->cases.size() == 0) { + if (sw->empty()) { cs->switches.erase(cs->switches.begin() + (i--)); did_something = true; delete sw; @@ -119,7 +142,7 @@ void proc_clean_case(RTLIL::CaseRule *cs, bool &did_something, int &count, int m YOSYS_NAMESPACE_END PRIVATE_NAMESPACE_BEGIN -void proc_clean(RTLIL::Module *mod, RTLIL::Process *proc, int &total_count) +void proc_clean(RTLIL::Module *mod, RTLIL::Process *proc, int &total_count, bool quiet) { int count = 0; bool did_something = true; @@ -136,29 +159,43 @@ void proc_clean(RTLIL::Module *mod, RTLIL::Process *proc, int &total_count) did_something = false; proc_clean_case(&proc->root_case, did_something, count, -1); } - if (count > 0) + if (count > 0 && !quiet) log("Found and cleaned up %d empty switch%s in `%s.%s'.\n", count, count == 1 ? "" : "es", mod->name.c_str(), proc->name.c_str()); total_count += count; } struct ProcCleanPass : public Pass { ProcCleanPass() : Pass("proc_clean", "remove empty parts of processes") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); - log(" proc_clean [selection]\n"); + log(" proc_clean [options] [selection]\n"); + log("\n"); + log(" -quiet\n"); + log(" do not print any messages.\n"); log("\n"); log("This pass removes empty parts of processes and ultimately removes a process\n"); log("if it contains only empty structures.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { int total_count = 0; - log_header(design, "Executing PROC_CLEAN pass (remove empty switches from decision trees).\n"); + bool quiet = false; + + if (find(args.begin(), args.end(), "-quiet") == args.end()) + log_header(design, "Executing PROC_CLEAN pass (remove empty switches from decision trees).\n"); - extra_args(args, 1, design); + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + if (args[argidx] == "-quiet") { + quiet = true; + continue; + } + } + extra_args(args, argidx, design); for (auto mod : design->modules()) { std::vector<RTLIL::IdString> delme; @@ -167,10 +204,11 @@ struct ProcCleanPass : public Pass { for (auto &proc_it : mod->processes) { if (!design->selected(mod, proc_it.second)) continue; - proc_clean(mod, proc_it.second, total_count); + proc_clean(mod, proc_it.second, total_count, quiet); if (proc_it.second->syncs.size() == 0 && proc_it.second->root_case.switches.size() == 0 && proc_it.second->root_case.actions.size() == 0) { - log("Removing empty process `%s.%s'.\n", log_id(mod), proc_it.second->name.c_str()); + if (!quiet) + log("Removing empty process `%s.%s'.\n", log_id(mod), proc_it.second->name.c_str()); delme.push_back(proc_it.first); } } @@ -180,7 +218,8 @@ struct ProcCleanPass : public Pass { } } - log("Cleaned up %d empty switch%s.\n", total_count, total_count == 1 ? "" : "es"); + if (!quiet) + log("Cleaned up %d empty switch%s.\n", total_count, total_count == 1 ? "" : "es"); } } ProcCleanPass; diff --git a/passes/proc/proc_dff.cc b/passes/proc/proc_dff.cc index f732baa17..519d35cd6 100644 --- a/passes/proc/proc_dff.cc +++ b/passes/proc/proc_dff.cc @@ -370,7 +370,7 @@ void proc_dff(RTLIL::Module *mod, RTLIL::Process *proc, ConstEval &ce) struct ProcDffPass : public Pass { ProcDffPass() : Pass("proc_dff", "extract flip-flops from processes") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -380,7 +380,7 @@ struct ProcDffPass : public Pass { log("d-type flip-flop cells.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing PROC_DFF pass (convert process syncs to FFs).\n"); diff --git a/passes/proc/proc_dlatch.cc b/passes/proc/proc_dlatch.cc index 15200ec12..d9d5dfbed 100644 --- a/passes/proc/proc_dlatch.cc +++ b/passes/proc/proc_dlatch.cc @@ -422,7 +422,7 @@ void proc_dlatch(proc_dlatch_db_t &db, RTLIL::Process *proc) struct ProcDlatchPass : public Pass { ProcDlatchPass() : Pass("proc_dlatch", "extract latches from processes") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -432,7 +432,7 @@ struct ProcDlatchPass : public Pass { log("d-type latches.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing PROC_DLATCH pass (convert process syncs to latches).\n"); diff --git a/passes/proc/proc_init.cc b/passes/proc/proc_init.cc index 0c8fb83dc..462a384b7 100644 --- a/passes/proc/proc_init.cc +++ b/passes/proc/proc_init.cc @@ -26,21 +26,7 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN -void proc_get_const(RTLIL::SigSpec &sig, RTLIL::CaseRule &rule) -{ - log_assert(rule.compare.size() == 0); - - while (1) { - RTLIL::SigSpec tmp = sig; - for (auto &it : rule.actions) - tmp.replace(it.first, it.second); - if (tmp == sig) - break; - sig = tmp; - } -} - -void proc_init(RTLIL::Module *mod, RTLIL::Process *proc) +void proc_init(RTLIL::Module *mod, SigMap &sigmap, RTLIL::Process *proc) { bool found_init = false; @@ -53,9 +39,7 @@ void proc_init(RTLIL::Module *mod, RTLIL::Process *proc) for (auto &action : sync->actions) { RTLIL::SigSpec lhs = action.first; - RTLIL::SigSpec rhs = action.second; - - proc_get_const(rhs, proc->root_case); + RTLIL::SigSpec rhs = sigmap(action.second); if (!rhs.is_fully_const()) log_cmd_error("Failed to get a constant init value for %s: %s\n", log_signal(lhs), log_signal(rhs)); @@ -102,7 +86,7 @@ void proc_init(RTLIL::Module *mod, RTLIL::Process *proc) struct ProcInitPass : public Pass { ProcInitPass() : Pass("proc_init", "convert initial block to init attributes") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -113,17 +97,19 @@ struct ProcInitPass : public Pass { log("respective wire.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing PROC_INIT pass (extract init attributes).\n"); extra_args(args, 1, design); for (auto mod : design->modules()) - if (design->selected(mod)) + if (design->selected(mod)) { + SigMap sigmap(mod); for (auto &proc_it : mod->processes) if (design->selected(mod, proc_it.second)) - proc_init(mod, proc_it.second); + proc_init(mod, sigmap, proc_it.second); + } } } ProcInitPass; diff --git a/passes/proc/proc_mux.cc b/passes/proc/proc_mux.cc index 57e131ca5..d029282fd 100644 --- a/passes/proc/proc_mux.cc +++ b/passes/proc/proc_mux.cc @@ -108,6 +108,7 @@ struct SigSnippets struct SnippetSwCache { + dict<RTLIL::SwitchRule*, pool<RTLIL::SigBit>, hash_ptr_ops> full_case_bits_cache; dict<RTLIL::SwitchRule*, pool<int>, hash_ptr_ops> cache; const SigSnippets *snippets; int current_snippet; @@ -143,7 +144,13 @@ struct SnippetSwCache } }; -RTLIL::SigSpec gen_cmp(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::vector<RTLIL::SigSpec> &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<RTLIL::SigSpec> &compare, RTLIL::SwitchRule *sw, RTLIL::CaseRule *cs, bool ifxmode) { std::stringstream sstr; sstr << "$procmux$" << (autoidx++); @@ -172,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); @@ -198,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); @@ -211,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<RTLIL::SigSpec> &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<RTLIL::SigSpec> &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()); @@ -223,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); @@ -233,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); @@ -245,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<RTLIL::SigSpec> &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<RTLIL::SigSpec> &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()); @@ -253,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"; @@ -268,6 +275,49 @@ void append_pmux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::ve last_mux_cell->parameters["\\S_WIDTH"] = last_mux_cell->getPort("\\S").size(); } +const pool<SigBit> &get_full_case_bits(SnippetSwCache &swcache, RTLIL::SwitchRule *sw) +{ + if (!swcache.full_case_bits_cache.count(sw)) + { + pool<SigBit> bits; + + if (sw->get_bool_attribute("\\full_case")) + { + bool first_case = true; + + for (auto cs : sw->cases) + { + pool<SigBit> case_bits; + + for (auto it : cs->actions) { + for (auto bit : it.first) + case_bits.insert(bit); + } + + for (auto it : cs->switches) { + for (auto bit : get_full_case_bits(swcache, it)) + case_bits.insert(bit); + } + + if (first_case) { + first_case = false; + bits = case_bits; + } else { + pool<SigBit> new_bits; + for (auto bit : bits) + if (case_bits.count(bit)) + new_bits.insert(bit); + bits.swap(new_bits); + } + } + } + + bits.swap(swcache.full_case_bits_cache[sw]); + } + + return swcache.full_case_bits_cache.at(sw); +} + RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, dict<RTLIL::SwitchRule*, bool, hash_ptr_ops> &swpara, RTLIL::CaseRule *cs, const RTLIL::SigSpec &sig, const RTLIL::SigSpec &defval, bool ifxmode) { @@ -337,6 +387,12 @@ RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, d } } + // mask default bits that are irrelevant because the output is driven by a full case + const pool<SigBit> &full_case_bits = get_full_case_bits(swcache, sw); + for (int i = 0; i < GetSize(sig); i++) + if (full_case_bits.count(sig[i])) + result[i] = State::Sx; + // evaluate in reverse order to give the first entry the top priority RTLIL::SigSpec initial_val = result; RTLIL::Cell *last_mux_cell = NULL; @@ -345,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); } } @@ -382,7 +438,7 @@ void proc_mux(RTLIL::Module *mod, RTLIL::Process *proc, bool ifxmode) struct ProcMuxPass : public Pass { ProcMuxPass() : Pass("proc_mux", "convert decision trees to multiplexers") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -396,7 +452,7 @@ struct ProcMuxPass : public Pass { log(" 'case' expressions and 'if' conditions.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { bool ifxmode = false; log_header(design, "Executing PROC_MUX pass (convert decision trees to multiplexers).\n"); diff --git a/passes/proc/proc_prune.cc b/passes/proc/proc_prune.cc new file mode 100644 index 000000000..d4aee9df0 --- /dev/null +++ b/passes/proc/proc_prune.cc @@ -0,0 +1,165 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2019 whitequark <whitequark@whitequark.org> + * + * 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/register.h" +#include "kernel/sigtools.h" +#include "kernel/log.h" +#include <stdlib.h> +#include <stdio.h> + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct PruneWorker +{ + RTLIL::Module *module; + SigMap sigmap; + + int removed_count = 0, promoted_count = 0; + + PruneWorker(RTLIL::Module *mod) : module(mod), sigmap(mod) {} + + pool<RTLIL::SigBit> do_switch(RTLIL::SwitchRule *sw, pool<RTLIL::SigBit> assigned, pool<RTLIL::SigBit> &affected) + { + pool<RTLIL::SigBit> all_assigned; + bool full_case = sw->get_bool_attribute("\\full_case"); + bool first = true; + for (auto it : sw->cases) { + if (it->compare.empty()) + full_case = true; + pool<RTLIL::SigBit> case_assigned = do_case(it, assigned, affected); + if (first) { + first = false; + all_assigned = case_assigned; + } else { + for (auto &bit : all_assigned) + if (!case_assigned[bit]) + all_assigned.erase(bit); + } + } + if (full_case) + assigned.insert(all_assigned.begin(), all_assigned.end()); + return assigned; + } + + pool<RTLIL::SigBit> do_case(RTLIL::CaseRule *cs, pool<RTLIL::SigBit> assigned, pool<RTLIL::SigBit> &affected, + bool root = false) + { + for (auto it = cs->switches.rbegin(); it != cs->switches.rend(); ++it) { + pool<RTLIL::SigBit> sw_assigned = do_switch((*it), assigned, affected); + assigned.insert(sw_assigned.begin(), sw_assigned.end()); + } + for (auto it = cs->actions.rbegin(); it != cs->actions.rend(); ) { + RTLIL::SigSpec lhs = sigmap(it->first); + bool redundant = true; + for (auto &bit : lhs) { + if (bit.wire && !assigned[bit]) { + redundant = false; + break; + } + } + bool remove = false; + if (redundant) { + removed_count++; + remove = true; + } else { + if (root) { + bool promotable = true; + for (auto &bit : lhs) { + if (bit.wire && affected[bit] && !assigned[bit]) { + promotable = false; + break; + } + } + if (promotable) { + RTLIL::SigSpec rhs = sigmap(it->second); + RTLIL::SigSig conn; + for (int i = 0; i < GetSize(lhs); i++) { + RTLIL::SigBit lhs_bit = lhs[i]; + if (lhs_bit.wire && !assigned[lhs_bit]) { + conn.first.append_bit(lhs_bit); + conn.second.append(rhs.extract(i)); + } + } + promoted_count++; + module->connect(conn); + remove = true; + } + } + for (auto &bit : lhs) + if (bit.wire) + assigned.insert(bit); + for (auto &bit : lhs) + if (bit.wire) + affected.insert(bit); + } + if (remove) + cs->actions.erase((it++).base() - 1); + else it++; + } + return assigned; + } + + void do_process(RTLIL::Process *pr) + { + pool<RTLIL::SigBit> affected; + do_case(&pr->root_case, {}, affected, /*root=*/true); + } +}; + +struct ProcPrunePass : public Pass { + ProcPrunePass() : Pass("proc_prune", "remove redundant assignments") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" proc_prune [selection]\n"); + log("\n"); + log("This pass identifies assignments in processes that are always overwritten by\n"); + log("a later assignment to the same signal and removes them.\n"); + log("\n"); + } + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + int total_removed_count = 0, total_promoted_count = 0; + log_header(design, "Executing PROC_PRUNE pass (remove redundant assignments in processes).\n"); + + extra_args(args, 1, design); + + for (auto mod : design->modules()) { + if (!design->selected(mod)) + continue; + PruneWorker worker(mod); + for (auto &proc_it : mod->processes) { + if (!design->selected(mod, proc_it.second)) + continue; + worker.do_process(proc_it.second); + } + total_removed_count += worker.removed_count; + total_promoted_count += worker.promoted_count; + } + + log("Removed %d redundant assignment%s.\n", + total_removed_count, total_removed_count == 1 ? "" : "s"); + log("Promoted %d assignment%s to connection%s.\n", + total_promoted_count, total_promoted_count == 1 ? "" : "s", total_promoted_count == 1 ? "" : "s"); + } +} ProcPrunePass; + +PRIVATE_NAMESPACE_END diff --git a/passes/proc/proc_rmdead.cc b/passes/proc/proc_rmdead.cc index 5672fb475..4f40be446 100644 --- a/passes/proc/proc_rmdead.cc +++ b/passes/proc/proc_rmdead.cc @@ -28,7 +28,7 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN -void proc_rmdead(RTLIL::SwitchRule *sw, int &counter) +void proc_rmdead(RTLIL::SwitchRule *sw, int &counter, int &full_case_counter) { BitPatternPool pool(sw->signal); @@ -56,16 +56,21 @@ void proc_rmdead(RTLIL::SwitchRule *sw, int &counter) } for (auto switch_it : sw->cases[i]->switches) - proc_rmdead(switch_it, counter); + proc_rmdead(switch_it, counter, full_case_counter); if (is_default) pool.take_all(); } + + if (pool.empty() && !sw->get_bool_attribute("\\full_case")) { + sw->set_bool_attribute("\\full_case"); + full_case_counter++; + } } struct ProcRmdeadPass : public Pass { ProcRmdeadPass() : Pass("proc_rmdead", "eliminate dead trees in decision trees") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -74,7 +79,7 @@ struct ProcRmdeadPass : public Pass { log("This pass identifies unreachable branches in decision trees and removes them.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing PROC_RMDEAD pass (remove dead branches from decision trees).\n"); @@ -87,12 +92,15 @@ struct ProcRmdeadPass : public Pass { for (auto &proc_it : mod->processes) { if (!design->selected(mod, proc_it.second)) continue; - int counter = 0; + int counter = 0, full_case_counter = 0; for (auto switch_it : proc_it.second->root_case.switches) - proc_rmdead(switch_it, counter); + proc_rmdead(switch_it, counter, full_case_counter); if (counter > 0) log("Removed %d dead cases from process %s in module %s.\n", counter, - proc_it.first.c_str(), log_id(mod)); + log_id(proc_it.first), log_id(mod)); + if (full_case_counter > 0) + log("Marked %d switch rules as full_case in process %s in module %s.\n", + full_case_counter, log_id(proc_it.first), log_id(mod)); total_counter += counter; } } diff --git a/passes/sat/Makefile.inc b/passes/sat/Makefile.inc index 4fcce2fad..fc3ac879e 100644 --- a/passes/sat/Makefile.inc +++ b/passes/sat/Makefile.inc @@ -7,4 +7,9 @@ OBJS += passes/sat/miter.o OBJS += passes/sat/expose.o OBJS += passes/sat/assertpmux.o OBJS += passes/sat/clk2fflogic.o +OBJS += passes/sat/async2sync.o +OBJS += passes/sat/supercover.o +OBJS += passes/sat/fmcombine.o +OBJS += passes/sat/mutate.o +OBJS += passes/sat/cutpoint.o diff --git a/passes/sat/assertpmux.cc b/passes/sat/assertpmux.cc index 63a907671..3b432c461 100644 --- a/passes/sat/assertpmux.cc +++ b/passes/sat/assertpmux.cc @@ -180,8 +180,8 @@ struct AssertpmuxWorker }; struct AssertpmuxPass : public Pass { - AssertpmuxPass() : Pass("assertpmux", "convert internal signals to module ports") { } - virtual void help() + AssertpmuxPass() : Pass("assertpmux", "adds asserts for parallel muxes") { } + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -195,11 +195,11 @@ 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"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { bool flag_noinit = false; bool flag_always = false; diff --git a/passes/sat/async2sync.cc b/passes/sat/async2sync.cc new file mode 100644 index 000000000..24ae6e448 --- /dev/null +++ b/passes/sat/async2sync.cc @@ -0,0 +1,231 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * + * 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 Async2syncPass : public Pass { + Async2syncPass() : Pass("async2sync", "convert async FF inputs to sync circuits") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" async2sync [options] [selection]\n"); + log("\n"); + log("This command replaces async FF inputs with sync circuits emulating the same\n"); + log("behavior for when the async signals are actually synchronized to the clock.\n"); + log("\n"); + log("This pass assumes negative hold time for the async FF inputs. For example when\n"); + log("a reset deasserts with the clock edge, then the FF output will still drive the\n"); + log("reset value in the next cycle regardless of the data-in value at the time of\n"); + log("the clock edge.\n"); + log("\n"); + log("Currently only $adff, $dffsr, and $dlatch cells are supported by this pass.\n"); + log("\n"); + } + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + // bool flag_noinit = false; + + log_header(design, "Executing ASYNC2SYNC pass.\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + // if (args[argidx] == "-noinit") { + // flag_noinit = true; + // continue; + // } + break; + } + extra_args(args, argidx, design); + + for (auto module : design->selected_modules()) + { + SigMap sigmap(module); + dict<SigBit, State> initbits; + pool<SigBit> del_initbits; + + for (auto wire : module->wires()) + if (wire->attributes.count("\\init") > 0) + { + Const initval = wire->attributes.at("\\init"); + SigSpec initsig = sigmap(wire); + + for (int i = 0; i < GetSize(initval) && i < GetSize(initsig); i++) + if (initval[i] == State::S0 || initval[i] == State::S1) + initbits[initsig[i]] = initval[i]; + } + + for (auto cell : vector<Cell*>(module->selected_cells())) + { + if (cell->type.in("$adff")) + { + // bool clk_pol = cell->parameters["\\CLK_POLARITY"].as_bool(); + bool arst_pol = cell->parameters["\\ARST_POLARITY"].as_bool(); + Const arst_val = cell->parameters["\\ARST_VALUE"]; + + // SigSpec sig_clk = cell->getPort("\\CLK"); + SigSpec sig_arst = cell->getPort("\\ARST"); + SigSpec sig_d = cell->getPort("\\D"); + SigSpec sig_q = cell->getPort("\\Q"); + + log("Replacing %s.%s (%s): ARST=%s, D=%s, Q=%s\n", + log_id(module), log_id(cell), log_id(cell->type), + log_signal(sig_arst), log_signal(sig_d), log_signal(sig_q)); + + Const init_val; + for (int i = 0; i < GetSize(sig_q); i++) { + SigBit bit = sigmap(sig_q[i]); + init_val.bits.push_back(initbits.count(bit) ? initbits.at(bit) : State::Sx); + del_initbits.insert(bit); + } + + Wire *new_d = module->addWire(NEW_ID, GetSize(sig_d)); + Wire *new_q = module->addWire(NEW_ID, GetSize(sig_q)); + new_q->attributes["\\init"] = init_val; + + if (arst_pol) { + module->addMux(NEW_ID, sig_d, arst_val, sig_arst, new_d); + module->addMux(NEW_ID, new_q, arst_val, sig_arst, sig_q); + } else { + module->addMux(NEW_ID, arst_val, sig_d, sig_arst, new_d); + module->addMux(NEW_ID, arst_val, new_q, sig_arst, sig_q); + } + + cell->setPort("\\D", new_d); + cell->setPort("\\Q", new_q); + cell->unsetPort("\\ARST"); + cell->unsetParam("\\ARST_POLARITY"); + cell->unsetParam("\\ARST_VALUE"); + cell->type = "$dff"; + continue; + } + + if (cell->type.in("$dffsr")) + { + // bool clk_pol = cell->parameters["\\CLK_POLARITY"].as_bool(); + bool set_pol = cell->parameters["\\SET_POLARITY"].as_bool(); + bool clr_pol = cell->parameters["\\CLR_POLARITY"].as_bool(); + + // SigSpec sig_clk = cell->getPort("\\CLK"); + SigSpec sig_set = cell->getPort("\\SET"); + SigSpec sig_clr = cell->getPort("\\CLR"); + SigSpec sig_d = cell->getPort("\\D"); + SigSpec sig_q = cell->getPort("\\Q"); + + log("Replacing %s.%s (%s): SET=%s, CLR=%s, D=%s, Q=%s\n", + log_id(module), log_id(cell), log_id(cell->type), + log_signal(sig_set), log_signal(sig_clr), log_signal(sig_d), log_signal(sig_q)); + + Const init_val; + for (int i = 0; i < GetSize(sig_q); i++) { + SigBit bit = sigmap(sig_q[i]); + init_val.bits.push_back(initbits.count(bit) ? initbits.at(bit) : State::Sx); + del_initbits.insert(bit); + } + + Wire *new_d = module->addWire(NEW_ID, GetSize(sig_d)); + Wire *new_q = module->addWire(NEW_ID, GetSize(sig_q)); + new_q->attributes["\\init"] = init_val; + + if (!set_pol) + sig_set = module->Not(NEW_ID, sig_set); + + if (clr_pol) + sig_clr = module->Not(NEW_ID, sig_clr); + + SigSpec tmp = module->Or(NEW_ID, sig_d, sig_set); + module->addAnd(NEW_ID, tmp, sig_clr, new_d); + + tmp = module->Or(NEW_ID, new_q, sig_set); + module->addAnd(NEW_ID, tmp, sig_clr, sig_q); + + cell->setPort("\\D", new_d); + cell->setPort("\\Q", new_q); + cell->unsetPort("\\SET"); + cell->unsetPort("\\CLR"); + cell->unsetParam("\\SET_POLARITY"); + cell->unsetParam("\\CLR_POLARITY"); + cell->type = "$dff"; + continue; + } + + if (cell->type.in("$dlatch")) + { + bool en_pol = cell->parameters["\\EN_POLARITY"].as_bool(); + + SigSpec sig_en = cell->getPort("\\EN"); + SigSpec sig_d = cell->getPort("\\D"); + SigSpec sig_q = cell->getPort("\\Q"); + + log("Replacing %s.%s (%s): EN=%s, D=%s, Q=%s\n", + log_id(module), log_id(cell), log_id(cell->type), + log_signal(sig_en), log_signal(sig_d), log_signal(sig_q)); + + Const init_val; + for (int i = 0; i < GetSize(sig_q); i++) { + SigBit bit = sigmap(sig_q[i]); + init_val.bits.push_back(initbits.count(bit) ? initbits.at(bit) : State::Sx); + del_initbits.insert(bit); + } + + Wire *new_q = module->addWire(NEW_ID, GetSize(sig_q)); + new_q->attributes["\\init"] = init_val; + + if (en_pol) { + module->addMux(NEW_ID, new_q, sig_d, sig_en, sig_q); + } else { + module->addMux(NEW_ID, sig_d, new_q, sig_en, sig_q); + } + + cell->setPort("\\Q", new_q); + cell->unsetPort("\\EN"); + cell->unsetParam("\\EN_POLARITY"); + cell->type = "$ff"; + continue; + } + } + + for (auto wire : module->wires()) + if (wire->attributes.count("\\init") > 0) + { + bool delete_initattr = true; + Const initval = wire->attributes.at("\\init"); + SigSpec initsig = sigmap(wire); + + for (int i = 0; i < GetSize(initval) && i < GetSize(initsig); i++) + if (del_initbits.count(initsig[i]) > 0) + initval[i] = State::Sx; + else if (initval[i] != State::Sx) + delete_initattr = false; + + if (delete_initattr) + wire->attributes.erase("\\init"); + else + wire->attributes.at("\\init") = initval; + } + } + } +} Async2syncPass; + +PRIVATE_NAMESPACE_END diff --git a/passes/sat/clk2fflogic.cc b/passes/sat/clk2fflogic.cc index 736c6f571..4bb4aa047 100644 --- a/passes/sat/clk2fflogic.cc +++ b/passes/sat/clk2fflogic.cc @@ -25,7 +25,7 @@ PRIVATE_NAMESPACE_BEGIN struct Clk2fflogicPass : public Pass { Clk2fflogicPass() : Pass("clk2fflogic", "convert clocked FFs to generic $ff cells") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -36,7 +36,7 @@ struct Clk2fflogicPass : public Pass { log("multiple clocks.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { // bool flag_noinit = false; @@ -253,6 +253,13 @@ struct Clk2fflogicPass : public Pass { SigSpec qval = module->Mux(NEW_ID, past_q, past_d, clock_edge); Const rstval = cell->parameters["\\ARST_VALUE"]; + Wire *past_arst = module->addWire(NEW_ID); + module->addFf(NEW_ID, arst, past_arst); + if (cell->parameters["\\ARST_POLARITY"].as_bool()) + arst = module->LogicOr(NEW_ID, arst, past_arst); + else + arst = module->LogicAnd(NEW_ID, arst, past_arst); + if (cell->parameters["\\ARST_POLARITY"].as_bool()) module->addMux(NEW_ID, qval, rstval, arst, sig_q); else diff --git a/passes/sat/cutpoint.cc b/passes/sat/cutpoint.cc new file mode 100644 index 000000000..b4549bc39 --- /dev/null +++ b/passes/sat/cutpoint.cc @@ -0,0 +1,168 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * + * 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 CutpointPass : public Pass { + CutpointPass() : Pass("cutpoint", "adds formal cut points to the design") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" cutpoint [options] [selection]\n"); + log("\n"); + log("This command adds formal cut points to the design.\n"); + log("\n"); + log(" -undef\n"); + log(" set cupoint nets to undef (x). the default behavior is to create a\n"); + log(" $anyseq cell and drive the cutpoint net from that\n"); + log("\n"); + } + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + bool flag_undef = false; + + log_header(design, "Executing CUTPOINT pass.\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + if (args[argidx] == "-undef") { + flag_undef = true; + continue; + } + break; + } + extra_args(args, argidx, design); + + for (auto module : design->selected_modules()) + { + if (design->selected_whole_module(module->name)) { + log("Making all outputs of module %s cut points, removing module contents.\n", log_id(module)); + module->new_connections(std::vector<RTLIL::SigSig>()); + for (auto cell : vector<Cell*>(module->cells())) + module->remove(cell); + vector<Wire*> output_wires; + for (auto wire : module->wires()) + if (wire->port_output) + output_wires.push_back(wire); + for (auto wire : output_wires) + module->connect(wire, flag_undef ? Const(State::Sx, GetSize(wire)) : module->Anyseq(NEW_ID, GetSize(wire))); + continue; + } + + SigMap sigmap(module); + pool<SigBit> cutpoint_bits; + + for (auto cell : module->selected_cells()) { + if (cell->type == "$anyseq") + continue; + log("Removing cell %s.%s, making all cell outputs cutpoints.\n", log_id(module), log_id(cell)); + for (auto &conn : cell->connections()) { + if (cell->output(conn.first)) + module->connect(conn.second, flag_undef ? Const(State::Sx, GetSize(conn.second)) : module->Anyseq(NEW_ID, GetSize(conn.second))); + } + module->remove(cell); + } + + for (auto wire : module->selected_wires()) { + if (wire->port_output) { + log("Making output wire %s.%s a cutpoint.\n", log_id(module), log_id(wire)); + Wire *new_wire = module->addWire(NEW_ID, wire); + module->swap_names(wire, new_wire); + module->connect(new_wire, flag_undef ? Const(State::Sx, GetSize(new_wire)) : module->Anyseq(NEW_ID, GetSize(new_wire))); + wire->port_id = 0; + wire->port_input = false; + wire->port_output = false; + continue; + } + log("Making wire %s.%s a cutpoint.\n", log_id(module), log_id(wire)); + for (auto bit : sigmap(wire)) + cutpoint_bits.insert(bit); + } + + if (!cutpoint_bits.empty()) + { + for (auto cell : module->cells()) { + for (auto &conn : cell->connections()) { + if (!cell->output(conn.first)) + continue; + SigSpec sig = sigmap(conn.second); + int bit_count = 0; + for (auto &bit : sig) { + if (cutpoint_bits.count(bit)) + bit_count++; + } + if (bit_count == 0) + continue; + SigSpec dummy = module->addWire(NEW_ID, bit_count); + bit_count = 0; + for (auto &bit : sig) { + if (cutpoint_bits.count(bit)) + bit = dummy[bit_count++]; + } + cell->setPort(conn.first, sig); + } + } + + vector<Wire*> rewrite_wires; + for (auto wire : module->wires()) { + if (!wire->port_input) + continue; + int bit_count = 0; + for (auto &bit : sigmap(wire)) + if (cutpoint_bits.count(bit)) + bit_count++; + if (bit_count) + rewrite_wires.push_back(wire); + } + + for (auto wire : rewrite_wires) { + Wire *new_wire = module->addWire(NEW_ID, wire); + SigSpec lhs, rhs, sig = sigmap(wire); + for (int i = 0; i < GetSize(sig); i++) + if (!cutpoint_bits.count(sig[i])) { + lhs.append(SigBit(wire, i)); + rhs.append(SigBit(new_wire, i)); + } + if (GetSize(lhs)) + module->connect(lhs, rhs); + module->swap_names(wire, new_wire); + wire->port_id = 0; + wire->port_input = false; + wire->port_output = false; + } + + SigSpec sig(cutpoint_bits); + sig.sort_and_unify(); + + for (auto chunk : sig.chunks()) { + SigSpec s(chunk); + module->connect(s, flag_undef ? Const(State::Sx, GetSize(s)) : module->Anyseq(NEW_ID, GetSize(s))); + } + } + } + } +} CutpointPass; + +PRIVATE_NAMESPACE_END diff --git a/passes/sat/eval.cc b/passes/sat/eval.cc index 09f69cc5c..e0bb439f4 100644 --- a/passes/sat/eval.cc +++ b/passes/sat/eval.cc @@ -47,8 +47,8 @@ struct BruteForceEquivChecker { if (inputs.size() < mod1_inputs.size()) { RTLIL::SigSpec inputs0 = inputs, inputs1 = inputs; - inputs0.append(RTLIL::Const(0, 1)); - inputs1.append(RTLIL::Const(1, 1)); + inputs0.append(State::S0); + inputs1.append(State::S1); run_checker(inputs0); run_checker(inputs1); return; @@ -360,7 +360,7 @@ struct VlogHammerReporter struct EvalPass : public Pass { EvalPass() : Pass("eval", "evaluate the circuit given an input") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -383,7 +383,7 @@ struct EvalPass : public Pass { log(" then all output ports of the current module are used.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { std::vector<std::pair<std::string, std::string>> sets; std::vector<std::string> shows, tables; diff --git a/passes/sat/expose.cc b/passes/sat/expose.cc index fa8f0c6be..29dfc7b19 100644 --- a/passes/sat/expose.cc +++ b/passes/sat/expose.cc @@ -143,7 +143,7 @@ void create_dff_dq_map(std::map<RTLIL::IdString, dff_map_info_t> &map, RTLIL::De continue; } - if (info.cell->type == "$_DFF_N_" || info.cell->type == "$_DFF_P_") { + if (info.cell->type.in("$_DFF_N_", "$_DFF_P_")) { info.bit_clk = sigmap(info.cell->getPort("\\C")).as_bit(); info.clk_polarity = info.cell->type == "$_DFF_P_"; info.bit_d = sigmap(info.cell->getPort("\\D")).as_bit(); @@ -151,7 +151,7 @@ void create_dff_dq_map(std::map<RTLIL::IdString, dff_map_info_t> &map, RTLIL::De continue; } - if (info.cell->type.size() == 10 && info.cell->type.substr(0, 6) == "$_DFF_") { + if (info.cell->type.size() == 10 && info.cell->type.begins_with("$_DFF_")) { info.bit_clk = sigmap(info.cell->getPort("\\C")).as_bit(); info.bit_arst = sigmap(info.cell->getPort("\\R")).as_bit(); info.clk_polarity = info.cell->type[6] == 'P'; @@ -220,7 +220,7 @@ RTLIL::Wire *add_new_wire(RTLIL::Module *module, RTLIL::IdString name, int width struct ExposePass : public Pass { ExposePass() : Pass("expose", "convert internal signals to module ports") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -257,7 +257,7 @@ struct ExposePass : public Pass { log(" designator for the exposed signal.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { bool flag_shared = false; bool flag_evert = false; @@ -508,7 +508,7 @@ struct ExposePass : public Pass { } for (auto &conn : module->connections_) - conn.first = out_to_in_map(sigmap(conn.first)); + conn.first = out_to_in_map(conn.first); } if (flag_cut) diff --git a/passes/sat/fmcombine.cc b/passes/sat/fmcombine.cc new file mode 100644 index 000000000..00c098542 --- /dev/null +++ b/passes/sat/fmcombine.cc @@ -0,0 +1,376 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * + * 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" +#include "kernel/celltypes.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct opts_t +{ + bool initeq = false; + bool anyeq = false; + bool fwd = false; + bool bwd = false; + bool nop = false; +}; + +struct FmcombineWorker +{ + const opts_t &opts; + Design *design; + Module *original = nullptr; + Module *module = nullptr; + IdString orig_type, combined_type; + + FmcombineWorker(Design *design, IdString orig_type, const opts_t &opts) : + opts(opts), design(design), original(design->module(orig_type)), + orig_type(orig_type), combined_type("$fmcombine" + orig_type.str()) + { + } + + SigSpec import_sig(SigSpec sig, const string &suffix) + { + SigSpec newsig; + for (auto chunk : sig.chunks()) { + if (chunk.wire != nullptr) + chunk.wire = module->wire(chunk.wire->name.str() + suffix); + newsig.append(chunk); + } + return newsig; + } + + Cell *import_prim_cell(Cell *cell, const string &suffix) + { + Cell *c = module->addCell(cell->name.str() + suffix, cell->type); + c->parameters = cell->parameters; + c->attributes = cell->attributes; + + for (auto &conn : cell->connections()) + c->setPort(conn.first, import_sig(conn.second, suffix)); + + return c; + } + + void import_hier_cell(Cell *cell) + { + if (!cell->parameters.empty()) + log_cmd_error("Cell %s.%s has unresolved instance parameters.\n", log_id(original), log_id(cell)); + + FmcombineWorker sub_worker(design, cell->type, opts); + sub_worker.generate(); + + Cell *c = module->addCell(cell->name.str() + "_combined", sub_worker.combined_type); + // c->parameters = cell->parameters; + c->attributes = cell->attributes; + + for (auto &conn : cell->connections()) { + c->setPort(conn.first.str() + "_gold", import_sig(conn.second, "_gold")); + c->setPort(conn.first.str() + "_gate", import_sig(conn.second, "_gate")); + } + } + + void generate() + { + if (design->module(combined_type)) { + // log("Combined module %s already exists.\n", log_id(combined_type)); + return; + } + + log("Generating combined module %s from module %s.\n", log_id(combined_type), log_id(orig_type)); + module = design->addModule(combined_type); + + for (auto wire : original->wires()) { + module->addWire(wire->name.str() + "_gold", wire); + module->addWire(wire->name.str() + "_gate", wire); + } + module->fixup_ports(); + + for (auto cell : original->cells()) { + if (design->module(cell->type) == nullptr) { + if (opts.anyeq && cell->type.in("$anyseq", "$anyconst")) { + Cell *gold = import_prim_cell(cell, "_gold"); + for (auto &conn : cell->connections()) + module->connect(import_sig(conn.second, "_gate"), gold->getPort(conn.first)); + } else { + Cell *gold = import_prim_cell(cell, "_gold"); + Cell *gate = import_prim_cell(cell, "_gate"); + if (opts.initeq) { + if (cell->type.in("$ff", "$dff", "$dffe", + "$dffsr", "$adff", "$dlatch", "$dlatchsr")) { + SigSpec gold_q = gold->getPort("\\Q"); + SigSpec gate_q = gate->getPort("\\Q"); + SigSpec en = module->Initstate(NEW_ID); + SigSpec eq = module->Eq(NEW_ID, gold_q, gate_q); + module->addAssume(NEW_ID, eq, en); + } + } + } + } else { + import_hier_cell(cell); + } + } + + for (auto &conn : original->connections()) { + module->connect(import_sig(conn.first, "_gold"), import_sig(conn.second, "_gold")); + module->connect(import_sig(conn.first, "_gate"), import_sig(conn.second, "_gate")); + } + + if (opts.nop) + return; + + CellTypes ct; + ct.setup_internals_eval(); + ct.setup_stdcells_eval(); + + SigMap sigmap(module); + + dict<SigBit, SigBit> data_bit_to_eq_net; + dict<Cell*, SigSpec> cell_to_eq_nets; + dict<SigSpec, SigSpec> reduce_db; + dict<SigSpec, SigSpec> invert_db; + + for (auto cell : original->cells()) + { + if (!ct.cell_known(cell->type)) + continue; + + for (auto &conn : cell->connections()) + { + if (!cell->output(conn.first)) + continue; + + SigSpec A = import_sig(conn.second, "_gold"); + SigSpec B = import_sig(conn.second, "_gate"); + SigBit EQ = module->Eq(NEW_ID, A, B); + + for (auto bit : sigmap({A, B})) + data_bit_to_eq_net[bit] = EQ; + + cell_to_eq_nets[cell].append(EQ); + } + } + + for (auto cell : original->cells()) + { + if (!ct.cell_known(cell->type)) + continue; + + bool skip_cell = !cell_to_eq_nets.count(cell); + pool<SigBit> src_eq_bits; + + for (auto &conn : cell->connections()) + { + if (skip_cell) + break; + + if (cell->output(conn.first)) + continue; + + SigSpec A = import_sig(conn.second, "_gold"); + SigSpec B = import_sig(conn.second, "_gate"); + + for (auto bit : sigmap({A, B})) { + if (data_bit_to_eq_net.count(bit)) + src_eq_bits.insert(data_bit_to_eq_net.at(bit)); + else + skip_cell = true; + } + } + + if (!skip_cell) { + SigSpec antecedent = SigSpec(src_eq_bits); + antecedent.sort_and_unify(); + + if (GetSize(antecedent) > 1) { + if (reduce_db.count(antecedent) == 0) + reduce_db[antecedent] = module->ReduceAnd(NEW_ID, antecedent); + antecedent = reduce_db.at(antecedent); + } + + SigSpec consequent = cell_to_eq_nets.at(cell); + consequent.sort_and_unify(); + + if (GetSize(consequent) > 1) { + if (reduce_db.count(consequent) == 0) + reduce_db[consequent] = module->ReduceAnd(NEW_ID, consequent); + consequent = reduce_db.at(consequent); + } + + if (opts.fwd) + module->addAssume(NEW_ID, consequent, antecedent); + + if (opts.bwd) + { + if (invert_db.count(antecedent) == 0) + invert_db[antecedent] = module->Not(NEW_ID, antecedent); + + if (invert_db.count(consequent) == 0) + invert_db[consequent] = module->Not(NEW_ID, consequent); + + module->addAssume(NEW_ID, invert_db.at(antecedent), invert_db.at(consequent)); + } + } + } + } +}; + +struct FmcombinePass : public Pass { + FmcombinePass() : Pass("fmcombine", "combine two instances of a cell into one") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" fmcombine [options] module_name gold_cell gate_cell\n"); + // log(" fmcombine [options] @gold_cell @gate_cell\n"); + log("\n"); + log("This pass takes two cells, which are instances of the same module, and replaces\n"); + log("them with one instance of a special 'combined' module, that effectively\n"); + log("contains two copies of the original module, plus some formal properties.\n"); + log("\n"); + log("This is useful for formal test benches that check what differences in behavior\n"); + log("a slight difference in input causes in a module.\n"); + log("\n"); + log(" -initeq\n"); + log(" Insert assumptions that initially all FFs in both circuits have the\n"); + log(" same initial values.\n"); + log("\n"); + log(" -anyeq\n"); + log(" Do not duplicate $anyseq/$anyconst cells.\n"); + log("\n"); + log(" -fwd\n"); + log(" Insert forward hint assumptions into the combined module.\n"); + log("\n"); + log(" -bwd\n"); + log(" Insert backward hint assumptions into the combined module.\n"); + log(" (Backward hints are logically equivalend to fordward hits, but\n"); + log(" some solvers are faster with bwd hints, or even both -bwd and -fwd.)\n"); + log("\n"); + log(" -nop\n"); + log(" Don't insert hint assumptions into the combined module.\n"); + log(" (This should not provide any speedup over the original design, but\n"); + log(" strangely sometimes it does.)\n"); + log("\n"); + log("If none of -fwd, -bwd, and -nop is given, then -fwd is used as default.\n"); + log("\n"); + } + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + opts_t opts; + Module *module = nullptr; + Cell *gold_cell = nullptr; + Cell *gate_cell = nullptr; + + log_header(design, "Executing FMCOMBINE pass.\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + // if (args[argidx] == "-o" && argidx+1 < args.size()) { + // filename = args[++argidx]; + // continue; + // } + if (args[argidx] == "-initeq") { + opts.initeq = true; + continue; + } + if (args[argidx] == "-anyeq") { + opts.anyeq = true; + continue; + } + if (args[argidx] == "-fwd") { + opts.fwd = true; + continue; + } + if (args[argidx] == "-bwd") { + opts.bwd = true; + continue; + } + if (args[argidx] == "-nop") { + opts.nop = true; + continue; + } + break; + } + if (argidx+2 == args.size()) + { + string gold_name = args[argidx++]; + string gate_name = args[argidx++]; + log_cmd_error("fmcombine @gold_cell @gate_cell call style is not implemented yet."); + } + else if (argidx+3 == args.size()) + { + IdString module_name = RTLIL::escape_id(args[argidx++]); + IdString gold_name = RTLIL::escape_id(args[argidx++]); + IdString gate_name = RTLIL::escape_id(args[argidx++]); + + module = design->module(module_name); + if (module == nullptr) + log_cmd_error("Module %s not found.\n", log_id(module_name)); + + gold_cell = module->cell(gold_name); + if (gold_cell == nullptr) + log_cmd_error("Gold cell %s not found in module %s.\n", log_id(gold_name), log_id(module)); + + gate_cell = module->cell(gate_name); + if (gate_cell == nullptr) + log_cmd_error("Gate cell %s not found in module %s.\n", log_id(gate_name), log_id(module)); + } + else + { + log_cmd_error("Invalid number of arguments.\n"); + } + // extra_args(args, argidx, design); + + if (opts.nop && (opts.fwd || opts.bwd)) + log_cmd_error("Option -nop can not be combined with -fwd and/or -bwd.\n"); + + if (!opts.nop && !opts.fwd && !opts.bwd) + opts.fwd = true; + + if (gold_cell->type != gate_cell->type) + log_cmd_error("Types of gold and gate cells do not match.\n"); + if (!gold_cell->parameters.empty()) + log_cmd_error("Gold cell has unresolved instance parameters.\n"); + if (!gate_cell->parameters.empty()) + log_cmd_error("Gate cell has unresolved instance parameters.\n"); + + FmcombineWorker worker(design, gold_cell->type, opts); + worker.generate(); + IdString combined_cell_name = module->uniquify(stringf("\\%s_%s", log_id(gold_cell), log_id(gate_cell))); + + Cell *cell = module->addCell(combined_cell_name, worker.combined_type); + cell->attributes = gold_cell->attributes; + cell->add_strpool_attribute("\\src", gate_cell->get_strpool_attribute("\\src")); + + log("Combining cells %s and %s in module %s into new cell %s.\n", log_id(gold_cell), log_id(gate_cell), log_id(module), log_id(cell)); + + for (auto &conn : gold_cell->connections()) + cell->setPort(conn.first.str() + "_gold", conn.second); + module->remove(gold_cell); + + for (auto &conn : gate_cell->connections()) + cell->setPort(conn.first.str() + "_gate", conn.second); + module->remove(gate_cell); + } +} FmcombinePass; + +PRIVATE_NAMESPACE_END diff --git a/passes/sat/freduce.cc b/passes/sat/freduce.cc index a3028bfce..f29631639 100644 --- a/passes/sat/freduce.cc +++ b/passes/sat/freduce.cc @@ -760,7 +760,7 @@ struct FreduceWorker struct FreducePass : public Pass { FreducePass() : Pass("freduce", "perform functional reduction") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -791,7 +791,7 @@ struct FreducePass : public Pass { log("circuit that is analyzed.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { reduce_counter = 0; reduce_stop_at = 0; diff --git a/passes/sat/miter.cc b/passes/sat/miter.cc index 9e150b60c..49ef40061 100644 --- a/passes/sat/miter.cc +++ b/passes/sat/miter.cc @@ -59,7 +59,7 @@ void create_miter_equiv(struct Pass *that, std::vector<std::string> args, RTLIL: } break; } - if (argidx+3 != args.size() || args[argidx].substr(0, 1) == "-") + if (argidx+3 != args.size() || args[argidx].compare(0, 1, "-") == 0) that->cmd_error(args, argidx, "command argument error"); RTLIL::IdString gold_name = RTLIL::escape_id(args[argidx++]); @@ -236,7 +236,7 @@ void create_miter_equiv(struct Pass *that, std::vector<std::string> args, RTLIL: if (flag_make_assert) { RTLIL::Cell *assert_cell = miter_module->addCell(NEW_ID, "$assert"); assert_cell->setPort("\\A", all_conditions); - assert_cell->setPort("\\EN", RTLIL::SigSpec(1, 1)); + assert_cell->setPort("\\EN", State::S1); } RTLIL::Wire *w_trigger = miter_module->addWire("\\trigger"); @@ -254,7 +254,7 @@ void create_miter_equiv(struct Pass *that, std::vector<std::string> args, RTLIL: if (flag_flatten) { log_push(); - Pass::call_on_module(design, miter_module, "flatten; opt_expr -keepdc -undriven;;"); + Pass::call_on_module(design, miter_module, "flatten -wb; opt_expr -keepdc -undriven;;"); log_pop(); } } @@ -279,7 +279,7 @@ void create_miter_assert(struct Pass *that, std::vector<std::string> args, RTLIL } break; } - if ((argidx+1 != args.size() && argidx+2 != args.size()) || args[argidx].substr(0, 1) == "-") + if ((argidx+1 != args.size() && argidx+2 != args.size()) || args[argidx].compare(0, 1, "-") == 0) that->cmd_error(args, argidx, "command argument error"); IdString module_name = RTLIL::escape_id(args[argidx++]); @@ -308,7 +308,7 @@ void create_miter_assert(struct Pass *that, std::vector<std::string> args, RTLIL if (flag_flatten) { log_push(); - Pass::call_on_module(design, module, "flatten;;"); + Pass::call_on_module(design, module, "flatten -wb;;"); log_pop(); } @@ -358,7 +358,7 @@ void create_miter_assert(struct Pass *that, std::vector<std::string> args, RTLIL struct MiterPass : public Pass { MiterPass() : Pass("miter", "automatically create a miter circuit") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -385,7 +385,7 @@ struct MiterPass : public Pass { log(" also create an 'assert' cell that checks if trigger is always low.\n"); log("\n"); log(" -flatten\n"); - log(" call 'flatten; opt_expr -keepdc -undriven;;' on the miter circuit.\n"); + log(" call 'flatten -wb; opt_expr -keepdc -undriven;;' on the miter circuit.\n"); log("\n"); log("\n"); log(" miter -assert [options] module [miter_name]\n"); @@ -399,10 +399,10 @@ struct MiterPass : public Pass { log(" keep module output ports.\n"); log("\n"); log(" -flatten\n"); - log(" call 'flatten; opt_expr -keepdc -undriven;;' on the miter circuit.\n"); + log(" call 'flatten -wb; opt_expr -keepdc -undriven;;' on the miter circuit.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { if (args.size() > 1 && args[1] == "-equiv") { create_miter_equiv(this, args, design); diff --git a/passes/sat/mutate.cc b/passes/sat/mutate.cc new file mode 100644 index 000000000..b53bbfeb2 --- /dev/null +++ b/passes/sat/mutate.cc @@ -0,0 +1,988 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * + * 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 mutate_t { + string mode; + pool<string> src; + IdString module, cell; + IdString port, wire; + int portbit = -1; + int ctrlbit = -1; + int wirebit = -1; + bool used = false; +}; + +struct mutate_opts_t { + int seed = 0; + std::string mode; + pool<string> src; + IdString module, cell, port, wire; + int portbit = -1; + int ctrlbit = -1; + int wirebit = -1; + + IdString ctrl_name; + int ctrl_width = -1, ctrl_value = -1; + + bool none = false; + + int pick_cover_prcnt = 80; + + int weight_cover = 500; + + int weight_pq_w = 100; + int weight_pq_b = 100; + int weight_pq_c = 100; + int weight_pq_s = 100; + + int weight_pq_mw = 100; + int weight_pq_mb = 100; + int weight_pq_mc = 100; + int weight_pq_ms = 100; +}; + +void database_add(std::vector<mutate_t> &database, const mutate_opts_t &opts, const mutate_t &entry) +{ + if (!opts.mode.empty() && opts.mode != entry.mode) + return; + + if (!opts.src.empty()) { + bool found_match = false; + for (auto &s : opts.src) { + if (entry.src.count(s)) + found_match = true; + } + if (!found_match) + return; + } + + if (!opts.module.empty() && opts.module != entry.module) + return; + + if (!opts.cell.empty() && opts.cell != entry.cell) + return; + + if (!opts.port.empty() && opts.port != entry.port) + return; + + if (opts.portbit >= 0 && opts.portbit != entry.portbit) + return; + + if (opts.ctrlbit >= 0 && opts.ctrlbit != entry.ctrlbit) + return; + + if (!opts.wire.empty() && opts.wire != entry.wire) + return; + + if (opts.wirebit >= 0 && opts.wirebit != entry.wirebit) + return; + + database.push_back(entry); +} + +struct xs128_t +{ + uint32_t x = 123456789; + uint32_t y = 0, z = 0, w = 0; + + xs128_t(int seed = 0) : w(seed) { + next(); + next(); + next(); + } + + void next() { + uint32_t t = x ^ (x << 11); + x = y, y = z, z = w; + w ^= (w >> 19) ^ t ^ (t >> 8); + } + + int operator()() { + next(); + return w & 0x3fffffff; + } + + int operator()(int n) { + if (n < 2) + return 0; + while (1) { + int k = (*this)(), p = k % n; + if ((k - p + n) <= 0x40000000) + return p; + } + } +}; + +struct coverdb_t +{ + dict<string, int> src_db; + dict<tuple<IdString, IdString>, int> wire_db; + dict<tuple<IdString, IdString, int>, int> wirebit_db; + + void insert(const mutate_t &m) { + if (!m.wire.empty()) { + wire_db[tuple<IdString, IdString>(m.module, m.wire)] = 0; + wirebit_db[tuple<IdString, IdString, int>(m.module, m.wire, m.wirebit)] = 0; + } + for (auto &s : m.src) { + src_db[s] = 0; + } + } + + void update(const mutate_t &m) { + if (!m.wire.empty()) { + wire_db.at(tuple<IdString, IdString>(m.module, m.wire))++; + wirebit_db.at(tuple<IdString, IdString, int>(m.module, m.wire, m.wirebit))++; + } + for (auto &s : m.src) { + src_db.at(s)++; + } + } + + int score(const mutate_t &m) { + int this_score = m.src.empty() ? 0 : 1; + if (!m.wire.empty()) { + this_score += wire_db.at(tuple<IdString, IdString>(m.module, m.wire)) ? 0 : 5; + this_score += wirebit_db.at(tuple<IdString, IdString, int>(m.module, m.wire, m.wirebit)) ? 0 : 1; + } + for (auto &s : m.src) { + this_score += src_db.at(s) ? 0 : 5; + } + return this_score; + } +}; + +struct mutate_queue_t +{ + pool<mutate_t*, hash_ptr_ops> db; + + mutate_t *pick(xs128_t &rng, coverdb_t &coverdb, const mutate_opts_t &opts) { + mutate_t *m = nullptr; + if (rng(100) < opts.pick_cover_prcnt) { + vector<mutate_t*> candidates, rmqueue; + int best_score = -1; + for (auto p : db) { + if (p->used) { + rmqueue.push_back(p); + continue; + } + int this_score = coverdb.score(*p); + if (this_score > best_score) { + best_score = this_score; + candidates.clear(); + } + if (best_score == this_score) + candidates.push_back(p); + } + for (auto p : rmqueue) + db.erase(p); + if (!candidates.empty()) + m = candidates[rng(GetSize(candidates))]; + } + if (m == nullptr) { + while (!db.empty()) { + int i = rng(GetSize(db)); + auto it = db.element(i); + mutate_t *p = *it; + db.erase(it); + if (p->used == false) { + m = p; + break; + } + } + } + return m; + } + + void add(mutate_t *m) { + db.insert(m); + } +}; + +template <typename K, typename T> +struct mutate_chain_queue_t +{ + dict<K, T> db; + + mutate_t *pick(xs128_t &rng, coverdb_t &coverdb, const mutate_opts_t &opts) { + while (!db.empty()) { + int i = rng(GetSize(db)); + auto it = db.element(i); + mutate_t *m = it->second.pick(rng, coverdb, opts); + if (m != nullptr) + return m; + db.erase(it); + } + return nullptr; + } + + template<typename... Args> + void add(mutate_t *m, K key, Args... args) { + db[key].add(m, args...); + } +}; + +template <typename K, typename T> +struct mutate_once_queue_t +{ + dict<K, T> db; + + mutate_t *pick(xs128_t &rng, coverdb_t &coverdb, const mutate_opts_t &opts) { + while (!db.empty()) { + int i = rng(GetSize(db)); + auto it = db.element(i); + mutate_t *m = it->second.pick(rng, coverdb, opts); + db.erase(it); + if (m != nullptr) + return m; + } + return nullptr; + } + + template<typename... Args> + void add(mutate_t *m, K key, Args... args) { + db[key].add(m, args...); + } +}; + +void database_reduce(std::vector<mutate_t> &database, const mutate_opts_t &opts, int N, xs128_t &rng) +{ + std::vector<mutate_t> new_database; + coverdb_t coverdb; + + int total_weight = opts.weight_cover + opts.weight_pq_w + opts.weight_pq_b + opts.weight_pq_c + opts.weight_pq_s; + total_weight += opts.weight_pq_mw + opts.weight_pq_mb + opts.weight_pq_mc + opts.weight_pq_ms; + + if (N >= GetSize(database)) + return; + + mutate_once_queue_t<tuple<IdString, IdString>, mutate_queue_t> primary_queue_wire; + mutate_once_queue_t<tuple<IdString, IdString, int>, mutate_queue_t> primary_queue_bit; + mutate_once_queue_t<tuple<IdString, IdString>, mutate_queue_t> primary_queue_cell; + mutate_once_queue_t<string, mutate_queue_t> primary_queue_src; + + mutate_chain_queue_t<IdString, mutate_once_queue_t<IdString, mutate_queue_t>> primary_queue_module_wire; + mutate_chain_queue_t<IdString, mutate_once_queue_t<pair<IdString, int>, mutate_queue_t>> primary_queue_module_bit; + mutate_chain_queue_t<IdString, mutate_once_queue_t<IdString, mutate_queue_t>> primary_queue_module_cell; + mutate_chain_queue_t<IdString, mutate_once_queue_t<string, mutate_queue_t>> primary_queue_module_src; + + for (auto &m : database) + { + coverdb.insert(m); + + if (!m.wire.empty()) { + primary_queue_wire.add(&m, tuple<IdString, IdString>(m.module, m.wire)); + primary_queue_bit.add(&m, tuple<IdString, IdString, int>(m.module, m.wire, m.wirebit)); + primary_queue_module_wire.add(&m, m.module, m.wire); + primary_queue_module_bit.add(&m, m.module, pair<IdString, int>(m.wire, m.wirebit)); + } + + primary_queue_cell.add(&m, tuple<IdString, IdString>(m.module, m.cell)); + primary_queue_module_cell.add(&m, m.module, m.cell); + + for (auto &s : m.src) { + primary_queue_src.add(&m, s); + primary_queue_module_src.add(&m, m.module, s); + } + } + + vector<mutate_t*> cover_candidates; + int best_cover_score = -1; + bool skip_cover = false; + + while (GetSize(new_database) < N) + { + int k = rng(total_weight); + + k -= opts.weight_cover; + if (k < 0) { + while (!skip_cover) { + if (cover_candidates.empty()) { + best_cover_score = -1; + for (auto &m : database) { + if (m.used || m.src.empty()) + continue; + int this_score = -1; + for (auto &s : m.src) { + if (this_score == -1 || this_score > coverdb.src_db.at(s)) + this_score = coverdb.src_db.at(s); + } + log_assert(this_score != -1); + if (best_cover_score == -1 || this_score < best_cover_score) { + cover_candidates.clear(); + best_cover_score = this_score; + } + if (best_cover_score == this_score) + cover_candidates.push_back(&m); + } + if (best_cover_score == -1) { + skip_cover = true; + break; + } + } + + mutate_t *m = nullptr; + while (!cover_candidates.empty()) + { + int idx = rng(GetSize(cover_candidates)); + mutate_t *p = cover_candidates[idx]; + cover_candidates[idx] = cover_candidates.back(); + cover_candidates.pop_back(); + + if (p->used) + continue; + + int this_score = -1; + for (auto &s : p->src) { + if (this_score == -1 || this_score > coverdb.src_db.at(s)) + this_score = coverdb.src_db.at(s); + } + + if (this_score != best_cover_score) + continue; + + m = p; + break; + } + + if (m != nullptr) { + m->used = true; + coverdb.update(*m); + new_database.push_back(*m); + break; + } + } + continue; + } + +#define X(__wght, __queue) \ + k -= __wght; \ + if (k < 0) { \ + mutate_t *m = __queue.pick(rng, coverdb, opts); \ + if (m != nullptr) { \ + m->used = true; \ + coverdb.update(*m); \ + new_database.push_back(*m); \ + }; \ + continue; \ + } + + X(opts.weight_pq_w, primary_queue_wire) + X(opts.weight_pq_b, primary_queue_bit) + X(opts.weight_pq_c, primary_queue_cell) + X(opts.weight_pq_s, primary_queue_src) + + X(opts.weight_pq_mw, primary_queue_module_wire) + X(opts.weight_pq_mb, primary_queue_module_bit) + X(opts.weight_pq_mc, primary_queue_module_cell) + X(opts.weight_pq_ms, primary_queue_module_src) +#undef X + } + + std::swap(new_database, database); + + int covered_src_cnt = 0; + int covered_wire_cnt = 0; + int covered_wirebit_cnt = 0; + + for (auto &it : coverdb.src_db) + if (it.second) + covered_src_cnt++; + + for (auto &it : coverdb.wire_db) + if (it.second) + covered_wire_cnt++; + + for (auto &it : coverdb.wirebit_db) + if (it.second) + covered_wirebit_cnt++; + + log("Covered %d/%d src attributes (%.2f%%).\n", covered_src_cnt, GetSize(coverdb.src_db), 100.0 * covered_src_cnt / GetSize(coverdb.src_db)); + log("Covered %d/%d wires (%.2f%%).\n", covered_wire_cnt, GetSize(coverdb.wire_db), 100.0 * covered_wire_cnt / GetSize(coverdb.wire_db)); + log("Covered %d/%d wire bits (%.2f%%).\n", covered_wirebit_cnt, GetSize(coverdb.wirebit_db), 100.0 * covered_wirebit_cnt / GetSize(coverdb.wirebit_db)); +} + +void mutate_list(Design *design, const mutate_opts_t &opts, const string &filename, const string &srcsfile, int N) +{ + pool<string> sources; + std::vector<mutate_t> database; + xs128_t rng(opts.seed); + + for (auto module : design->selected_modules()) + { + if (!opts.module.empty() && module->name != opts.module) + continue; + + SigMap sigmap(module); + dict<SigBit, int> bit_user_cnt; + + for (auto wire : module->wires()) { + if (wire->name[0] == '\\' && wire->attributes.count("\\src")) + sigmap.add(wire); + } + + for (auto cell : module->cells()) { + for (auto &conn : cell->connections()) { + if (cell->output(conn.first)) + continue; + for (auto bit : sigmap(conn.second)) + bit_user_cnt[bit]++; + } + } + + for (auto wire : module->selected_wires()) + { + for (SigBit bit : SigSpec(wire)) + { + SigBit sigbit = sigmap(bit); + + if (bit.wire == nullptr || sigbit.wire == nullptr) + continue; + + if (!bit.wire->port_id != !sigbit.wire->port_id) { + if (bit.wire->port_id) + sigmap.add(bit); + continue; + } + + if (!bit.wire->name[0] != !sigbit.wire->name[0]) { + if (bit.wire->name[0] == '\\') + sigmap.add(bit); + continue; + } + } + } + + for (auto cell : module->selected_cells()) + { + if (!opts.cell.empty() && cell->name != opts.cell) + continue; + + for (auto &conn : cell->connections()) + { + for (int i = 0; i < GetSize(conn.second); i++) { + mutate_t entry; + entry.module = module->name; + entry.cell = cell->name; + entry.port = conn.first; + entry.portbit = i; + + for (auto &s : cell->get_strpool_attribute("\\src")) + entry.src.insert(s); + + SigBit bit = sigmap(conn.second[i]); + if (bit.wire && bit.wire->name[0] == '\\' && (cell->output(conn.first) || bit_user_cnt[bit] == 1)) { + for (auto &s : bit.wire->get_strpool_attribute("\\src")) + entry.src.insert(s); + entry.wire = bit.wire->name; + entry.wirebit = bit.offset; + } + + if (!srcsfile.empty()) + sources.insert(entry.src.begin(), entry.src.end()); + + entry.mode = "inv"; + database_add(database, opts, entry); + + entry.mode = "const0"; + database_add(database, opts, entry); + + entry.mode = "const1"; + database_add(database, opts, entry); + + entry.mode = "cnot0"; + entry.ctrlbit = rng(GetSize(conn.second)); + if (entry.ctrlbit != entry.portbit && conn.second[entry.ctrlbit].wire) + database_add(database, opts, entry); + + entry.mode = "cnot1"; + entry.ctrlbit = rng(GetSize(conn.second)); + if (entry.ctrlbit != entry.portbit && conn.second[entry.ctrlbit].wire) + database_add(database, opts, entry); + } + } + } + } + + log("Raw database size: %d\n", GetSize(database)); + if (N != 0) { + database_reduce(database, opts, opts.none ? N-1 : N, rng); + log("Reduced database size: %d\n", GetSize(database)); + } + + if (!srcsfile.empty()) { + std::ofstream sout; + sout.open(srcsfile, std::ios::out | std::ios::trunc); + if (!sout.is_open()) + log_error("Could not open file \"%s\" with write access.\n", srcsfile.c_str()); + sources.sort(); + for (auto &s : sources) + sout << s << std::endl; + } + + std::ofstream fout; + + if (!filename.empty()) { + fout.open(filename, std::ios::out | std::ios::trunc); + if (!fout.is_open()) + log_error("Could not open file \"%s\" with write access.\n", filename.c_str()); + } + + int ctrl_value = opts.ctrl_value; + + if (opts.none) { + string str = "mutate"; + if (!opts.ctrl_name.empty()) + str += stringf(" -ctrl %s %d %d", log_id(opts.ctrl_name), opts.ctrl_width, ctrl_value++); + str += " -mode none"; + if (filename.empty()) + log("%s\n", str.c_str()); + else + fout << str << std::endl; + } + + for (auto &entry : database) { + string str = "mutate"; + if (!opts.ctrl_name.empty()) + str += stringf(" -ctrl %s %d %d", log_id(opts.ctrl_name), opts.ctrl_width, ctrl_value++); + str += stringf(" -mode %s", entry.mode.c_str()); + if (!entry.module.empty()) + str += stringf(" -module %s", log_id(entry.module)); + if (!entry.cell.empty()) + str += stringf(" -cell %s", log_id(entry.cell)); + if (!entry.port.empty()) + str += stringf(" -port %s", log_id(entry.port)); + if (entry.portbit >= 0) + str += stringf(" -portbit %d", entry.portbit); + if (entry.ctrlbit >= 0) + str += stringf(" -ctrlbit %d", entry.ctrlbit); + if (!entry.wire.empty()) + str += stringf(" -wire %s", log_id(entry.wire)); + if (entry.wirebit >= 0) + str += stringf(" -wirebit %d", entry.wirebit); + for (auto &s : entry.src) + str += stringf(" -src %s", s.c_str()); + if (filename.empty()) + log("%s\n", str.c_str()); + else + fout << str << std::endl; + } +} + +SigSpec mutate_ctrl_sig(Module *module, IdString name, int width) +{ + Wire *ctrl_wire = module->wire(name); + + if (ctrl_wire == nullptr) + { + log("Adding ctrl port %s to module %s.\n", log_id(name), log_id(module)); + + ctrl_wire = module->addWire(name, width); + ctrl_wire->port_input = true; + module->fixup_ports(); + + for (auto mod : module->design->modules()) + for (auto cell : mod->cells()) + { + if (cell->type != module->name) + continue; + + SigSpec ctrl = mutate_ctrl_sig(mod, name, width); + + log("Connecting ctrl port to cell %s in module %s.\n", log_id(cell), log_id(mod)); + cell->setPort(name, ctrl); + } + } + + log_assert(GetSize(ctrl_wire) == width); + return ctrl_wire; +} + +SigBit mutate_ctrl(Module *module, const mutate_opts_t &opts) +{ + if (opts.ctrl_name.empty()) + return State::S1; + + SigSpec sig = mutate_ctrl_sig(module, opts.ctrl_name, opts.ctrl_width); + return module->Eq(NEW_ID, sig, Const(opts.ctrl_value, GetSize(sig))); +} + +SigSpec mutate_ctrl_mux(Module *module, const mutate_opts_t &opts, SigSpec unchanged_sig, SigSpec changed_sig) +{ + SigBit ctrl_bit = mutate_ctrl(module, opts); + if (ctrl_bit == State::S0) + return unchanged_sig; + if (ctrl_bit == State::S1) + return changed_sig; + return module->Mux(NEW_ID, unchanged_sig, changed_sig, ctrl_bit); +} + +void mutate_inv(Design *design, const mutate_opts_t &opts) +{ + Module *module = design->module(opts.module); + Cell *cell = module->cell(opts.cell); + + SigBit bit = cell->getPort(opts.port)[opts.portbit]; + SigBit inbit, outbit; + + if (cell->input(opts.port)) + { + log("Add input inverter at %s.%s.%s[%d].\n", log_id(module), log_id(cell), log_id(opts.port), opts.portbit); + SigBit outbit = module->Not(NEW_ID, bit); + bit = mutate_ctrl_mux(module, opts, bit, outbit); + } + else + { + log("Add output inverter at %s.%s.%s[%d].\n", log_id(module), log_id(cell), log_id(opts.port), opts.portbit); + SigBit inbit = module->addWire(NEW_ID); + SigBit outbit = module->Not(NEW_ID, inbit); + module->connect(bit, mutate_ctrl_mux(module, opts, inbit, outbit)); + bit = inbit; + } + + SigSpec s = cell->getPort(opts.port); + s[opts.portbit] = bit; + cell->setPort(opts.port, s); +} + +void mutate_const(Design *design, const mutate_opts_t &opts, bool one) +{ + Module *module = design->module(opts.module); + Cell *cell = module->cell(opts.cell); + + SigBit bit = cell->getPort(opts.port)[opts.portbit]; + SigBit inbit, outbit; + + if (cell->input(opts.port)) + { + log("Add input constant %d at %s.%s.%s[%d].\n", one ? 1 : 0, log_id(module), log_id(cell), log_id(opts.port), opts.portbit); + SigBit outbit = one ? State::S1 : State::S0; + bit = mutate_ctrl_mux(module, opts, bit, outbit); + } + else + { + log("Add output constant %d at %s.%s.%s[%d].\n", one ? 1 : 0, log_id(module), log_id(cell), log_id(opts.port), opts.portbit); + SigBit inbit = module->addWire(NEW_ID); + SigBit outbit = one ? State::S1 : State::S0; + module->connect(bit, mutate_ctrl_mux(module, opts, inbit, outbit)); + bit = inbit; + } + + SigSpec s = cell->getPort(opts.port); + s[opts.portbit] = bit; + cell->setPort(opts.port, s); +} + +void mutate_cnot(Design *design, const mutate_opts_t &opts, bool one) +{ + Module *module = design->module(opts.module); + Cell *cell = module->cell(opts.cell); + + SigBit bit = cell->getPort(opts.port)[opts.portbit]; + SigBit ctrl = cell->getPort(opts.port)[opts.ctrlbit]; + SigBit inbit, outbit; + + if (cell->input(opts.port)) + { + log("Add input cnot%d at %s.%s.%s[%d,%d].\n", one ? 1 : 0, log_id(module), log_id(cell), log_id(opts.port), opts.portbit, opts.ctrlbit); + SigBit outbit = one ? module->Xor(NEW_ID, bit, ctrl) : module->Xnor(NEW_ID, bit, ctrl); + bit = mutate_ctrl_mux(module, opts, bit, outbit); + } + else + { + log("Add output cnot%d at %s.%s.%s[%d,%d].\n", one ? 1 : 0, log_id(module), log_id(cell), log_id(opts.port), opts.portbit, opts.ctrlbit); + SigBit inbit = module->addWire(NEW_ID); + SigBit outbit = one ? module->Xor(NEW_ID, inbit, ctrl) : module->Xnor(NEW_ID, inbit, ctrl); + module->connect(bit, mutate_ctrl_mux(module, opts, inbit, outbit)); + bit = inbit; + } + + SigSpec s = cell->getPort(opts.port); + s[opts.portbit] = bit; + cell->setPort(opts.port, s); +} + +struct MutatePass : public Pass { + MutatePass() : Pass("mutate", "generate or apply design mutations") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" mutate -list N [options] [selection]\n"); + log("\n"); + log("Create a list of N mutations using an even sampling.\n"); + log("\n"); + log(" -o filename\n"); + log(" Write list to this file instead of console output\n"); + log("\n"); + log(" -s filename\n"); + log(" Write a list of all src tags found in the design to the specified file\n"); + log("\n"); + log(" -seed N\n"); + log(" RNG seed for selecting mutations\n"); + log("\n"); + log(" -none\n"); + log(" Include a \"none\" mutation in the output\n"); + log("\n"); + log(" -ctrl name width value\n"); + log(" Add -ctrl options to the output. Use 'value' for first mutation, then\n"); + log(" simply count up from there.\n"); + log("\n"); + log(" -mode name\n"); + log(" -module name\n"); + log(" -cell name\n"); + log(" -port name\n"); + log(" -portbit int\n"); + log(" -ctrlbit int\n"); + log(" -wire name\n"); + log(" -wirebit int\n"); + log(" -src string\n"); + log(" Filter list of mutation candidates to those matching\n"); + log(" the given parameters.\n"); + log("\n"); + log(" -cfg option int\n"); + log(" Set a configuration option. Options available:\n"); + log(" weight_pq_w weight_pq_b weight_pq_c weight_pq_s\n"); + log(" weight_pq_mw weight_pq_mb weight_pq_mc weight_pq_ms\n"); + log(" weight_cover pick_cover_prcnt\n"); + log("\n"); + log("\n"); + log(" mutate -mode MODE [options]\n"); + log("\n"); + log("Apply the given mutation.\n"); + log("\n"); + log(" -ctrl name width value\n"); + log(" Add a control signal with the given name and width. The mutation is\n"); + log(" activated if the control signal equals the given value.\n"); + log("\n"); + log(" -module name\n"); + log(" -cell name\n"); + log(" -port name\n"); + log(" -portbit int\n"); + log(" -ctrlbit int\n"); + log(" Mutation parameters, as generated by 'mutate -list N'.\n"); + log("\n"); + log(" -wire name\n"); + log(" -wirebit int\n"); + log(" -src string\n"); + log(" Ignored. (They are generated by -list for documentation purposes.)\n"); + log("\n"); + } + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + mutate_opts_t opts; + string filename; + string srcsfile; + int N = -1; + + log_header(design, "Executing MUTATE pass.\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + if (args[argidx] == "-list" && argidx+1 < args.size()) { + N = atoi(args[++argidx].c_str()); + continue; + } + if (args[argidx] == "-o" && argidx+1 < args.size()) { + filename = args[++argidx]; + continue; + } + if (args[argidx] == "-s" && argidx+1 < args.size()) { + srcsfile = args[++argidx]; + continue; + } + if (args[argidx] == "-seed" && argidx+1 < args.size()) { + opts.seed = atoi(args[++argidx].c_str()); + continue; + } + if (args[argidx] == "-none") { + opts.none = true; + continue; + } + if (args[argidx] == "-mode" && argidx+1 < args.size()) { + opts.mode = args[++argidx]; + continue; + } + if (args[argidx] == "-ctrl" && argidx+3 < args.size()) { + opts.ctrl_name = RTLIL::escape_id(args[++argidx]); + opts.ctrl_width = atoi(args[++argidx].c_str()); + opts.ctrl_value = atoi(args[++argidx].c_str()); + continue; + } + if (args[argidx] == "-module" && argidx+1 < args.size()) { + opts.module = RTLIL::escape_id(args[++argidx]); + continue; + } + if (args[argidx] == "-cell" && argidx+1 < args.size()) { + opts.cell = RTLIL::escape_id(args[++argidx]); + continue; + } + if (args[argidx] == "-port" && argidx+1 < args.size()) { + opts.port = RTLIL::escape_id(args[++argidx]); + continue; + } + if (args[argidx] == "-portbit" && argidx+1 < args.size()) { + opts.portbit = atoi(args[++argidx].c_str()); + continue; + } + if (args[argidx] == "-ctrlbit" && argidx+1 < args.size()) { + opts.ctrlbit = atoi(args[++argidx].c_str()); + continue; + } + if (args[argidx] == "-wire" && argidx+1 < args.size()) { + opts.wire = RTLIL::escape_id(args[++argidx]); + continue; + } + if (args[argidx] == "-wirebit" && argidx+1 < args.size()) { + opts.wirebit = atoi(args[++argidx].c_str()); + continue; + } + if (args[argidx] == "-src" && argidx+1 < args.size()) { + opts.src.insert(args[++argidx]); + continue; + } + if (args[argidx] == "-cfg" && argidx+2 < args.size()) { + if (args[argidx+1] == "pick_cover_prcnt") { + opts.pick_cover_prcnt = atoi(args[argidx+2].c_str()); + argidx += 2; + continue; + } + if (args[argidx+1] == "weight_cover") { + opts.weight_cover = atoi(args[argidx+2].c_str()); + argidx += 2; + continue; + } + if (args[argidx+1] == "weight_pq_w") { + opts.weight_pq_w = atoi(args[argidx+2].c_str()); + argidx += 2; + continue; + } + if (args[argidx+1] == "weight_pq_b") { + opts.weight_pq_b = atoi(args[argidx+2].c_str()); + argidx += 2; + continue; + } + if (args[argidx+1] == "weight_pq_c") { + opts.weight_pq_c = atoi(args[argidx+2].c_str()); + argidx += 2; + continue; + } + if (args[argidx+1] == "weight_pq_s") { + opts.weight_pq_s = atoi(args[argidx+2].c_str()); + argidx += 2; + continue; + } + if (args[argidx+1] == "weight_pq_mw") { + opts.weight_pq_mw = atoi(args[argidx+2].c_str()); + argidx += 2; + continue; + } + if (args[argidx+1] == "weight_pq_mb") { + opts.weight_pq_mb = atoi(args[argidx+2].c_str()); + argidx += 2; + continue; + } + if (args[argidx+1] == "weight_pq_mc") { + opts.weight_pq_mc = atoi(args[argidx+2].c_str()); + argidx += 2; + continue; + } + if (args[argidx+1] == "weight_pq_ms") { + opts.weight_pq_ms = atoi(args[argidx+2].c_str()); + argidx += 2; + continue; + } + } + break; + } + extra_args(args, argidx, design); + + if (N >= 0) { + mutate_list(design, opts, filename, srcsfile, N); + return; + } + + if (opts.mode == "none") { + if (!opts.ctrl_name.empty()) { + Module *topmod = opts.module.empty() ? design->top_module() : design->module(opts.module); + if (topmod) + mutate_ctrl_sig(topmod, opts.ctrl_name, opts.ctrl_width); + } + return; + } + + if (opts.module.empty()) + log_cmd_error("Missing -module argument.\n"); + + Module *module = design->module(opts.module); + if (module == nullptr) + log_cmd_error("Module %s not found.\n", log_id(opts.module)); + + if (opts.cell.empty()) + log_cmd_error("Missing -cell argument.\n"); + + Cell *cell = module->cell(opts.cell); + if (cell == nullptr) + log_cmd_error("Cell %s not found in module %s.\n", log_id(opts.cell), log_id(opts.module)); + + if (opts.port.empty()) + log_cmd_error("Missing -port argument.\n"); + + if (!cell->hasPort(opts.port)) + log_cmd_error("Port %s not found on cell %s.%s.\n", log_id(opts.port), log_id(opts.module), log_id(opts.cell)); + + if (opts.portbit < 0) + log_cmd_error("Missing -portbit argument.\n"); + + if (GetSize(cell->getPort(opts.port)) <= opts.portbit) + log_cmd_error("Out-of-range -portbit argument for port %s on cell %s.%s.\n", log_id(opts.port), log_id(opts.module), log_id(opts.cell)); + + if (opts.mode == "inv") { + mutate_inv(design, opts); + return; + } + + if (opts.mode == "const0" || opts.mode == "const1") { + mutate_const(design, opts, opts.mode == "const1"); + return; + } + + if (opts.ctrlbit < 0) + log_cmd_error("Missing -ctrlbit argument.\n"); + + if (GetSize(cell->getPort(opts.port)) <= opts.ctrlbit) + log_cmd_error("Out-of-range -ctrlbit argument for port %s on cell %s.%s.\n", log_id(opts.port), log_id(opts.module), log_id(opts.cell)); + + if (opts.mode == "cnot0" || opts.mode == "cnot1") { + mutate_cnot(design, opts, opts.mode == "cnot1"); + return; + } + + log_cmd_error("Invalid mode: %s\n", opts.mode.c_str()); + } +} MutatePass; + +PRIVATE_NAMESPACE_END diff --git a/passes/sat/sat.cc b/passes/sat/sat.cc index 6c0834deb..430bba1e8 100644 --- a/passes/sat/sat.cc +++ b/passes/sat/sat.cc @@ -268,7 +268,7 @@ struct SatHelper RTLIL::SigSpec removed_bits; for (int i = 0; i < lhs.size(); i++) { RTLIL::SigSpec bit = lhs.extract(i, 1); - if (!satgen.initial_state.check_all(bit)) { + if (rhs[i] == State::Sx || !satgen.initial_state.check_all(bit)) { removed_bits.append(bit); lhs.remove(i, 1); rhs.remove(i, 1); @@ -519,7 +519,7 @@ struct SatHelper for (auto &p : d->connections()) { if (d->type == "$dff" && p.first == "\\CLK") continue; - if (d->type.substr(0, 6) == "$_DFF_" && p.first == "\\C") + if (d->type.begins_with("$_DFF_") && p.first == "\\C") continue; queued_signals.add(handled_signals.remove(sigmap(p.second))); } @@ -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)); @@ -795,7 +797,7 @@ struct SatHelper vector<string> data; string name = wd.first.c_str(); - while (name.substr(0, 1) == "\\") + while (name.compare(0, 1, "\\") == 0) name = name.substr(1); fprintf(f, " { \"name\": \"%s\", \"wave\": \"", name.c_str()); @@ -890,7 +892,7 @@ void print_qed() struct SatPass : public Pass { SatPass() : Pass("sat", "solve a SAT problem in the circuit") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -1057,7 +1059,7 @@ struct SatPass : public Pass { log(" Like -falsify but do not return an error for timeouts.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { std::vector<std::pair<std::string, std::string>> sets, sets_init, prove, prove_x; std::map<int, std::vector<std::pair<std::string, std::string>>> sets_at; @@ -1169,6 +1171,7 @@ struct SatPass : public Pass { if (args[argidx] == "-tempinduct-def") { tempinduct = true; tempinduct_def = true; + enable_undef = true; continue; } if (args[argidx] == "-tempinduct-baseonly") { @@ -1350,7 +1353,7 @@ struct SatPass : public Pass { if (show_regs) { pool<Wire*> reg_wires; for (auto cell : module->cells()) { - if (cell->type == "$dff" || cell->type.substr(0, 6) == "$_DFF_") + if (cell->type == "$dff" || cell->type.begins_with("$_DFF_")) for (auto bit : cell->getPort("\\Q")) if (bit.wire) reg_wires.insert(bit.wire); @@ -1504,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)); @@ -1607,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/passes/sat/sim.cc b/passes/sat/sim.cc index b49c12529..4c3022c70 100644 --- a/passes/sat/sim.cc +++ b/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; @@ -745,7 +747,7 @@ struct SimWorker : SimShared struct SimPass : public Pass { SimPass() : Pass("sim", "simulate the circuit") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -778,7 +780,7 @@ struct SimPass : public Pass { log(" number of cycles to simulate (default: 20)\n"); log("\n"); log(" -a\n"); - log(" include all nets in VCD output, nut just those with public names\n"); + log(" include all nets in VCD output, not just those with public names\n"); log("\n"); log(" -w\n"); log(" writeback mode: use final simulation state as new init state\n"); @@ -787,7 +789,7 @@ struct SimPass : public Pass { log(" enable debug output\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { SimWorker worker; int numcycles = 20; @@ -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/passes/sat/supercover.cc b/passes/sat/supercover.cc new file mode 100644 index 000000000..ba44f02d8 --- /dev/null +++ b/passes/sat/supercover.cc @@ -0,0 +1,92 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * + * 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 SupercoverPass : public Pass { + SupercoverPass() : Pass("supercover", "add hi/lo cover cells for each wire bit") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" supercover [options] [selection]\n"); + log("\n"); + log("This command adds two cover cells for each bit of each selected wire, one\n"); + log("checking for a hi signal level and one checking for lo level.\n"); + log("\n"); + } + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + // bool flag_noinit = false; + + log_header(design, "Executing SUPERCOVER pass.\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + // if (args[argidx] == "-noinit") { + // flag_noinit = true; + // continue; + // } + break; + } + extra_args(args, argidx, design); + + for (auto module : design->selected_modules()) + { + SigMap sigmap(module); + pool<SigBit> handled_bits; + + int cnt_wire = 0, cnt_bits = 0; + log("Adding cover cells to module %s.\n", log_id(module)); + for (auto wire : module->selected_wires()) + { + bool counted_wire = false; + std::string src = wire->get_src_attribute(); + + for (auto bit : sigmap(SigSpec(wire))) + { + if (bit.wire == nullptr) + continue; + + if (handled_bits.count(bit)) + continue; + + SigSpec inv = module->Not(NEW_ID, bit); + module->addCover(NEW_ID, bit, State::S1, src); + module->addCover(NEW_ID, inv, State::S1, src); + + handled_bits.insert(bit); + if (!counted_wire) { + counted_wire = false; + cnt_wire++; + } + cnt_bits++; + } + } + log(" added cover cells to %d wires, %d bits.\n", cnt_wire, cnt_bits); + } + } +} SupercoverPass; + +PRIVATE_NAMESPACE_END diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc index 140a9f892..cd357d72a 100644 --- a/passes/techmap/Makefile.inc +++ b/passes/techmap/Makefile.inc @@ -7,13 +7,16 @@ OBJS += passes/techmap/libparse.o ifeq ($(ENABLE_ABC),1) OBJS += passes/techmap/abc.o +OBJS += passes/techmap/abc9.o ifneq ($(ABCEXTERNAL),) passes/techmap/abc.o: CXXFLAGS += -DABCEXTERNAL='"$(ABCEXTERNAL)"' +passes/techmap/abc9.o: CXXFLAGS += -DABCEXTERNAL='"$(ABCEXTERNAL)"' endif endif ifneq ($(SMALL),1) OBJS += passes/techmap/iopadmap.o +OBJS += passes/techmap/clkbufmap.o OBJS += passes/techmap/hilomap.o OBJS += passes/techmap/extract.o OBJS += passes/techmap/extract_fa.o @@ -35,6 +38,9 @@ OBJS += passes/techmap/insbuf.o OBJS += passes/techmap/attrmvcp.o OBJS += passes/techmap/attrmap.o OBJS += passes/techmap/zinit.o +OBJS += passes/techmap/dff2dffs.o +OBJS += passes/techmap/flowmap.o +OBJS += passes/techmap/extractinv.o endif GENFILES += passes/techmap/techmap.inc @@ -57,4 +63,3 @@ yosys-filterlib$(EXE): passes/techmap/filterlib.o $(Q) mkdir -p $(dir $@) $(P) $(LD) -o yosys-filterlib$(EXE) $(LDFLAGS) $^ $(LDLIBS) endif - diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index 18868c6d7..b29480e26 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -29,17 +29,17 @@ // Kahn, Arthur B. (1962), "Topological sorting of large networks", Communications of the ACM 5 (11): 558-562, doi:10.1145/368996.369025 // http://en.wikipedia.org/wiki/Topological_sorting -#define ABC_COMMAND_LIB "strash; ifraig; scorr; dc2; dretime; strash; &get -n; &dch -f; &nf {D}; &put" -#define ABC_COMMAND_CTR "strash; ifraig; scorr; dc2; dretime; strash; &get -n; &dch -f; &nf {D}; &put; buffer; upsize {D}; dnsize {D}; stime -p" -#define ABC_COMMAND_LUT "strash; ifraig; scorr; dc2; dretime; strash; dch -f; if; mfs2" -#define ABC_COMMAND_SOP "strash; ifraig; scorr; dc2; dretime; strash; dch -f; cover {I} {P}" -#define ABC_COMMAND_DFL "strash; ifraig; scorr; dc2; dretime; strash; &get -n; &dch -f; &nf {D}; &put" - -#define ABC_FAST_COMMAND_LIB "strash; dretime; map {D}" -#define ABC_FAST_COMMAND_CTR "strash; dretime; map {D}; buffer; upsize {D}; dnsize {D}; stime -p" -#define ABC_FAST_COMMAND_LUT "strash; dretime; if" -#define ABC_FAST_COMMAND_SOP "strash; dretime; cover -I {I} -P {P}" -#define ABC_FAST_COMMAND_DFL "strash; dretime; map" +#define ABC_COMMAND_LIB "strash; ifraig; scorr; dc2; dretime; retime {D}; strash; &get -n; &dch -f; &nf {D}; &put" +#define ABC_COMMAND_CTR "strash; ifraig; scorr; dc2; dretime; retime {D}; strash; &get -n; &dch -f; &nf {D}; &put; buffer; upsize {D}; dnsize {D}; stime -p" +#define ABC_COMMAND_LUT "strash; ifraig; scorr; dc2; dretime; retime {D}; strash; dch -f; if; mfs2" +#define ABC_COMMAND_SOP "strash; ifraig; scorr; dc2; dretime; retime {D}; strash; dch -f; cover {I} {P}" +#define ABC_COMMAND_DFL "strash; ifraig; scorr; dc2; dretime; retime {D}; strash; &get -n; &dch -f; &nf {D}; &put" + +#define ABC_FAST_COMMAND_LIB "strash; dretime; retime {D}; map {D}" +#define ABC_FAST_COMMAND_CTR "strash; dretime; retime {D}; map {D}; buffer; upsize {D}; dnsize {D}; stime -p" +#define ABC_FAST_COMMAND_LUT "strash; dretime; retime {D}; if" +#define ABC_FAST_COMMAND_SOP "strash; dretime; retime {D}; cover -I {I} -P {P}" +#define ABC_FAST_COMMAND_DFL "strash; dretime; retime {D}; map" #include "kernel/register.h" #include "kernel/sigtools.h" @@ -49,6 +49,7 @@ #include <stdlib.h> #include <stdio.h> #include <string.h> +#include <cctype> #include <cerrno> #include <sstream> #include <climits> @@ -81,6 +82,7 @@ enum class gate_type_t { G_ANDNOT, G_ORNOT, G_MUX, + G_NMUX, G_AOI3, G_OAI3, G_AOI4, @@ -111,7 +113,7 @@ std::vector<gate_t> signal_list; std::map<RTLIL::SigBit, int> signal_map; std::map<RTLIL::SigBit, RTLIL::State> signal_init; pool<std::string> enabled_gates; -bool recover_init; +bool recover_init, cmos_cost; bool clk_polarity, en_polarity; RTLIL::SigSpec clk_sig, en_sig; @@ -164,39 +166,39 @@ void mark_port(RTLIL::SigSpec sig) void extract_cell(RTLIL::Cell *cell, bool keepff) { - if (cell->type == "$_DFF_N_" || cell->type == "$_DFF_P_") + if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_))) { - if (clk_polarity != (cell->type == "$_DFF_P_")) + if (clk_polarity != (cell->type == ID($_DFF_P_))) return; - if (clk_sig != assign_map(cell->getPort("\\C"))) + if (clk_sig != assign_map(cell->getPort(ID(C)))) return; if (GetSize(en_sig) != 0) return; goto matching_dff; } - if (cell->type == "$_DFFE_NN_" || cell->type == "$_DFFE_NP_" || cell->type == "$_DFFE_PN_" || cell->type == "$_DFFE_PP_") + if (cell->type.in(ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_))) { - if (clk_polarity != (cell->type == "$_DFFE_PN_" || cell->type == "$_DFFE_PP_")) + if (clk_polarity != cell->type.in(ID($_DFFE_PN_), ID($_DFFE_PP_))) return; - if (en_polarity != (cell->type == "$_DFFE_NP_" || cell->type == "$_DFFE_PP_")) + if (en_polarity != cell->type.in(ID($_DFFE_NP_), ID($_DFFE_PP_))) return; - if (clk_sig != assign_map(cell->getPort("\\C"))) + if (clk_sig != assign_map(cell->getPort(ID(C)))) return; - if (en_sig != assign_map(cell->getPort("\\E"))) + if (en_sig != assign_map(cell->getPort(ID(E)))) return; goto matching_dff; } if (0) { matching_dff: - RTLIL::SigSpec sig_d = cell->getPort("\\D"); - RTLIL::SigSpec sig_q = cell->getPort("\\Q"); + RTLIL::SigSpec sig_d = cell->getPort(ID(D)); + RTLIL::SigSpec sig_q = cell->getPort(ID(Q)); if (keepff) for (auto &c : sig_q.chunks()) if (c.wire != NULL) - c.wire->attributes["\\keep"] = 1; + c.wire->attributes[ID::keep] = 1; assign_map.apply(sig_d); assign_map.apply(sig_q); @@ -207,25 +209,25 @@ void extract_cell(RTLIL::Cell *cell, bool keepff) return; } - if (cell->type.in("$_BUF_", "$_NOT_")) + if (cell->type.in(ID($_BUF_), ID($_NOT_))) { - RTLIL::SigSpec sig_a = cell->getPort("\\A"); - RTLIL::SigSpec sig_y = cell->getPort("\\Y"); + RTLIL::SigSpec sig_a = cell->getPort(ID::A); + RTLIL::SigSpec sig_y = cell->getPort(ID::Y); assign_map.apply(sig_a); assign_map.apply(sig_y); - map_signal(sig_y, cell->type == "$_BUF_" ? G(BUF) : G(NOT), map_signal(sig_a)); + map_signal(sig_y, cell->type == ID($_BUF_) ? G(BUF) : G(NOT), map_signal(sig_a)); module->remove(cell); return; } - if (cell->type.in("$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_")) + if (cell->type.in(ID($_AND_), ID($_NAND_), ID($_OR_), ID($_NOR_), ID($_XOR_), ID($_XNOR_), ID($_ANDNOT_), ID($_ORNOT_))) { - RTLIL::SigSpec sig_a = cell->getPort("\\A"); - RTLIL::SigSpec sig_b = cell->getPort("\\B"); - RTLIL::SigSpec sig_y = cell->getPort("\\Y"); + RTLIL::SigSpec sig_a = cell->getPort(ID::A); + RTLIL::SigSpec sig_b = cell->getPort(ID::B); + RTLIL::SigSpec sig_y = cell->getPort(ID::Y); assign_map.apply(sig_a); assign_map.apply(sig_b); @@ -234,21 +236,21 @@ void extract_cell(RTLIL::Cell *cell, bool keepff) int mapped_a = map_signal(sig_a); int mapped_b = map_signal(sig_b); - if (cell->type == "$_AND_") + if (cell->type == ID($_AND_)) map_signal(sig_y, G(AND), mapped_a, mapped_b); - else if (cell->type == "$_NAND_") + else if (cell->type == ID($_NAND_)) map_signal(sig_y, G(NAND), mapped_a, mapped_b); - else if (cell->type == "$_OR_") + else if (cell->type == ID($_OR_)) map_signal(sig_y, G(OR), mapped_a, mapped_b); - else if (cell->type == "$_NOR_") + else if (cell->type == ID($_NOR_)) map_signal(sig_y, G(NOR), mapped_a, mapped_b); - else if (cell->type == "$_XOR_") + else if (cell->type == ID($_XOR_)) map_signal(sig_y, G(XOR), mapped_a, mapped_b); - else if (cell->type == "$_XNOR_") + else if (cell->type == ID($_XNOR_)) map_signal(sig_y, G(XNOR), mapped_a, mapped_b); - else if (cell->type == "$_ANDNOT_") + else if (cell->type == ID($_ANDNOT_)) map_signal(sig_y, G(ANDNOT), mapped_a, mapped_b); - else if (cell->type == "$_ORNOT_") + else if (cell->type == ID($_ORNOT_)) map_signal(sig_y, G(ORNOT), mapped_a, mapped_b); else log_abort(); @@ -257,12 +259,12 @@ void extract_cell(RTLIL::Cell *cell, bool keepff) return; } - if (cell->type == "$_MUX_") + if (cell->type.in(ID($_MUX_), ID($_NMUX_))) { - RTLIL::SigSpec sig_a = cell->getPort("\\A"); - RTLIL::SigSpec sig_b = cell->getPort("\\B"); - RTLIL::SigSpec sig_s = cell->getPort("\\S"); - RTLIL::SigSpec sig_y = cell->getPort("\\Y"); + RTLIL::SigSpec sig_a = cell->getPort(ID::A); + RTLIL::SigSpec sig_b = cell->getPort(ID::B); + RTLIL::SigSpec sig_s = cell->getPort(ID(S)); + RTLIL::SigSpec sig_y = cell->getPort(ID::Y); assign_map.apply(sig_a); assign_map.apply(sig_b); @@ -273,18 +275,18 @@ void extract_cell(RTLIL::Cell *cell, bool keepff) int mapped_b = map_signal(sig_b); int mapped_s = map_signal(sig_s); - map_signal(sig_y, G(MUX), mapped_a, mapped_b, mapped_s); + map_signal(sig_y, cell->type == ID($_MUX_) ? G(MUX) : G(NMUX), mapped_a, mapped_b, mapped_s); module->remove(cell); return; } - if (cell->type.in("$_AOI3_", "$_OAI3_")) + if (cell->type.in(ID($_AOI3_), ID($_OAI3_))) { - RTLIL::SigSpec sig_a = cell->getPort("\\A"); - RTLIL::SigSpec sig_b = cell->getPort("\\B"); - RTLIL::SigSpec sig_c = cell->getPort("\\C"); - RTLIL::SigSpec sig_y = cell->getPort("\\Y"); + RTLIL::SigSpec sig_a = cell->getPort(ID::A); + RTLIL::SigSpec sig_b = cell->getPort(ID::B); + RTLIL::SigSpec sig_c = cell->getPort(ID(C)); + RTLIL::SigSpec sig_y = cell->getPort(ID::Y); assign_map.apply(sig_a); assign_map.apply(sig_b); @@ -295,19 +297,19 @@ void extract_cell(RTLIL::Cell *cell, bool keepff) int mapped_b = map_signal(sig_b); int mapped_c = map_signal(sig_c); - map_signal(sig_y, cell->type == "$_AOI3_" ? G(AOI3) : G(OAI3), mapped_a, mapped_b, mapped_c); + map_signal(sig_y, cell->type == ID($_AOI3_) ? G(AOI3) : G(OAI3), mapped_a, mapped_b, mapped_c); module->remove(cell); return; } - if (cell->type.in("$_AOI4_", "$_OAI4_")) + if (cell->type.in(ID($_AOI4_), ID($_OAI4_))) { - RTLIL::SigSpec sig_a = cell->getPort("\\A"); - RTLIL::SigSpec sig_b = cell->getPort("\\B"); - RTLIL::SigSpec sig_c = cell->getPort("\\C"); - RTLIL::SigSpec sig_d = cell->getPort("\\D"); - RTLIL::SigSpec sig_y = cell->getPort("\\Y"); + RTLIL::SigSpec sig_a = cell->getPort(ID::A); + RTLIL::SigSpec sig_b = cell->getPort(ID::B); + RTLIL::SigSpec sig_c = cell->getPort(ID(C)); + RTLIL::SigSpec sig_d = cell->getPort(ID(D)); + RTLIL::SigSpec sig_y = cell->getPort(ID::Y); assign_map.apply(sig_a); assign_map.apply(sig_b); @@ -320,18 +322,50 @@ void extract_cell(RTLIL::Cell *cell, bool keepff) int mapped_c = map_signal(sig_c); int mapped_d = map_signal(sig_d); - map_signal(sig_y, cell->type == "$_AOI4_" ? G(AOI4) : G(OAI4), mapped_a, mapped_b, mapped_c, mapped_d); + map_signal(sig_y, cell->type == ID($_AOI4_) ? G(AOI4) : G(OAI4), mapped_a, mapped_b, mapped_c, mapped_d); module->remove(cell); return; } } -std::string remap_name(RTLIL::IdString abc_name) +std::string remap_name(RTLIL::IdString abc_name, RTLIL::Wire **orig_wire = nullptr) { - std::stringstream sstr; - sstr << "$abc$" << map_autoidx << "$" << abc_name.substr(1); - return sstr.str(); + std::string abc_sname = abc_name.substr(1); + bool isnew = false; + if (abc_sname.compare(0, 4, "new_") == 0) + { + abc_sname.erase(0, 4); + isnew = true; + } + if (abc_sname.compare(0, 5, "ys__n") == 0) + { + abc_sname.erase(0, 5); + if (std::isdigit(abc_sname.at(0))) + { + int sid = std::atoi(abc_sname.c_str()); + size_t postfix_start = abc_sname.find_first_not_of("0123456789"); + std::string postfix = postfix_start != std::string::npos ? abc_sname.substr(postfix_start) : ""; + + if (sid < GetSize(signal_list)) + { + auto sig = signal_list.at(sid); + if (sig.bit.wire != nullptr) + { + std::string s = stringf("$abc$%d$%s", map_autoidx, sig.bit.wire->name.c_str()+1); + if (sig.bit.wire->width != 1) + s += stringf("[%d]", sig.bit.offset); + if (isnew) + s += "_new"; + s += postfix; + if (orig_wire != nullptr) + *orig_wire = sig.bit.wire; + return s; + } + } + } + } + return stringf("$abc$%d$%s", map_autoidx, abc_name.c_str()+1); } void dump_loop_graph(FILE *f, int &nr, std::map<int, std::set<int>> &edges, std::set<int> &workpool, std::vector<int> &in_counts) @@ -353,12 +387,12 @@ void dump_loop_graph(FILE *f, int &nr, std::map<int, std::set<int>> &edges, std: } for (auto n : nodes) - fprintf(f, " n%d [label=\"%s\\nid=%d, count=%d\"%s];\n", n, log_signal(signal_list[n].bit), + fprintf(f, " ys__n%d [label=\"%s\\nid=%d, count=%d\"%s];\n", n, log_signal(signal_list[n].bit), n, in_counts[n], workpool.count(n) ? ", shape=box" : ""); for (auto &e : edges) for (auto n : e.second) - fprintf(f, " n%d -> n%d;\n", e.first, n); + fprintf(f, " ys__n%d -> ys__n%d;\n", e.first, n); fprintf(f, "}\n"); } @@ -624,7 +658,7 @@ struct abc_output_filter void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file, std::string liberty_file, std::string constr_file, bool cleanup, vector<int> lut_costs, bool dff_mode, std::string clk_str, bool keepff, std::string delay_target, std::string sop_inputs, std::string sop_products, std::string lutin_shared, bool fast_mode, - const std::vector<RTLIL::Cell*> &cells, bool show_tempdir, bool sop_mode) + const std::vector<RTLIL::Cell*> &cells, bool show_tempdir, bool sop_mode, bool abc_dress) { module = current_module; map_autoidx = autoidx++; @@ -713,10 +747,6 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin else abc_script += fast_mode ? ABC_FAST_COMMAND_DFL : ABC_COMMAND_DFL; - if (script_file.empty() && !delay_target.empty()) - for (size_t pos = abc_script.find("dretime;"); pos != std::string::npos; pos = abc_script.find("dretime;", pos+1)) - abc_script = abc_script.substr(0, pos) + "dretime; retime -o {D};" + abc_script.substr(pos+8); - for (size_t pos = abc_script.find("{D}"); pos != std::string::npos; pos = abc_script.find("{D}", pos)) abc_script = abc_script.substr(0, pos) + delay_target + abc_script.substr(pos+3); @@ -728,7 +758,8 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin for (size_t pos = abc_script.find("{S}"); pos != std::string::npos; pos = abc_script.find("{S}", pos)) abc_script = abc_script.substr(0, pos) + lutin_shared + abc_script.substr(pos+3); - + if (abc_dress) + abc_script += "; dress"; abc_script += stringf("; write_blif %s/output.blif", tempdir_name.c_str()); abc_script = add_echos_to_abc_cmd(abc_script); @@ -756,7 +787,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin extract_cell(c, keepff); for (auto &wire_it : module->wires_) { - if (wire_it.second->port_id > 0 || wire_it.second->get_bool_attribute("\\keep")) + if (wire_it.second->port_id > 0 || wire_it.second->get_bool_attribute(ID::keep)) mark_port(RTLIL::SigSpec(wire_it.second)); } @@ -784,7 +815,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin for (auto &si : signal_list) { if (!si.is_port || si.type != G(NONE)) continue; - fprintf(f, " n%d", si.id); + fprintf(f, " ys__n%d", si.id); pi_map[count_input++] = log_signal(si.bit); } if (count_input == 0) @@ -796,17 +827,17 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin for (auto &si : signal_list) { if (!si.is_port || si.type == G(NONE)) continue; - fprintf(f, " n%d", si.id); + fprintf(f, " ys__n%d", si.id); po_map[count_output++] = log_signal(si.bit); } fprintf(f, "\n"); for (auto &si : signal_list) - fprintf(f, "# n%-5d %s\n", si.id, log_signal(si.bit)); + fprintf(f, "# ys__n%-5d %s\n", si.id, log_signal(si.bit)); for (auto &si : signal_list) { if (si.bit.wire == NULL) { - fprintf(f, ".names n%d\n", si.id); + fprintf(f, ".names ys__n%d\n", si.id); if (si.bit == RTLIL::State::S1) fprintf(f, "1\n"); } @@ -815,68 +846,72 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin int count_gates = 0; for (auto &si : signal_list) { if (si.type == G(BUF)) { - fprintf(f, ".names n%d n%d\n", si.in1, si.id); + fprintf(f, ".names ys__n%d ys__n%d\n", si.in1, si.id); fprintf(f, "1 1\n"); } else if (si.type == G(NOT)) { - fprintf(f, ".names n%d n%d\n", si.in1, si.id); + fprintf(f, ".names ys__n%d ys__n%d\n", si.in1, si.id); fprintf(f, "0 1\n"); } else if (si.type == G(AND)) { - fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id); + fprintf(f, ".names ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.id); fprintf(f, "11 1\n"); } else if (si.type == G(NAND)) { - fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id); + fprintf(f, ".names ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.id); fprintf(f, "0- 1\n"); fprintf(f, "-0 1\n"); } else if (si.type == G(OR)) { - fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id); + fprintf(f, ".names ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.id); fprintf(f, "-1 1\n"); fprintf(f, "1- 1\n"); } else if (si.type == G(NOR)) { - fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id); + fprintf(f, ".names ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.id); fprintf(f, "00 1\n"); } else if (si.type == G(XOR)) { - fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id); + fprintf(f, ".names ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.id); fprintf(f, "01 1\n"); fprintf(f, "10 1\n"); } else if (si.type == G(XNOR)) { - fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id); + fprintf(f, ".names ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.id); fprintf(f, "00 1\n"); fprintf(f, "11 1\n"); } else if (si.type == G(ANDNOT)) { - fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id); + fprintf(f, ".names ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.id); fprintf(f, "10 1\n"); } else if (si.type == G(ORNOT)) { - fprintf(f, ".names n%d n%d n%d\n", si.in1, si.in2, si.id); + fprintf(f, ".names ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.id); fprintf(f, "1- 1\n"); fprintf(f, "-0 1\n"); } else if (si.type == G(MUX)) { - fprintf(f, ".names n%d n%d n%d n%d\n", si.in1, si.in2, si.in3, si.id); + fprintf(f, ".names ys__n%d ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.in3, si.id); fprintf(f, "1-0 1\n"); fprintf(f, "-11 1\n"); + } else if (si.type == G(NMUX)) { + fprintf(f, ".names ys__n%d ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.in3, si.id); + fprintf(f, "0-0 1\n"); + fprintf(f, "-01 1\n"); } else if (si.type == G(AOI3)) { - fprintf(f, ".names n%d n%d n%d n%d\n", si.in1, si.in2, si.in3, si.id); + fprintf(f, ".names ys__n%d ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.in3, si.id); fprintf(f, "-00 1\n"); fprintf(f, "0-0 1\n"); } else if (si.type == G(OAI3)) { - fprintf(f, ".names n%d n%d n%d n%d\n", si.in1, si.in2, si.in3, si.id); + fprintf(f, ".names ys__n%d ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.in3, si.id); fprintf(f, "00- 1\n"); fprintf(f, "--0 1\n"); } else if (si.type == G(AOI4)) { - fprintf(f, ".names n%d n%d n%d n%d n%d\n", si.in1, si.in2, si.in3, si.in4, si.id); + fprintf(f, ".names ys__n%d ys__n%d ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.in3, si.in4, si.id); fprintf(f, "-0-0 1\n"); fprintf(f, "-00- 1\n"); fprintf(f, "0--0 1\n"); fprintf(f, "0-0- 1\n"); } else if (si.type == G(OAI4)) { - fprintf(f, ".names n%d n%d n%d n%d n%d\n", si.in1, si.in2, si.in3, si.in4, si.id); + fprintf(f, ".names ys__n%d ys__n%d ys__n%d ys__n%d ys__n%d\n", si.in1, si.in2, si.in3, si.in4, si.id); fprintf(f, "00-- 1\n"); fprintf(f, "--00 1\n"); } else if (si.type == G(FF)) { if (si.init == State::S0 || si.init == State::S1) { - fprintf(f, ".latch n%d n%d %d\n", si.in1, si.id, si.init == State::S1 ? 1 : 0); + fprintf(f, ".latch ys__n%d ys__n%d %d\n", si.in1, si.id, si.init == State::S1 ? 1 : 0); recover_init = true; } else - fprintf(f, ".latch n%d n%d 2\n", si.in1, si.id); + fprintf(f, ".latch ys__n%d ys__n%d 2\n", si.in1, si.id); } else if (si.type != G(NONE)) log_abort(); if (si.type != G(NONE)) @@ -889,51 +924,54 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin log("Extracted %d gates and %d wires to a netlist network with %d inputs and %d outputs.\n", count_gates, GetSize(signal_list), count_input, count_output); log_push(); - if (count_output > 0) { log_header(design, "Executing ABC.\n"); + auto &cell_cost = cmos_cost ? CellCosts::cmos_gate_cost() : CellCosts::default_gate_cost(); + buffer = stringf("%s/stdcells.genlib", tempdir_name.c_str()); f = fopen(buffer.c_str(), "wt"); if (f == NULL) log_error("Opening %s for writing failed: %s\n", buffer.c_str(), strerror(errno)); fprintf(f, "GATE ZERO 1 Y=CONST0;\n"); fprintf(f, "GATE ONE 1 Y=CONST1;\n"); - fprintf(f, "GATE BUF %d Y=A; PIN * NONINV 1 999 1 0 1 0\n", get_cell_cost("$_BUF_")); - fprintf(f, "GATE NOT %d Y=!A; PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_NOT_")); - if (enabled_gates.empty() || enabled_gates.count("AND")) - fprintf(f, "GATE AND %d Y=A*B; PIN * NONINV 1 999 1 0 1 0\n", get_cell_cost("$_AND_")); - if (enabled_gates.empty() || enabled_gates.count("NAND")) - fprintf(f, "GATE NAND %d Y=!(A*B); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_NAND_")); - if (enabled_gates.empty() || enabled_gates.count("OR")) - fprintf(f, "GATE OR %d Y=A+B; PIN * NONINV 1 999 1 0 1 0\n", get_cell_cost("$_OR_")); - if (enabled_gates.empty() || enabled_gates.count("NOR")) - fprintf(f, "GATE NOR %d Y=!(A+B); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_NOR_")); - if (enabled_gates.empty() || enabled_gates.count("XOR")) - fprintf(f, "GATE XOR %d Y=(A*!B)+(!A*B); PIN * UNKNOWN 1 999 1 0 1 0\n", get_cell_cost("$_XOR_")); - if (enabled_gates.empty() || enabled_gates.count("XNOR")) - fprintf(f, "GATE XNOR %d Y=(A*B)+(!A*!B); PIN * UNKNOWN 1 999 1 0 1 0\n", get_cell_cost("$_XNOR_")); - if (enabled_gates.empty() || enabled_gates.count("ANDNOT")) - fprintf(f, "GATE ANDNOT %d Y=A*!B; PIN * UNKNOWN 1 999 1 0 1 0\n", get_cell_cost("$_ANDNOT_")); - if (enabled_gates.empty() || enabled_gates.count("ORNOT")) - fprintf(f, "GATE ORNOT %d Y=A+!B; PIN * UNKNOWN 1 999 1 0 1 0\n", get_cell_cost("$_ORNOT_")); - if (enabled_gates.empty() || enabled_gates.count("AOI3")) - fprintf(f, "GATE AOI3 %d Y=!((A*B)+C); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_AOI3_")); - if (enabled_gates.empty() || enabled_gates.count("OAI3")) - fprintf(f, "GATE OAI3 %d Y=!((A+B)*C); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_OAI3_")); - if (enabled_gates.empty() || enabled_gates.count("AOI4")) - fprintf(f, "GATE AOI4 %d Y=!((A*B)+(C*D)); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_AOI4_")); - if (enabled_gates.empty() || enabled_gates.count("OAI4")) - fprintf(f, "GATE OAI4 %d Y=!((A+B)*(C+D)); PIN * INV 1 999 1 0 1 0\n", get_cell_cost("$_OAI4_")); - if (enabled_gates.empty() || enabled_gates.count("MUX")) - fprintf(f, "GATE MUX %d Y=(A*B)+(S*B)+(!S*A); PIN * UNKNOWN 1 999 1 0 1 0\n", get_cell_cost("$_MUX_")); + fprintf(f, "GATE BUF %d Y=A; PIN * NONINV 1 999 1 0 1 0\n", cell_cost.at(ID($_BUF_))); + fprintf(f, "GATE NOT %d Y=!A; PIN * INV 1 999 1 0 1 0\n", cell_cost.at(ID($_NOT_))); + if (enabled_gates.count("AND")) + fprintf(f, "GATE AND %d Y=A*B; PIN * NONINV 1 999 1 0 1 0\n", cell_cost.at(ID($_AND_))); + if (enabled_gates.count("NAND")) + fprintf(f, "GATE NAND %d Y=!(A*B); PIN * INV 1 999 1 0 1 0\n", cell_cost.at(ID($_NAND_))); + if (enabled_gates.count("OR")) + fprintf(f, "GATE OR %d Y=A+B; PIN * NONINV 1 999 1 0 1 0\n", cell_cost.at(ID($_OR_))); + if (enabled_gates.count("NOR")) + fprintf(f, "GATE NOR %d Y=!(A+B); PIN * INV 1 999 1 0 1 0\n", cell_cost.at(ID($_NOR_))); + if (enabled_gates.count("XOR")) + fprintf(f, "GATE XOR %d Y=(A*!B)+(!A*B); PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost.at(ID($_XOR_))); + if (enabled_gates.count("XNOR")) + fprintf(f, "GATE XNOR %d Y=(A*B)+(!A*!B); PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost.at(ID($_XNOR_))); + if (enabled_gates.count("ANDNOT")) + fprintf(f, "GATE ANDNOT %d Y=A*!B; PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost.at(ID($_ANDNOT_))); + if (enabled_gates.count("ORNOT")) + fprintf(f, "GATE ORNOT %d Y=A+!B; PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost.at(ID($_ORNOT_))); + if (enabled_gates.count("AOI3")) + fprintf(f, "GATE AOI3 %d Y=!((A*B)+C); PIN * INV 1 999 1 0 1 0\n", cell_cost.at(ID($_AOI3_))); + if (enabled_gates.count("OAI3")) + fprintf(f, "GATE OAI3 %d Y=!((A+B)*C); PIN * INV 1 999 1 0 1 0\n", cell_cost.at(ID($_OAI3_))); + if (enabled_gates.count("AOI4")) + fprintf(f, "GATE AOI4 %d Y=!((A*B)+(C*D)); PIN * INV 1 999 1 0 1 0\n", cell_cost.at(ID($_AOI4_))); + if (enabled_gates.count("OAI4")) + fprintf(f, "GATE OAI4 %d Y=!((A+B)*(C+D)); PIN * INV 1 999 1 0 1 0\n", cell_cost.at(ID($_OAI4_))); + if (enabled_gates.count("MUX")) + fprintf(f, "GATE MUX %d Y=(A*B)+(S*B)+(!S*A); PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost.at(ID($_MUX_))); + if (enabled_gates.count("NMUX")) + fprintf(f, "GATE NMUX %d Y=!((A*B)+(S*B)+(!S*A)); PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost.at(ID($_NMUX_))); if (map_mux4) - fprintf(f, "GATE MUX4 %d Y=(!S*!T*A)+(S*!T*B)+(!S*T*C)+(S*T*D); PIN * UNKNOWN 1 999 1 0 1 0\n", 2*get_cell_cost("$_MUX_")); + fprintf(f, "GATE MUX4 %d Y=(!S*!T*A)+(S*!T*B)+(!S*T*C)+(S*T*D); PIN * UNKNOWN 1 999 1 0 1 0\n", 2*cell_cost.at(ID($_MUX_))); if (map_mux8) - fprintf(f, "GATE MUX8 %d Y=(!S*!T*!U*A)+(S*!T*!U*B)+(!S*T*!U*C)+(S*T*!U*D)+(!S*!T*U*E)+(S*!T*U*F)+(!S*T*U*G)+(S*T*U*H); PIN * UNKNOWN 1 999 1 0 1 0\n", 4*get_cell_cost("$_MUX_")); + fprintf(f, "GATE MUX8 %d Y=(!S*!T*!U*A)+(S*!T*!U*B)+(!S*T*!U*C)+(S*T*!U*D)+(!S*!T*U*E)+(S*!T*U*F)+(!S*T*U*G)+(S*T*U*H); PIN * UNKNOWN 1 999 1 0 1 0\n", 4*cell_cost.at(ID($_MUX_))); if (map_mux16) - fprintf(f, "GATE MUX16 %d Y=(!S*!T*!U*!V*A)+(S*!T*!U*!V*B)+(!S*T*!U*!V*C)+(S*T*!U*!V*D)+(!S*!T*U*!V*E)+(S*!T*U*!V*F)+(!S*T*U*!V*G)+(S*T*U*!V*H)+(!S*!T*!U*V*I)+(S*!T*!U*V*J)+(!S*T*!U*V*K)+(S*T*!U*V*L)+(!S*!T*U*V*M)+(S*!T*U*V*N)+(!S*T*U*V*O)+(S*T*U*V*P); PIN * UNKNOWN 1 999 1 0 1 0\n", 8*get_cell_cost("$_MUX_")); + fprintf(f, "GATE MUX16 %d Y=(!S*!T*!U*!V*A)+(S*!T*!U*!V*B)+(!S*T*!U*!V*C)+(S*T*!U*!V*D)+(!S*!T*U*!V*E)+(S*!T*U*!V*F)+(!S*T*U*!V*G)+(S*T*U*!V*H)+(!S*!T*!U*V*I)+(S*!T*!U*V*J)+(!S*T*!U*V*K)+(S*T*!U*V*L)+(!S*!T*U*V*M)+(S*!T*U*V*N)+(!S*T*U*V*O)+(S*T*U*V*P); PIN * UNKNOWN 1 999 1 0 1 0\n", 8*cell_cost.at(ID($_MUX_))); fclose(f); if (!lut_costs.empty()) { @@ -978,18 +1016,21 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin bool builtin_lib = liberty_file.empty(); RTLIL::Design *mapped_design = new RTLIL::Design; - parse_blif(mapped_design, ifs, builtin_lib ? "\\DFF" : "\\_dff_", false, sop_mode); + parse_blif(mapped_design, ifs, builtin_lib ? ID(DFF) : ID(_dff_), false, sop_mode); ifs.close(); log_header(design, "Re-integrating ABC results.\n"); - RTLIL::Module *mapped_mod = mapped_design->modules_["\\netlist"]; + RTLIL::Module *mapped_mod = mapped_design->modules_[ID(netlist)]; if (mapped_mod == NULL) log_error("ABC output file does not contain a module `netlist'.\n"); for (auto &it : mapped_mod->wires_) { RTLIL::Wire *w = it.second; - RTLIL::Wire *wire = module->addWire(remap_name(w->name)); - if (markgroups) wire->attributes["\\abcgroup"] = map_autoidx; + RTLIL::Wire *orig_wire = nullptr; + RTLIL::Wire *wire = module->addWire(remap_name(w->name, &orig_wire)); + if (orig_wire != nullptr && orig_wire->attributes.count(ID(src))) + wire->attributes[ID(src)] = orig_wire->attributes[ID(src)]; + if (markgroups) wire->attributes[ID(abcgroup)] = map_autoidx; design->select(module, wire); } @@ -999,183 +1040,182 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin if (builtin_lib) { cell_stats[RTLIL::unescape_id(c->type)]++; - if (c->type == "\\ZERO" || c->type == "\\ONE") { + if (c->type.in(ID(ZERO), ID(ONE))) { RTLIL::SigSig conn; - conn.first = RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)]); - conn.second = RTLIL::SigSpec(c->type == "\\ZERO" ? 0 : 1, 1); + conn.first = RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::Y).as_wire()->name)]); + conn.second = RTLIL::SigSpec(c->type == ID(ZERO) ? 0 : 1, 1); module->connect(conn); continue; } - if (c->type == "\\BUF") { + if (c->type == ID(BUF)) { RTLIL::SigSig conn; - conn.first = RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)]); - conn.second = RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\A").as_wire()->name)]); + conn.first = RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::Y).as_wire()->name)]); + conn.second = RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::A).as_wire()->name)]); module->connect(conn); continue; } - if (c->type == "\\NOT") { - RTLIL::Cell *cell = module->addCell(remap_name(c->name), "$_NOT_"); - if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx; - cell->setPort("\\A", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\A").as_wire()->name)])); - cell->setPort("\\Y", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)])); + if (c->type == ID(NOT)) { + RTLIL::Cell *cell = module->addCell(remap_name(c->name), ID($_NOT_)); + if (markgroups) cell->attributes[ID(abcgroup)] = map_autoidx; + cell->setPort(ID::A, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::A).as_wire()->name)])); + cell->setPort(ID::Y, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::Y).as_wire()->name)])); design->select(module, cell); continue; } - if (c->type == "\\AND" || c->type == "\\OR" || c->type == "\\XOR" || c->type == "\\NAND" || c->type == "\\NOR" || - c->type == "\\XNOR" || c->type == "\\ANDNOT" || c->type == "\\ORNOT") { - RTLIL::Cell *cell = module->addCell(remap_name(c->name), "$_" + c->type.substr(1) + "_"); - if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx; - cell->setPort("\\A", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\A").as_wire()->name)])); - cell->setPort("\\B", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\B").as_wire()->name)])); - cell->setPort("\\Y", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)])); + if (c->type.in(ID(AND), ID(OR), ID(XOR), ID(NAND), ID(NOR), ID(XNOR), ID(ANDNOT), ID(ORNOT))) { + RTLIL::Cell *cell = module->addCell(remap_name(c->name), stringf("$_%s_", c->type.c_str()+1)); + if (markgroups) cell->attributes[ID(abcgroup)] = map_autoidx; + cell->setPort(ID::A, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::A).as_wire()->name)])); + cell->setPort(ID::B, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::B).as_wire()->name)])); + cell->setPort(ID::Y, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::Y).as_wire()->name)])); design->select(module, cell); continue; } - if (c->type == "\\MUX") { - RTLIL::Cell *cell = module->addCell(remap_name(c->name), "$_MUX_"); - if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx; - cell->setPort("\\A", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\A").as_wire()->name)])); - cell->setPort("\\B", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\B").as_wire()->name)])); - cell->setPort("\\S", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\S").as_wire()->name)])); - cell->setPort("\\Y", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)])); + if (c->type.in(ID(MUX), ID(NMUX))) { + RTLIL::Cell *cell = module->addCell(remap_name(c->name), stringf("$_%s_", c->type.c_str()+1)); + if (markgroups) cell->attributes[ID(abcgroup)] = map_autoidx; + cell->setPort(ID::A, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::A).as_wire()->name)])); + cell->setPort(ID::B, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::B).as_wire()->name)])); + cell->setPort(ID(S), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(S)).as_wire()->name)])); + cell->setPort(ID::Y, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::Y).as_wire()->name)])); design->select(module, cell); continue; } - if (c->type == "\\MUX4") { - RTLIL::Cell *cell = module->addCell(remap_name(c->name), "$_MUX4_"); - if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx; - cell->setPort("\\A", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\A").as_wire()->name)])); - cell->setPort("\\B", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\B").as_wire()->name)])); - cell->setPort("\\C", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\C").as_wire()->name)])); - cell->setPort("\\D", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\D").as_wire()->name)])); - cell->setPort("\\S", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\S").as_wire()->name)])); - cell->setPort("\\T", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\T").as_wire()->name)])); - cell->setPort("\\Y", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)])); + if (c->type == ID(MUX4)) { + RTLIL::Cell *cell = module->addCell(remap_name(c->name), ID($_MUX4_)); + if (markgroups) cell->attributes[ID(abcgroup)] = map_autoidx; + cell->setPort(ID::A, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::A).as_wire()->name)])); + cell->setPort(ID::B, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::B).as_wire()->name)])); + cell->setPort(ID(C), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(C)).as_wire()->name)])); + cell->setPort(ID(D), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(D)).as_wire()->name)])); + cell->setPort(ID(S), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(S)).as_wire()->name)])); + cell->setPort(ID(T), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(T)).as_wire()->name)])); + cell->setPort(ID::Y, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::Y).as_wire()->name)])); design->select(module, cell); continue; } - if (c->type == "\\MUX8") { - RTLIL::Cell *cell = module->addCell(remap_name(c->name), "$_MUX8_"); - if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx; - cell->setPort("\\A", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\A").as_wire()->name)])); - cell->setPort("\\B", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\B").as_wire()->name)])); - cell->setPort("\\C", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\C").as_wire()->name)])); - cell->setPort("\\D", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\D").as_wire()->name)])); - cell->setPort("\\E", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\E").as_wire()->name)])); - cell->setPort("\\F", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\F").as_wire()->name)])); - cell->setPort("\\G", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\G").as_wire()->name)])); - cell->setPort("\\H", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\H").as_wire()->name)])); - cell->setPort("\\S", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\S").as_wire()->name)])); - cell->setPort("\\T", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\T").as_wire()->name)])); - cell->setPort("\\U", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\U").as_wire()->name)])); - cell->setPort("\\Y", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)])); + if (c->type == ID(MUX8)) { + RTLIL::Cell *cell = module->addCell(remap_name(c->name), ID($_MUX8_)); + if (markgroups) cell->attributes[ID(abcgroup)] = map_autoidx; + cell->setPort(ID::A, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::A).as_wire()->name)])); + cell->setPort(ID::B, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::B).as_wire()->name)])); + cell->setPort(ID(C), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(C)).as_wire()->name)])); + cell->setPort(ID(D), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(D)).as_wire()->name)])); + cell->setPort(ID(E), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(E)).as_wire()->name)])); + cell->setPort(ID(F), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(F)).as_wire()->name)])); + cell->setPort(ID(G), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(G)).as_wire()->name)])); + cell->setPort(ID(H), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(H)).as_wire()->name)])); + cell->setPort(ID(S), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(S)).as_wire()->name)])); + cell->setPort(ID(T), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(T)).as_wire()->name)])); + cell->setPort(ID(U), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(U)).as_wire()->name)])); + cell->setPort(ID::Y, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::Y).as_wire()->name)])); design->select(module, cell); continue; } - if (c->type == "\\MUX16") { - RTLIL::Cell *cell = module->addCell(remap_name(c->name), "$_MUX16_"); - if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx; - cell->setPort("\\A", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\A").as_wire()->name)])); - cell->setPort("\\B", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\B").as_wire()->name)])); - cell->setPort("\\C", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\C").as_wire()->name)])); - cell->setPort("\\D", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\D").as_wire()->name)])); - cell->setPort("\\E", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\E").as_wire()->name)])); - cell->setPort("\\F", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\F").as_wire()->name)])); - cell->setPort("\\G", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\G").as_wire()->name)])); - cell->setPort("\\H", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\H").as_wire()->name)])); - cell->setPort("\\I", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\I").as_wire()->name)])); - cell->setPort("\\J", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\J").as_wire()->name)])); - cell->setPort("\\K", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\K").as_wire()->name)])); - cell->setPort("\\L", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\L").as_wire()->name)])); - cell->setPort("\\M", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\M").as_wire()->name)])); - cell->setPort("\\N", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\N").as_wire()->name)])); - cell->setPort("\\O", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\O").as_wire()->name)])); - cell->setPort("\\P", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\P").as_wire()->name)])); - cell->setPort("\\S", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\S").as_wire()->name)])); - cell->setPort("\\T", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\T").as_wire()->name)])); - cell->setPort("\\U", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\U").as_wire()->name)])); - cell->setPort("\\V", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\V").as_wire()->name)])); - cell->setPort("\\Y", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)])); + if (c->type == ID(MUX16)) { + RTLIL::Cell *cell = module->addCell(remap_name(c->name), ID($_MUX16_)); + if (markgroups) cell->attributes[ID(abcgroup)] = map_autoidx; + cell->setPort(ID::A, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::A).as_wire()->name)])); + cell->setPort(ID::B, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::B).as_wire()->name)])); + cell->setPort(ID(C), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(C)).as_wire()->name)])); + cell->setPort(ID(D), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(D)).as_wire()->name)])); + cell->setPort(ID(E), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(E)).as_wire()->name)])); + cell->setPort(ID(F), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(F)).as_wire()->name)])); + cell->setPort(ID(G), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(G)).as_wire()->name)])); + cell->setPort(ID(H), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(H)).as_wire()->name)])); + cell->setPort(ID(I), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(I)).as_wire()->name)])); + cell->setPort(ID(J), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(J)).as_wire()->name)])); + cell->setPort(ID(K), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(K)).as_wire()->name)])); + cell->setPort(ID(L), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(L)).as_wire()->name)])); + cell->setPort(ID(M), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(M)).as_wire()->name)])); + cell->setPort(ID(N), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(N)).as_wire()->name)])); + cell->setPort(ID(O), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(O)).as_wire()->name)])); + cell->setPort(ID(P), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(P)).as_wire()->name)])); + cell->setPort(ID(S), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(S)).as_wire()->name)])); + cell->setPort(ID(T), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(T)).as_wire()->name)])); + cell->setPort(ID(U), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(U)).as_wire()->name)])); + cell->setPort(ID(V), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(V)).as_wire()->name)])); + cell->setPort(ID::Y, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::Y).as_wire()->name)])); design->select(module, cell); continue; } - if (c->type == "\\AOI3" || c->type == "\\OAI3") { - RTLIL::Cell *cell = module->addCell(remap_name(c->name), "$_" + c->type.substr(1) + "_"); - if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx; - cell->setPort("\\A", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\A").as_wire()->name)])); - cell->setPort("\\B", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\B").as_wire()->name)])); - cell->setPort("\\C", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\C").as_wire()->name)])); - cell->setPort("\\Y", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)])); + if (c->type.in(ID(AOI3), ID(OAI3))) { + RTLIL::Cell *cell = module->addCell(remap_name(c->name), stringf("$_%s_", c->type.c_str()+1)); + if (markgroups) cell->attributes[ID(abcgroup)] = map_autoidx; + cell->setPort(ID::A, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::A).as_wire()->name)])); + cell->setPort(ID::B, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::B).as_wire()->name)])); + cell->setPort(ID(C), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(C)).as_wire()->name)])); + cell->setPort(ID::Y, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::Y).as_wire()->name)])); design->select(module, cell); continue; } - if (c->type == "\\AOI4" || c->type == "\\OAI4") { - RTLIL::Cell *cell = module->addCell(remap_name(c->name), "$_" + c->type.substr(1) + "_"); - if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx; - cell->setPort("\\A", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\A").as_wire()->name)])); - cell->setPort("\\B", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\B").as_wire()->name)])); - cell->setPort("\\C", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\C").as_wire()->name)])); - cell->setPort("\\D", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\D").as_wire()->name)])); - cell->setPort("\\Y", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)])); + if (c->type.in(ID(AOI4), ID(OAI4))) { + RTLIL::Cell *cell = module->addCell(remap_name(c->name), stringf("$_%s_", c->type.c_str()+1)); + if (markgroups) cell->attributes[ID(abcgroup)] = map_autoidx; + cell->setPort(ID::A, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::A).as_wire()->name)])); + cell->setPort(ID::B, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::B).as_wire()->name)])); + cell->setPort(ID(C), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(C)).as_wire()->name)])); + cell->setPort(ID(D), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(D)).as_wire()->name)])); + cell->setPort(ID::Y, RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID::Y).as_wire()->name)])); design->select(module, cell); continue; } - if (c->type == "\\DFF") { + if (c->type == ID(DFF)) { log_assert(clk_sig.size() == 1); RTLIL::Cell *cell; if (en_sig.size() == 0) { - cell = module->addCell(remap_name(c->name), clk_polarity ? "$_DFF_P_" : "$_DFF_N_"); + cell = module->addCell(remap_name(c->name), clk_polarity ? ID($_DFF_P_) : ID($_DFF_N_)); } else { log_assert(en_sig.size() == 1); cell = module->addCell(remap_name(c->name), stringf("$_DFFE_%c%c_", clk_polarity ? 'P' : 'N', en_polarity ? 'P' : 'N')); - cell->setPort("\\E", en_sig); + cell->setPort(ID(E), en_sig); } - if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx; - cell->setPort("\\D", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\D").as_wire()->name)])); - cell->setPort("\\Q", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Q").as_wire()->name)])); - cell->setPort("\\C", clk_sig); + if (markgroups) cell->attributes[ID(abcgroup)] = map_autoidx; + cell->setPort(ID(D), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(D)).as_wire()->name)])); + cell->setPort(ID(Q), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(Q)).as_wire()->name)])); + cell->setPort(ID(C), clk_sig); design->select(module, cell); continue; } } + else + cell_stats[RTLIL::unescape_id(c->type)]++; - cell_stats[RTLIL::unescape_id(c->type)]++; - - if (c->type == "\\_const0_" || c->type == "\\_const1_") { + if (c->type.in(ID(_const0_), ID(_const1_))) { RTLIL::SigSig conn; conn.first = RTLIL::SigSpec(module->wires_[remap_name(c->connections().begin()->second.as_wire()->name)]); - conn.second = RTLIL::SigSpec(c->type == "\\_const0_" ? 0 : 1, 1); + conn.second = RTLIL::SigSpec(c->type == ID(_const0_) ? 0 : 1, 1); module->connect(conn); continue; } - if (c->type == "\\_dff_") { + if (c->type == ID(_dff_)) { log_assert(clk_sig.size() == 1); RTLIL::Cell *cell; if (en_sig.size() == 0) { - cell = module->addCell(remap_name(c->name), clk_polarity ? "$_DFF_P_" : "$_DFF_N_"); + cell = module->addCell(remap_name(c->name), clk_polarity ? ID($_DFF_P_) : ID($_DFF_N_)); } else { log_assert(en_sig.size() == 1); cell = module->addCell(remap_name(c->name), stringf("$_DFFE_%c%c_", clk_polarity ? 'P' : 'N', en_polarity ? 'P' : 'N')); - cell->setPort("\\E", en_sig); + cell->setPort(ID(E), en_sig); } - if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx; - cell->setPort("\\D", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\D").as_wire()->name)])); - cell->setPort("\\Q", RTLIL::SigSpec(module->wires_[remap_name(c->getPort("\\Q").as_wire()->name)])); - cell->setPort("\\C", clk_sig); + if (markgroups) cell->attributes[ID(abcgroup)] = map_autoidx; + cell->setPort(ID(D), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(D)).as_wire()->name)])); + cell->setPort(ID(Q), RTLIL::SigSpec(module->wires_[remap_name(c->getPort(ID(Q)).as_wire()->name)])); + cell->setPort(ID(C), clk_sig); design->select(module, cell); continue; } - if (c->type == "$lut" && GetSize(c->getPort("\\A")) == 1 && c->getParam("\\LUT").as_int() == 2) { - SigSpec my_a = module->wires_[remap_name(c->getPort("\\A").as_wire()->name)]; - SigSpec my_y = module->wires_[remap_name(c->getPort("\\Y").as_wire()->name)]; + if (c->type == ID($lut) && GetSize(c->getPort(ID::A)) == 1 && c->getParam(ID(LUT)).as_int() == 2) { + SigSpec my_a = module->wires_[remap_name(c->getPort(ID::A).as_wire()->name)]; + SigSpec my_y = module->wires_[remap_name(c->getPort(ID::Y).as_wire()->name)]; module->connect(my_y, my_a); continue; } RTLIL::Cell *cell = module->addCell(remap_name(c->name), c->type); - if (markgroups) cell->attributes["\\abcgroup"] = map_autoidx; + if (markgroups) cell->attributes[ID(abcgroup)] = map_autoidx; cell->parameters = c->parameters; for (auto &conn : c->connections()) { RTLIL::SigSpec newsig; @@ -1200,10 +1240,10 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin if (recover_init) for (auto wire : mapped_mod->wires()) { - if (wire->attributes.count("\\init")) { + if (wire->attributes.count(ID(init))) { Wire *w = module->wires_[remap_name(wire->name)]; - log_assert(w->attributes.count("\\init") == 0); - w->attributes["\\init"] = wire->attributes.at("\\init"); + log_assert(w->attributes.count(ID(init)) == 0); + w->attributes[ID(init)] = wire->attributes.at(ID(init)); } } @@ -1213,7 +1253,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin for (auto &si : signal_list) if (si.is_port) { char buffer[100]; - snprintf(buffer, 100, "\\n%d", si.id); + snprintf(buffer, 100, "\\ys__n%d", si.id); RTLIL::SigSig conn; if (si.type != G(NONE)) { conn.first = si.bit; @@ -1248,7 +1288,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin struct AbcPass : public Pass { AbcPass() : Pass("abc", "use ABC for technology mapping") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -1367,20 +1407,27 @@ struct AbcPass : public Pass { // log("\n"); log(" -g type1,type2,...\n"); log(" Map to the specified list of gate types. Supported gates types are:\n"); - log(" AND, NAND, OR, NOR, XOR, XNOR, ANDNOT, ORNOT, MUX, AOI3, OAI3, AOI4, OAI4.\n"); + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log(" AND, NAND, OR, NOR, XOR, XNOR, ANDNOT, ORNOT, MUX,\n"); + log(" NMUX, AOI3, OAI3, AOI4, OAI4.\n"); log(" (The NOT gate is always added to this list automatically.)\n"); log("\n"); log(" The following aliases can be used to reference common sets of gate types:\n"); log(" simple: AND OR XOR MUX\n"); - log(" cmos2: NAND NOR\n"); - log(" cmos3: NAND NOR AOI3 OAI3\n"); - log(" cmos4: NAND NOR AOI3 OAI3 AOI4 OAI4\n"); - log(" gates: AND NAND OR NOR XOR XNOR ANDNOT ORNOT\n"); - log(" aig: AND NAND OR NOR ANDNOT ORNOT\n"); + log(" cmos2: NAND NOR\n"); + log(" cmos3: NAND NOR AOI3 OAI3\n"); + log(" cmos4: NAND NOR AOI3 OAI3 AOI4 OAI4\n"); + log(" cmos: NAND NOR AOI3 OAI3 AOI4 OAI4 NMUX MUX XOR XNOR\n"); + log(" gates: AND NAND OR NOR XOR XNOR ANDNOT ORNOT\n"); + log(" aig: AND NAND OR NOR ANDNOT ORNOT\n"); + log("\n"); + log(" The alias 'all' represent the full set of all gate types.\n"); log("\n"); log(" Prefix a gate type with a '-' to remove it from the list. For example\n"); log(" the arguments 'AND,OR,XOR' and 'simple,-MUX' are equivalent.\n"); log("\n"); + log(" The default is 'all,-NMUX,-AOI3,-OAI3,-AOI4,-OAI4'.\n"); + log("\n"); log(" -dff\n"); log(" also pass $_DFF_?_ and $_DFFE_??_ cells through ABC. modules with many\n"); log(" clock domains are automatically partitioned in clock domains and each\n"); @@ -1407,6 +1454,11 @@ struct AbcPass : public Pass { log(" this attribute is a unique integer for each ABC process started. This\n"); log(" is useful for debugging the partitioning of clock domains.\n"); log("\n"); + log(" -dress\n"); + log(" run the 'dress' command after all other ABC commands. This aims to\n"); + log(" preserve naming by an equivalence check between the original and post-ABC\n"); + log(" netlists (experimental).\n"); + log("\n"); log("When neither -liberty nor -lut is used, the Yosys standard cell library is\n"); log("loaded into ABC before the ABC script is executed.\n"); log("\n"); @@ -1414,13 +1466,13 @@ struct AbcPass : public Pass { log("internally. This is not going to \"run ABC on your design\". It will instead run\n"); log("ABC on logic snippets extracted from your design. You will not get any useful\n"); log("output when passing an ABC script that writes a file. Instead write your full\n"); - log("design as BLIF file with write_blif and the load that into ABC externally if\n"); + log("design as BLIF file with write_blif and then load that into ABC externally if\n"); log("you want to use ABC to convert your design into another format.\n"); log("\n"); log("[1] http://www.eecs.berkeley.edu/~alanmi/abc/\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing ABC pass (technology mapping using ABC).\n"); log_push(); @@ -1441,6 +1493,7 @@ struct AbcPass : public Pass { std::string delay_target, sop_inputs, sop_products, lutin_shared = "-S 1"; bool fast_mode = false, dff_mode = false, keepff = false, cleanup = true; bool show_tempdir = false, sop_mode = false; + bool abc_dress = false; vector<int> lut_costs; markgroups = false; @@ -1448,6 +1501,7 @@ struct AbcPass : public Pass { map_mux8 = false; map_mux16 = false; enabled_gates.clear(); + cmos_cost = false; #ifdef _WIN32 #ifndef ABCEXTERNAL @@ -1532,7 +1586,7 @@ struct AbcPass : public Pass { else if (GetSize(parts) == 1) lut_costs.push_back(atoi(parts.at(0).c_str())); else if (GetSize(parts) == 2) - while (GetSize(lut_costs) < atoi(parts.at(0).c_str())) + while (GetSize(lut_costs) < std::atoi(parts.at(0).c_str())) lut_costs.push_back(atoi(parts.at(1).c_str())); else log_cmd_error("Invalid -luts syntax.\n"); @@ -1555,6 +1609,10 @@ struct AbcPass : public Pass { map_mux16 = true; continue; } + if (arg == "-dress") { + abc_dress = true; + continue; + } if (arg == "-g" && argidx+1 < args.size()) { for (auto g : split_tokens(args[++argidx], ",")) { vector<string> gate_list; @@ -1572,6 +1630,7 @@ struct AbcPass : public Pass { if (g == "ANDNOT") goto ok_gate; if (g == "ORNOT") goto ok_gate; if (g == "MUX") goto ok_gate; + if (g == "NMUX") goto ok_gate; if (g == "AOI3") goto ok_gate; if (g == "OAI3") goto ok_gate; if (g == "AOI4") goto ok_gate; @@ -1584,11 +1643,15 @@ struct AbcPass : public Pass { goto ok_alias; } if (g == "cmos2") { + if (!remove_gates) + cmos_cost = true; gate_list.push_back("NAND"); gate_list.push_back("NOR"); goto ok_alias; } if (g == "cmos3") { + if (!remove_gates) + cmos_cost = true; gate_list.push_back("NAND"); gate_list.push_back("NOR"); gate_list.push_back("AOI3"); @@ -1596,12 +1659,29 @@ struct AbcPass : public Pass { goto ok_alias; } if (g == "cmos4") { + if (!remove_gates) + cmos_cost = true; + gate_list.push_back("NAND"); + gate_list.push_back("NOR"); + gate_list.push_back("AOI3"); + gate_list.push_back("OAI3"); + gate_list.push_back("AOI4"); + gate_list.push_back("OAI4"); + goto ok_alias; + } + if (g == "cmos") { + if (!remove_gates) + cmos_cost = true; gate_list.push_back("NAND"); gate_list.push_back("NOR"); gate_list.push_back("AOI3"); gate_list.push_back("OAI3"); gate_list.push_back("AOI4"); gate_list.push_back("OAI4"); + gate_list.push_back("NMUX"); + gate_list.push_back("MUX"); + gate_list.push_back("XOR"); + gate_list.push_back("XNOR"); goto ok_alias; } if (g == "gates") { @@ -1624,6 +1704,22 @@ struct AbcPass : public Pass { gate_list.push_back("ORNOT"); goto ok_alias; } + if (g == "all") { + gate_list.push_back("AND"); + gate_list.push_back("NAND"); + gate_list.push_back("OR"); + gate_list.push_back("NOR"); + gate_list.push_back("XOR"); + gate_list.push_back("XNOR"); + gate_list.push_back("ANDNOT"); + gate_list.push_back("ORNOT"); + gate_list.push_back("AOI3"); + gate_list.push_back("OAI3"); + gate_list.push_back("AOI4"); + gate_list.push_back("OAI4"); + gate_list.push_back("MUX"); + gate_list.push_back("NMUX"); + } cmd_error(args, argidx, stringf("Unsupported gate type: %s", g.c_str())); ok_gate: gate_list.push_back(g); @@ -1675,6 +1771,23 @@ struct AbcPass : public Pass { if (!constr_file.empty() && liberty_file.empty()) log_cmd_error("Got -constr but no -liberty!\n"); + if (enabled_gates.empty()) { + enabled_gates.insert("AND"); + enabled_gates.insert("NAND"); + enabled_gates.insert("OR"); + enabled_gates.insert("NOR"); + enabled_gates.insert("XOR"); + enabled_gates.insert("XNOR"); + enabled_gates.insert("ANDNOT"); + enabled_gates.insert("ORNOT"); + // enabled_gates.insert("AOI3"); + // enabled_gates.insert("OAI3"); + // enabled_gates.insert("AOI4"); + // enabled_gates.insert("OAI4"); + enabled_gates.insert("MUX"); + // enabled_gates.insert("NMUX"); + } + for (auto mod : design->selected_modules()) { if (mod->processes.size() > 0) { @@ -1686,16 +1799,16 @@ struct AbcPass : public Pass { signal_init.clear(); for (Wire *wire : mod->wires()) - if (wire->attributes.count("\\init")) { + if (wire->attributes.count(ID(init))) { SigSpec initsig = assign_map(wire); - Const initval = wire->attributes.at("\\init"); + Const initval = wire->attributes.at(ID(init)); for (int i = 0; i < GetSize(initsig) && i < GetSize(initval); i++) switch (initval[i]) { case State::S0: signal_init[initsig[i]] = State::S0; break; case State::S1: - signal_init[initsig[i]] = State::S0; + signal_init[initsig[i]] = State::S1; break; default: break; @@ -1704,7 +1817,7 @@ struct AbcPass : public Pass { if (!dff_mode || !clk_str.empty()) { abc_module(design, mod, script_file, exe_file, liberty_file, constr_file, cleanup, lut_costs, dff_mode, clk_str, keepff, - delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, mod->selected_cells(), show_tempdir, sop_mode); + delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, mod->selected_cells(), show_tempdir, sop_mode, abc_dress); continue; } @@ -1745,16 +1858,16 @@ struct AbcPass : public Pass { } } - if (cell->type == "$_DFF_N_" || cell->type == "$_DFF_P_") + if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_))) { - key = clkdomain_t(cell->type == "$_DFF_P_", assign_map(cell->getPort("\\C")), true, RTLIL::SigSpec()); + key = clkdomain_t(cell->type == ID($_DFF_P_), assign_map(cell->getPort(ID(C))), true, RTLIL::SigSpec()); } else - if (cell->type == "$_DFFE_NN_" || cell->type == "$_DFFE_NP_" || cell->type == "$_DFFE_PN_" || cell->type == "$_DFFE_PP_") + if (cell->type.in(ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_))) { - bool this_clk_pol = cell->type == "$_DFFE_PN_" || cell->type == "$_DFFE_PP_"; - bool this_en_pol = cell->type == "$_DFFE_NP_" || cell->type == "$_DFFE_PP_"; - key = clkdomain_t(this_clk_pol, assign_map(cell->getPort("\\C")), this_en_pol, assign_map(cell->getPort("\\E"))); + bool this_clk_pol = cell->type.in(ID($_DFFE_PN_), ID($_DFFE_PP_)); + bool this_en_pol = cell->type.in(ID($_DFFE_NP_), ID($_DFFE_PP_)); + key = clkdomain_t(this_clk_pol, assign_map(cell->getPort(ID(C))), this_en_pol, assign_map(cell->getPort(ID(E)))); } else continue; @@ -1849,7 +1962,7 @@ struct AbcPass : public Pass { en_polarity = std::get<2>(it.first); en_sig = assign_map(std::get<3>(it.first)); abc_module(design, mod, script_file, exe_file, liberty_file, constr_file, cleanup, lut_costs, !clk_sig.empty(), "$", - keepff, delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, it.second, show_tempdir, sop_mode); + keepff, delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, it.second, show_tempdir, sop_mode, abc_dress); assign_map.set(mod); } } diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc new file mode 100644 index 000000000..7eac08d17 --- /dev/null +++ b/passes/techmap/abc9.cc @@ -0,0 +1,1278 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * 2019 Eddie Hung <eddie@fpgeh.com> + * + * 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. + * + */ + +// [[CITE]] ABC +// Berkeley Logic Synthesis and Verification Group, ABC: A System for Sequential Synthesis and Verification +// http://www.eecs.berkeley.edu/~alanmi/abc/ + +#if 0 +// Based on &flow3 - better QoR but more experimental +#define ABC_COMMAND_LUT "&st; &ps -l; &sweep -v; &scorr; " \ + "&st; &if {W}; &save; &st; &syn2; &if {W} -v; &save; &load; "\ + "&st; &if -g -K 6; &dch -f; &if {W} -v; &save; &load; "\ + "&st; &if -g -K 6; &synch2; &if {W} -v; &save; &load; "\ + "&mfs; &ps -l" +#else +#define ABC_COMMAND_LUT "&st; &scorr; &sweep; &dc2; &st; &dch -f; &ps; &if {W} {D} -v; &mfs; &ps -l" +#endif + + +#define ABC_FAST_COMMAND_LUT "&st; &if {W} {D}" + +#include "kernel/register.h" +#include "kernel/sigtools.h" +#include "kernel/celltypes.h" +#include "kernel/cost.h" +#include "kernel/log.h" +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <cerrno> +#include <sstream> +#include <climits> + +#ifndef _WIN32 +# include <unistd.h> +# include <dirent.h> +#endif + +#include "frontends/aiger/aigerparse.h" +#include "kernel/utils.h" + +#ifdef YOSYS_LINK_ABC +extern "C" int Abc_RealMain(int argc, char *argv[]); +#endif + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +bool markgroups; +int map_autoidx; +SigMap assign_map; +RTLIL::Module *module; + +bool clk_polarity, en_polarity; +RTLIL::SigSpec clk_sig, en_sig; + +inline std::string remap_name(RTLIL::IdString abc_name) +{ + return stringf("$abc$%d$%s", map_autoidx, abc_name.c_str()+1); +} + +void handle_loops(RTLIL::Design *design) +{ + Pass::call(design, "scc -set_attr abc_scc_id {}"); + + // For every unique SCC found, (arbitrarily) find the first + // cell in the component, and select (and mark) all its output + // wires + pool<RTLIL::Const> ids_seen; + for (auto cell : module->cells()) { + auto it = cell->attributes.find(ID(abc_scc_id)); + if (it != cell->attributes.end()) { + auto r = ids_seen.insert(it->second); + if (r.second) { + for (auto &c : cell->connections_) { + if (c.second.is_fully_const()) continue; + if (cell->output(c.first)) { + SigBit b = c.second.as_bit(); + Wire *w = b.wire; + log_assert(!w->port_input); + w->port_input = true; + w = module->wire(stringf("%s.abci", w->name.c_str())); + if (!w) { + w = module->addWire(stringf("%s.abci", b.wire->name.c_str()), GetSize(b.wire)); + w->port_output = true; + } + else { + log_assert(w->port_input); + log_assert(b.offset < GetSize(w)); + } + w->set_bool_attribute(ID(abc_scc_break)); + module->swap_names(b.wire, w); + c.second = RTLIL::SigBit(w, b.offset); + } + } + } + cell->attributes.erase(it); + } + } + + module->fixup_ports(); +} + +std::string add_echos_to_abc_cmd(std::string str) +{ + std::string new_str, token; + for (size_t i = 0; i < str.size(); i++) { + token += str[i]; + if (str[i] == ';') { + while (i+1 < str.size() && str[i+1] == ' ') + i++; + new_str += "echo + " + token + " " + token + " "; + token.clear(); + } + } + + if (!token.empty()) { + if (!new_str.empty()) + new_str += "echo + " + token + "; "; + new_str += token; + } + + return new_str; +} + +std::string fold_abc_cmd(std::string str) +{ + std::string token, new_str = " "; + int char_counter = 10; + + for (size_t i = 0; i <= str.size(); i++) { + if (i < str.size()) + token += str[i]; + if (i == str.size() || str[i] == ';') { + if (char_counter + token.size() > 75) + new_str += "\n ", char_counter = 14; + new_str += token, char_counter += token.size(); + token.clear(); + } + } + + return new_str; +} + +std::string replace_tempdir(std::string text, std::string tempdir_name, bool show_tempdir) +{ + if (show_tempdir) + return text; + + while (1) { + size_t pos = text.find(tempdir_name); + if (pos == std::string::npos) + break; + text = text.substr(0, pos) + "<abc-temp-dir>" + text.substr(pos + GetSize(tempdir_name)); + } + + std::string selfdir_name = proc_self_dirname(); + if (selfdir_name != "/") { + while (1) { + size_t pos = text.find(selfdir_name); + if (pos == std::string::npos) + break; + text = text.substr(0, pos) + "<yosys-exe-dir>/" + text.substr(pos + GetSize(selfdir_name)); + } + } + + return text; +} + +struct abc_output_filter +{ + bool got_cr; + int escape_seq_state; + std::string linebuf; + std::string tempdir_name; + bool show_tempdir; + + abc_output_filter(std::string tempdir_name, bool show_tempdir) : tempdir_name(tempdir_name), show_tempdir(show_tempdir) + { + got_cr = false; + escape_seq_state = 0; + } + + void next_char(char ch) + { + if (escape_seq_state == 0 && ch == '\033') { + escape_seq_state = 1; + return; + } + if (escape_seq_state == 1) { + escape_seq_state = ch == '[' ? 2 : 0; + return; + } + if (escape_seq_state == 2) { + if ((ch < '0' || '9' < ch) && ch != ';') + escape_seq_state = 0; + return; + } + escape_seq_state = 0; + if (ch == '\r') { + got_cr = true; + return; + } + if (ch == '\n') { + log("ABC: %s\n", replace_tempdir(linebuf, tempdir_name, show_tempdir).c_str()); + got_cr = false, linebuf.clear(); + return; + } + if (got_cr) + got_cr = false, linebuf.clear(); + linebuf += ch; + } + + void next_line(const std::string &line) + { + //int pi, po; + //if (sscanf(line.c_str(), "Start-point = pi%d. End-point = po%d.", &pi, &po) == 2) { + // log("ABC: Start-point = pi%d (%s). End-point = po%d (%s).\n", + // pi, pi_map.count(pi) ? pi_map.at(pi).c_str() : "???", + // po, po_map.count(po) ? po_map.at(po).c_str() : "???"); + // return; + //} + + for (char ch : line) + next_char(ch); + } +}; + +void abc9_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file, + bool cleanup, vector<int> lut_costs, bool dff_mode, std::string clk_str, + bool /*keepff*/, std::string delay_target, std::string /*lutin_shared*/, bool fast_mode, + bool show_tempdir, std::string box_file, std::string lut_file, + std::string wire_delay, const dict<int,IdString> &box_lookup +) +{ + module = current_module; + map_autoidx = autoidx++; + + if (clk_str != "$") + { + clk_polarity = true; + clk_sig = RTLIL::SigSpec(); + + en_polarity = true; + en_sig = RTLIL::SigSpec(); + } + + if (!clk_str.empty() && clk_str != "$") + { + if (clk_str.find(',') != std::string::npos) { + int pos = clk_str.find(','); + std::string en_str = clk_str.substr(pos+1); + clk_str = clk_str.substr(0, pos); + if (en_str[0] == '!') { + en_polarity = false; + en_str = en_str.substr(1); + } + if (module->wires_.count(RTLIL::escape_id(en_str)) != 0) + en_sig = assign_map(RTLIL::SigSpec(module->wires_.at(RTLIL::escape_id(en_str)), 0)); + } + if (clk_str[0] == '!') { + clk_polarity = false; + clk_str = clk_str.substr(1); + } + if (module->wires_.count(RTLIL::escape_id(clk_str)) != 0) + clk_sig = assign_map(RTLIL::SigSpec(module->wires_.at(RTLIL::escape_id(clk_str)), 0)); + } + + if (dff_mode && clk_sig.empty()) + log_cmd_error("Clock domain %s not found.\n", clk_str.c_str()); + + std::string tempdir_name = "/tmp/yosys-abc-XXXXXX"; + if (!cleanup) + tempdir_name[0] = tempdir_name[4] = '_'; + tempdir_name = make_temp_dir(tempdir_name); + log_header(design, "Extracting gate netlist of module `%s' to `%s/input.xaig'..\n", + module->name.c_str(), replace_tempdir(tempdir_name, tempdir_name, show_tempdir).c_str()); + + std::string abc_script; + + if (!lut_costs.empty()) { + abc_script += stringf("read_lut %s/lutdefs.txt; ", tempdir_name.c_str()); + if (!box_file.empty()) + abc_script += stringf("read_box -v %s; ", box_file.c_str()); + } + else + if (!lut_file.empty()) { + abc_script += stringf("read_lut %s; ", lut_file.c_str()); + if (!box_file.empty()) + abc_script += stringf("read_box -v %s; ", box_file.c_str()); + } + else + log_abort(); + + abc_script += stringf("&read %s/input.xaig; &ps; ", tempdir_name.c_str()); + + if (!script_file.empty()) { + if (script_file[0] == '+') { + for (size_t i = 1; i < script_file.size(); i++) + if (script_file[i] == '\'') + abc_script += "'\\''"; + else if (script_file[i] == ',') + abc_script += " "; + else + abc_script += script_file[i]; + } else + abc_script += stringf("source %s", script_file.c_str()); + } else if (!lut_costs.empty() || !lut_file.empty()) { + //bool all_luts_cost_same = true; + //for (int this_cost : lut_costs) + // if (this_cost != lut_costs.front()) + // all_luts_cost_same = false; + abc_script += fast_mode ? ABC_FAST_COMMAND_LUT : ABC_COMMAND_LUT; + //if (all_luts_cost_same && !fast_mode) + // abc_script += "; lutpack {S}"; + } else + log_abort(); + + //if (script_file.empty() && !delay_target.empty()) + // for (size_t pos = abc_script.find("dretime;"); pos != std::string::npos; pos = abc_script.find("dretime;", pos+1)) + // abc_script = abc_script.substr(0, pos) + "dretime; retime -o {D};" + abc_script.substr(pos+8); + + for (size_t pos = abc_script.find("{D}"); pos != std::string::npos; pos = abc_script.find("{D}", pos)) + abc_script = abc_script.substr(0, pos) + delay_target + abc_script.substr(pos+3); + + //for (size_t pos = abc_script.find("{S}"); pos != std::string::npos; pos = abc_script.find("{S}", pos)) + // abc_script = abc_script.substr(0, pos) + lutin_shared + abc_script.substr(pos+3); + + for (size_t pos = abc_script.find("{W}"); pos != std::string::npos; pos = abc_script.find("{W}", pos)) + abc_script = abc_script.substr(0, pos) + wire_delay + abc_script.substr(pos+3); + + abc_script += stringf("; &write %s/output.aig", tempdir_name.c_str()); + abc_script = add_echos_to_abc_cmd(abc_script); + + for (size_t i = 0; i+1 < abc_script.size(); i++) + if (abc_script[i] == ';' && abc_script[i+1] == ' ') + abc_script[i+1] = '\n'; + + FILE *f = fopen(stringf("%s/abc.script", tempdir_name.c_str()).c_str(), "wt"); + fprintf(f, "%s\n", abc_script.c_str()); + fclose(f); + + if (dff_mode || !clk_str.empty()) + { + if (clk_sig.size() == 0) + log("No%s clock domain found. Not extracting any FF cells.\n", clk_str.empty() ? "" : " matching"); + else { + log("Found%s %s clock domain: %s", clk_str.empty() ? "" : " matching", clk_polarity ? "posedge" : "negedge", log_signal(clk_sig)); + if (en_sig.size() != 0) + log(", enabled by %s%s", en_polarity ? "" : "!", log_signal(en_sig)); + log("\n"); + } + } + + bool count_output = false; + for (auto port_name : module->ports) { + RTLIL::Wire *port_wire = module->wire(port_name); + log_assert(port_wire); + if (port_wire->port_output) { + count_output = true; + break; + } + } + + log_push(); + + if (count_output) + { + design->selection_stack.emplace_back(false); + RTLIL::Selection& sel = design->selection_stack.back(); + sel.select(module); + + handle_loops(design); + + Pass::call(design, "aigmap"); + + //log("Extracted %d gates and %d wires to a netlist network with %d inputs and %d outputs.\n", + // count_gates, GetSize(signal_list), count_input, count_output); + + Pass::call(design, stringf("write_xaiger -map %s/input.sym %s/input.xaig", tempdir_name.c_str(), tempdir_name.c_str())); + + std::string buffer; + std::ifstream ifs; +#if 0 + buffer = stringf("%s/%s", tempdir_name.c_str(), "input.xaig"); + ifs.open(buffer); + if (ifs.fail()) + log_error("Can't open ABC output file `%s'.\n", buffer.c_str()); + buffer = stringf("%s/%s", tempdir_name.c_str(), "input.sym"); + log_assert(!design->module(ID($__abc9__))); + { + AigerReader reader(design, ifs, ID($__abc9__), "" /* clk_name */, buffer.c_str() /* map_filename */, true /* wideports */); + reader.parse_xaiger(); + } + ifs.close(); + Pass::call(design, stringf("write_verilog -noexpr -norename")); + design->remove(design->module(ID($__abc9__))); +#endif + + design->selection_stack.pop_back(); + + // Now 'unexpose' those wires by undoing + // the expose operation -- remove them from PO/PI + // and re-connecting them back together + for (auto wire : module->wires()) { + auto it = wire->attributes.find(ID(abc_scc_break)); + if (it != wire->attributes.end()) { + wire->attributes.erase(it); + log_assert(wire->port_output); + wire->port_output = false; + RTLIL::Wire *i_wire = module->wire(wire->name.str() + ".abci"); + log_assert(i_wire); + log_assert(i_wire->port_input); + i_wire->port_input = false; + module->connect(i_wire, wire); + } + } + module->fixup_ports(); + + log_header(design, "Executing ABC9.\n"); + + if (!lut_costs.empty()) { + buffer = stringf("%s/lutdefs.txt", tempdir_name.c_str()); + f = fopen(buffer.c_str(), "wt"); + if (f == NULL) + log_error("Opening %s for writing failed: %s\n", buffer.c_str(), strerror(errno)); + for (int i = 0; i < GetSize(lut_costs); i++) + fprintf(f, "%d %d.00 1.00\n", i+1, lut_costs.at(i)); + fclose(f); + } + + buffer = stringf("%s -s -f %s/abc.script 2>&1", exe_file.c_str(), tempdir_name.c_str()); + log("Running ABC command: %s\n", replace_tempdir(buffer, tempdir_name, show_tempdir).c_str()); + +#ifndef YOSYS_LINK_ABC + abc_output_filter filt(tempdir_name, show_tempdir); + int ret = run_command(buffer, std::bind(&abc_output_filter::next_line, filt, std::placeholders::_1)); +#else + // These needs to be mutable, supposedly due to getopt + char *abc_argv[5]; + string tmp_script_name = stringf("%s/abc.script", tempdir_name.c_str()); + abc_argv[0] = strdup(exe_file.c_str()); + abc_argv[1] = strdup("-s"); + abc_argv[2] = strdup("-f"); + abc_argv[3] = strdup(tmp_script_name.c_str()); + abc_argv[4] = 0; + int ret = Abc_RealMain(4, abc_argv); + free(abc_argv[0]); + free(abc_argv[1]); + free(abc_argv[2]); + free(abc_argv[3]); +#endif + if (ret != 0) + log_error("ABC: execution of command \"%s\" failed: return code %d.\n", buffer.c_str(), ret); + + buffer = stringf("%s/%s", tempdir_name.c_str(), "output.aig"); + ifs.open(buffer); + if (ifs.fail()) + log_error("Can't open ABC output file `%s'.\n", buffer.c_str()); + + buffer = stringf("%s/%s", tempdir_name.c_str(), "input.sym"); + log_assert(!design->module(ID($__abc9__))); + + AigerReader reader(design, ifs, ID($__abc9__), "" /* clk_name */, buffer.c_str() /* map_filename */, true /* wideports */); + reader.parse_xaiger(box_lookup); + ifs.close(); + +#if 0 + Pass::call(design, stringf("write_verilog -noexpr -norename")); +#endif + + log_header(design, "Re-integrating ABC9 results.\n"); + RTLIL::Module *mapped_mod = design->module(ID($__abc9__)); + if (mapped_mod == NULL) + log_error("ABC output file does not contain a module `$__abc9__'.\n"); + + pool<RTLIL::SigBit> output_bits; + for (auto &it : mapped_mod->wires_) { + RTLIL::Wire *w = it.second; + RTLIL::Wire *remap_wire = module->addWire(remap_name(w->name), GetSize(w)); + if (markgroups) remap_wire->attributes[ID(abcgroup)] = map_autoidx; + if (w->port_output) { + RTLIL::Wire *wire = module->wire(w->name); + log_assert(wire); + for (int i = 0; i < GetSize(w); i++) + output_bits.insert({wire, i}); + } + } + + for (auto &it : module->connections_) { + auto &signal = it.first; + auto bits = signal.bits(); + for (auto &b : bits) + if (output_bits.count(b)) + b = module->addWire(NEW_ID); + signal = std::move(bits); + } + + dict<IdString, bool> abc_box; + vector<RTLIL::Cell*> boxes; + for (const auto &it : module->cells_) { + auto cell = it.second; + if (cell->type.in(ID($_AND_), ID($_NOT_))) { + module->remove(cell); + continue; + } + auto jt = abc_box.find(cell->type); + if (jt == abc_box.end()) { + RTLIL::Module* box_module = design->module(cell->type); + jt = abc_box.insert(std::make_pair(cell->type, box_module && box_module->attributes.count(ID(abc_box_id)))).first; + } + if (jt->second) + boxes.emplace_back(cell); + } + + dict<SigBit, pool<IdString>> bit_drivers, bit_users; + TopoSort<IdString, RTLIL::sort_by_id_str> toposort; + dict<RTLIL::Cell*,RTLIL::Cell*> not2drivers; + dict<SigBit, std::vector<RTLIL::Cell*>> bit2sinks; + + std::map<IdString, int> cell_stats; + for (auto c : mapped_mod->cells()) + { + toposort.node(c->name); + + RTLIL::Cell *cell = nullptr; + if (c->type == ID($_NOT_)) { + RTLIL::SigBit a_bit = c->getPort(ID::A); + RTLIL::SigBit y_bit = c->getPort(ID::Y); + bit_users[a_bit].insert(c->name); + bit_drivers[y_bit].insert(c->name); + + if (!a_bit.wire) { + c->setPort(ID::Y, module->addWire(NEW_ID)); + RTLIL::Wire *wire = module->wire(remap_name(y_bit.wire->name)); + log_assert(wire); + module->connect(RTLIL::SigBit(wire, y_bit.offset), State::S1); + } + else if (!lut_costs.empty() || !lut_file.empty()) { + RTLIL::Cell* driver_lut = nullptr; + // ABC can return NOT gates that drive POs + if (!a_bit.wire->port_input) { + // If it's not a NOT gate that that comes from a PI directly, + // find the driver LUT and clone that to guarantee that we won't + // increase the max logic depth + // (TODO: Optimise by not cloning unless will increase depth) + RTLIL::IdString driver_name; + if (GetSize(a_bit.wire) == 1) + driver_name = stringf("%s$lut", a_bit.wire->name.c_str()); + else + driver_name = stringf("%s[%d]$lut", a_bit.wire->name.c_str(), a_bit.offset); + driver_lut = mapped_mod->cell(driver_name); + } + + if (!driver_lut) { + // If a driver couldn't be found (could be from PI or box CI) + // then implement using a LUT + cell = module->addLut(remap_name(stringf("%s$lut", c->name.c_str())), + RTLIL::SigBit(module->wires_.at(remap_name(a_bit.wire->name)), a_bit.offset), + RTLIL::SigBit(module->wires_.at(remap_name(y_bit.wire->name)), y_bit.offset), + RTLIL::Const::from_string("01")); + bit2sinks[cell->getPort(ID::A)].push_back(cell); + cell_stats[ID($lut)]++; + } + else + not2drivers[c] = driver_lut; + continue; + } + else + log_abort(); + if (cell && markgroups) cell->attributes[ID(abcgroup)] = map_autoidx; + continue; + } + cell_stats[c->type]++; + + RTLIL::Cell *existing_cell = nullptr; + if (c->type == ID($lut)) { + if (GetSize(c->getPort(ID::A)) == 1 && c->getParam(ID(LUT)) == RTLIL::Const::from_string("01")) { + SigSpec my_a = module->wires_.at(remap_name(c->getPort(ID::A).as_wire()->name)); + SigSpec my_y = module->wires_.at(remap_name(c->getPort(ID::Y).as_wire()->name)); + module->connect(my_y, my_a); + if (markgroups) c->attributes[ID(abcgroup)] = map_autoidx; + log_abort(); + continue; + } + cell = module->addCell(remap_name(c->name), c->type); + } + else { + existing_cell = module->cell(c->name); + log_assert(existing_cell); + cell = module->addCell(remap_name(c->name), c->type); + module->swap_names(cell, existing_cell); + } + + if (markgroups) cell->attributes[ID(abcgroup)] = map_autoidx; + if (existing_cell) { + cell->parameters = existing_cell->parameters; + cell->attributes = existing_cell->attributes; + } + else { + cell->parameters = c->parameters; + cell->attributes = c->attributes; + } + for (auto &conn : c->connections()) { + RTLIL::SigSpec newsig; + for (auto c : conn.second.chunks()) { + if (c.width == 0) + continue; + //log_assert(c.width == 1); + if (c.wire) + c.wire = module->wires_.at(remap_name(c.wire->name)); + newsig.append(c); + } + cell->setPort(conn.first, newsig); + + if (cell->input(conn.first)) { + for (auto i : newsig) + bit2sinks[i].push_back(cell); + for (auto i : conn.second) + bit_users[i].insert(c->name); + } + if (cell->output(conn.first)) + for (auto i : conn.second) + bit_drivers[i].insert(c->name); + } + } + + for (auto cell : boxes) + module->remove(cell); + + // Copy connections (and rename) from mapped_mod to module + for (auto conn : mapped_mod->connections()) { + if (!conn.first.is_fully_const()) { + auto chunks = conn.first.chunks(); + for (auto &c : chunks) + c.wire = module->wires_.at(remap_name(c.wire->name)); + conn.first = std::move(chunks); + } + if (!conn.second.is_fully_const()) { + auto chunks = conn.second.chunks(); + for (auto &c : chunks) + if (c.wire) + c.wire = module->wires_.at(remap_name(c.wire->name)); + conn.second = std::move(chunks); + } + module->connect(conn); + } + + for (auto &it : cell_stats) + log("ABC RESULTS: %15s cells: %8d\n", it.first.c_str(), it.second); + int in_wires = 0, out_wires = 0; + + // Stitch in mapped_mod's inputs/outputs into module + for (auto port : mapped_mod->ports) { + RTLIL::Wire *w = mapped_mod->wire(port); + RTLIL::Wire *wire = module->wire(port); + log_assert(wire); + RTLIL::Wire *remap_wire = module->wire(remap_name(port)); + RTLIL::SigSpec signal = RTLIL::SigSpec(wire, 0, GetSize(remap_wire)); + log_assert(GetSize(signal) >= GetSize(remap_wire)); + + RTLIL::SigSig conn; + if (w->port_output) { + conn.first = signal; + conn.second = remap_wire; + out_wires++; + module->connect(conn); + } + else if (w->port_input) { + conn.first = remap_wire; + conn.second = signal; + in_wires++; + module->connect(conn); + } + } + + for (auto &it : bit_users) + if (bit_drivers.count(it.first)) + for (auto driver_cell : bit_drivers.at(it.first)) + for (auto user_cell : it.second) + toposort.edge(driver_cell, user_cell); + bool no_loops YS_ATTRIBUTE(unused) = toposort.sort(); + log_assert(no_loops); + + for (auto ii = toposort.sorted.rbegin(); ii != toposort.sorted.rend(); ii++) { + RTLIL::Cell *not_cell = mapped_mod->cell(*ii); + log_assert(not_cell); + if (not_cell->type != ID($_NOT_)) + continue; + auto it = not2drivers.find(not_cell); + if (it == not2drivers.end()) + continue; + RTLIL::Cell *driver_lut = it->second; + RTLIL::SigBit a_bit = not_cell->getPort(ID::A); + RTLIL::SigBit y_bit = not_cell->getPort(ID::Y); + RTLIL::Const driver_mask; + + a_bit.wire = module->wires_.at(remap_name(a_bit.wire->name)); + y_bit.wire = module->wires_.at(remap_name(y_bit.wire->name)); + + auto jt = bit2sinks.find(a_bit); + if (jt == bit2sinks.end()) + goto clone_lut; + + for (auto sink_cell : jt->second) + if (sink_cell->type != ID($lut)) + goto clone_lut; + + // Push downstream LUTs past inverter + for (auto sink_cell : jt->second) { + SigSpec A = sink_cell->getPort(ID::A); + RTLIL::Const mask = sink_cell->getParam(ID(LUT)); + int index = 0; + for (; index < GetSize(A); index++) + if (A[index] == a_bit) + break; + log_assert(index < GetSize(A)); + int i = 0; + while (i < GetSize(mask)) { + for (int j = 0; j < (1 << index); j++) + std::swap(mask[i+j], mask[i+j+(1 << index)]); + i += 1 << (index+1); + } + A[index] = y_bit; + sink_cell->setPort(ID::A, A); + sink_cell->setParam(ID(LUT), mask); + } + + // Since we have rewritten all sinks (which we know + // to be only LUTs) to be after the inverter, we can + // go ahead and clone the LUT with the expectation + // that the original driving LUT will become dangling + // and get cleaned away +clone_lut: + driver_mask = driver_lut->getParam(ID(LUT)); + for (auto &b : driver_mask.bits) { + if (b == RTLIL::State::S0) b = RTLIL::State::S1; + else if (b == RTLIL::State::S1) b = RTLIL::State::S0; + } + auto cell = module->addLut(NEW_ID, + driver_lut->getPort(ID::A), + y_bit, + driver_mask); + for (auto &bit : cell->connections_.at(ID::A)) { + bit.wire = module->wires_.at(remap_name(bit.wire->name)); + bit2sinks[bit].push_back(cell); + } + } + + //log("ABC RESULTS: internal signals: %8d\n", int(signal_list.size()) - in_wires - out_wires); + log("ABC RESULTS: input signals: %8d\n", in_wires); + log("ABC RESULTS: output signals: %8d\n", out_wires); + + design->remove(mapped_mod); + } + else + { + log("Don't call ABC as there is nothing to map.\n"); + } + + if (cleanup) + { + log("Removing temp directory.\n"); + remove_directory(tempdir_name); + } + + log_pop(); +} + +struct Abc9Pass : public Pass { + Abc9Pass() : Pass("abc9", "use ABC9 for technology mapping") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" abc9 [options] [selection]\n"); + log("\n"); + log("This pass uses the ABC tool [1] for technology mapping of yosys's internal gate\n"); + log("library to a target architecture.\n"); + log("\n"); + log(" -exe <command>\n"); +#ifdef ABCEXTERNAL + log(" use the specified command instead of \"" ABCEXTERNAL "\" to execute ABC.\n"); +#else + log(" use the specified command instead of \"<yosys-bindir>/yosys-abc\" to execute ABC.\n"); +#endif + log(" This can e.g. be used to call a specific version of ABC or a wrapper.\n"); + log("\n"); + log(" -script <file>\n"); + log(" use the specified ABC script file instead of the default script.\n"); + log("\n"); + log(" if <file> starts with a plus sign (+), then the rest of the filename\n"); + log(" string is interpreted as the command string to be passed to ABC. The\n"); + log(" leading plus sign is removed and all commas (,) in the string are\n"); + log(" replaced with blanks before the string is passed to ABC.\n"); + log("\n"); + log(" if no -script parameter is given, the following scripts are used:\n"); + log("\n"); + log(" for -lut/-luts (only one LUT size):\n"); + log("%s\n", fold_abc_cmd(ABC_COMMAND_LUT /*"; lutpack {S}"*/).c_str()); + log("\n"); + log(" for -lut/-luts (different LUT sizes):\n"); + log("%s\n", fold_abc_cmd(ABC_COMMAND_LUT).c_str()); + log("\n"); + log(" -fast\n"); + log(" use different default scripts that are slightly faster (at the cost\n"); + log(" of output quality):\n"); + log("\n"); + log(" for -lut/-luts:\n"); + log("%s\n", fold_abc_cmd(ABC_FAST_COMMAND_LUT).c_str()); + log("\n"); + log(" -D <picoseconds>\n"); + log(" set delay target. the string {D} in the default scripts above is\n"); + log(" replaced by this option when used, and an empty string otherwise\n"); + log(" (indicating best possible delay).\n"); +// log(" This also replaces 'dretime' with 'dretime; retime -o {D}' in the\n"); +// log(" default scripts above.\n"); + log("\n"); +// log(" -S <num>\n"); +// log(" maximum number of LUT inputs shared.\n"); +// log(" (replaces {S} in the default scripts above, default: -S 1)\n"); +// log("\n"); + log(" -lut <width>\n"); + log(" generate netlist using luts of (max) the specified width.\n"); + log("\n"); + log(" -lut <w1>:<w2>\n"); + log(" generate netlist using luts of (max) the specified width <w2>. All\n"); + log(" luts with width <= <w1> have constant cost. for luts larger than <w1>\n"); + log(" the area cost doubles with each additional input bit. the delay cost\n"); + log(" is still constant for all lut widths.\n"); + log("\n"); + log(" -lut <file>\n"); + log(" pass this file with lut library to ABC.\n"); + log("\n"); + log(" -luts <cost1>,<cost2>,<cost3>,<sizeN>:<cost4-N>,..\n"); + log(" generate netlist using luts. Use the specified costs for luts with 1,\n"); + log(" 2, 3, .. inputs.\n"); + log("\n"); +// log(" -dff\n"); +// log(" also pass $_DFF_?_ and $_DFFE_??_ cells through ABC. modules with many\n"); +// log(" clock domains are automatically partitioned in clock domains and each\n"); +// log(" domain is passed through ABC independently.\n"); +// log("\n"); +// log(" -clk [!]<clock-signal-name>[,[!]<enable-signal-name>]\n"); +// log(" use only the specified clock domain. this is like -dff, but only FF\n"); +// log(" cells that belong to the specified clock domain are used.\n"); +// log("\n"); +// log(" -keepff\n"); +// log(" set the \"keep\" attribute on flip-flop output wires. (and thus preserve\n"); +// log(" them, for example for equivalence checking.)\n"); +// log("\n"); + log(" -nocleanup\n"); + log(" when this option is used, the temporary files created by this pass\n"); + log(" are not removed. this is useful for debugging.\n"); + log("\n"); + log(" -showtmp\n"); + log(" print the temp dir name in log. usually this is suppressed so that the\n"); + log(" command output is identical across runs.\n"); + log("\n"); + log(" -markgroups\n"); + log(" set a 'abcgroup' attribute on all objects created by ABC. The value of\n"); + log(" this attribute is a unique integer for each ABC process started. This\n"); + log(" is useful for debugging the partitioning of clock domains.\n"); + log("\n"); + log(" -box <file>\n"); + log(" pass this file with box library to ABC. Use with -lut.\n"); + log("\n"); + log("Note that this is a logic optimization pass within Yosys that is calling ABC\n"); + log("internally. This is not going to \"run ABC on your design\". It will instead run\n"); + log("ABC on logic snippets extracted from your design. You will not get any useful\n"); + log("output when passing an ABC script that writes a file. Instead write your full\n"); + log("design as BLIF file with write_blif and then load that into ABC externally if\n"); + log("you want to use ABC to convert your design into another format.\n"); + log("\n"); + log("[1] http://www.eecs.berkeley.edu/~alanmi/abc/\n"); + log("\n"); + } + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + log_header(design, "Executing ABC9 pass (technology mapping using ABC9).\n"); + log_push(); + + assign_map.clear(); + +#ifdef ABCEXTERNAL + std::string exe_file = ABCEXTERNAL; +#else + std::string exe_file = proc_self_dirname() + "yosys-abc"; +#endif + std::string script_file, clk_str, box_file, lut_file; + std::string delay_target, lutin_shared = "-S 1", wire_delay; + bool fast_mode = false, dff_mode = false, keepff = false, cleanup = true; + bool show_tempdir = false; + vector<int> lut_costs; + markgroups = false; + +#if 0 + cleanup = false; + show_tempdir = true; +#endif + +#ifdef _WIN32 +#ifndef ABCEXTERNAL + if (!check_file_exists(exe_file + ".exe") && check_file_exists(proc_self_dirname() + "..\\yosys-abc.exe")) + exe_file = proc_self_dirname() + "..\\yosys-abc"; +#endif +#endif + + size_t argidx; + char pwd [PATH_MAX]; + if (!getcwd(pwd, sizeof(pwd))) { + log_cmd_error("getcwd failed: %s\n", strerror(errno)); + log_abort(); + } + for (argidx = 1; argidx < args.size(); argidx++) { + std::string arg = args[argidx]; + if (arg == "-exe" && argidx+1 < args.size()) { + exe_file = args[++argidx]; + continue; + } + if (arg == "-script" && argidx+1 < args.size()) { + script_file = args[++argidx]; + rewrite_filename(script_file); + if (!script_file.empty() && !is_absolute_path(script_file) && script_file[0] != '+') + script_file = std::string(pwd) + "/" + script_file; + continue; + } + if (arg == "-D" && argidx+1 < args.size()) { + delay_target = "-D " + args[++argidx]; + continue; + } + //if (arg == "-S" && argidx+1 < args.size()) { + // lutin_shared = "-S " + args[++argidx]; + // continue; + //} + if (arg == "-lut" && argidx+1 < args.size()) { + string arg = args[++argidx]; + size_t pos = arg.find_first_of(':'); + int lut_mode = 0, lut_mode2 = 0; + if (pos != string::npos) { + lut_mode = atoi(arg.substr(0, pos).c_str()); + lut_mode2 = atoi(arg.substr(pos+1).c_str()); + } else { + pos = arg.find_first_of('.'); + if (pos != string::npos) { + lut_file = arg; + rewrite_filename(lut_file); + if (!lut_file.empty() && !is_absolute_path(lut_file)) + lut_file = std::string(pwd) + "/" + lut_file; + } + else { + lut_mode = atoi(arg.c_str()); + lut_mode2 = lut_mode; + } + } + lut_costs.clear(); + for (int i = 0; i < lut_mode; i++) + lut_costs.push_back(1); + for (int i = lut_mode; i < lut_mode2; i++) + lut_costs.push_back(2 << (i - lut_mode)); + continue; + } + if (arg == "-luts" && argidx+1 < args.size()) { + lut_costs.clear(); + for (auto &tok : split_tokens(args[++argidx], ",")) { + auto parts = split_tokens(tok, ":"); + if (GetSize(parts) == 0 && !lut_costs.empty()) + lut_costs.push_back(lut_costs.back()); + else if (GetSize(parts) == 1) + lut_costs.push_back(atoi(parts.at(0).c_str())); + else if (GetSize(parts) == 2) + while (GetSize(lut_costs) < atoi(parts.at(0).c_str())) + lut_costs.push_back(atoi(parts.at(1).c_str())); + else + log_cmd_error("Invalid -luts syntax.\n"); + } + continue; + } + if (arg == "-fast") { + fast_mode = true; + continue; + } + //if (arg == "-dff") { + // dff_mode = true; + // continue; + //} + //if (arg == "-clk" && argidx+1 < args.size()) { + // clk_str = args[++argidx]; + // dff_mode = true; + // continue; + //} + //if (arg == "-keepff") { + // keepff = true; + // continue; + //} + if (arg == "-nocleanup") { + cleanup = false; + continue; + } + if (arg == "-showtmp") { + show_tempdir = true; + continue; + } + if (arg == "-markgroups") { + markgroups = true; + continue; + } + if (arg == "-box" && argidx+1 < args.size()) { + box_file = args[++argidx]; + continue; + } + if (arg == "-W" && argidx+1 < args.size()) { + wire_delay = "-W " + args[++argidx]; + continue; + } + break; + } + extra_args(args, argidx, design); + + // ABC expects a box file for XAIG + if (box_file.empty()) + box_file = "+/dummy.box"; + + rewrite_filename(box_file); + if (!box_file.empty() && !is_absolute_path(box_file)) + box_file = std::string(pwd) + "/" + box_file; + + dict<int,IdString> box_lookup; + for (auto m : design->modules()) { + auto it = m->attributes.find(ID(abc_box_id)); + if (it == m->attributes.end()) + continue; + if (m->name.begins_with("$paramod")) + continue; + auto id = it->second.as_int(); + auto r = box_lookup.insert(std::make_pair(id, m->name)); + if (!r.second) + log_error("Module '%s' has the same abc_box_id = %d value as '%s'.\n", + log_id(m), id, log_id(r.first->second)); + log_assert(r.second); + + RTLIL::Wire *carry_in = nullptr, *carry_out = nullptr; + for (auto p : m->ports) { + auto w = m->wire(p); + log_assert(w); + if (w->attributes.count(ID(abc_carry))) { + if (w->port_input) { + if (carry_in) + log_error("Module '%s' contains more than one 'abc_carry' input port.\n", log_id(m)); + carry_in = w; + } + else if (w->port_output) { + if (carry_out) + log_error("Module '%s' contains more than one 'abc_carry' input port.\n", log_id(m)); + carry_out = w; + } + } + } + if (carry_in || carry_out) { + if (carry_in && !carry_out) + log_error("Module '%s' contains an 'abc_carry' input port but no output port.\n", log_id(m)); + if (!carry_in && carry_out) + log_error("Module '%s' contains an 'abc_carry' output port but no input port.\n", log_id(m)); + // Make carry_in the last PI, and carry_out the last PO + // since ABC requires it this way + auto &ports = m->ports; + for (auto it = ports.begin(); it != ports.end(); ) { + RTLIL::Wire* w = m->wire(*it); + log_assert(w); + if (w == carry_in || w == carry_out) { + it = ports.erase(it); + continue; + } + if (w->port_id > carry_in->port_id) + --w->port_id; + if (w->port_id > carry_out->port_id) + --w->port_id; + log_assert(w->port_input || w->port_output); + log_assert(ports[w->port_id-1] == w->name); + ++it; + } + ports.push_back(carry_in->name); + carry_in->port_id = ports.size(); + ports.push_back(carry_out->name); + carry_out->port_id = ports.size(); + } + } + + for (auto mod : design->selected_modules()) + { + if (mod->attributes.count(ID(abc_box_id))) + continue; + + if (mod->processes.size() > 0) { + log("Skipping module %s as it contains processes.\n", log_id(mod)); + continue; + } + + assign_map.set(mod); + + if (!dff_mode || !clk_str.empty()) { + abc9_module(design, mod, script_file, exe_file, cleanup, lut_costs, dff_mode, clk_str, keepff, + delay_target, lutin_shared, fast_mode, show_tempdir, + box_file, lut_file, wire_delay, box_lookup); + continue; + } + + CellTypes ct(design); + + std::vector<RTLIL::Cell*> all_cells = mod->selected_cells(); + std::set<RTLIL::Cell*> unassigned_cells(all_cells.begin(), all_cells.end()); + + std::set<RTLIL::Cell*> expand_queue, next_expand_queue; + std::set<RTLIL::Cell*> expand_queue_up, next_expand_queue_up; + std::set<RTLIL::Cell*> expand_queue_down, next_expand_queue_down; + + typedef tuple<bool, RTLIL::SigSpec, bool, RTLIL::SigSpec> clkdomain_t; + std::map<clkdomain_t, std::vector<RTLIL::Cell*>> assigned_cells; + std::map<RTLIL::Cell*, clkdomain_t> assigned_cells_reverse; + + std::map<RTLIL::Cell*, std::set<RTLIL::SigBit>> cell_to_bit, cell_to_bit_up, cell_to_bit_down; + std::map<RTLIL::SigBit, std::set<RTLIL::Cell*>> bit_to_cell, bit_to_cell_up, bit_to_cell_down; + + for (auto cell : all_cells) + { + clkdomain_t key; + + for (auto &conn : cell->connections()) + for (auto bit : conn.second) { + bit = assign_map(bit); + if (bit.wire != nullptr) { + cell_to_bit[cell].insert(bit); + bit_to_cell[bit].insert(cell); + if (ct.cell_input(cell->type, conn.first)) { + cell_to_bit_up[cell].insert(bit); + bit_to_cell_down[bit].insert(cell); + } + if (ct.cell_output(cell->type, conn.first)) { + cell_to_bit_down[cell].insert(bit); + bit_to_cell_up[bit].insert(cell); + } + } + } + + if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_))) + { + key = clkdomain_t(cell->type == ID($_DFF_P_), assign_map(cell->getPort(ID(C))), true, RTLIL::SigSpec()); + } + else + if (cell->type.in(ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_))) + { + bool this_clk_pol = cell->type.in(ID($_DFFE_PN_), ID($_DFFE_PP_)); + bool this_en_pol = cell->type.in(ID($_DFFE_NP_), ID($_DFFE_PP_)); + key = clkdomain_t(this_clk_pol, assign_map(cell->getPort(ID(C))), this_en_pol, assign_map(cell->getPort(ID(E)))); + } + else + continue; + + unassigned_cells.erase(cell); + expand_queue.insert(cell); + expand_queue_up.insert(cell); + expand_queue_down.insert(cell); + + assigned_cells[key].push_back(cell); + assigned_cells_reverse[cell] = key; + } + + while (!expand_queue_up.empty() || !expand_queue_down.empty()) + { + if (!expand_queue_up.empty()) + { + RTLIL::Cell *cell = *expand_queue_up.begin(); + clkdomain_t key = assigned_cells_reverse.at(cell); + expand_queue_up.erase(cell); + + for (auto bit : cell_to_bit_up[cell]) + for (auto c : bit_to_cell_up[bit]) + if (unassigned_cells.count(c)) { + unassigned_cells.erase(c); + next_expand_queue_up.insert(c); + assigned_cells[key].push_back(c); + assigned_cells_reverse[c] = key; + expand_queue.insert(c); + } + } + + if (!expand_queue_down.empty()) + { + RTLIL::Cell *cell = *expand_queue_down.begin(); + clkdomain_t key = assigned_cells_reverse.at(cell); + expand_queue_down.erase(cell); + + for (auto bit : cell_to_bit_down[cell]) + for (auto c : bit_to_cell_down[bit]) + if (unassigned_cells.count(c)) { + unassigned_cells.erase(c); + next_expand_queue_up.insert(c); + assigned_cells[key].push_back(c); + assigned_cells_reverse[c] = key; + expand_queue.insert(c); + } + } + + if (expand_queue_up.empty() && expand_queue_down.empty()) { + expand_queue_up.swap(next_expand_queue_up); + expand_queue_down.swap(next_expand_queue_down); + } + } + + while (!expand_queue.empty()) + { + RTLIL::Cell *cell = *expand_queue.begin(); + clkdomain_t key = assigned_cells_reverse.at(cell); + expand_queue.erase(cell); + + for (auto bit : cell_to_bit.at(cell)) { + for (auto c : bit_to_cell[bit]) + if (unassigned_cells.count(c)) { + unassigned_cells.erase(c); + next_expand_queue.insert(c); + assigned_cells[key].push_back(c); + assigned_cells_reverse[c] = key; + } + bit_to_cell[bit].clear(); + } + + if (expand_queue.empty()) + expand_queue.swap(next_expand_queue); + } + + clkdomain_t key(true, RTLIL::SigSpec(), true, RTLIL::SigSpec()); + for (auto cell : unassigned_cells) { + assigned_cells[key].push_back(cell); + assigned_cells_reverse[cell] = key; + } + + log_header(design, "Summary of detected clock domains:\n"); + for (auto &it : assigned_cells) + log(" %d cells in clk=%s%s, en=%s%s\n", GetSize(it.second), + std::get<0>(it.first) ? "" : "!", log_signal(std::get<1>(it.first)), + std::get<2>(it.first) ? "" : "!", log_signal(std::get<3>(it.first))); + + for (auto &it : assigned_cells) { + clk_polarity = std::get<0>(it.first); + clk_sig = assign_map(std::get<1>(it.first)); + en_polarity = std::get<2>(it.first); + en_sig = assign_map(std::get<3>(it.first)); + abc9_module(design, mod, script_file, exe_file, cleanup, lut_costs, !clk_sig.empty(), "$", + keepff, delay_target, lutin_shared, fast_mode, show_tempdir, + box_file, lut_file, wire_delay, box_lookup); + assign_map.set(mod); + } + } + + assign_map.clear(); + + log_pop(); + } +} Abc9Pass; + +PRIVATE_NAMESPACE_END diff --git a/passes/techmap/aigmap.cc b/passes/techmap/aigmap.cc index b9ac7aded..1d5e1286b 100644 --- a/passes/techmap/aigmap.cc +++ b/passes/techmap/aigmap.cc @@ -25,7 +25,7 @@ PRIVATE_NAMESPACE_BEGIN struct AigmapPass : public Pass { AigmapPass() : Pass("aigmap", "map logic to and-inverter-graph circuit") { } - virtual void help() + void help() YS_OVERRIDE { log("\n"); log(" aigmap [options] [selection]\n"); @@ -37,7 +37,7 @@ struct AigmapPass : public Pass { log(" Enable creation of $_NAND_ cells\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { bool nand_mode = false; @@ -66,10 +66,10 @@ struct AigmapPass : public Pass { { Aig aig(cell); - if (cell->type == "$_AND_" || cell->type == "$_NOT_") + if (cell->type.in(ID($_AND_), ID($_NOT_))) aig.name.clear(); - if (nand_mode && cell->type == "$_NAND_") + if (nand_mode && cell->type == ID($_NAND_)) aig.name.clear(); if (aig.name.empty()) { diff --git a/passes/techmap/alumacc.cc b/passes/techmap/alumacc.cc index 95be7ab3b..034731b87 100644 --- a/passes/techmap/alumacc.cc +++ b/passes/techmap/alumacc.cc @@ -48,20 +48,31 @@ struct AlumaccWorker RTLIL::SigSpec cached_cf, cached_of, cached_sf; RTLIL::SigSpec get_lt() { - if (GetSize(cached_lt) == 0) - cached_lt = is_signed ? alu_cell->module->Xor(NEW_ID, get_of(), get_sf()) : get_cf(); + if (GetSize(cached_lt) == 0) { + if (is_signed) { + get_of(); + get_sf(); + cached_lt = alu_cell->module->Xor(NEW_ID, cached_of, cached_sf); + } + else + cached_lt = get_cf(); + } return cached_lt; } RTLIL::SigSpec get_gt() { - if (GetSize(cached_gt) == 0) - cached_gt = alu_cell->module->Not(NEW_ID, alu_cell->module->Or(NEW_ID, get_lt(), get_eq()), false, alu_cell->get_src_attribute()); + if (GetSize(cached_gt) == 0) { + get_lt(); + get_eq(); + SigSpec Or = alu_cell->module->Or(NEW_ID, cached_lt, cached_eq); + cached_gt = alu_cell->module->Not(NEW_ID, Or, false, alu_cell->get_src_attribute()); + } return cached_gt; } RTLIL::SigSpec get_eq() { if (GetSize(cached_eq) == 0) - cached_eq = alu_cell->module->ReduceAnd(NEW_ID, alu_cell->getPort("\\X"), false, alu_cell->get_src_attribute()); + cached_eq = alu_cell->module->ReduceAnd(NEW_ID, alu_cell->getPort(ID(X)), false, alu_cell->get_src_attribute()); return cached_eq; } @@ -73,7 +84,7 @@ struct AlumaccWorker RTLIL::SigSpec get_cf() { if (GetSize(cached_cf) == 0) { - cached_cf = alu_cell->getPort("\\CO"); + cached_cf = alu_cell->getPort(ID(CO)); log_assert(GetSize(cached_cf) >= 1); cached_cf = alu_cell->module->Not(NEW_ID, cached_cf[GetSize(cached_cf)-1], false, alu_cell->get_src_attribute()); } @@ -82,7 +93,7 @@ struct AlumaccWorker RTLIL::SigSpec get_of() { if (GetSize(cached_of) == 0) { - cached_of = {alu_cell->getPort("\\CO"), alu_cell->getPort("\\CI")}; + cached_of = {alu_cell->getPort(ID(CO)), alu_cell->getPort(ID(CI))}; log_assert(GetSize(cached_of) >= 2); cached_of = alu_cell->module->Xor(NEW_ID, cached_of[GetSize(cached_of)-1], cached_of[GetSize(cached_of)-2]); } @@ -91,7 +102,7 @@ struct AlumaccWorker RTLIL::SigSpec get_sf() { if (GetSize(cached_sf) == 0) { - cached_sf = alu_cell->getPort("\\Y"); + cached_sf = alu_cell->getPort(ID::Y); cached_sf = cached_sf[GetSize(cached_sf)-1]; } return cached_sf; @@ -125,7 +136,7 @@ struct AlumaccWorker { for (auto cell : module->selected_cells()) { - if (!cell->type.in("$pos", "$neg", "$add", "$sub", "$mul")) + if (!cell->type.in(ID($pos), ID($neg), ID($add), ID($sub), ID($mul))) continue; log(" creating $macc model for %s (%s).\n", log_id(cell), log_id(cell->type)); @@ -134,38 +145,38 @@ struct AlumaccWorker Macc::port_t new_port; n->cell = cell; - n->y = sigmap(cell->getPort("\\Y")); + n->y = sigmap(cell->getPort(ID::Y)); n->users = 0; for (auto bit : n->y) n->users = max(n->users, bit_users.at(bit) - 1); - if (cell->type.in("$pos", "$neg")) + if (cell->type.in(ID($pos), ID($neg))) { - new_port.in_a = sigmap(cell->getPort("\\A")); - new_port.is_signed = cell->getParam("\\A_SIGNED").as_bool(); - new_port.do_subtract = cell->type == "$neg"; + new_port.in_a = sigmap(cell->getPort(ID::A)); + new_port.is_signed = cell->getParam(ID(A_SIGNED)).as_bool(); + new_port.do_subtract = cell->type == ID($neg); n->macc.ports.push_back(new_port); } - if (cell->type.in("$add", "$sub")) + if (cell->type.in(ID($add), ID($sub))) { - new_port.in_a = sigmap(cell->getPort("\\A")); - new_port.is_signed = cell->getParam("\\A_SIGNED").as_bool(); + new_port.in_a = sigmap(cell->getPort(ID::A)); + new_port.is_signed = cell->getParam(ID(A_SIGNED)).as_bool(); new_port.do_subtract = false; n->macc.ports.push_back(new_port); - new_port.in_a = sigmap(cell->getPort("\\B")); - new_port.is_signed = cell->getParam("\\B_SIGNED").as_bool(); - new_port.do_subtract = cell->type == "$sub"; + new_port.in_a = sigmap(cell->getPort(ID::B)); + new_port.is_signed = cell->getParam(ID(B_SIGNED)).as_bool(); + new_port.do_subtract = cell->type == ID($sub); n->macc.ports.push_back(new_port); } - if (cell->type.in("$mul")) + if (cell->type.in(ID($mul))) { - new_port.in_a = sigmap(cell->getPort("\\A")); - new_port.in_b = sigmap(cell->getPort("\\B")); - new_port.is_signed = cell->getParam("\\A_SIGNED").as_bool(); + new_port.in_a = sigmap(cell->getPort(ID::A)); + new_port.in_b = sigmap(cell->getPort(ID::B)); + new_port.is_signed = cell->getParam(ID(A_SIGNED)).as_bool(); new_port.do_subtract = false; n->macc.ports.push_back(new_port); } @@ -315,7 +326,7 @@ struct AlumaccWorker } if (subtract_b) - C.append(RTLIL::S1); + C.append(State::S1); if (GetSize(C) > 1) goto next_macc; @@ -351,7 +362,7 @@ struct AlumaccWorker for (auto &it : sig_macc) { auto n = it.second; - auto cell = module->addCell(NEW_ID, "$macc"); + auto cell = module->addCell(NEW_ID, ID($macc)); macc_counter++; @@ -361,7 +372,7 @@ struct AlumaccWorker n->macc.optimize(GetSize(n->y)); n->macc.to_cell(cell); - cell->setPort("\\Y", n->y); + cell->setPort(ID::Y, n->y); cell->fixup_parameters(); module->remove(n->cell); delete n; @@ -376,9 +387,9 @@ struct AlumaccWorker for (auto cell : module->selected_cells()) { - if (cell->type.in("$lt", "$le", "$ge", "$gt")) + if (cell->type.in(ID($lt), ID($le), ID($ge), ID($gt))) lge_cells.push_back(cell); - if (cell->type.in("$eq", "$eqx", "$ne", "$nex")) + if (cell->type.in(ID($eq), ID($eqx), ID($ne), ID($nex))) eq_cells.push_back(cell); } @@ -386,13 +397,13 @@ struct AlumaccWorker { log(" creating $alu model for %s (%s):", log_id(cell), log_id(cell->type)); - bool cmp_less = cell->type.in("$lt", "$le"); - bool cmp_equal = cell->type.in("$le", "$ge"); - bool is_signed = cell->getParam("\\A_SIGNED").as_bool(); + bool cmp_less = cell->type.in(ID($lt), ID($le)); + bool cmp_equal = cell->type.in(ID($le), ID($ge)); + bool is_signed = cell->getParam(ID(A_SIGNED)).as_bool(); - RTLIL::SigSpec A = sigmap(cell->getPort("\\A")); - RTLIL::SigSpec B = sigmap(cell->getPort("\\B")); - RTLIL::SigSpec Y = sigmap(cell->getPort("\\Y")); + RTLIL::SigSpec A = sigmap(cell->getPort(ID::A)); + RTLIL::SigSpec B = sigmap(cell->getPort(ID::B)); + RTLIL::SigSpec Y = sigmap(cell->getPort(ID::Y)); if (B < A && GetSize(B)) { cmp_less = !cmp_less; @@ -402,7 +413,7 @@ struct AlumaccWorker alunode_t *n = nullptr; for (auto node : sig_alu[RTLIL::SigSig(A, B)]) - if (node->is_signed == is_signed && node->invert_b && node->c == RTLIL::S1) { + if (node->is_signed == is_signed && node->invert_b && node->c == State::S1) { n = node; break; } @@ -411,7 +422,7 @@ struct AlumaccWorker n = new alunode_t; n->a = A; n->b = B; - n->c = RTLIL::S1; + n->c = State::S1; n->y = module->addWire(NEW_ID, max(GetSize(A), GetSize(B))); n->is_signed = is_signed; n->invert_b = true; @@ -427,12 +438,12 @@ struct AlumaccWorker for (auto cell : eq_cells) { - bool cmp_equal = cell->type.in("$eq", "$eqx"); - bool is_signed = cell->getParam("\\A_SIGNED").as_bool(); + bool cmp_equal = cell->type.in(ID($eq), ID($eqx)); + bool is_signed = cell->getParam(ID(A_SIGNED)).as_bool(); - RTLIL::SigSpec A = sigmap(cell->getPort("\\A")); - RTLIL::SigSpec B = sigmap(cell->getPort("\\B")); - RTLIL::SigSpec Y = sigmap(cell->getPort("\\Y")); + RTLIL::SigSpec A = sigmap(cell->getPort(ID::A)); + RTLIL::SigSpec B = sigmap(cell->getPort(ID::B)); + RTLIL::SigSpec Y = sigmap(cell->getPort(ID::Y)); if (B < A && GetSize(B)) std::swap(A, B); @@ -440,7 +451,7 @@ struct AlumaccWorker alunode_t *n = nullptr; for (auto node : sig_alu[RTLIL::SigSig(A, B)]) - if (node->is_signed == is_signed && node->invert_b && node->c == RTLIL::S1) { + if (node->is_signed == is_signed && node->invert_b && node->c == State::S1) { n = node; break; } @@ -471,7 +482,7 @@ struct AlumaccWorker goto delete_node; } - n->alu_cell = module->addCell(NEW_ID, "$alu"); + n->alu_cell = module->addCell(NEW_ID, ID($alu)); alu_counter++; log(" creating $alu cell for "); @@ -482,13 +493,13 @@ struct AlumaccWorker if (n->cells.size() > 0) n->alu_cell->set_src_attribute(n->cells[0]->get_src_attribute()); - n->alu_cell->setPort("\\A", n->a); - n->alu_cell->setPort("\\B", n->b); - n->alu_cell->setPort("\\CI", GetSize(n->c) ? n->c : RTLIL::S0); - n->alu_cell->setPort("\\BI", n->invert_b ? RTLIL::S1 : RTLIL::S0); - n->alu_cell->setPort("\\Y", n->y); - n->alu_cell->setPort("\\X", module->addWire(NEW_ID, GetSize(n->y))); - n->alu_cell->setPort("\\CO", module->addWire(NEW_ID, GetSize(n->y))); + n->alu_cell->setPort(ID::A, n->a); + n->alu_cell->setPort(ID::B, n->b); + n->alu_cell->setPort(ID(CI), GetSize(n->c) ? n->c : State::S0); + n->alu_cell->setPort(ID(BI), n->invert_b ? State::S1 : State::S0); + n->alu_cell->setPort(ID::Y, n->y); + n->alu_cell->setPort(ID(X), module->addWire(NEW_ID, GetSize(n->y))); + n->alu_cell->setPort(ID(CO), module->addWire(NEW_ID, GetSize(n->y))); n->alu_cell->fixup_parameters(n->is_signed, n->is_signed); for (auto &it : n->cmp) @@ -539,7 +550,7 @@ struct AlumaccWorker struct AlumaccPass : public Pass { AlumaccPass() : Pass("alumacc", "extract ALU and MACC cells") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -549,7 +560,7 @@ struct AlumaccPass : public Pass { log("and $macc cells.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing ALUMACC pass (create $alu and $macc cells).\n"); diff --git a/passes/techmap/attrmap.cc b/passes/techmap/attrmap.cc index dec81d216..5f30817d4 100644 --- a/passes/techmap/attrmap.cc +++ b/passes/techmap/attrmap.cc @@ -81,7 +81,7 @@ struct AttrmapAction { struct AttrmapTocase : AttrmapAction { string name; - virtual bool apply(IdString &id, Const&) { + bool apply(IdString &id, Const&) YS_OVERRIDE { if (match_name(name, id, true)) id = RTLIL::escape_id(name); return true; @@ -90,7 +90,7 @@ struct AttrmapTocase : AttrmapAction { struct AttrmapRename : AttrmapAction { string old_name, new_name; - virtual bool apply(IdString &id, Const&) { + bool apply(IdString &id, Const&) YS_OVERRIDE { if (match_name(old_name, id)) id = RTLIL::escape_id(new_name); return true; @@ -101,7 +101,7 @@ struct AttrmapMap : AttrmapAction { bool imap; string old_name, new_name; string old_value, new_value; - virtual bool apply(IdString &id, Const &val) { + bool apply(IdString &id, Const &val) YS_OVERRIDE { if (match_name(old_name, id) && match_value(old_value, val, true)) { id = RTLIL::escape_id(new_name); val = make_value(new_value); @@ -111,9 +111,10 @@ struct AttrmapMap : AttrmapAction { }; struct AttrmapRemove : AttrmapAction { + bool has_value; string name, value; - virtual bool apply(IdString &id, Const &val) { - return !(match_name(name, id) && match_value(value, val)); + bool apply(IdString &id, Const &val) YS_OVERRIDE { + return !(match_name(name, id) && (!has_value || match_value(value, val))); } }; @@ -142,33 +143,94 @@ void attrmap_apply(string objname, vector<std::unique_ptr<AttrmapAction>> &actio attributes.swap(new_attributes); } +void log_attrmap_paramap_options() +{ + log(" -tocase <name>\n"); + log(" Match attribute names case-insensitively and set it to the specified\n"); + log(" name.\n"); + log("\n"); + log(" -rename <old_name> <new_name>\n"); + log(" Rename attributes as specified\n"); + log("\n"); + log(" -map <old_name>=<old_value> <new_name>=<new_value>\n"); + log(" Map key/value pairs as indicated.\n"); + log("\n"); + log(" -imap <old_name>=<old_value> <new_name>=<new_value>\n"); + log(" Like -map, but use case-insensitive match for <old_value> when\n"); + log(" it is a string value.\n"); + log("\n"); + log(" -remove <name>=<value>\n"); + log(" Remove attributes matching this pattern.\n"); +} + +bool parse_attrmap_paramap_options(size_t &argidx, std::vector<std::string> &args, vector<std::unique_ptr<AttrmapAction>> &actions) +{ + std::string arg = args[argidx]; + if (arg == "-tocase" && argidx+1 < args.size()) { + auto action = new AttrmapTocase; + action->name = args[++argidx]; + actions.push_back(std::unique_ptr<AttrmapAction>(action)); + return true; + } + if (arg == "-rename" && argidx+2 < args.size()) { + auto action = new AttrmapRename; + action->old_name = args[++argidx]; + action->new_name = args[++argidx]; + actions.push_back(std::unique_ptr<AttrmapAction>(action)); + return true; + } + if ((arg == "-map" || arg == "-imap") && argidx+2 < args.size()) { + string arg1 = args[++argidx]; + string arg2 = args[++argidx]; + string val1, val2; + size_t p = arg1.find("="); + if (p != string::npos) { + val1 = arg1.substr(p+1); + arg1 = arg1.substr(0, p); + } + p = arg2.find("="); + if (p != string::npos) { + val2 = arg2.substr(p+1); + arg2 = arg2.substr(0, p); + } + auto action = new AttrmapMap; + action->imap = (arg == "-map"); + action->old_name = arg1; + action->new_name = arg2; + action->old_value = val1; + action->new_value = val2; + actions.push_back(std::unique_ptr<AttrmapAction>(action)); + return true; + } + if (arg == "-remove" && argidx+1 < args.size()) { + string arg1 = args[++argidx], val1; + size_t p = arg1.find("="); + if (p != string::npos) { + val1 = arg1.substr(p+1); + arg1 = arg1.substr(0, p); + } + auto action = new AttrmapRemove; + action->name = arg1; + action->has_value = (p != string::npos); + action->value = val1; + actions.push_back(std::unique_ptr<AttrmapAction>(action)); + return true; + } + return false; +} + struct AttrmapPass : public Pass { AttrmapPass() : Pass("attrmap", "renaming attributes") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); log(" attrmap [options] [selection]\n"); log("\n"); - log("This command renames attributes and/or mapps key/value pairs to\n"); + log("This command renames attributes and/or maps key/value pairs to\n"); log("other key/value pairs.\n"); log("\n"); - log(" -tocase <name>\n"); - log(" Match attribute names case-insensitively and set it to the specified\n"); - log(" name.\n"); - log("\n"); - log(" -rename <old_name> <new_name>\n"); - log(" Rename attributes as specified\n"); - log("\n"); - log(" -map <old_name>=<old_value> <new_name>=<new_value>\n"); - log(" Map key/value pairs as indicated.\n"); - log("\n"); - log(" -imap <old_name>=<old_value> <new_name>=<new_value>\n"); - log(" Like -map, but use case-insensitive match for <old_value> when\n"); - log(" it is a string value.\n"); - log("\n"); - log(" -remove <name>=<value>\n"); - log(" Remove attributes matching this pattern.\n"); + log_attrmap_paramap_options(); log("\n"); log(" -modattr\n"); log(" Operate on module attributes instead of attributes on wires and cells.\n"); @@ -179,7 +241,7 @@ struct AttrmapPass : public Pass { log(" -imap keep=\"false\" keep=0 -remove keep=0\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing ATTRMAP pass (move or copy attributes).\n"); @@ -189,57 +251,9 @@ struct AttrmapPass : public Pass { size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { - std::string arg = args[argidx]; - if (arg == "-tocase" && argidx+1 < args.size()) { - auto action = new AttrmapTocase; - action->name = args[++argidx]; - actions.push_back(std::unique_ptr<AttrmapAction>(action)); - continue; - } - if (arg == "-rename" && argidx+2 < args.size()) { - auto action = new AttrmapRename; - action->old_name = args[++argidx]; - action->new_name = args[++argidx]; - actions.push_back(std::unique_ptr<AttrmapAction>(action)); - continue; - } - if ((arg == "-map" || arg == "-imap") && argidx+2 < args.size()) { - string arg1 = args[++argidx]; - string arg2 = args[++argidx]; - string val1, val2; - size_t p = arg1.find("="); - if (p != string::npos) { - val1 = arg1.substr(p+1); - arg1 = arg1.substr(0, p); - } - p = arg2.find("="); - if (p != string::npos) { - val2 = arg2.substr(p+1); - arg2 = arg2.substr(0, p); - } - auto action = new AttrmapMap; - action->imap = (arg == "-map"); - action->old_name = arg1; - action->new_name = arg2; - action->old_value = val1; - action->new_value = val2; - actions.push_back(std::unique_ptr<AttrmapAction>(action)); - continue; - } - if (arg == "-remove" && argidx+1 < args.size()) { - string arg1 = args[++argidx], val1; - size_t p = arg1.find("="); - if (p != string::npos) { - val1 = arg1.substr(p+1); - arg1 = arg1.substr(0, p); - } - auto action = new AttrmapRemove; - action->name = arg1; - action->value = val1; - actions.push_back(std::unique_ptr<AttrmapAction>(action)); + if (parse_attrmap_paramap_options(argidx, args, actions)) continue; - } - if (arg == "-modattr") { + if (args[argidx] == "-modattr") { modattr_mode = true; continue; } @@ -261,9 +275,67 @@ struct AttrmapPass : public Pass { for (auto cell : module->selected_cells()) attrmap_apply(stringf("%s.%s", log_id(module), log_id(cell)), actions, cell->attributes); + + for (auto proc : module->processes) + { + if (!design->selected(module, proc.second)) + continue; + attrmap_apply(stringf("%s.%s", log_id(module), log_id(proc.first)), actions, proc.second->attributes); + + std::vector<RTLIL::CaseRule*> all_cases = {&proc.second->root_case}; + while (!all_cases.empty()) { + RTLIL::CaseRule *cs = all_cases.back(); + all_cases.pop_back(); + attrmap_apply(stringf("%s.%s (case)", log_id(module), log_id(proc.first)), actions, cs->attributes); + + for (auto &sw : cs->switches) { + attrmap_apply(stringf("%s.%s (switch)", log_id(module), log_id(proc.first)), actions, sw->attributes); + all_cases.insert(all_cases.end(), sw->cases.begin(), sw->cases.end()); + } + } + } } } } } AttrmapPass; +struct ParamapPass : public Pass { + ParamapPass() : Pass("paramap", "renaming cell parameters") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" paramap [options] [selection]\n"); + log("\n"); + log("This command renames cell parameters and/or maps key/value pairs to\n"); + log("other key/value pairs.\n"); + log("\n"); + log_attrmap_paramap_options(); + log("\n"); + log("For example, mapping Diamond-style ECP5 \"init\" attributes to Yosys-style:\n"); + log("\n"); + log(" paramap -tocase INIT t:LUT4\n"); + log("\n"); + } + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + log_header(design, "Executing PARAMAP pass (move or copy cell parameters).\n"); + + vector<std::unique_ptr<AttrmapAction>> actions; + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + if (parse_attrmap_paramap_options(argidx, args, actions)) + continue; + break; + } + extra_args(args, argidx, design); + + for (auto module : design->selected_modules()) + for (auto cell : module->selected_cells()) + attrmap_apply(stringf("%s.%s", log_id(module), log_id(cell)), actions, cell->parameters); + } +} ParamapPass; + PRIVATE_NAMESPACE_END diff --git a/passes/techmap/attrmvcp.cc b/passes/techmap/attrmvcp.cc index 1537def00..e59aa6518 100644 --- a/passes/techmap/attrmvcp.cc +++ b/passes/techmap/attrmvcp.cc @@ -25,7 +25,7 @@ PRIVATE_NAMESPACE_BEGIN struct AttrmvcpPass : public Pass { AttrmvcpPass() : Pass("attrmvcp", "move or copy attributes from wires to driving cells") { } - virtual void help() + void help() YS_OVERRIDE { log("\n"); log(" attrmvcp [options] [selection]\n"); @@ -53,7 +53,7 @@ struct AttrmvcpPass : public Pass { log(" multiple times.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing ATTRMVCP pass (move or copy attributes).\n"); diff --git a/passes/techmap/clkbufmap.cc b/passes/techmap/clkbufmap.cc new file mode 100644 index 000000000..246932d81 --- /dev/null +++ b/passes/techmap/clkbufmap.cc @@ -0,0 +1,298 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * Copyright (C) 2019 Marcin Kościelnicki <mwk@0x04.net> + * + * 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 + +void split_portname_pair(std::string &port1, std::string &port2) +{ + size_t pos = port1.find_first_of(':'); + if (pos != std::string::npos) { + port2 = port1.substr(pos+1); + port1 = port1.substr(0, pos); + } +} + +struct ClkbufmapPass : public Pass { + ClkbufmapPass() : Pass("clkbufmap", "insert global buffers on clock networks") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" clkbufmap [options] [selection]\n"); + log("\n"); + log("Inserts global buffers between nets connected to clock inputs and their drivers.\n"); + log("\n"); + log("In the absence of any selection, all wires without the 'clkbuf_inhibit'\n"); + log("attribute will be considered for global buffer insertion.\n"); + log("Alternatively, to consider all wires without the 'buffer_type' attribute set to\n"); + log("'none' or 'bufr' one would specify:\n"); + log(" 'w:* a:buffer_type=none a:buffer_type=bufr %%u %%d'\n"); + log("as the selection.\n"); + log("\n"); + log(" -buf <celltype> <portname_out>:<portname_in>\n"); + log(" Specifies the cell type to use for the global buffers\n"); + log(" and its port names. The first port will be connected to\n"); + log(" the clock network sinks, and the second will be connected\n"); + log(" to the actual clock source. This option is required.\n"); + log("\n"); + log(" -inpad <celltype> <portname_out>:<portname_in>\n"); + log(" If specified, a PAD cell of the given type is inserted on\n"); + log(" clock nets that are also top module's inputs (in addition\n"); + log(" to the global buffer).\n"); + log("\n"); + } + + void module_queue(Design *design, Module *module, std::vector<Module *> &modules_sorted, pool<Module *> &modules_processed) { + if (modules_processed.count(module)) + return; + for (auto cell : module->cells()) { + Module *submodule = design->module(cell->type); + if (!submodule) + continue; + module_queue(design, submodule, modules_sorted, modules_processed); + } + modules_sorted.push_back(module); + modules_processed.insert(module); + } + + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + log_header(design, "Executing CLKBUFMAP pass (inserting global clock buffers).\n"); + + std::string buf_celltype, buf_portname, buf_portname2; + std::string inpad_celltype, inpad_portname, inpad_portname2; + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + std::string arg = args[argidx]; + if (arg == "-buf" && argidx+2 < args.size()) { + buf_celltype = args[++argidx]; + buf_portname = args[++argidx]; + split_portname_pair(buf_portname, buf_portname2); + continue; + } + if (arg == "-inpad" && argidx+2 < args.size()) { + inpad_celltype = args[++argidx]; + inpad_portname = args[++argidx]; + split_portname_pair(inpad_portname, inpad_portname2); + continue; + } + break; + } + + bool select = false; + if (argidx < args.size()) { + if (args[argidx].compare(0, 1, "-") != 0) + select = true; + extra_args(args, argidx, design); + } + + if (buf_celltype.empty()) + log_error("The -buf option is required.\n"); + + // Cell type, port name, bit index. + pool<pair<IdString, pair<IdString, int>>> sink_ports; + pool<pair<IdString, pair<IdString, int>>> buf_ports; + + // Process submodules before module using them. + std::vector<Module *> modules_sorted; + pool<Module *> modules_processed; + for (auto module : design->selected_modules()) + module_queue(design, module, modules_sorted, modules_processed); + + for (auto module : modules_sorted) + { + if (module->get_blackbox_attribute()) { + for (auto port : module->ports) { + auto wire = module->wire(port); + if (wire->get_bool_attribute("\\clkbuf_driver")) + for (int i = 0; i < GetSize(wire); i++) + buf_ports.insert(make_pair(module->name, make_pair(wire->name, i))); + if (wire->get_bool_attribute("\\clkbuf_sink")) + for (int i = 0; i < GetSize(wire); i++) + sink_ports.insert(make_pair(module->name, make_pair(wire->name, i))); + } + continue; + } + pool<SigBit> sink_wire_bits; + pool<SigBit> buf_wire_bits; + pool<SigBit> driven_wire_bits; + SigMap sigmap(module); + // bit -> (buffer, buffer's input) + dict<SigBit, pair<Cell *, Wire *>> buffered_bits; + + // First, collect nets that could use a clock buffer. + for (auto cell : module->cells()) + for (auto port : cell->connections()) + for (int i = 0; i < port.second.size(); i++) + if (sink_ports.count(make_pair(cell->type, make_pair(port.first, i)))) + sink_wire_bits.insert(sigmap(port.second[i])); + + // Second, collect ones that already have a clock buffer. + for (auto cell : module->cells()) + for (auto port : cell->connections()) + for (int i = 0; i < port.second.size(); i++) + if (buf_ports.count(make_pair(cell->type, make_pair(port.first, i)))) + buf_wire_bits.insert(sigmap(port.second[i])); + + // Collect all driven bits. + for (auto cell : module->cells()) + for (auto port : cell->connections()) + if (cell->output(port.first)) + for (int i = 0; i < port.second.size(); i++) + driven_wire_bits.insert(port.second[i]); + + // Insert buffers. + std::vector<pair<Wire *, Wire *>> input_queue; + // Copy current wire list, as we will be adding new ones during iteration. + std::vector<Wire *> wires(module->wires()); + for (auto wire : wires) + { + // Should not happen. + if (wire->port_input && wire->port_output) + continue; + bool process_wire = module->selected(wire); + if (!select && wire->get_bool_attribute("\\clkbuf_inhibit")) + process_wire = false; + if (!process_wire) { + // This wire is supposed to be bypassed, so make sure we don't buffer it in + // some buffer higher up in the hierarchy. + if (wire->port_output) + for (int i = 0; i < GetSize(wire); i++) + buf_ports.insert(make_pair(module->name, make_pair(wire->name, i))); + continue; + } + + pool<int> input_bits; + + for (int i = 0; i < GetSize(wire); i++) + { + SigBit wire_bit(wire, i); + SigBit mapped_wire_bit = sigmap(wire_bit); + if (buf_wire_bits.count(mapped_wire_bit)) { + // Already buffered downstream. If this is an output, mark it. + if (wire->port_output) + buf_ports.insert(make_pair(module->name, make_pair(wire->name, i))); + } else if (!sink_wire_bits.count(mapped_wire_bit)) { + // Nothing to do. + } else if (driven_wire_bits.count(wire_bit) || (wire->port_input && module->get_bool_attribute("\\top"))) { + // Clock network not yet buffered, driven by one of + // our cells or a top-level input -- buffer it. + + log("Inserting %s on %s.%s[%d].\n", buf_celltype.c_str(), log_id(module), log_id(wire), i); + RTLIL::Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(buf_celltype)); + Wire *iwire = module->addWire(NEW_ID); + cell->setPort(RTLIL::escape_id(buf_portname), mapped_wire_bit); + cell->setPort(RTLIL::escape_id(buf_portname2), iwire); + if (wire->port_input && !inpad_celltype.empty() && module->get_bool_attribute("\\top")) { + log("Inserting %s on %s.%s[%d].\n", inpad_celltype.c_str(), log_id(module), log_id(wire), i); + RTLIL::Cell *cell2 = module->addCell(NEW_ID, RTLIL::escape_id(inpad_celltype)); + cell2->setPort(RTLIL::escape_id(inpad_portname), iwire); + iwire = module->addWire(NEW_ID); + cell2->setPort(RTLIL::escape_id(inpad_portname2), iwire); + } + buffered_bits[mapped_wire_bit] = make_pair(cell, iwire); + + if (wire->port_input) { + input_bits.insert(i); + } + } else if (wire->port_input) { + // A clock input in a submodule -- mark it, let higher level + // worry about it. + if (wire->port_input) + sink_ports.insert(make_pair(module->name, make_pair(wire->name, i))); + } + } + if (!input_bits.empty()) { + // This is an input port and some buffers were inserted -- we need + // to create a new input wire and transfer attributes. + Wire *new_wire = module->addWire(NEW_ID, wire); + + for (int i = 0; i < wire->width; i++) { + SigBit wire_bit(wire, i); + SigBit mapped_wire_bit = sigmap(wire_bit); + auto it = buffered_bits.find(mapped_wire_bit); + if (it != buffered_bits.end()) { + + module->connect(it->second.second, SigSpec(new_wire, i)); + } else { + module->connect(SigSpec(wire, i), SigSpec(new_wire, i)); + } + } + input_queue.push_back(make_pair(wire, new_wire)); + } + } + + // Mark any newly-buffered output ports as such. + for (auto wire : module->selected_wires()) { + if (wire->port_input || !wire->port_output) + continue; + for (int i = 0; i < GetSize(wire); i++) + { + SigBit wire_bit(wire, i); + SigBit mapped_wire_bit = sigmap(wire_bit); + if (buffered_bits.count(mapped_wire_bit)) + buf_ports.insert(make_pair(module->name, make_pair(wire->name, i))); + } + } + + // Reconnect the drivers to buffer inputs. + for (auto cell : module->cells()) + for (auto port : cell->connections()) { + if (!cell->output(port.first)) + continue; + SigSpec sig = port.second; + bool newsig = false; + for (auto &bit : sig) { + const auto it = buffered_bits.find(sigmap(bit)); + if (it == buffered_bits.end()) + continue; + // Avoid substituting buffer's own output pin. + if (cell == it->second.first) + continue; + bit = it->second.second; + newsig = true; + } + if (newsig) + cell->setPort(port.first, sig); + } + + // This has to be done last, to avoid upsetting sigmap before the port reconnections. + for (auto &it : input_queue) { + Wire *wire = it.first; + Wire *new_wire = it.second; + module->swap_names(new_wire, wire); + wire->attributes.clear(); + wire->port_id = 0; + wire->port_input = false; + wire->port_output = false; + } + + module->fixup_ports(); + } + } +} ClkbufmapPass; + +PRIVATE_NAMESPACE_END diff --git a/passes/techmap/deminout.cc b/passes/techmap/deminout.cc index 0b8fd5246..b976b401b 100644 --- a/passes/techmap/deminout.cc +++ b/passes/techmap/deminout.cc @@ -25,7 +25,7 @@ PRIVATE_NAMESPACE_BEGIN struct DeminoutPass : public Pass { DeminoutPass() : Pass("deminout", "demote inout ports to input or output") { } - virtual void help() + void help() YS_OVERRIDE { log("\n"); log(" deminout [options] [selection]\n"); @@ -33,7 +33,7 @@ struct DeminoutPass : public Pass { log("\"Demote\" inout ports to input or output ports, if possible.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing DEMINOUT pass (demote inout ports to input or output).\n"); @@ -83,13 +83,13 @@ struct DeminoutPass : public Pass { for (auto bit : sigmap(conn.second)) bits_used.insert(bit); - if (conn.first == "\\Y" && cell->type.in("$mux", "$pmux", "$_MUX_", "$_TBUF_")) + if (conn.first == ID::Y && cell->type.in(ID($mux), ID($pmux), ID($_MUX_), ID($_TBUF_), ID($tribuf))) { - bool tribuf = (cell->type == "$_TBUF_"); + bool tribuf = cell->type.in(ID($_TBUF_), ID($tribuf)); if (!tribuf) { for (auto &c : cell->connections()) { - if (!c.first.in("\\A", "\\B")) + if (!c.first.in(ID::A, ID::B)) continue; for (auto b : sigmap(c.second)) if (b == State::Sz) @@ -113,7 +113,8 @@ struct DeminoutPass : public Pass { { if (bits_numports[bit] > 1 || bits_inout.count(bit)) new_input = true, new_output = true; - + if (bit == State::S0 || bit == State::S1) + new_output = true; if (bits_written.count(bit)) { new_output = true; if (bits_tribuf.count(bit)) diff --git a/passes/techmap/dff2dffe.cc b/passes/techmap/dff2dffe.cc index 1b8920bb7..0242256e5 100644 --- a/passes/techmap/dff2dffe.cc +++ b/passes/techmap/dff2dffe.cc @@ -52,13 +52,13 @@ struct Dff2dffeWorker } for (auto cell : module->cells()) { - if (cell->type == "$mux" || cell->type == "$pmux" || cell->type == "$_MUX_") { - RTLIL::SigSpec sig_y = sigmap(cell->getPort("\\Y")); + if (cell->type.in(ID($mux), ID($pmux), ID($_MUX_))) { + RTLIL::SigSpec sig_y = sigmap(cell->getPort(ID::Y)); for (int i = 0; i < GetSize(sig_y); i++) bit2mux[sig_y[i]] = cell_int_t(cell, i); } if (direct_dict.empty()) { - if (cell->type == "$dff" || cell->type == "$_DFF_N_" || cell->type == "$_DFF_P_") + if (cell->type.in(ID($dff), ID($_DFF_N_), ID($_DFF_P_))) dff_cells.push_back(cell); } else { if (direct_dict.count(cell->type)) @@ -86,9 +86,9 @@ struct Dff2dffeWorker return ret; cell_int_t mux_cell_int = bit2mux.at(d); - RTLIL::SigSpec sig_a = sigmap(mux_cell_int.first->getPort("\\A")); - RTLIL::SigSpec sig_b = sigmap(mux_cell_int.first->getPort("\\B")); - RTLIL::SigSpec sig_s = sigmap(mux_cell_int.first->getPort("\\S")); + RTLIL::SigSpec sig_a = sigmap(mux_cell_int.first->getPort(ID::A)); + RTLIL::SigSpec sig_b = sigmap(mux_cell_int.first->getPort(ID::B)); + RTLIL::SigSpec sig_s = sigmap(mux_cell_int.first->getPort(ID(S))); int width = GetSize(sig_a), index = mux_cell_int.second; for (int i = 0; i < GetSize(sig_s); i++) @@ -97,9 +97,9 @@ struct Dff2dffeWorker ret = find_muxtree_feedback_patterns(sig_b[i*width + index], q, path); if (sig_b[i*width + index] == q) { - RTLIL::SigSpec s = mux_cell_int.first->getPort("\\B"); + RTLIL::SigSpec s = mux_cell_int.first->getPort(ID::B); s[i*width + index] = RTLIL::Sx; - mux_cell_int.first->setPort("\\B", s); + mux_cell_int.first->setPort(ID::B, s); } return ret; @@ -120,9 +120,9 @@ struct Dff2dffeWorker ret.insert(pat); if (sig_b[i*width + index] == q) { - RTLIL::SigSpec s = mux_cell_int.first->getPort("\\B"); + RTLIL::SigSpec s = mux_cell_int.first->getPort(ID::B); s[i*width + index] = RTLIL::Sx; - mux_cell_int.first->setPort("\\B", s); + mux_cell_int.first->setPort(ID::B, s); } } @@ -130,9 +130,9 @@ struct Dff2dffeWorker ret.insert(pat); if (sig_a[index] == q) { - RTLIL::SigSpec s = mux_cell_int.first->getPort("\\A"); + RTLIL::SigSpec s = mux_cell_int.first->getPort(ID::A); s[index] = RTLIL::Sx; - mux_cell_int.first->setPort("\\A", s); + mux_cell_int.first->setPort(ID::A, s); } return ret; @@ -167,7 +167,7 @@ struct Dff2dffeWorker } if (GetSize(or_input) == 0) - return RTLIL::S1; + return State::S1; if (GetSize(or_input) == 1) return or_input; @@ -185,8 +185,8 @@ struct Dff2dffeWorker void handle_dff_cell(RTLIL::Cell *dff_cell) { - RTLIL::SigSpec sig_d = sigmap(dff_cell->getPort("\\D")); - RTLIL::SigSpec sig_q = sigmap(dff_cell->getPort("\\Q")); + RTLIL::SigSpec sig_d = sigmap(dff_cell->getPort(ID(D))); + RTLIL::SigSpec sig_q = sigmap(dff_cell->getPort(ID(Q))); std::map<patterns_t, std::set<int>> grouped_patterns; std::set<int> remaining_indices; @@ -208,16 +208,16 @@ struct Dff2dffeWorker } if (!direct_dict.empty()) { log(" converting %s cell %s to %s for %s -> %s.\n", log_id(dff_cell->type), log_id(dff_cell), log_id(direct_dict.at(dff_cell->type)), log_signal(new_sig_d), log_signal(new_sig_q)); - dff_cell->setPort("\\E", make_patterns_logic(it.first, true)); + dff_cell->setPort(ID(E), make_patterns_logic(it.first, true)); dff_cell->type = direct_dict.at(dff_cell->type); } else - if (dff_cell->type == "$dff") { - RTLIL::Cell *new_cell = module->addDffe(NEW_ID, dff_cell->getPort("\\CLK"), make_patterns_logic(it.first, false), - new_sig_d, new_sig_q, dff_cell->getParam("\\CLK_POLARITY").as_bool(), true); + if (dff_cell->type == ID($dff)) { + RTLIL::Cell *new_cell = module->addDffe(NEW_ID, dff_cell->getPort(ID(CLK)), make_patterns_logic(it.first, false), + new_sig_d, new_sig_q, dff_cell->getParam(ID(CLK_POLARITY)).as_bool(), true); log(" created $dffe cell %s for %s -> %s.\n", log_id(new_cell), log_signal(new_sig_d), log_signal(new_sig_q)); } else { - RTLIL::Cell *new_cell = module->addDffeGate(NEW_ID, dff_cell->getPort("\\C"), make_patterns_logic(it.first, true), - new_sig_d, new_sig_q, dff_cell->type == "$_DFF_P_", true); + RTLIL::Cell *new_cell = module->addDffeGate(NEW_ID, dff_cell->getPort(ID(C)), make_patterns_logic(it.first, true), + new_sig_d, new_sig_q, dff_cell->type == ID($_DFF_P_), true); log(" created %s cell %s for %s -> %s.\n", log_id(new_cell->type), log_id(new_cell), log_signal(new_sig_d), log_signal(new_sig_q)); } } @@ -235,9 +235,9 @@ struct Dff2dffeWorker new_sig_d.append(sig_d[i]); new_sig_q.append(sig_q[i]); } - dff_cell->setPort("\\D", new_sig_d); - dff_cell->setPort("\\Q", new_sig_q); - dff_cell->setParam("\\WIDTH", GetSize(remaining_indices)); + dff_cell->setPort(ID(D), new_sig_d); + dff_cell->setPort(ID(Q), new_sig_q); + dff_cell->setParam(ID(WIDTH), GetSize(remaining_indices)); } } @@ -253,7 +253,7 @@ struct Dff2dffeWorker struct Dff2dffePass : public Pass { Dff2dffePass() : Pass("dff2dffe", "transform $dff cells to $dffe cells") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -265,7 +265,11 @@ struct Dff2dffePass : public Pass { log("\n"); log(" -unmap\n"); log(" operate in the opposite direction: replace $dffe cells with combinations\n"); - log(" of $dff and $mux cells. the options below are ignore in unmap mode.\n"); + log(" of $dff and $mux cells. the options below are ignored in unmap mode.\n"); + log("\n"); + log(" -unmap-mince N\n"); + log(" Same as -unmap but only unmap $dffe where the clock enable port\n"); + log(" signal is used by less $dffe than the specified number\n"); log("\n"); log(" -direct <internal_gate_type> <external_gate_type>\n"); log(" map directly to external gate type. <internal_gate_type> can\n"); @@ -279,15 +283,17 @@ struct Dff2dffePass : public Pass { log(" -direct-match <pattern>\n"); log(" like -direct for all DFF cell types matching the expression.\n"); log(" this will use $__DFFE_* as <external_gate_type> matching the\n"); - log(" internal gate type $_DFF_*_, except for $_DFF_[NP]_, which is\n"); - log(" converted to $_DFFE_[NP]_.\n"); + log(" internal gate type $_DFF_*_, and $__DFFSE_* for those matching\n"); + log(" $_DFFS_*_, except for $_DFF_[NP]_, which is converted to \n"); + log(" $_DFFE_[NP]_.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing DFF2DFFE pass (transform $dff to $dffe where applicable).\n"); bool unmap_mode = false; + int min_ce_use = -1; dict<IdString, IdString> direct_dict; size_t argidx; @@ -296,6 +302,11 @@ struct Dff2dffePass : public Pass { unmap_mode = true; continue; } + if (args[argidx] == "-unmap-mince" && argidx + 1 < args.size()) { + unmap_mode = true; + min_ce_use = atoi(args[++argidx].c_str()); + continue; + } if (args[argidx] == "-direct" && argidx + 2 < args.size()) { string direct_from = RTLIL::escape_id(args[++argidx]); string direct_to = RTLIL::escape_id(args[++argidx]); @@ -305,16 +316,25 @@ struct Dff2dffePass : public Pass { if (args[argidx] == "-direct-match" && argidx + 1 < args.size()) { bool found_match = false; const char *pattern = args[++argidx].c_str(); - if (patmatch(pattern, "$_DFF_P_" )) found_match = true, direct_dict["$_DFF_P_" ] = "$_DFFE_PP_"; - if (patmatch(pattern, "$_DFF_N_" )) found_match = true, direct_dict["$_DFF_N_" ] = "$_DFFE_NP_"; - if (patmatch(pattern, "$_DFF_NN0_")) found_match = true, direct_dict["$_DFF_NN0_"] = "$__DFFE_NN0"; - if (patmatch(pattern, "$_DFF_NN1_")) found_match = true, direct_dict["$_DFF_NN1_"] = "$__DFFE_NN1"; - if (patmatch(pattern, "$_DFF_NP0_")) found_match = true, direct_dict["$_DFF_NP0_"] = "$__DFFE_NP0"; - if (patmatch(pattern, "$_DFF_NP1_")) found_match = true, direct_dict["$_DFF_NP1_"] = "$__DFFE_NP1"; - if (patmatch(pattern, "$_DFF_PN0_")) found_match = true, direct_dict["$_DFF_PN0_"] = "$__DFFE_PN0"; - if (patmatch(pattern, "$_DFF_PN1_")) found_match = true, direct_dict["$_DFF_PN1_"] = "$__DFFE_PN1"; - if (patmatch(pattern, "$_DFF_PP0_")) found_match = true, direct_dict["$_DFF_PP0_"] = "$__DFFE_PP0"; - if (patmatch(pattern, "$_DFF_PP1_")) found_match = true, direct_dict["$_DFF_PP1_"] = "$__DFFE_PP1"; + if (patmatch(pattern, "$_DFF_P_" )) found_match = true, direct_dict[ID($_DFF_P_) ] = ID($_DFFE_PP_); + if (patmatch(pattern, "$_DFF_N_" )) found_match = true, direct_dict[ID($_DFF_N_) ] = ID($_DFFE_NP_); + if (patmatch(pattern, "$_DFF_NN0_")) found_match = true, direct_dict[ID($_DFF_NN0_)] = ID($__DFFE_NN0); + if (patmatch(pattern, "$_DFF_NN1_")) found_match = true, direct_dict[ID($_DFF_NN1_)] = ID($__DFFE_NN1); + if (patmatch(pattern, "$_DFF_NP0_")) found_match = true, direct_dict[ID($_DFF_NP0_)] = ID($__DFFE_NP0); + if (patmatch(pattern, "$_DFF_NP1_")) found_match = true, direct_dict[ID($_DFF_NP1_)] = ID($__DFFE_NP1); + if (patmatch(pattern, "$_DFF_PN0_")) found_match = true, direct_dict[ID($_DFF_PN0_)] = ID($__DFFE_PN0); + if (patmatch(pattern, "$_DFF_PN1_")) found_match = true, direct_dict[ID($_DFF_PN1_)] = ID($__DFFE_PN1); + if (patmatch(pattern, "$_DFF_PP0_")) found_match = true, direct_dict[ID($_DFF_PP0_)] = ID($__DFFE_PP0); + if (patmatch(pattern, "$_DFF_PP1_")) found_match = true, direct_dict[ID($_DFF_PP1_)] = ID($__DFFE_PP1); + + if (patmatch(pattern, "$__DFFS_NN0_")) found_match = true, direct_dict[ID($__DFFS_NN0_)] = ID($__DFFSE_NN0); + if (patmatch(pattern, "$__DFFS_NN1_")) found_match = true, direct_dict[ID($__DFFS_NN1_)] = ID($__DFFSE_NN1); + if (patmatch(pattern, "$__DFFS_NP0_")) found_match = true, direct_dict[ID($__DFFS_NP0_)] = ID($__DFFSE_NP0); + if (patmatch(pattern, "$__DFFS_NP1_")) found_match = true, direct_dict[ID($__DFFS_NP1_)] = ID($__DFFSE_NP1); + if (patmatch(pattern, "$__DFFS_PN0_")) found_match = true, direct_dict[ID($__DFFS_PN0_)] = ID($__DFFSE_PN0); + if (patmatch(pattern, "$__DFFS_PN1_")) found_match = true, direct_dict[ID($__DFFS_PN1_)] = ID($__DFFSE_PN1); + if (patmatch(pattern, "$__DFFS_PP0_")) found_match = true, direct_dict[ID($__DFFS_PP0_)] = ID($__DFFSE_PP0); + if (patmatch(pattern, "$__DFFS_PP1_")) found_match = true, direct_dict[ID($__DFFS_PP1_)] = ID($__DFFSE_PP1); if (!found_match) log_cmd_error("No cell types matched pattern '%s'.\n", pattern); continue; @@ -333,26 +353,51 @@ struct Dff2dffePass : public Pass { if (!mod->has_processes_warn()) { if (unmap_mode) { + SigMap sigmap(mod); for (auto cell : mod->selected_cells()) { - if (cell->type == "$dffe") { - RTLIL::SigSpec tmp = mod->addWire(NEW_ID, GetSize(cell->getPort("\\D"))); - mod->addDff(NEW_ID, cell->getPort("\\CLK"), tmp, cell->getPort("\\Q"), cell->getParam("\\CLK_POLARITY").as_bool()); - if (cell->getParam("\\EN_POLARITY").as_bool()) - mod->addMux(NEW_ID, cell->getPort("\\Q"), cell->getPort("\\D"), cell->getPort("\\EN"), tmp); + if (cell->type == ID($dffe)) { + if (min_ce_use >= 0) { + int ce_use = 0; + for (auto cell_other : mod->selected_cells()) { + if (cell_other->type != cell->type) + continue; + if (sigmap(cell->getPort(ID(EN))) == sigmap(cell_other->getPort(ID(EN)))) + ce_use++; + } + if (ce_use >= min_ce_use) + continue; + } + + RTLIL::SigSpec tmp = mod->addWire(NEW_ID, GetSize(cell->getPort(ID(D)))); + mod->addDff(NEW_ID, cell->getPort(ID(CLK)), tmp, cell->getPort(ID(Q)), cell->getParam(ID(CLK_POLARITY)).as_bool()); + if (cell->getParam(ID(EN_POLARITY)).as_bool()) + mod->addMux(NEW_ID, cell->getPort(ID(Q)), cell->getPort(ID(D)), cell->getPort(ID(EN)), tmp); else - mod->addMux(NEW_ID, cell->getPort("\\D"), cell->getPort("\\Q"), cell->getPort("\\EN"), tmp); + mod->addMux(NEW_ID, cell->getPort(ID(D)), cell->getPort(ID(Q)), cell->getPort(ID(EN)), tmp); mod->remove(cell); continue; } - if (cell->type.substr(0, 7) == "$_DFFE_") { - bool clk_pol = cell->type.substr(7, 1) == "P"; - bool en_pol = cell->type.substr(8, 1) == "P"; + if (cell->type.begins_with("$_DFFE_")) { + if (min_ce_use >= 0) { + int ce_use = 0; + for (auto cell_other : mod->selected_cells()) { + if (cell_other->type != cell->type) + continue; + if (sigmap(cell->getPort(ID(E))) == sigmap(cell_other->getPort(ID(E)))) + ce_use++; + } + if (ce_use >= min_ce_use) + continue; + } + + bool clk_pol = cell->type.compare(7, 1, "P") == 0; + bool en_pol = cell->type.compare(8, 1, "P") == 0; RTLIL::SigSpec tmp = mod->addWire(NEW_ID); - mod->addDff(NEW_ID, cell->getPort("\\C"), tmp, cell->getPort("\\Q"), clk_pol); + mod->addDff(NEW_ID, cell->getPort(ID(C)), tmp, cell->getPort(ID(Q)), clk_pol); if (en_pol) - mod->addMux(NEW_ID, cell->getPort("\\Q"), cell->getPort("\\D"), cell->getPort("\\E"), tmp); + mod->addMux(NEW_ID, cell->getPort(ID(Q)), cell->getPort(ID(D)), cell->getPort(ID(E)), tmp); else - mod->addMux(NEW_ID, cell->getPort("\\D"), cell->getPort("\\Q"), cell->getPort("\\E"), tmp); + mod->addMux(NEW_ID, cell->getPort(ID(D)), cell->getPort(ID(Q)), cell->getPort(ID(E)), tmp); mod->remove(cell); continue; } diff --git a/passes/techmap/dff2dffs.cc b/passes/techmap/dff2dffs.cc new file mode 100644 index 000000000..3fa1ed5cf --- /dev/null +++ b/passes/techmap/dff2dffs.cc @@ -0,0 +1,165 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * Copyright (C) 2018 David Shah <dave@ds0.me> + * + * 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 Dff2dffsPass : public Pass { + Dff2dffsPass() : Pass("dff2dffs", "process sync set/reset with SR over CE priority") { } + void help() YS_OVERRIDE + { + log("\n"); + log(" dff2dffs [options] [selection]\n"); + log("\n"); + log("Merge synchronous set/reset $_MUX_ cells to create $__DFFS_[NP][NP][01], to be run before\n"); + log("dff2dffe for SR over CE priority.\n"); + log("\n"); + log(" -match-init\n"); + log(" Disallow merging synchronous set/reset that has polarity opposite of the\n"); + log(" output wire's init attribute (if any).\n"); + log("\n"); + } + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + log_header(design, "Executing dff2dffs pass (merge synchronous set/reset into FF cells).\n"); + + bool match_init = false; + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + // if (args[argidx] == "-singleton") { + // singleton_mode = true; + // continue; + // } + if (args[argidx] == "-match-init") { + match_init = true; + continue; + } + break; + } + extra_args(args, argidx, design); + + pool<IdString> dff_types; + dff_types.insert(ID($_DFF_N_)); + dff_types.insert(ID($_DFF_P_)); + + for (auto module : design->selected_modules()) + { + log("Merging set/reset $_MUX_ cells into DFFs in %s.\n", log_id(module)); + + SigMap sigmap(module); + dict<SigBit, Cell*> sr_muxes; + vector<Cell*> ff_cells; + + for (auto cell : module->selected_cells()) + { + if (dff_types.count(cell->type)) { + ff_cells.push_back(cell); + continue; + } + + if (cell->type != ID($_MUX_)) + continue; + + SigBit bit_a = sigmap(cell->getPort(ID::A)); + SigBit bit_b = sigmap(cell->getPort(ID::B)); + + if (bit_a.wire == nullptr || bit_b.wire == nullptr) + sr_muxes[sigmap(cell->getPort(ID::Y))] = cell; + } + + for (auto cell : ff_cells) + { + SigSpec sig_d = cell->getPort(ID(D)); + + if (GetSize(sig_d) < 1) + continue; + + SigBit bit_d = sigmap(sig_d[0]); + + if (sr_muxes.count(bit_d) == 0) + continue; + + Cell *mux_cell = sr_muxes.at(bit_d); + SigBit bit_a = sigmap(mux_cell->getPort(ID::A)); + SigBit bit_b = sigmap(mux_cell->getPort(ID::B)); + SigBit bit_s = sigmap(mux_cell->getPort(ID(S))); + + SigBit sr_val, sr_sig; + bool invert_sr; + sr_sig = bit_s; + if (bit_a.wire == nullptr) { + bit_d = bit_b; + sr_val = bit_a; + invert_sr = true; + } else { + log_assert(bit_b.wire == nullptr); + bit_d = bit_a; + sr_val = bit_b; + invert_sr = false; + } + + if (match_init) { + SigBit bit_q = cell->getPort(ID(Q)); + if (bit_q.wire) { + auto it = bit_q.wire->attributes.find(ID(init)); + if (it != bit_q.wire->attributes.end()) { + auto init_val = it->second[bit_q.offset]; + if (init_val == State::S1 && sr_val != State::S1) + continue; + if (init_val == State::S0 && sr_val != State::S0) + continue; + } + } + } + + log(" Merging %s (A=%s, B=%s, S=%s) into %s (%s).\n", log_id(mux_cell), + log_signal(bit_a), log_signal(bit_b), log_signal(bit_s), log_id(cell), log_id(cell->type)); + + if (sr_val == State::S1) { + if (cell->type == ID($_DFF_N_)) { + if (invert_sr) cell->type = ID($__DFFS_NN1_); + else cell->type = ID($__DFFS_NP1_); + } else { + log_assert(cell->type == ID($_DFF_P_)); + if (invert_sr) cell->type = ID($__DFFS_PN1_); + else cell->type = ID($__DFFS_PP1_); + } + } else { + if (cell->type == ID($_DFF_N_)) { + if (invert_sr) cell->type = ID($__DFFS_NN0_); + else cell->type = ID($__DFFS_NP0_); + } else { + log_assert(cell->type == ID($_DFF_P_)); + if (invert_sr) cell->type = ID($__DFFS_PN0_); + else cell->type = ID($__DFFS_PP0_); + } + } + cell->setPort(ID(R), sr_sig); + cell->setPort(ID(D), bit_d); + } + } + } +} Dff2dffsPass; + +PRIVATE_NAMESPACE_END diff --git a/passes/techmap/dffinit.cc b/passes/techmap/dffinit.cc index 6a8a86383..cf9301442 100644 --- a/passes/techmap/dffinit.cc +++ b/passes/techmap/dffinit.cc @@ -25,7 +25,7 @@ PRIVATE_NAMESPACE_BEGIN struct DffinitPass : public Pass { DffinitPass() : Pass("dffinit", "set INIT param on FF cells") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -43,18 +43,37 @@ struct DffinitPass : public Pass { log(" initial value of 1 or 0. (multi-bit values are not supported in this\n"); log(" mode.)\n"); log("\n"); + log(" -strinit <string for high> <string for low> \n"); + log(" use string values in the command line to represent a single-bit\n"); + log(" initial value of 1 or 0. (multi-bit values are not supported in this\n"); + log(" mode.)\n"); + log("\n"); + log(" -noreinit\n"); + log(" fail if the FF cell has already a defined initial value set in other\n"); + log(" passes and the initial value of the net it drives is not equal to\n"); + log(" the already defined initial value.\n"); + log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing DFFINIT pass (set INIT param on FF cells).\n"); dict<IdString, dict<IdString, IdString>> ff_types; - bool highlow_mode = false; + bool highlow_mode = false, noreinit = false; + std::string high_string, low_string; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { if (args[argidx] == "-highlow") { highlow_mode = true; + high_string = "high"; + low_string = "low"; + continue; + } + if (args[argidx] == "-strinit" && argidx+2 < args.size()) { + highlow_mode = true; + high_string = args[++argidx]; + low_string = args[++argidx]; continue; } if (args[argidx] == "-ff" && argidx+3 < args.size()) { @@ -64,6 +83,10 @@ struct DffinitPass : public Pass { ff_types[cell_name][output_port] = init_param; continue; } + if (args[argidx] == "-noreinit") { + noreinit = true; + continue; + } break; } extra_args(args, argidx, design); @@ -76,10 +99,11 @@ struct DffinitPass : public Pass { pool<SigBit> used_bits; for (auto wire : module->selected_wires()) { - if (wire->attributes.count("\\init")) { - Const value = wire->attributes.at("\\init"); + if (wire->attributes.count(ID(init))) { + Const value = wire->attributes.at(ID(init)); for (int i = 0; i < min(GetSize(value), GetSize(wire)); i++) - init_bits[sigmap(SigBit(wire, i))] = value[i]; + if (value[i] != State::Sx) + init_bits[sigmap(SigBit(wire, i))] = value[i]; } if (wire->port_output) for (auto bit : sigmap(wire)) @@ -112,6 +136,10 @@ struct DffinitPass : public Pass { continue; while (GetSize(value.bits) <= i) value.bits.push_back(State::S0); + if (noreinit && value.bits[i] != State::Sx && value.bits[i] != init_bits.at(sig[i])) + log_error("Trying to assign a different init value for %s.%s.%s which technically " + "have a conflicted init value.\n", + log_id(module), log_id(cell), log_id(it.second)); value.bits[i] = init_bits.at(sig[i]); cleanup_bits.insert(sig[i]); } @@ -121,9 +149,9 @@ struct DffinitPass : public Pass { log_error("Multi-bit init value for %s.%s.%s is incompatible with -highlow mode.\n", log_id(module), log_id(cell), log_id(it.second)); if (value[0] == State::S1) - value = Const("high"); + value = Const(high_string); else - value = Const("low"); + value = Const(low_string); } log("Setting %s.%s.%s (port=%s, net=%s) to %s.\n", log_id(module), log_id(cell), log_id(it.second), @@ -133,8 +161,8 @@ struct DffinitPass : public Pass { } for (auto wire : module->selected_wires()) - if (wire->attributes.count("\\init")) { - Const &value = wire->attributes.at("\\init"); + if (wire->attributes.count(ID(init))) { + Const &value = wire->attributes.at(ID(init)); bool do_cleanup = true; for (int i = 0; i < min(GetSize(value), GetSize(wire)); i++) { SigBit bit = sigmap(SigBit(wire, i)); @@ -145,7 +173,7 @@ struct DffinitPass : public Pass { } if (do_cleanup) { log("Removing init attribute from wire %s.%s.\n", log_id(module), log_id(wire)); - wire->attributes.erase("\\init"); + wire->attributes.erase(ID(init)); } } } diff --git a/passes/techmap/dfflibmap.cc b/passes/techmap/dfflibmap.cc index 5ccb770c4..b15109cd3 100644 --- a/passes/techmap/dfflibmap.cc +++ b/passes/techmap/dfflibmap.cc @@ -27,12 +27,12 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN struct cell_mapping { - std::string cell_name; + IdString cell_name; std::map<std::string, char> ports; }; static std::map<RTLIL::IdString, cell_mapping> cell_mappings; -static void logmap(std::string dff) +static void logmap(IdString dff) { if (cell_mappings.count(dff) == 0) { log(" unmapped dff cell: %s\n", dff.c_str()); @@ -54,26 +54,26 @@ static void logmap(std::string dff) static void logmap_all() { - logmap("$_DFF_N_"); - logmap("$_DFF_P_"); - - logmap("$_DFF_NN0_"); - logmap("$_DFF_NN1_"); - logmap("$_DFF_NP0_"); - logmap("$_DFF_NP1_"); - logmap("$_DFF_PN0_"); - logmap("$_DFF_PN1_"); - logmap("$_DFF_PP0_"); - logmap("$_DFF_PP1_"); - - logmap("$_DFFSR_NNN_"); - logmap("$_DFFSR_NNP_"); - logmap("$_DFFSR_NPN_"); - logmap("$_DFFSR_NPP_"); - logmap("$_DFFSR_PNN_"); - logmap("$_DFFSR_PNP_"); - logmap("$_DFFSR_PPN_"); - logmap("$_DFFSR_PPP_"); + logmap(ID($_DFF_N_)); + logmap(ID($_DFF_P_)); + + logmap(ID($_DFF_NN0_)); + logmap(ID($_DFF_NN1_)); + logmap(ID($_DFF_NP0_)); + logmap(ID($_DFF_NP1_)); + logmap(ID($_DFF_PN0_)); + logmap(ID($_DFF_PN1_)); + logmap(ID($_DFF_PP0_)); + logmap(ID($_DFF_PP1_)); + + logmap(ID($_DFFSR_NNN_)); + logmap(ID($_DFFSR_NNP_)); + logmap(ID($_DFFSR_NPN_)); + logmap(ID($_DFFSR_NPP_)); + logmap(ID($_DFFSR_PNN_)); + logmap(ID($_DFFSR_PNP_)); + logmap(ID($_DFFSR_PPN_)); + logmap(ID($_DFFSR_PPP_)); } static bool parse_pin(LibertyAst *cell, LibertyAst *attr, std::string &pin_name, bool &pin_pol) @@ -100,10 +100,22 @@ static bool parse_pin(LibertyAst *cell, LibertyAst *attr, std::string &pin_name, for (auto child : cell->children) if (child->id == "pin" && child->args.size() == 1 && child->args[0] == pin_name) return true; + + /* If we end up here, the pin specified in the attribute does not exist, which is an error, + or, the attribute contains an expression which we do not yet support. + For now, we'll simply produce a warning to let the user know something is up. + */ + if (pin_name.find_first_of("^*|&") == std::string::npos) { + log_warning("Malformed liberty file - cannot find pin '%s' in cell '%s' - skipping.\n", pin_name.c_str(), cell->args[0].c_str()); + } + else { + log_warning("Found unsupported expression '%s' in pin attribute of cell '%s' - skipping.\n", pin_name.c_str(), cell->args[0].c_str()); + } + return false; } -static void find_cell(LibertyAst *ast, std::string cell_type, bool clkpol, bool has_reset, bool rstpol, bool rstval, bool prepare_mode) +static void find_cell(LibertyAst *ast, IdString cell_type, bool clkpol, bool has_reset, bool rstpol, bool rstval, bool prepare_mode) { LibertyAst *best_cell = NULL; std::map<std::string, char> best_cell_ports; @@ -218,13 +230,13 @@ static void find_cell(LibertyAst *ast, std::string cell_type, bool clkpol, bool cell_mappings[cell_type].ports["D"] = 'D'; cell_mappings[cell_type].ports["Q"] = 'Q'; } else { - cell_mappings[cell_type].cell_name = best_cell->args[0]; + cell_mappings[cell_type].cell_name = RTLIL::escape_id(best_cell->args[0]); cell_mappings[cell_type].ports = best_cell_ports; } } } -static void find_cell_sr(LibertyAst *ast, std::string cell_type, bool clkpol, bool setpol, bool clrpol, bool prepare_mode) +static void find_cell_sr(LibertyAst *ast, IdString cell_type, bool clkpol, bool setpol, bool clrpol, bool prepare_mode) { LibertyAst *best_cell = NULL; std::map<std::string, char> best_cell_ports; @@ -335,7 +347,7 @@ static void find_cell_sr(LibertyAst *ast, std::string cell_type, bool clkpol, bo cell_mappings[cell_type].ports["D"] = 'D'; cell_mappings[cell_type].ports["Q"] = 'Q'; } else { - cell_mappings[cell_type].cell_name = best_cell->args[0]; + cell_mappings[cell_type].cell_name = RTLIL::escape_id(best_cell->args[0]); cell_mappings[cell_type].ports = best_cell_ports; } } @@ -392,7 +404,7 @@ static bool expand_cellmap(std::string pattern, std::string inv) return return_status; } -static void map_sr_to_arst(const char *from, const char *to) +static void map_sr_to_arst(IdString from, IdString to) { if (!cell_mappings.count(from) || cell_mappings.count(to) > 0) return; @@ -407,7 +419,7 @@ static void map_sr_to_arst(const char *from, const char *to) log_assert(from_clk_pol == to_clk_pol); log_assert(to_rst_pol == from_set_pol && to_rst_pol == from_clr_pol); - log(" create mapping for %s from mapping for %s.\n", to, from); + log(" create mapping for %s from mapping for %s.\n", to.c_str(), from.c_str()); cell_mappings[to].cell_name = cell_mappings[from].cell_name; cell_mappings[to].ports = cell_mappings[from].ports; @@ -438,7 +450,7 @@ static void map_sr_to_arst(const char *from, const char *to) } } -static void map_adff_to_dff(const char *from, const char *to) +static void map_adff_to_dff(IdString from, IdString to) { if (!cell_mappings.count(from) || cell_mappings.count(to) > 0) return; @@ -449,7 +461,7 @@ static void map_adff_to_dff(const char *from, const char *to) log_assert(from_clk_pol == to_clk_pol); - log(" create mapping for %s from mapping for %s.\n", to, from); + log(" create mapping for %s from mapping for %s.\n", to.c_str(), from.c_str()); cell_mappings[to].cell_name = cell_mappings[from].cell_name; cell_mappings[to].ports = cell_mappings[from].ports; @@ -472,8 +484,8 @@ static void dfflibmap(RTLIL::Design *design, RTLIL::Module *module, bool prepare for (auto &it : module->cells_) { if (design->selected(module, it.second) && cell_mappings.count(it.second->type) > 0) cell_list.push_back(it.second); - if (it.second->type == "$_NOT_") - notmap[sigmap(it.second->getPort("\\A"))].insert(it.second); + if (it.second->type == ID($_NOT_)) + notmap[sigmap(it.second->getPort(ID::A))].insert(it.second); } std::map<std::string, int> stats; @@ -487,7 +499,7 @@ static void dfflibmap(RTLIL::Design *design, RTLIL::Module *module, bool prepare module->remove(cell); cell_mapping &cm = cell_mappings[cell_type]; - RTLIL::Cell *new_cell = module->addCell(cell_name, prepare_mode ? cm.cell_name : "\\" + cm.cell_name); + RTLIL::Cell *new_cell = module->addCell(cell_name, prepare_mode ? cm.cell_name : cm.cell_name); new_cell->set_src_attribute(src); @@ -507,8 +519,8 @@ static void dfflibmap(RTLIL::Design *design, RTLIL::Module *module, bool prepare sig = module->addWire(NEW_ID, GetSize(old_sig)); if (has_q && has_qn) { for (auto &it : notmap[sigmap(old_sig)]) { - module->connect(it->getPort("\\Y"), sig); - it->setPort("\\Y", module->addWire(NEW_ID, GetSize(old_sig))); + module->connect(it->getPort(ID::Y), sig); + it->setPort(ID::Y, module->addWire(NEW_ID, GetSize(old_sig))); } } else { module->addNotGate(NEW_ID, sig, old_sig); @@ -537,7 +549,7 @@ static void dfflibmap(RTLIL::Design *design, RTLIL::Module *module, bool prepare struct DfflibmapPass : public Pass { DfflibmapPass() : Pass("dfflibmap", "technology mapping of flip-flops") { } - virtual void help() + void help() YS_OVERRIDE { log("\n"); log(" dfflibmap [-prepare] -liberty <file> [selection]\n"); @@ -553,7 +565,7 @@ struct DfflibmapPass : public Pass { log("liberty file.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing DFFLIBMAP pass (mapping DFF cells to sequential cells from liberty file).\n"); @@ -587,26 +599,26 @@ struct DfflibmapPass : public Pass { LibertyParser libparser(f); f.close(); - find_cell(libparser.ast, "$_DFF_N_", false, false, false, false, prepare_mode); - find_cell(libparser.ast, "$_DFF_P_", true, false, false, false, prepare_mode); - - find_cell(libparser.ast, "$_DFF_NN0_", false, true, false, false, prepare_mode); - find_cell(libparser.ast, "$_DFF_NN1_", false, true, false, true, prepare_mode); - find_cell(libparser.ast, "$_DFF_NP0_", false, true, true, false, prepare_mode); - find_cell(libparser.ast, "$_DFF_NP1_", false, true, true, true, prepare_mode); - find_cell(libparser.ast, "$_DFF_PN0_", true, true, false, false, prepare_mode); - find_cell(libparser.ast, "$_DFF_PN1_", true, true, false, true, prepare_mode); - find_cell(libparser.ast, "$_DFF_PP0_", true, true, true, false, prepare_mode); - find_cell(libparser.ast, "$_DFF_PP1_", true, true, true, true, prepare_mode); - - find_cell_sr(libparser.ast, "$_DFFSR_NNN_", false, false, false, prepare_mode); - find_cell_sr(libparser.ast, "$_DFFSR_NNP_", false, false, true, prepare_mode); - find_cell_sr(libparser.ast, "$_DFFSR_NPN_", false, true, false, prepare_mode); - find_cell_sr(libparser.ast, "$_DFFSR_NPP_", false, true, true, prepare_mode); - find_cell_sr(libparser.ast, "$_DFFSR_PNN_", true, false, false, prepare_mode); - find_cell_sr(libparser.ast, "$_DFFSR_PNP_", true, false, true, prepare_mode); - find_cell_sr(libparser.ast, "$_DFFSR_PPN_", true, true, false, prepare_mode); - find_cell_sr(libparser.ast, "$_DFFSR_PPP_", true, true, true, prepare_mode); + find_cell(libparser.ast, ID($_DFF_N_), false, false, false, false, prepare_mode); + find_cell(libparser.ast, ID($_DFF_P_), true, false, false, false, prepare_mode); + + find_cell(libparser.ast, ID($_DFF_NN0_), false, true, false, false, prepare_mode); + find_cell(libparser.ast, ID($_DFF_NN1_), false, true, false, true, prepare_mode); + find_cell(libparser.ast, ID($_DFF_NP0_), false, true, true, false, prepare_mode); + find_cell(libparser.ast, ID($_DFF_NP1_), false, true, true, true, prepare_mode); + find_cell(libparser.ast, ID($_DFF_PN0_), true, true, false, false, prepare_mode); + find_cell(libparser.ast, ID($_DFF_PN1_), true, true, false, true, prepare_mode); + find_cell(libparser.ast, ID($_DFF_PP0_), true, true, true, false, prepare_mode); + find_cell(libparser.ast, ID($_DFF_PP1_), true, true, true, true, prepare_mode); + + find_cell_sr(libparser.ast, ID($_DFFSR_NNN_), false, false, false, prepare_mode); + find_cell_sr(libparser.ast, ID($_DFFSR_NNP_), false, false, true, prepare_mode); + find_cell_sr(libparser.ast, ID($_DFFSR_NPN_), false, true, false, prepare_mode); + find_cell_sr(libparser.ast, ID($_DFFSR_NPP_), false, true, true, prepare_mode); + find_cell_sr(libparser.ast, ID($_DFFSR_PNN_), true, false, false, prepare_mode); + find_cell_sr(libparser.ast, ID($_DFFSR_PNP_), true, false, true, prepare_mode); + find_cell_sr(libparser.ast, ID($_DFFSR_PPN_), true, true, false, prepare_mode); + find_cell_sr(libparser.ast, ID($_DFFSR_PPP_), true, true, true, prepare_mode); // try to implement as many cells as possible just by inverting // the SET and RESET pins. If necessary, implement cell types @@ -630,29 +642,29 @@ struct DfflibmapPass : public Pass { break; } - map_sr_to_arst("$_DFFSR_NNN_", "$_DFF_NN0_"); - map_sr_to_arst("$_DFFSR_NNN_", "$_DFF_NN1_"); - map_sr_to_arst("$_DFFSR_NPP_", "$_DFF_NP0_"); - map_sr_to_arst("$_DFFSR_NPP_", "$_DFF_NP1_"); - map_sr_to_arst("$_DFFSR_PNN_", "$_DFF_PN0_"); - map_sr_to_arst("$_DFFSR_PNN_", "$_DFF_PN1_"); - map_sr_to_arst("$_DFFSR_PPP_", "$_DFF_PP0_"); - map_sr_to_arst("$_DFFSR_PPP_", "$_DFF_PP1_"); - - map_adff_to_dff("$_DFF_NN0_", "$_DFF_N_"); - map_adff_to_dff("$_DFF_NN1_", "$_DFF_N_"); - map_adff_to_dff("$_DFF_NP0_", "$_DFF_N_"); - map_adff_to_dff("$_DFF_NP1_", "$_DFF_N_"); - map_adff_to_dff("$_DFF_PN0_", "$_DFF_P_"); - map_adff_to_dff("$_DFF_PN1_", "$_DFF_P_"); - map_adff_to_dff("$_DFF_PP0_", "$_DFF_P_"); - map_adff_to_dff("$_DFF_PP1_", "$_DFF_P_"); - - log(" final dff cell mappings:\n"); - logmap_all(); + map_sr_to_arst(ID($_DFFSR_NNN_), ID($_DFF_NN0_)); + map_sr_to_arst(ID($_DFFSR_NNN_), ID($_DFF_NN1_)); + map_sr_to_arst(ID($_DFFSR_NPP_), ID($_DFF_NP0_)); + map_sr_to_arst(ID($_DFFSR_NPP_), ID($_DFF_NP1_)); + map_sr_to_arst(ID($_DFFSR_PNN_), ID($_DFF_PN0_)); + map_sr_to_arst(ID($_DFFSR_PNN_), ID($_DFF_PN1_)); + map_sr_to_arst(ID($_DFFSR_PPP_), ID($_DFF_PP0_)); + map_sr_to_arst(ID($_DFFSR_PPP_), ID($_DFF_PP1_)); + + map_adff_to_dff(ID($_DFF_NN0_), ID($_DFF_N_)); + map_adff_to_dff(ID($_DFF_NN1_), ID($_DFF_N_)); + map_adff_to_dff(ID($_DFF_NP0_), ID($_DFF_N_)); + map_adff_to_dff(ID($_DFF_NP1_), ID($_DFF_N_)); + map_adff_to_dff(ID($_DFF_PN0_), ID($_DFF_P_)); + map_adff_to_dff(ID($_DFF_PN1_), ID($_DFF_P_)); + map_adff_to_dff(ID($_DFF_PP0_), ID($_DFF_P_)); + map_adff_to_dff(ID($_DFF_PP1_), ID($_DFF_P_)); + + log(" final dff cell mappings:\n"); + logmap_all(); for (auto &it : design->modules_) - if (design->selected(it.second) && !it.second->get_bool_attribute("\\blackbox")) + if (design->selected(it.second) && !it.second->get_blackbox_attribute()) dfflibmap(design, it.second, prepare_mode); cell_mappings.clear(); diff --git a/passes/techmap/dffsr2dff.cc b/passes/techmap/dffsr2dff.cc index 0d4d53627..61b06fdc1 100644 --- a/passes/techmap/dffsr2dff.cc +++ b/passes/techmap/dffsr2dff.cc @@ -25,17 +25,17 @@ PRIVATE_NAMESPACE_BEGIN void dffsr_worker(SigMap &sigmap, Module *module, Cell *cell) { - if (cell->type == "$dffsr") + if (cell->type == ID($dffsr)) { - int width = cell->getParam("\\WIDTH").as_int(); - bool setpol = cell->getParam("\\SET_POLARITY").as_bool(); - bool clrpol = cell->getParam("\\CLR_POLARITY").as_bool(); + int width = cell->getParam(ID(WIDTH)).as_int(); + bool setpol = cell->getParam(ID(SET_POLARITY)).as_bool(); + bool clrpol = cell->getParam(ID(CLR_POLARITY)).as_bool(); SigBit setunused = setpol ? State::S0 : State::S1; SigBit clrunused = clrpol ? State::S0 : State::S1; - SigSpec setsig = sigmap(cell->getPort("\\SET")); - SigSpec clrsig = sigmap(cell->getPort("\\CLR")); + SigSpec setsig = sigmap(cell->getPort(ID(SET))); + SigSpec clrsig = sigmap(cell->getPort(ID(CLR))); Const reset_val; SigSpec setctrl, clrctrl; @@ -78,32 +78,32 @@ void dffsr_worker(SigMap &sigmap, Module *module, Cell *cell) log("Converting %s cell %s.%s to $adff.\n", log_id(cell->type), log_id(module), log_id(cell)); if (GetSize(setctrl) == 1) { - cell->setPort("\\ARST", setctrl); - cell->setParam("\\ARST_POLARITY", setpol); + cell->setPort(ID(ARST), setctrl); + cell->setParam(ID(ARST_POLARITY), setpol); } else { - cell->setPort("\\ARST", clrctrl); - cell->setParam("\\ARST_POLARITY", clrpol); + cell->setPort(ID(ARST), clrctrl); + cell->setParam(ID(ARST_POLARITY), clrpol); } - cell->type = "$adff"; - cell->unsetPort("\\SET"); - cell->unsetPort("\\CLR"); - cell->setParam("\\ARST_VALUE", reset_val); - cell->unsetParam("\\SET_POLARITY"); - cell->unsetParam("\\CLR_POLARITY"); + cell->type = ID($adff); + cell->unsetPort(ID(SET)); + cell->unsetPort(ID(CLR)); + cell->setParam(ID(ARST_VALUE), reset_val); + cell->unsetParam(ID(SET_POLARITY)); + cell->unsetParam(ID(CLR_POLARITY)); return; } - if (cell->type.in("$_DFFSR_NNN_", "$_DFFSR_NNP_", "$_DFFSR_NPN_", "$_DFFSR_NPP_", - "$_DFFSR_PNN_", "$_DFFSR_PNP_", "$_DFFSR_PPN_", "$_DFFSR_PPP_")) + if (cell->type.in(ID($_DFFSR_NNN_), ID($_DFFSR_NNP_), ID($_DFFSR_NPN_), ID($_DFFSR_NPP_), + ID($_DFFSR_PNN_), ID($_DFFSR_PNP_), ID($_DFFSR_PPN_), ID($_DFFSR_PPP_))) { char clkpol = cell->type.c_str()[8]; char setpol = cell->type.c_str()[9]; char clrpol = cell->type.c_str()[10]; - SigBit setbit = sigmap(cell->getPort("\\S")); - SigBit clrbit = sigmap(cell->getPort("\\R")); + SigBit setbit = sigmap(cell->getPort(ID(S))); + SigBit clrbit = sigmap(cell->getPort(ID(R))); SigBit setunused = setpol == 'P' ? State::S0 : State::S1; SigBit clrunused = clrpol == 'P' ? State::S0 : State::S1; @@ -112,14 +112,14 @@ void dffsr_worker(SigMap &sigmap, Module *module, Cell *cell) if (setbit == setunused) { cell->type = stringf("$_DFF_%c%c0_", clkpol, clrpol); - cell->unsetPort("\\S"); + cell->unsetPort(ID(S)); goto converted_gate; } if (clrbit == clrunused) { cell->type = stringf("$_DFF_%c%c1_", clkpol, setpol); - cell->setPort("\\R", cell->getPort("\\S")); - cell->unsetPort("\\S"); + cell->setPort(ID(R), cell->getPort(ID(S))); + cell->unsetPort(ID(S)); goto converted_gate; } @@ -133,32 +133,32 @@ void dffsr_worker(SigMap &sigmap, Module *module, Cell *cell) void adff_worker(SigMap &sigmap, Module *module, Cell *cell) { - if (cell->type == "$adff") + if (cell->type == ID($adff)) { - bool rstpol = cell->getParam("\\ARST_POLARITY").as_bool(); + bool rstpol = cell->getParam(ID(ARST_POLARITY)).as_bool(); SigBit rstunused = rstpol ? State::S0 : State::S1; - SigSpec rstsig = sigmap(cell->getPort("\\ARST")); + SigSpec rstsig = sigmap(cell->getPort(ID(ARST))); if (rstsig != rstunused) return; log("Converting %s cell %s.%s to $dff.\n", log_id(cell->type), log_id(module), log_id(cell)); - cell->type = "$dff"; - cell->unsetPort("\\ARST"); - cell->unsetParam("\\ARST_VALUE"); - cell->unsetParam("\\ARST_POLARITY"); + cell->type = ID($dff); + cell->unsetPort(ID(ARST)); + cell->unsetParam(ID(ARST_VALUE)); + cell->unsetParam(ID(ARST_POLARITY)); return; } - if (cell->type.in("$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_", - "$_DFF_PN0_", "$_DFF_PN1_", "$_DFF_PP0_", "$_DFF_PP1_")) + if (cell->type.in(ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_), + ID($_DFF_PN0_), ID($_DFF_PN1_), ID($_DFF_PP0_), ID($_DFF_PP1_))) { char clkpol = cell->type.c_str()[6]; char rstpol = cell->type.c_str()[7]; - SigBit rstbit = sigmap(cell->getPort("\\R")); + SigBit rstbit = sigmap(cell->getPort(ID(R))); SigBit rstunused = rstpol == 'P' ? State::S0 : State::S1; if (rstbit != rstunused) @@ -168,7 +168,7 @@ void adff_worker(SigMap &sigmap, Module *module, Cell *cell) log("Converting %s cell %s.%s to %s.\n", log_id(cell->type), log_id(module), log_id(cell), log_id(newtype)); cell->type = newtype; - cell->unsetPort("\\R"); + cell->unsetPort(ID(R)); return; } @@ -176,7 +176,7 @@ void adff_worker(SigMap &sigmap, Module *module, Cell *cell) struct Dffsr2dffPass : public Pass { Dffsr2dffPass() : Pass("dffsr2dff", "convert DFFSR cells to simpler FF cell types") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -186,7 +186,7 @@ struct Dffsr2dffPass : public Pass { log("$_DFF_???_) to simpler FF cell types when any of the set/reset inputs is unused.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing DFFSR2DFF pass (mapping DFFSR cells to simpler FFs).\n"); diff --git a/passes/techmap/extract.cc b/passes/techmap/extract.cc index 71e29c60b..f8798eea5 100644 --- a/passes/techmap/extract.cc +++ b/passes/techmap/extract.cc @@ -54,40 +54,40 @@ public: RTLIL::Const unified_param(RTLIL::IdString cell_type, RTLIL::IdString param, RTLIL::Const value) { - if (cell_type.substr(0, 1) != "$" || cell_type.substr(0, 2) == "$_") + if (!cell_type.begins_with("$") || cell_type.begins_with("$_")) return value; #define param_bool(_n) if (param == _n) return value.as_bool(); - param_bool("\\ARST_POLARITY"); - param_bool("\\A_SIGNED"); - param_bool("\\B_SIGNED"); - param_bool("\\CLK_ENABLE"); - param_bool("\\CLK_POLARITY"); - param_bool("\\CLR_POLARITY"); - param_bool("\\EN_POLARITY"); - param_bool("\\SET_POLARITY"); - param_bool("\\TRANSPARENT"); + param_bool(ID(ARST_POLARITY)); + param_bool(ID(A_SIGNED)); + param_bool(ID(B_SIGNED)); + param_bool(ID(CLK_ENABLE)); + param_bool(ID(CLK_POLARITY)); + param_bool(ID(CLR_POLARITY)); + param_bool(ID(EN_POLARITY)); + param_bool(ID(SET_POLARITY)); + param_bool(ID(TRANSPARENT)); #undef param_bool #define param_int(_n) if (param == _n) return value.as_int(); - param_int("\\ABITS") - param_int("\\A_WIDTH") - param_int("\\B_WIDTH") - param_int("\\CTRL_IN_WIDTH") - param_int("\\CTRL_OUT_WIDTH") - param_int("\\OFFSET") - param_int("\\PRIORITY") - param_int("\\RD_PORTS") - param_int("\\SIZE") - param_int("\\STATE_BITS") - param_int("\\STATE_NUM") - param_int("\\STATE_NUM_LOG2") - param_int("\\STATE_RST") - param_int("\\S_WIDTH") - param_int("\\TRANS_NUM") - param_int("\\WIDTH") - param_int("\\WR_PORTS") - param_int("\\Y_WIDTH") + param_int(ID(ABITS)) + param_int(ID(A_WIDTH)) + param_int(ID(B_WIDTH)) + param_int(ID(CTRL_IN_WIDTH)) + param_int(ID(CTRL_OUT_WIDTH)) + param_int(ID(OFFSET)) + param_int(ID(PRIORITY)) + param_int(ID(RD_PORTS)) + param_int(ID(SIZE)) + param_int(ID(STATE_BITS)) + param_int(ID(STATE_NUM)) + param_int(ID(STATE_NUM_LOG2)) + param_int(ID(STATE_RST)) + param_int(ID(S_WIDTH)) + param_int(ID(TRANS_NUM)) + param_int(ID(WIDTH)) + param_int(ID(WR_PORTS)) + param_int(ID(Y_WIDTH)) #undef param_int return value; @@ -203,7 +203,7 @@ bool module2graph(SubCircuit::Graph &graph, RTLIL::Module *mod, bool constports, continue; std::string type = cell->type.str(); - if (sel == NULL && type.substr(0, 2) == "\\$") + if (sel == NULL && type.compare(0, 2, "\\$") == 0) type = type.substr(1); graph.createNode(cell->name.str(), type, (void*)cell); @@ -341,10 +341,10 @@ RTLIL::Cell *replace(RTLIL::Module *needle, RTLIL::Module *haystack, SubCircuit: bool compareSortNeedleList(RTLIL::Module *left, RTLIL::Module *right) { int left_idx = 0, right_idx = 0; - if (left->attributes.count("\\extract_order") > 0) - left_idx = left->attributes.at("\\extract_order").as_int(); - if (right->attributes.count("\\extract_order") > 0) - right_idx = right->attributes.at("\\extract_order").as_int(); + if (left->attributes.count(ID(extract_order)) > 0) + left_idx = left->attributes.at(ID(extract_order)).as_int(); + if (right->attributes.count(ID(extract_order)) > 0) + right_idx = right->attributes.at(ID(extract_order)).as_int(); if (left_idx != right_idx) return left_idx < right_idx; return left->name < right->name; @@ -352,7 +352,7 @@ bool compareSortNeedleList(RTLIL::Module *left, RTLIL::Module *right) struct ExtractPass : public Pass { ExtractPass() : Pass("extract", "find subcircuits and replace them with cells") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -440,7 +440,7 @@ struct ExtractPass : public Pass { log("See 'help techmap' for a pass that does the opposite thing.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing EXTRACT pass (map subcircuits to cells).\n"); log_push(); @@ -594,7 +594,7 @@ struct ExtractPass : public Pass { map = new RTLIL::Design; for (auto &filename : map_filenames) { - if (filename.substr(0, 1) == "%") + if (filename.compare(0, 1, "%") == 0) { if (!saved_designs.count(filename.substr(1))) { delete map; @@ -613,10 +613,10 @@ struct ExtractPass : public Pass { delete map; log_cmd_error("Can't open map file `%s'.\n", filename.c_str()); } - Frontend::frontend_call(map, &f, filename, (filename.size() > 3 && filename.substr(filename.size()-3) == ".il") ? "ilang" : "verilog"); + Frontend::frontend_call(map, &f, filename, (filename.size() > 3 && filename.compare(filename.size()-3, std::string::npos, ".il") == 0 ? "ilang" : "verilog")); f.close(); - if (filename.size() <= 3 || filename.substr(filename.size()-3) != ".il") { + if (filename.size() <= 3 || filename.compare(filename.size()-3, std::string::npos, ".il") != 0) { Pass::call(map, "proc"); Pass::call(map, "opt_clean"); } diff --git a/passes/techmap/extract_counter.cc b/passes/techmap/extract_counter.cc index af0eb852a..17a99493d 100644 --- a/passes/techmap/extract_counter.cc +++ b/passes/techmap/extract_counter.cc @@ -120,71 +120,71 @@ int counter_tryextract( //A counter with less than 2 bits makes no sense //TODO: configurable min threshold - int a_width = cell->getParam("\\A_WIDTH").as_int(); + int a_width = cell->getParam(ID(A_WIDTH)).as_int(); extract.width = a_width; if( (a_width < 2) || (a_width > maxwidth) ) return 1; //Second input must be a single bit - int b_width = cell->getParam("\\B_WIDTH").as_int(); + int b_width = cell->getParam(ID(B_WIDTH)).as_int(); if(b_width != 1) return 2; //Both inputs must be unsigned, so don't extract anything with a signed input - bool a_sign = cell->getParam("\\A_SIGNED").as_bool(); - bool b_sign = cell->getParam("\\B_SIGNED").as_bool(); + bool a_sign = cell->getParam(ID(A_SIGNED)).as_bool(); + bool b_sign = cell->getParam(ID(B_SIGNED)).as_bool(); if(a_sign || b_sign) return 3; //To be a counter, one input of the ALU must be a constant 1 //TODO: can A or B be swapped in synthesized RTL or is B always the 1? - const RTLIL::SigSpec b_port = sigmap(cell->getPort("\\B")); + const RTLIL::SigSpec b_port = sigmap(cell->getPort(ID::B)); if(!b_port.is_fully_const() || (b_port.as_int() != 1) ) return 4; //BI and CI must be constant 1 as well - const RTLIL::SigSpec bi_port = sigmap(cell->getPort("\\BI")); + const RTLIL::SigSpec bi_port = sigmap(cell->getPort(ID(BI))); if(!bi_port.is_fully_const() || (bi_port.as_int() != 1) ) return 5; - const RTLIL::SigSpec ci_port = sigmap(cell->getPort("\\CI")); + const RTLIL::SigSpec ci_port = sigmap(cell->getPort(ID(CI))); if(!ci_port.is_fully_const() || (ci_port.as_int() != 1) ) return 6; //CO and X must be unconnected (exactly one connection to each port) - if(!is_unconnected(sigmap(cell->getPort("\\CO")), index)) + if(!is_unconnected(sigmap(cell->getPort(ID(CO))), index)) return 7; - if(!is_unconnected(sigmap(cell->getPort("\\X")), index)) + if(!is_unconnected(sigmap(cell->getPort(ID(X))), index)) return 8; //Y must have exactly one connection, and it has to be a $mux cell. //We must have a direct bus connection from our Y to their A. - const RTLIL::SigSpec aluy = sigmap(cell->getPort("\\Y")); + const RTLIL::SigSpec aluy = sigmap(cell->getPort(ID::Y)); pool<Cell*> y_loads = get_other_cells(aluy, index, cell); if(y_loads.size() != 1) return 9; Cell* count_mux = *y_loads.begin(); extract.count_mux = count_mux; - if(count_mux->type != "$mux") + if(count_mux->type != ID($mux)) return 10; - if(!is_full_bus(aluy, index, cell, "\\Y", count_mux, "\\A")) + if(!is_full_bus(aluy, index, cell, ID::Y, count_mux, ID::A)) return 11; //B connection of the mux is our underflow value - const RTLIL::SigSpec underflow = sigmap(count_mux->getPort("\\B")); + const RTLIL::SigSpec underflow = sigmap(count_mux->getPort(ID::B)); if(!underflow.is_fully_const()) return 12; extract.count_value = underflow.as_int(); //S connection of the mux must come from an inverter (need not be the only load) - const RTLIL::SigSpec muxsel = sigmap(count_mux->getPort("\\S")); + const RTLIL::SigSpec muxsel = sigmap(count_mux->getPort(ID(S))); extract.outsig = muxsel; pool<Cell*> muxsel_conns = get_other_cells(muxsel, index, count_mux); Cell* underflow_inv = NULL; for(auto c : muxsel_conns) { - if(c->type != "$logic_not") + if(c->type != ID($logic_not)) continue; - if(!is_full_bus(muxsel, index, c, "\\Y", count_mux, "\\S", true)) + if(!is_full_bus(muxsel, index, c, ID::Y, count_mux, ID(S), true)) continue; underflow_inv = c; @@ -196,7 +196,7 @@ int counter_tryextract( //Y connection of the mux must have exactly one load, the counter's internal register, if there's no clock enable //If we have a clock enable, Y drives the B input of a mux. A of that mux must come from our register - const RTLIL::SigSpec muxy = sigmap(count_mux->getPort("\\Y")); + const RTLIL::SigSpec muxy = sigmap(count_mux->getPort(ID::Y)); pool<Cell*> muxy_loads = get_other_cells(muxy, index, count_mux); if(muxy_loads.size() != 1) return 14; @@ -204,12 +204,12 @@ int counter_tryextract( Cell* count_reg = muxload; Cell* cemux = NULL; RTLIL::SigSpec cey; - if(muxload->type == "$mux") + if(muxload->type == ID($mux)) { //This mux is probably a clock enable mux. //Find our count register (should be our only load) cemux = muxload; - cey = sigmap(cemux->getPort("\\Y")); + cey = sigmap(cemux->getPort(ID::Y)); pool<Cell*> cey_loads = get_other_cells(cey, index, cemux); if(cey_loads.size() != 1) return 24; @@ -217,32 +217,32 @@ int counter_tryextract( //Mux should have A driven by count Q, and B by muxy //TODO: if A and B are swapped, CE polarity is inverted - if(sigmap(cemux->getPort("\\B")) != muxy) + if(sigmap(cemux->getPort(ID::B)) != muxy) return 24; - if(sigmap(cemux->getPort("\\A")) != sigmap(count_reg->getPort("\\Q"))) + if(sigmap(cemux->getPort(ID::A)) != sigmap(count_reg->getPort(ID(Q)))) return 24; - if(sigmap(cemux->getPort("\\Y")) != sigmap(count_reg->getPort("\\D"))) + if(sigmap(cemux->getPort(ID::Y)) != sigmap(count_reg->getPort(ID(D)))) return 24; //Select of the mux is our clock enable extract.has_ce = true; - extract.ce = sigmap(cemux->getPort("\\S")); + extract.ce = sigmap(cemux->getPort(ID(S))); } else extract.has_ce = false; extract.count_reg = count_reg; - if(count_reg->type == "$dff") + if(count_reg->type == ID($dff)) extract.has_reset = false; - else if(count_reg->type == "$adff") + else if(count_reg->type == ID($adff)) { extract.has_reset = true; //Check polarity of reset - we may have to add an inverter later on! - extract.rst_inverted = (count_reg->getParam("\\ARST_POLARITY").as_int() != 1); + extract.rst_inverted = (count_reg->getParam(ID(ARST_POLARITY)).as_int() != 1); //Verify ARST_VALUE is zero or full scale - int rst_value = count_reg->getParam("\\ARST_VALUE").as_int(); + int rst_value = count_reg->getParam(ID(ARST_VALUE)).as_int(); if(rst_value == 0) extract.rst_to_max = false; else if(rst_value == extract.count_value) @@ -251,7 +251,7 @@ int counter_tryextract( return 23; //Save the reset - extract.rst = sigmap(count_reg->getPort("\\ARST")); + extract.rst = sigmap(count_reg->getPort(ID(ARST))); } //TODO: support synchronous reset else @@ -260,12 +260,12 @@ int counter_tryextract( //Sanity check that we use the ALU output properly if(extract.has_ce) { - if(!is_full_bus(muxy, index, count_mux, "\\Y", cemux, "\\B")) + if(!is_full_bus(muxy, index, count_mux, ID::Y, cemux, ID::B)) return 16; - if(!is_full_bus(cey, index, cemux, "\\Y", count_reg, "\\D")) + if(!is_full_bus(cey, index, cemux, ID::Y, count_reg, ID(D))) return 16; } - else if(!is_full_bus(muxy, index, count_mux, "\\Y", count_reg, "\\D")) + else if(!is_full_bus(muxy, index, count_mux, ID::Y, count_reg, ID(D))) return 16; //TODO: Verify count_reg CLK_POLARITY is 1 @@ -273,7 +273,7 @@ int counter_tryextract( //Register output must have exactly two loads, the inverter and ALU //(unless we have a parallel output!) //If we have a clock enable, 3 is OK - const RTLIL::SigSpec qport = count_reg->getPort("\\Q"); + const RTLIL::SigSpec qport = count_reg->getPort(ID(Q)); const RTLIL::SigSpec cnout = sigmap(qport); pool<Cell*> cnout_loads = get_other_cells(cnout, index, count_reg); unsigned int max_loads = 2; @@ -312,19 +312,19 @@ int counter_tryextract( } } } - if(!is_full_bus(cnout, index, count_reg, "\\Q", underflow_inv, "\\A", true)) + if(!is_full_bus(cnout, index, count_reg, ID(Q), underflow_inv, ID::A, true)) return 18; - if(!is_full_bus(cnout, index, count_reg, "\\Q", cell, "\\A", true)) + if(!is_full_bus(cnout, index, count_reg, ID(Q), cell, ID::A, true)) return 19; //Look up the clock from the register - extract.clk = sigmap(count_reg->getPort("\\CLK")); + extract.clk = sigmap(count_reg->getPort(ID(CLK))); //Register output net must have an INIT attribute equal to the count value extract.rwire = cnout.as_wire(); - if(extract.rwire->attributes.find("\\init") == extract.rwire->attributes.end()) + if(extract.rwire->attributes.find(ID(init)) == extract.rwire->attributes.end()) return 20; - int rinit = extract.rwire->attributes["\\init"].as_int(); + int rinit = extract.rwire->attributes[ID(init)].as_int(); if(rinit != extract.count_value) return 21; @@ -343,21 +343,21 @@ void counter_worker( SigMap& sigmap = index.sigmap; //Core of the counter must be an ALU - if (cell->type != "$alu") + if (cell->type != ID($alu)) return; //A input is the count value. Check if it has COUNT_EXTRACT set. //If it's not a wire, don't even try - auto port = sigmap(cell->getPort("\\A")); + auto port = sigmap(cell->getPort(ID::A)); if(!port.is_wire()) return; RTLIL::Wire* a_wire = port.as_wire(); bool force_extract = false; bool never_extract = false; - string count_reg_src = a_wire->attributes["\\src"].decode_string().c_str(); - if(a_wire->attributes.find("\\COUNT_EXTRACT") != a_wire->attributes.end()) + string count_reg_src = a_wire->attributes[ID(src)].decode_string().c_str(); + if(a_wire->attributes.find(ID(COUNT_EXTRACT)) != a_wire->attributes.end()) { - pool<string> sa = a_wire->get_strpool_attribute("\\COUNT_EXTRACT"); + pool<string> sa = a_wire->get_strpool_attribute(ID(COUNT_EXTRACT)); string extract_value; if(sa.size() >= 1) { @@ -434,66 +434,66 @@ void counter_worker( string countname = string("$COUNTx$") + log_id(extract.rwire->name.str()); //Wipe all of the old connections to the ALU - cell->unsetPort("\\A"); - cell->unsetPort("\\B"); - cell->unsetPort("\\BI"); - cell->unsetPort("\\CI"); - cell->unsetPort("\\CO"); - cell->unsetPort("\\X"); - cell->unsetPort("\\Y"); - cell->unsetParam("\\A_SIGNED"); - cell->unsetParam("\\A_WIDTH"); - cell->unsetParam("\\B_SIGNED"); - cell->unsetParam("\\B_WIDTH"); - cell->unsetParam("\\Y_WIDTH"); + cell->unsetPort(ID::A); + cell->unsetPort(ID::B); + cell->unsetPort(ID(BI)); + cell->unsetPort(ID(CI)); + cell->unsetPort(ID(CO)); + cell->unsetPort(ID(X)); + cell->unsetPort(ID::Y); + cell->unsetParam(ID(A_SIGNED)); + cell->unsetParam(ID(A_WIDTH)); + cell->unsetParam(ID(B_SIGNED)); + cell->unsetParam(ID(B_WIDTH)); + cell->unsetParam(ID(Y_WIDTH)); //Change the cell type - cell->type = "$__COUNT_"; + cell->type = ID($__COUNT_); //Hook up resets if(extract.has_reset) { //TODO: support other kinds of reset - cell->setParam("\\RESET_MODE", RTLIL::Const("LEVEL")); + cell->setParam(ID(RESET_MODE), RTLIL::Const("LEVEL")); //If the reset is active low, infer an inverter ($__COUNT_ cells always have active high reset) if(extract.rst_inverted) { auto realreset = cell->module->addWire(NEW_ID); cell->module->addNot(NEW_ID, extract.rst, RTLIL::SigSpec(realreset)); - cell->setPort("\\RST", realreset); + cell->setPort(ID(RST), realreset); } else - cell->setPort("\\RST", extract.rst); + cell->setPort(ID(RST), extract.rst); } else { - cell->setParam("\\RESET_MODE", RTLIL::Const("RISING")); - cell->setPort("\\RST", RTLIL::SigSpec(false)); + cell->setParam(ID(RESET_MODE), RTLIL::Const("RISING")); + cell->setPort(ID(RST), RTLIL::SigSpec(false)); } //Hook up other stuff - //cell->setParam("\\CLKIN_DIVIDE", RTLIL::Const(1)); - cell->setParam("\\COUNT_TO", RTLIL::Const(extract.count_value)); - cell->setParam("\\WIDTH", RTLIL::Const(extract.width)); - cell->setPort("\\CLK", extract.clk); - cell->setPort("\\OUT", extract.outsig); + //cell->setParam(ID(CLKIN_DIVIDE), RTLIL::Const(1)); + cell->setParam(ID(COUNT_TO), RTLIL::Const(extract.count_value)); + cell->setParam(ID(WIDTH), RTLIL::Const(extract.width)); + cell->setPort(ID(CLK), extract.clk); + cell->setPort(ID(OUT), extract.outsig); //Hook up clock enable if(extract.has_ce) { - cell->setParam("\\HAS_CE", RTLIL::Const(1)); - cell->setPort("\\CE", extract.ce); + cell->setParam(ID(HAS_CE), RTLIL::Const(1)); + cell->setPort(ID(CE), extract.ce); } else - cell->setParam("\\HAS_CE", RTLIL::Const(0)); + cell->setParam(ID(HAS_CE), RTLIL::Const(0)); //Hook up hard-wired ports (for now up/down are not supported), default to no parallel output - cell->setParam("\\HAS_POUT", RTLIL::Const(0)); - cell->setParam("\\RESET_TO_MAX", RTLIL::Const(0)); - cell->setParam("\\DIRECTION", RTLIL::Const("DOWN")); - cell->setPort("\\CE", RTLIL::Const(1)); - cell->setPort("\\UP", RTLIL::Const(0)); + cell->setParam(ID(HAS_POUT), RTLIL::Const(0)); + cell->setParam(ID(RESET_TO_MAX), RTLIL::Const(0)); + cell->setParam(ID(DIRECTION), RTLIL::Const("DOWN")); + cell->setPort(ID(CE), RTLIL::Const(1)); + cell->setPort(ID(UP), RTLIL::Const(0)); //Hook up any parallel outputs for(auto load : extract.pouts) @@ -505,8 +505,8 @@ void counter_worker( //Connect it to our parallel output //(this is OK to do more than once b/c they all go to the same place) - cell->setPort("\\POUT", sig); - cell->setParam("\\HAS_POUT", RTLIL::Const(1)); + cell->setPort(ID(POUT), sig); + cell->setParam(ID(HAS_POUT), RTLIL::Const(1)); } //Delete the cells we've replaced (let opt_clean handle deleting the now-redundant wires) @@ -546,7 +546,7 @@ void counter_worker( int newbits = ceil(log2(extract.count_value)); if(extract.width != newbits) { - cell->setParam("\\WIDTH", RTLIL::Const(newbits)); + cell->setParam(ID(WIDTH), RTLIL::Const(newbits)); log(" Optimizing out %d unused high-order bits (new width is %d)\n", extract.width - newbits, newbits); @@ -559,7 +559,7 @@ void counter_worker( struct ExtractCounterPass : public Pass { ExtractCounterPass() : Pass("extract_counter", "Extract GreenPak4 counter cells") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -578,7 +578,7 @@ struct ExtractCounterPass : public Pass { log("\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing EXTRACT_COUNTER pass (find counters in netlist).\n"); diff --git a/passes/techmap/extract_fa.cc b/passes/techmap/extract_fa.cc index a68cc5e2e..29700c37b 100644 --- a/passes/techmap/extract_fa.cc +++ b/passes/techmap/extract_fa.cc @@ -85,11 +85,11 @@ struct ExtractFaWorker { for (auto cell : module->selected_cells()) { - if (cell->type.in( "$_BUF_", "$_NOT_", "$_AND_", "$_NAND_", "$_OR_", "$_NOR_", - "$_XOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_", "$_MUX_", - "$_AOI3_", "$_OAI3_", "$_AOI4_", "$_OAI4_")) + if (cell->type.in( ID($_BUF_), ID($_NOT_), ID($_AND_), ID($_NAND_), ID($_OR_), ID($_NOR_), + ID($_XOR_), ID($_XNOR_), ID($_ANDNOT_), ID($_ORNOT_), ID($_MUX_), ID($_NMUX_), + ID($_AOI3_), ID($_OAI3_), ID($_AOI4_), ID($_OAI4_))) { - SigBit y = sigmap(SigBit(cell->getPort("\\Y"))); + SigBit y = sigmap(SigBit(cell->getPort(ID::Y))); log_assert(driver.count(y) == 0); driver[y] = cell; } @@ -174,8 +174,10 @@ struct ExtractFaWorker SigSpec sig = root; - if (!ce.eval(sig)) - log_abort(); + if (!ce.eval(sig)) { + ce.pop(); + return; + } if (sig == State::S1) func |= 1 << i; @@ -214,8 +216,10 @@ struct ExtractFaWorker SigSpec sig = root; - if (!ce.eval(sig)) - log_abort(); + if (!ce.eval(sig)) { + ce.pop(); + return; + } if (sig == State::S1) func |= 1 << i; @@ -258,10 +262,10 @@ struct ExtractFaWorker pool<SigBit> new_leaves = leaves; new_leaves.erase(bit); - if (cell->hasPort("\\A")) new_leaves.insert(sigmap(SigBit(cell->getPort("\\A")))); - if (cell->hasPort("\\B")) new_leaves.insert(sigmap(SigBit(cell->getPort("\\B")))); - if (cell->hasPort("\\C")) new_leaves.insert(sigmap(SigBit(cell->getPort("\\C")))); - if (cell->hasPort("\\D")) new_leaves.insert(sigmap(SigBit(cell->getPort("\\D")))); + if (cell->hasPort(ID::A)) new_leaves.insert(sigmap(SigBit(cell->getPort(ID::A)))); + if (cell->hasPort(ID::B)) new_leaves.insert(sigmap(SigBit(cell->getPort(ID::B)))); + if (cell->hasPort(ID(C))) new_leaves.insert(sigmap(SigBit(cell->getPort(ID(C))))); + if (cell->hasPort(ID(D))) new_leaves.insert(sigmap(SigBit(cell->getPort(ID(D))))); if (GetSize(new_leaves) > maxbreadth) continue; @@ -273,8 +277,8 @@ struct ExtractFaWorker void assign_new_driver(SigBit bit, SigBit new_driver) { Cell *cell = driver.at(bit); - if (sigmap(cell->getPort("\\Y")) == bit) { - cell->setPort("\\Y", module->addWire(NEW_ID)); + if (sigmap(cell->getPort(ID::Y)) == bit) { + cell->setPort(ID::Y, module->addWire(NEW_ID)); module->connect(bit, new_driver); } } @@ -285,7 +289,7 @@ struct ExtractFaWorker for (auto it : driver) { - if (it.second->type.in("$_BUF_", "$_NOT_")) + if (it.second->type.in(ID($_BUF_), ID($_NOT_))) continue; SigBit root = it.first; @@ -386,20 +390,20 @@ struct ExtractFaWorker } else { - Cell *cell = module->addCell(NEW_ID, "$fa"); - cell->setParam("\\WIDTH", 1); + Cell *cell = module->addCell(NEW_ID, ID($fa)); + cell->setParam(ID(WIDTH), 1); log(" Created $fa cell %s.\n", log_id(cell)); - cell->setPort("\\A", f3i.inv_a ? module->NotGate(NEW_ID, A) : A); - cell->setPort("\\B", f3i.inv_b ? module->NotGate(NEW_ID, B) : B); - cell->setPort("\\C", f3i.inv_c ? module->NotGate(NEW_ID, C) : C); + cell->setPort(ID::A, f3i.inv_a ? module->NotGate(NEW_ID, A) : A); + cell->setPort(ID::B, f3i.inv_b ? module->NotGate(NEW_ID, B) : B); + cell->setPort(ID(C), f3i.inv_c ? module->NotGate(NEW_ID, C) : C); X = module->addWire(NEW_ID); Y = module->addWire(NEW_ID); - cell->setPort("\\X", X); - cell->setPort("\\Y", Y); + cell->setPort(ID(X), X); + cell->setPort(ID::Y, Y); facache[fakey] = make_tuple(X, Y, cell); } @@ -492,30 +496,30 @@ struct ExtractFaWorker } else { - Cell *cell = module->addCell(NEW_ID, "$fa"); - cell->setParam("\\WIDTH", 1); + Cell *cell = module->addCell(NEW_ID, ID($fa)); + cell->setParam(ID(WIDTH), 1); log(" Created $fa cell %s.\n", log_id(cell)); - cell->setPort("\\A", f2i.inv_a ? module->NotGate(NEW_ID, A) : A); - cell->setPort("\\B", f2i.inv_b ? module->NotGate(NEW_ID, B) : B); - cell->setPort("\\C", State::S0); + cell->setPort(ID::A, f2i.inv_a ? module->NotGate(NEW_ID, A) : A); + cell->setPort(ID::B, f2i.inv_b ? module->NotGate(NEW_ID, B) : B); + cell->setPort(ID(C), State::S0); X = module->addWire(NEW_ID); Y = module->addWire(NEW_ID); - cell->setPort("\\X", X); - cell->setPort("\\Y", Y); + cell->setPort(ID(X), X); + cell->setPort(ID::Y, Y); } if (func2.at(key).count(xor2_func)) { - SigBit YY = invert_xy ? module->NotGate(NEW_ID, Y) : Y; + SigBit YY = invert_xy || (f2i.inv_a && !f2i.inv_b) || (!f2i.inv_a && f2i.inv_b) ? module->NotGate(NEW_ID, Y) : Y; for (auto bit : func2.at(key).at(xor2_func)) assign_new_driver(bit, YY); } if (func2.at(key).count(xnor2_func)) { - SigBit YY = invert_xy ? Y : module->NotGate(NEW_ID, Y); + SigBit YY = invert_xy || (f2i.inv_a && !f2i.inv_b) || (!f2i.inv_a && f2i.inv_b) ? Y : module->NotGate(NEW_ID, Y); for (auto bit : func2.at(key).at(xnor2_func)) assign_new_driver(bit, YY); } @@ -531,7 +535,7 @@ struct ExtractFaWorker struct ExtractFaPass : public Pass { ExtractFaPass() : Pass("extract_fa", "find and extract full/half adders") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -553,7 +557,7 @@ struct ExtractFaPass : public Pass { log(" Verbose output\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { ExtractFaConfig config; diff --git a/passes/techmap/extract_reduce.cc b/passes/techmap/extract_reduce.cc index cc21c8665..11cfddcd9 100644 --- a/passes/techmap/extract_reduce.cc +++ b/passes/techmap/extract_reduce.cc @@ -19,6 +19,7 @@ #include "kernel/yosys.h" #include "kernel/sigtools.h" +#include <deque> USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -33,7 +34,7 @@ struct ExtractReducePass : public Pass ExtractReducePass() : Pass("extract_reduce", "converts gate chains into $reduce_* cells") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -57,12 +58,12 @@ struct ExtractReducePass : public Pass inline bool IsRightType(Cell* cell, GateType gt) { - return (cell->type == "$_AND_" && gt == GateType::And) || - (cell->type == "$_OR_" && gt == GateType::Or) || - (cell->type == "$_XOR_" && gt == GateType::Xor); + return (cell->type == ID($_AND_) && gt == GateType::And) || + (cell->type == ID($_OR_) && gt == GateType::Or) || + (cell->type == ID($_XOR_) && gt == GateType::Xor); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing EXTRACT_REDUCE pass.\n"); log_push(); @@ -123,11 +124,11 @@ struct ExtractReducePass : public Pass GateType gt; - if (cell->type == "$_AND_") + if (cell->type == ID($_AND_)) gt = GateType::And; - else if (cell->type == "$_OR_") + else if (cell->type == ID($_OR_)) gt = GateType::Or; - else if (cell->type == "$_XOR_") + else if (cell->type == ID($_XOR_)) gt = GateType::Xor; else continue; @@ -147,7 +148,7 @@ struct ExtractReducePass : public Pass head_cell = x; - auto y = sigmap(x->getPort("\\Y")); + auto y = sigmap(x->getPort(ID::Y)); log_assert(y.size() == 1); // Should only continue if there is one fanout back into a cell (not to a port) @@ -165,7 +166,7 @@ struct ExtractReducePass : public Pass { //BFS, following all chains until they hit a cell of a different type //Pick the longest one - auto y = sigmap(cell->getPort("\\Y")); + auto y = sigmap(cell->getPort(ID::Y)); pool<Cell*> current_loads = sig_to_sink[y]; pool<Cell*> next_loads; @@ -232,7 +233,7 @@ struct ExtractReducePass : public Pass cur_supercell.insert(x); - auto a = sigmap(x->getPort("\\A")); + auto a = sigmap(x->getPort(ID::A)); log_assert(a.size() == 1); // Must have only one sink unless we're going off chain @@ -248,7 +249,7 @@ struct ExtractReducePass : public Pass } } - auto b = sigmap(x->getPort("\\B")); + auto b = sigmap(x->getPort(ID::B)); log_assert(b.size() == 1); // Must have only one sink @@ -278,26 +279,26 @@ struct ExtractReducePass : public Pass pool<SigBit> input_pool_intermed; for (auto x : cur_supercell) { - input_pool.insert(sigmap(x->getPort("\\A"))[0]); - input_pool.insert(sigmap(x->getPort("\\B"))[0]); - input_pool_intermed.insert(sigmap(x->getPort("\\Y"))[0]); + input_pool.insert(sigmap(x->getPort(ID::A))[0]); + input_pool.insert(sigmap(x->getPort(ID::B))[0]); + input_pool_intermed.insert(sigmap(x->getPort(ID::Y))[0]); } SigSpec input; for (auto b : input_pool) if (input_pool_intermed.count(b) == 0) input.append_bit(b); - SigBit output = sigmap(head_cell->getPort("\\Y")[0]); + SigBit output = sigmap(head_cell->getPort(ID::Y)[0]); auto new_reduce_cell = module->addCell(NEW_ID, - gt == GateType::And ? "$reduce_and" : - gt == GateType::Or ? "$reduce_or" : - gt == GateType::Xor ? "$reduce_xor" : ""); - new_reduce_cell->setParam("\\A_SIGNED", 0); - new_reduce_cell->setParam("\\A_WIDTH", input.size()); - new_reduce_cell->setParam("\\Y_WIDTH", 1); - new_reduce_cell->setPort("\\A", input); - new_reduce_cell->setPort("\\Y", output); + gt == GateType::And ? ID($reduce_and) : + gt == GateType::Or ? ID($reduce_or) : + gt == GateType::Xor ? ID($reduce_xor) : ""); + new_reduce_cell->setParam(ID(A_SIGNED), 0); + new_reduce_cell->setParam(ID(A_WIDTH), input.size()); + new_reduce_cell->setParam(ID(Y_WIDTH), 1); + new_reduce_cell->setPort(ID::A, input); + new_reduce_cell->setPort(ID::Y, output); if(allow_off_chain) consumed_cells.insert(head_cell); diff --git a/passes/techmap/extractinv.cc b/passes/techmap/extractinv.cc new file mode 100644 index 000000000..dda71f12a --- /dev/null +++ b/passes/techmap/extractinv.cc @@ -0,0 +1,123 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * Copyright (C) 2019 Marcin Kościelnicki <mwk@0x04.net> + * + * 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 + +void split_portname_pair(std::string &port1, std::string &port2) +{ + size_t pos = port1.find_first_of(':'); + if (pos != std::string::npos) { + port2 = port1.substr(pos+1); + port1 = port1.substr(0, pos); + } +} + +struct ExtractinvPass : public Pass { + ExtractinvPass() : Pass("extractinv", "extract explicit inverter cells for invertible cell pins") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" extractinv [options] [selection]\n"); + log("\n"); + log("Searches the design for all cells with invertible pins controlled by a cell\n"); + log("parameter (eg. IS_CLK_INVERTED on many Xilinx cells) and removes the parameter.\n"); + log("If the parameter was set to 1, inserts an explicit inverter cell in front of\n"); + log("the pin instead. Normally used for output to ISE, which does not support the\n"); + log("inversion parameters.\n"); + log("\n"); + log("To mark a cell port as invertible, use (* invertible_pin = \"param_name\" *)\n"); + log("on the wire in the blackbox module. The parameter value should have\n"); + log("the same width as the port, and will be effectively XORed with it.\n"); + log("\n"); + log(" -inv <celltype> <portname_out>:<portname_in>\n"); + log(" Specifies the cell type to use for the inverters and its port names.\n"); + log(" This option is required.\n"); + log("\n"); + } + + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + log_header(design, "Executing EXTRACTINV pass (extracting pin inverters).\n"); + + std::string inv_celltype, inv_portname, inv_portname2; + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + std::string arg = args[argidx]; + if (arg == "-inv" && argidx+2 < args.size()) { + inv_celltype = args[++argidx]; + inv_portname = args[++argidx]; + split_portname_pair(inv_portname, inv_portname2); + continue; + } + break; + } + extra_args(args, argidx, design); + + if (inv_celltype.empty()) + log_error("The -inv option is required.\n"); + + for (auto module : design->selected_modules()) + { + for (auto cell : module->selected_cells()) + for (auto port : cell->connections()) { + auto cell_module = design->module(cell->type); + if (!cell_module) + continue; + auto cell_wire = cell_module->wire(port.first); + if (!cell_wire) + continue; + auto it = cell_wire->attributes.find("\\invertible_pin"); + if (it == cell_wire->attributes.end()) + continue; + IdString param_name = RTLIL::escape_id(it->second.decode_string()); + auto it2 = cell->parameters.find(param_name); + // Inversion not used -- skip. + if (it2 == cell->parameters.end()) + continue; + SigSpec sig = port.second; + if (it2->second.size() != sig.size()) + log_error("The inversion parameter needs to be the same width as the port (%s.%s port %s parameter %s)", log_id(module->name), log_id(cell->type), log_id(port.first), log_id(param_name)); + RTLIL::Const invmask = it2->second; + cell->parameters.erase(param_name); + if (invmask.is_fully_zero()) + continue; + Wire *iwire = module->addWire(NEW_ID, sig.size()); + for (int i = 0; i < sig.size(); i++) + if (invmask[i] == State::S1) { + RTLIL::Cell *icell = module->addCell(NEW_ID, RTLIL::escape_id(inv_celltype)); + icell->setPort(RTLIL::escape_id(inv_portname), SigSpec(iwire, i)); + icell->setPort(RTLIL::escape_id(inv_portname2), sig[i]); + log("Inserting %s on %s.%s.%s[%d].\n", inv_celltype.c_str(), log_id(module), log_id(cell->type), log_id(port.first), i); + sig[i] = SigBit(iwire, i); + } + cell->setPort(port.first, sig); + } + } + } +} ExtractinvPass; + +PRIVATE_NAMESPACE_END diff --git a/passes/techmap/flowmap.cc b/passes/techmap/flowmap.cc new file mode 100644 index 000000000..5807178dd --- /dev/null +++ b/passes/techmap/flowmap.cc @@ -0,0 +1,1613 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2018 whitequark <whitequark@whitequark.org> + * + * 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. + * + */ + +// [[CITE]] FlowMap algorithm +// Jason Cong; Yuzheng Ding, "An Optimal Technology Mapping Algorithm for Delay Optimization in Lookup-Table Based FPGA Designs," +// Computer-Aided Design of Integrated Circuits and Systems, IEEE Transactions on, Vol. 13, pp. 1-12, Jan. 1994. +// doi: 10.1109/43.273754 + +// [[CITE]] FlowMap-r algorithm +// Jason Cong; Yuzheng Ding, "On Area/Depth Tradeoff in LUT-Based FPGA Technology Mapping," +// Very Large Scale Integration Systems, IEEE Transactions on, Vol. 2, June 1994. +// doi: 10.1109/92.28574 + +// Required reading material: +// +// Min-cut max-flow theorem: +// https://www.coursera.org/lecture/algorithms-part2/maxflow-mincut-theorem-beb9G +// FlowMap paper: +// http://cadlab.cs.ucla.edu/~cong/papers/iccad92.pdf (short version) +// https://limsk.ece.gatech.edu/book/papers/flowmap.pdf (long version) +// FlowMap-r paper: +// http://cadlab.cs.ucla.edu/~cong/papers/dac93.pdf (short version) +// https://sci-hub.tw/10.1109/92.285741 (long version) + +// Notes on correspondence between paper and implementation: +// +// 1. In the FlowMap paper, the nodes are logic elements (analogous to Yosys cells) and edges are wires. However, in our implementation, +// we use an inverted approach: the nodes are Yosys wire bits, and the edges are derived from (but aren't represented by) Yosys cells. +// This may seem counterintuitive. Three observations may help understanding this. First, for a cell with a 1-bit Y output that is +// the sole driver of its output net (which is the typical case), these representations are equivalent, because there is an exact +// correspondence between cells and output wires. Second, in the paper, primary inputs (analogous to Yosys cell or module ports) are +// nodes, and in Yosys, inputs are wires; our approach allows a direct mapping from both primary inputs and 1-output logic elements to +// flow graph nodes. Third, Yosys cells may have multiple outputs or multi-bit outputs, and by using Yosys wire bits as flow graph nodes, +// such cells are supported without any additional effort; any Yosys cell with n output wire bits ends up being split into n flow graph +// nodes. +// +// 2. The FlowMap paper introduces three networks: Nt, Nt', and Nt''. The network Nt is directly represented by a subgraph of RTLIL graph, +// which is parsed into an equivalent but easier to traverse representation in FlowmapWorker. The network Nt' is built explicitly +// from a subgraph of Nt, and uses a similar representation in FlowGraph. The network Nt'' is implicit in FlowGraph, which is possible +// because of the following observation: each Nt' node corresponds to an Nt'' edge of capacity 1, and each Nt' edge corresponds to +// an Nt'' edge of capacity ∞. Therefore, we only need to explicitly record flow for Nt' edges and through Nt' nodes. +// +// 3. The FlowMap paper ambiguously states: "Moreover, we can find such a cut (X′′, X̅′′) by performing a depth first search starting at +// the source s, and including in X′′ all the nodes which are reachable from s." This actually refers to a specific kind of search, +// min-cut computation. Min-cut computation involves computing the set of nodes reachable from s by an undirected path with no full +// (i.e. zero capacity) forward edges or empty (i.e. no flow) backward edges. In addition, the depth first search is required to compute +// a max-volume max-flow min-cut specifically, because a max-flow min-cut is not, in general, unique. + +// Notes on implementation: +// +// 1. To compute depth optimal packing, an intermediate representation is used, where each cell with n output bits is split into n graph +// nodes. Each such graph node is represented directly with the wire bit (RTLIL::SigBit instance) that corresponds to the output bit +// it is created from. Fan-in and fan-out are represented explicitly by edge lists derived from the RTLIL graph. This IR never changes +// after it has been computed. +// +// In terms of data, this IR is comprised of `inputs`, `outputs`, `nodes`, `edges_fw` and `edges_bw` fields. +// +// We call this IR "gate IR". +// +// 2. To compute area optimal packing, another intermediate representation is used, which consists of some K-feasible cone for every node +// that exists in the gate IR. Immediately after depth optimal packing with FlowMap, each such cone occupies the lowest possible depth, +// but this is not true in general, and transformations of this IR may change the cones, although each transformation has to keep each +// cone K-feasible. In this IR, LUT fan-in and fan-out are represented explicitly by edge lists; if a K-feasible cone chosen for node A +// includes nodes B and C, there are edges between all predecessors of A, B and C in the gate IR and node A in this IR. Moreover, in +// this IR, cones may be *realized* or *derealized*. Only realized cones will end up mapped to actual LUTs in the output of this pass. +// +// Intuitively, this IR contains (some, ideally but not necessarily optimal) LUT representation for each input cell. By starting at outputs +// and traversing the graph of this IR backwards, each K-feasible cone is converted to an actual LUT at the end of the pass. This is +// the same as iterating through each realized LUT. +// +// The following are the invariants of this IR: +// a) Each gate IR node corresponds to a K-feasible cut. +// b) Each realized LUT is reachable through backward edges from some output. +// c) The LUT fan-in is exactly the fan-in of its constituent gates minus the fan-out of its constituent gates. +// The invariants are kept even for derealized LUTs, since the whole point of this IR is ease of packing, unpacking, and repacking LUTs. +// +// In terms of data, this IR is comprised of `lut_nodes` (the set of all realized LUTs), `lut_gates` (the map from a LUT to its +// constituent gates), `lut_edges_fw` and `lut_edges_bw` fields. The `inputs` and `outputs` fields are shared with the gate IR. +// +// We call this IR "LUT IR". + +#include "kernel/yosys.h" +#include "kernel/sigtools.h" +#include "kernel/modtools.h" +#include "kernel/consteval.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct GraphStyle +{ + string label; + string color, fillcolor; + + GraphStyle(string label = "", string color = "black", string fillcolor = "") : + label(label), color(color), fillcolor(fillcolor) {} +}; + +static string dot_escape(string value) +{ + std::string escaped; + for (char c : value) { + if (c == '\n') + { + escaped += "\\n"; + continue; + } + if (c == '\\' || c == '"') + escaped += "\\"; + escaped += c; + } + return escaped; +} + +static void dump_dot_graph(string filename, + pool<RTLIL::SigBit> nodes, dict<RTLIL::SigBit, pool<RTLIL::SigBit>> edges, + pool<RTLIL::SigBit> inputs, pool<RTLIL::SigBit> outputs, + std::function<GraphStyle(RTLIL::SigBit)> node_style = + [](RTLIL::SigBit) { return GraphStyle{}; }, + std::function<GraphStyle(RTLIL::SigBit, RTLIL::SigBit)> edge_style = + [](RTLIL::SigBit, RTLIL::SigBit) { return GraphStyle{}; }, + string name = "") +{ + FILE *f = fopen(filename.c_str(), "w"); + fprintf(f, "digraph \"%s\" {\n", name.c_str()); + fprintf(f, " rankdir=\"TB\";\n"); + + dict<RTLIL::SigBit, int> ids; + for (auto node : nodes) + { + ids[node] = ids.size(); + + string shape = "ellipse"; + if (inputs[node]) + shape = "box"; + if (outputs[node]) + shape = "octagon"; + auto prop = node_style(node); + string style = ""; + if (!prop.fillcolor.empty()) + style = "filled"; + fprintf(f, " n%d [ shape=%s, fontname=\"Monospace\", label=\"%s\", color=\"%s\", fillcolor=\"%s\", style=\"%s\" ];\n", + ids[node], shape.c_str(), dot_escape(prop.label.c_str()).c_str(), prop.color.c_str(), prop.fillcolor.c_str(), style.c_str()); + } + + fprintf(f, " { rank=\"source\"; "); + for (auto input : inputs) + if (nodes[input]) + fprintf(f, "n%d; ", ids[input]); + fprintf(f, "}\n"); + + fprintf(f, " { rank=\"sink\"; "); + for (auto output : outputs) + if (nodes[output]) + fprintf(f, "n%d; ", ids[output]); + fprintf(f, "}\n"); + + for (auto edge : edges) + { + auto source = edge.first; + for (auto sink : edge.second) { + if (nodes[source] && nodes[sink]) + { + auto prop = edge_style(source, sink); + fprintf(f, " n%d -> n%d [ label=\"%s\", color=\"%s\", fillcolor=\"%s\" ];\n", + ids[source], ids[sink], dot_escape(prop.label.c_str()).c_str(), prop.color.c_str(), prop.fillcolor.c_str()); + } + } + } + + fprintf(f, "}\n"); + fclose(f); +} + +struct FlowGraph +{ + const RTLIL::SigBit source; + RTLIL::SigBit sink; + pool<RTLIL::SigBit> nodes = {source}; + dict<RTLIL::SigBit, pool<RTLIL::SigBit>> edges_fw, edges_bw; + + const int MAX_NODE_FLOW = 1; + dict<RTLIL::SigBit, int> node_flow; + dict<pair<RTLIL::SigBit, RTLIL::SigBit>, int> edge_flow; + + dict<RTLIL::SigBit, pool<RTLIL::SigBit>> collapsed; + + void dump_dot_graph(string filename) + { + auto node_style = [&](RTLIL::SigBit node) { + string label = (node == source) ? "(source)" : log_signal(node); + for (auto collapsed_node : collapsed[node]) + label += stringf(" %s", log_signal(collapsed_node)); + int flow = node_flow[node]; + if (node != source && node != sink) + label += stringf("\n%d/%d", flow, MAX_NODE_FLOW); + else + label += stringf("\n%d/∞", flow); + return GraphStyle{label, flow < MAX_NODE_FLOW ? "green" : "black"}; + }; + auto edge_style = [&](RTLIL::SigBit source, RTLIL::SigBit sink) { + int flow = edge_flow[{source, sink}]; + return GraphStyle{stringf("%d/∞", flow), flow > 0 ? "blue" : "black"}; + }; + ::dump_dot_graph(filename, nodes, edges_fw, {source}, {sink}, node_style, edge_style); + } + + // Here, we are working on the Nt'' network, but our representation is the Nt' network. + // The difference between these is that where in Nt' we have a subgraph: + // + // v1 -> v2 -> v3 + // + // in Nt'' we have a corresponding subgraph: + // + // v'1b -∞-> v'2t -f-> v'2b -∞-> v'3t + // + // To address this, we split each node v into two nodes, v't and v'b. This representation is virtual, + // in the sense that nodes v't and v'b are overlaid on top of the original node v, and only exist + // in paths and worklists. + + struct NodePrime + { + RTLIL::SigBit node; + bool is_bottom; + + NodePrime(RTLIL::SigBit node, bool is_bottom) : + node(node), is_bottom(is_bottom) {} + + bool operator==(const NodePrime &other) const + { + return node == other.node && is_bottom == other.is_bottom; + } + bool operator!=(const NodePrime &other) const + { + return !(*this == other); + } + unsigned int hash() const + { + return hash_ops<pair<RTLIL::SigBit, int>>::hash({node, is_bottom}); + } + + static NodePrime top(RTLIL::SigBit node) + { + return NodePrime(node, /*is_bottom=*/false); + } + + static NodePrime bottom(RTLIL::SigBit node) + { + return NodePrime(node, /*is_bottom=*/true); + } + + NodePrime as_top() const + { + log_assert(is_bottom); + return top(node); + } + + NodePrime as_bottom() const + { + log_assert(!is_bottom); + return bottom(node); + } + }; + + bool find_augmenting_path(bool commit) + { + NodePrime source_prime = {source, true}; + NodePrime sink_prime = {sink, false}; + vector<NodePrime> path = {source_prime}; + pool<NodePrime> visited = {}; + bool found; + do { + found = false; + + auto node_prime = path.back(); + visited.insert(node_prime); + + if (!node_prime.is_bottom) // vt + { + if (!visited[node_prime.as_bottom()] && node_flow[node_prime.node] < MAX_NODE_FLOW) + { + path.push_back(node_prime.as_bottom()); + found = true; + } + else + { + for (auto node_pred : edges_bw[node_prime.node]) + { + if (!visited[NodePrime::bottom(node_pred)] && edge_flow[{node_pred, node_prime.node}] > 0) + { + path.push_back(NodePrime::bottom(node_pred)); + found = true; + break; + } + } + } + } + else // vb + { + if (!visited[node_prime.as_top()] && node_flow[node_prime.node] > 0) + { + path.push_back(node_prime.as_top()); + found = true; + } + else + { + for (auto node_succ : edges_fw[node_prime.node]) + { + if (!visited[NodePrime::top(node_succ)] /* && edge_flow[...] < ∞ */) + { + path.push_back(NodePrime::top(node_succ)); + found = true; + break; + } + } + } + } + + if (!found && path.size() > 1) + { + path.pop_back(); + found = true; + } + } while(path.back() != sink_prime && found); + + if (commit && path.back() == sink_prime) + { + auto prev_prime = path.front(); + for (auto node_prime : path) + { + if (node_prime == source_prime) + continue; + + log_assert(prev_prime.is_bottom ^ node_prime.is_bottom); + if (prev_prime.node == node_prime.node) + { + auto node = node_prime.node; + if (!prev_prime.is_bottom && node_prime.is_bottom) + { + log_assert(node_flow[node] == 0); + node_flow[node]++; + } + else + { + log_assert(node_flow[node] != 0); + node_flow[node]--; + } + } + else + { + if (prev_prime.is_bottom && !node_prime.is_bottom) + { + log_assert(true /* edge_flow[...] < ∞ */); + edge_flow[{prev_prime.node, node_prime.node}]++; + } + else + { + log_assert((edge_flow[{node_prime.node, prev_prime.node}] > 0)); + edge_flow[{node_prime.node, prev_prime.node}]--; + } + } + prev_prime = node_prime; + } + + node_flow[source]++; + node_flow[sink]++; + } + return path.back() == sink_prime; + } + + int maximum_flow(int order) + { + int flow = 0; + while (flow < order && find_augmenting_path(/*commit=*/true)) + flow++; + return flow + find_augmenting_path(/*commit=*/false); + } + + pair<pool<RTLIL::SigBit>, pool<RTLIL::SigBit>> edge_cut() + { + pool<RTLIL::SigBit> x, xi; + + NodePrime source_prime = {source, true}; + pool<NodePrime> visited; + vector<NodePrime> worklist = {source_prime}; + while (!worklist.empty()) + { + auto node_prime = worklist.back(); + worklist.pop_back(); + if (visited[node_prime]) + continue; + visited.insert(node_prime); + + if (!node_prime.is_bottom) + x.insert(node_prime.node); + + // Mincut is constructed by traversing a graph in an undirected way along forward edges that aren't full, or backward edges + // that aren't empty. + if (!node_prime.is_bottom) // top + { + if (node_flow[node_prime.node] < MAX_NODE_FLOW) + worklist.push_back(node_prime.as_bottom()); + for (auto node_pred : edges_bw[node_prime.node]) + if (edge_flow[{node_pred, node_prime.node}] > 0) + worklist.push_back(NodePrime::bottom(node_pred)); + } + else // bottom + { + if (node_flow[node_prime.node] > 0) + worklist.push_back(node_prime.as_top()); + for (auto node_succ : edges_fw[node_prime.node]) + if (true /* edge_flow[...] < ∞ */) + worklist.push_back(NodePrime::top(node_succ)); + } + } + + for (auto node : nodes) + if (!x[node]) + xi.insert(node); + + for (auto collapsed_node : collapsed[sink]) + xi.insert(collapsed_node); + + log_assert(!x[sink] && xi[sink]); + return {x, xi}; + } +}; + +struct FlowmapWorker +{ + int order; + int r_alpha, r_beta, r_gamma; + bool debug, debug_relax; + + RTLIL::Module *module; + SigMap sigmap; + ModIndex index; + + dict<RTLIL::SigBit, ModIndex::PortInfo> node_origins; + + // Gate IR + pool<RTLIL::SigBit> nodes, inputs, outputs; + dict<RTLIL::SigBit, pool<RTLIL::SigBit>> edges_fw, edges_bw; + dict<RTLIL::SigBit, int> labels; + + // LUT IR + pool<RTLIL::SigBit> lut_nodes; + dict<RTLIL::SigBit, pool<RTLIL::SigBit>> lut_gates; + dict<RTLIL::SigBit, pool<RTLIL::SigBit>> lut_edges_fw, lut_edges_bw; + dict<RTLIL::SigBit, int> lut_depths, lut_altitudes, lut_slacks; + + int gate_count = 0, lut_count = 0, packed_count = 0; + int gate_area = 0, lut_area = 0; + + enum class GraphMode { + Label, + Cut, + Slack, + }; + + void dump_dot_graph(string filename, GraphMode mode, + pool<RTLIL::SigBit> subgraph_nodes = {}, dict<RTLIL::SigBit, pool<RTLIL::SigBit>> subgraph_edges = {}, + dict<RTLIL::SigBit, pool<RTLIL::SigBit>> collapsed = {}, + pair<pool<RTLIL::SigBit>, pool<RTLIL::SigBit>> cut = {}) + { + if (subgraph_nodes.empty()) + subgraph_nodes = nodes; + if (subgraph_edges.empty()) + subgraph_edges = edges_fw; + + auto node_style = [&](RTLIL::SigBit node) { + string label = log_signal(node); + for (auto collapsed_node : collapsed[node]) + if (collapsed_node != node) + label += stringf(" %s", log_signal(collapsed_node)); + switch (mode) + { + case GraphMode::Label: + if (labels[node] == -1) + { + label += "\nl=?"; + return GraphStyle{label}; + } + else + { + label += stringf("\nl=%d", labels[node]); + string fillcolor = stringf("/set311/%d", 1 + labels[node] % 11); + return GraphStyle{label, "", fillcolor}; + } + + case GraphMode::Cut: + if (cut.first[node]) + return GraphStyle{label, "blue"}; + if (cut.second[node]) + return GraphStyle{label, "red"}; + return GraphStyle{label}; + + case GraphMode::Slack: + label += stringf("\nd=%d a=%d\ns=%d", lut_depths[node], lut_altitudes[node], lut_slacks[node]); + return GraphStyle{label, lut_slacks[node] == 0 ? "red" : "black"}; + } + return GraphStyle{label}; + }; + auto edge_style = [&](RTLIL::SigBit, RTLIL::SigBit) { + return GraphStyle{}; + }; + ::dump_dot_graph(filename, subgraph_nodes, subgraph_edges, inputs, outputs, node_style, edge_style, module->name.str()); + } + + void dump_dot_lut_graph(string filename, GraphMode mode) + { + pool<RTLIL::SigBit> lut_and_input_nodes; + lut_and_input_nodes.insert(lut_nodes.begin(), lut_nodes.end()); + lut_and_input_nodes.insert(inputs.begin(), inputs.end()); + dump_dot_graph(filename, mode, lut_and_input_nodes, lut_edges_fw, lut_gates); + } + + pool<RTLIL::SigBit> find_subgraph(RTLIL::SigBit sink) + { + pool<RTLIL::SigBit> subgraph; + pool<RTLIL::SigBit> worklist = {sink}; + while (!worklist.empty()) + { + auto node = worklist.pop(); + subgraph.insert(node); + for (auto source : edges_bw[node]) + { + if (!subgraph[source]) + worklist.insert(source); + } + } + return subgraph; + } + + FlowGraph build_flow_graph(RTLIL::SigBit sink, int p) + { + FlowGraph flow_graph; + flow_graph.sink = sink; + + pool<RTLIL::SigBit> worklist = {sink}, visited; + while (!worklist.empty()) + { + auto node = worklist.pop(); + visited.insert(node); + + auto collapsed_node = labels[node] == p ? sink : node; + if (node != collapsed_node) + flow_graph.collapsed[collapsed_node].insert(node); + flow_graph.nodes.insert(collapsed_node); + + for (auto node_pred : edges_bw[node]) + { + auto collapsed_node_pred = labels[node_pred] == p ? sink : node_pred; + if (node_pred != collapsed_node_pred) + flow_graph.collapsed[collapsed_node_pred].insert(node_pred); + if (collapsed_node != collapsed_node_pred) + { + flow_graph.edges_bw[collapsed_node].insert(collapsed_node_pred); + flow_graph.edges_fw[collapsed_node_pred].insert(collapsed_node); + } + if (inputs[node_pred]) + { + flow_graph.edges_bw[collapsed_node_pred].insert(flow_graph.source); + flow_graph.edges_fw[flow_graph.source].insert(collapsed_node_pred); + } + + if (!visited[node_pred]) + worklist.insert(node_pred); + } + } + return flow_graph; + } + + void discover_nodes(pool<IdString> cell_types) + { + for (auto cell : module->selected_cells()) + { + if (!cell_types[cell->type]) + continue; + + if (!cell->known()) + log_error("Cell %s (%s.%s) is unknown.\n", cell->type.c_str(), log_id(module), log_id(cell)); + + pool<RTLIL::SigBit> fanout; + for (auto conn : cell->connections()) + { + if (!cell->output(conn.first)) continue; + int offset = -1; + for (auto bit : conn.second) + { + offset++; + if (!bit.wire) continue; + auto mapped_bit = sigmap(bit); + if (nodes[mapped_bit]) + log_error("Multiple drivers found for wire %s.\n", log_signal(mapped_bit)); + nodes.insert(mapped_bit); + node_origins[mapped_bit] = ModIndex::PortInfo(cell, conn.first, offset); + fanout.insert(mapped_bit); + } + } + + int fanin = 0; + for (auto conn : cell->connections()) + { + if (!cell->input(conn.first)) continue; + for (auto bit : sigmap(conn.second)) + { + if (!bit.wire) continue; + for (auto fanout_bit : fanout) + { + edges_fw[bit].insert(fanout_bit); + edges_bw[fanout_bit].insert(bit); + } + fanin++; + } + } + + if (fanin > order) + log_error("Cell %s (%s.%s) with fan-in %d cannot be mapped to a %d-LUT.\n", + cell->type.c_str(), log_id(module), log_id(cell), fanin, order); + + gate_count++; + gate_area += 1 << fanin; + } + + for (auto edge : edges_fw) + { + if (!nodes[edge.first]) + { + inputs.insert(edge.first); + nodes.insert(edge.first); + } + } + + for (auto node : nodes) + { + auto node_info = index.query(node); + if (node_info->is_output && !inputs[node]) + outputs.insert(node); + for (auto port : node_info->ports) + if (!cell_types[port.cell->type] && !inputs[node]) + outputs.insert(node); + } + + if (debug) + { + dump_dot_graph("flowmap-initial.dot", GraphMode::Label); + log("Dumped initial graph to `flowmap-initial.dot`.\n"); + } + } + + void label_nodes() + { + for (auto node : nodes) + labels[node] = -1; + for (auto input : inputs) + { + if (input.wire->attributes.count(ID($flowmap_level))) + labels[input] = input.wire->attributes[ID($flowmap_level)].as_int(); + else + labels[input] = 0; + } + + pool<RTLIL::SigBit> worklist = nodes; + int debug_num = 0; + while (!worklist.empty()) + { + auto sink = worklist.pop(); + if (labels[sink] != -1) + continue; + + bool inputs_have_labels = true; + for (auto sink_input : edges_bw[sink]) + { + if (labels[sink_input] == -1) + { + inputs_have_labels = false; + break; + } + } + if (!inputs_have_labels) + continue; + + if (debug) + { + debug_num++; + log("Examining subgraph %d rooted in %s.\n", debug_num, log_signal(sink)); + } + + pool<RTLIL::SigBit> subgraph = find_subgraph(sink); + + int p = 1; + for (auto subgraph_node : subgraph) + p = max(p, labels[subgraph_node]); + + FlowGraph flow_graph = build_flow_graph(sink, p); + int flow = flow_graph.maximum_flow(order); + pool<RTLIL::SigBit> x, xi; + if (flow <= order) + { + labels[sink] = p; + auto cut = flow_graph.edge_cut(); + x = cut.first; + xi = cut.second; + } + else + { + labels[sink] = p + 1; + x = subgraph; + x.erase(sink); + xi.insert(sink); + } + lut_gates[sink] = xi; + + pool<RTLIL::SigBit> k; + for (auto xi_node : xi) + { + for (auto xi_node_pred : edges_bw[xi_node]) + if (x[xi_node_pred]) + k.insert(xi_node_pred); + } + log_assert((int)k.size() <= order); + lut_edges_bw[sink] = k; + for (auto k_node : k) + lut_edges_fw[k_node].insert(sink); + + if (debug) + { + log(" Maximum flow: %d. Assigned label %d.\n", flow, labels[sink]); + dump_dot_graph(stringf("flowmap-%d-sub.dot", debug_num), GraphMode::Cut, subgraph, {}, {}, {x, xi}); + log(" Dumped subgraph to `flowmap-%d-sub.dot`.\n", debug_num); + flow_graph.dump_dot_graph(stringf("flowmap-%d-flow.dot", debug_num)); + log(" Dumped flow graph to `flowmap-%d-flow.dot`.\n", debug_num); + log(" LUT inputs:"); + for (auto k_node : k) + log(" %s", log_signal(k_node)); + log(".\n"); + log(" LUT packed gates:"); + for (auto xi_node : xi) + log(" %s", log_signal(xi_node)); + log(".\n"); + } + + for (auto sink_succ : edges_fw[sink]) + worklist.insert(sink_succ); + } + + if (debug) + { + dump_dot_graph("flowmap-labeled.dot", GraphMode::Label); + log("Dumped labeled graph to `flowmap-labeled.dot`.\n"); + } + } + + int map_luts() + { + pool<RTLIL::SigBit> worklist = outputs; + while (!worklist.empty()) + { + auto lut_node = worklist.pop(); + lut_nodes.insert(lut_node); + for (auto input_node : lut_edges_bw[lut_node]) + if (!lut_nodes[input_node] && !inputs[input_node]) + worklist.insert(input_node); + } + + int depth = 0; + for (auto label : labels) + depth = max(depth, label.second); + log("Mapped to %d LUTs with maximum depth %d.\n", GetSize(lut_nodes), depth); + + if (debug) + { + dump_dot_lut_graph("flowmap-mapped.dot", GraphMode::Label); + log("Dumped mapped graph to `flowmap-mapped.dot`.\n"); + } + + return depth; + } + + void realize_derealize_lut(RTLIL::SigBit lut, pool<RTLIL::SigBit> *changed = nullptr) + { + pool<RTLIL::SigBit> worklist = {lut}; + while (!worklist.empty()) + { + auto lut = worklist.pop(); + if (inputs[lut]) + continue; + + bool realized_successors = false; + for (auto lut_succ : lut_edges_fw[lut]) + if (lut_nodes[lut_succ]) + realized_successors = true; + + if (realized_successors && !lut_nodes[lut]) + lut_nodes.insert(lut); + else if (!realized_successors && lut_nodes[lut]) + lut_nodes.erase(lut); + else + continue; + + for (auto lut_pred : lut_edges_bw[lut]) + worklist.insert(lut_pred); + + if (changed) + changed->insert(lut); + } + } + + void add_lut_edge(RTLIL::SigBit pred, RTLIL::SigBit succ, pool<RTLIL::SigBit> *changed = nullptr) + { + log_assert(!lut_edges_fw[pred][succ] && !lut_edges_bw[succ][pred]); + log_assert((int)lut_edges_bw[succ].size() < order); + + lut_edges_fw[pred].insert(succ); + lut_edges_bw[succ].insert(pred); + realize_derealize_lut(pred, changed); + + if (changed) + { + changed->insert(pred); + changed->insert(succ); + } + } + + void remove_lut_edge(RTLIL::SigBit pred, RTLIL::SigBit succ, pool<RTLIL::SigBit> *changed = nullptr) + { + log_assert(lut_edges_fw[pred][succ] && lut_edges_bw[succ][pred]); + + lut_edges_fw[pred].erase(succ); + lut_edges_bw[succ].erase(pred); + realize_derealize_lut(pred, changed); + + if (changed) + { + if (lut_nodes[pred]) + changed->insert(pred); + changed->insert(succ); + } + } + + pair<pool<RTLIL::SigBit>, pool<RTLIL::SigBit>> cut_lut_at_gate(RTLIL::SigBit lut, RTLIL::SigBit lut_gate) + { + pool<RTLIL::SigBit> gate_inputs = lut_edges_bw[lut]; + pool<RTLIL::SigBit> other_inputs; + pool<RTLIL::SigBit> worklist = {lut}; + while (!worklist.empty()) + { + auto node = worklist.pop(); + for (auto node_pred : edges_bw[node]) + { + if (node_pred == lut_gate) + continue; + if (lut_gates[lut][node_pred]) + worklist.insert(node_pred); + else + { + gate_inputs.erase(node_pred); + other_inputs.insert(node_pred); + } + } + } + return {gate_inputs, other_inputs}; + } + + void compute_lut_distances(dict<RTLIL::SigBit, int> &lut_distances, bool forward, + pool<RTLIL::SigBit> initial = {}, pool<RTLIL::SigBit> *changed = nullptr) + { + pool<RTLIL::SigBit> terminals = forward ? inputs : outputs; + auto &lut_edges_next = forward ? lut_edges_fw : lut_edges_bw; + auto &lut_edges_prev = forward ? lut_edges_bw : lut_edges_fw; + + if (initial.empty()) + initial = terminals; + for (auto node : initial) + lut_distances.erase(node); + + pool<RTLIL::SigBit> worklist = initial; + while (!worklist.empty()) + { + auto lut = worklist.pop(); + int lut_distance = 0; + if (forward && inputs[lut]) + lut_distance = labels[lut]; // to support (* $flowmap_level=n *) + for (auto lut_prev : lut_edges_prev[lut]) + if ((lut_nodes[lut_prev] || inputs[lut_prev]) && lut_distances.count(lut_prev)) + lut_distance = max(lut_distance, lut_distances[lut_prev] + 1); + if (!lut_distances.count(lut) || lut_distances[lut] != lut_distance) + { + lut_distances[lut] = lut_distance; + if (changed != nullptr && !inputs[lut]) + changed->insert(lut); + for (auto lut_next : lut_edges_next[lut]) + if (lut_nodes[lut_next] || inputs[lut_next]) + worklist.insert(lut_next); + } + } + } + + void check_lut_distances(const dict<RTLIL::SigBit, int> &lut_distances, bool forward) + { + dict<RTLIL::SigBit, int> gold_lut_distances; + compute_lut_distances(gold_lut_distances, forward); + for (auto lut_distance : lut_distances) + if (lut_nodes[lut_distance.first]) + log_assert(lut_distance.second == gold_lut_distances[lut_distance.first]); + } + + // LUT depth is the length of the longest path from any input in LUT fan-in to LUT. + // LUT altitude (for lack of a better term) is the length of the longest path from LUT to any output in LUT fan-out. + void update_lut_depths_altitudes(pool<RTLIL::SigBit> worklist = {}, pool<RTLIL::SigBit> *changed = nullptr) + { + compute_lut_distances(lut_depths, /*forward=*/true, worklist, changed); + compute_lut_distances(lut_altitudes, /*forward=*/false, worklist, changed); + if (debug_relax && !worklist.empty()) { + check_lut_distances(lut_depths, /*forward=*/true); + check_lut_distances(lut_altitudes, /*forward=*/false); + } + } + + // LUT critical output set is the set of outputs whose depth will increase (equivalently, slack will decrease) if the depth of + // the LUT increases. (This is referred to as RPOv for LUTv in the paper.) + void compute_lut_critical_outputs(dict<RTLIL::SigBit, pool<RTLIL::SigBit>> &lut_critical_outputs, + pool<RTLIL::SigBit> worklist = {}) + { + if (worklist.empty()) + worklist = lut_nodes; + + while (!worklist.empty()) + { + bool updated_some = false; + for (auto lut : worklist) + { + if (outputs[lut]) + lut_critical_outputs[lut] = {lut}; + else + { + bool all_succ_computed = true; + lut_critical_outputs[lut] = {}; + for (auto lut_succ : lut_edges_fw[lut]) + { + if (lut_nodes[lut_succ] && lut_depths[lut_succ] == lut_depths[lut] + 1) + { + if (lut_critical_outputs.count(lut_succ)) + lut_critical_outputs[lut].insert(lut_critical_outputs[lut_succ].begin(), lut_critical_outputs[lut_succ].end()); + else + { + all_succ_computed = false; + break; + } + } + } + if (!all_succ_computed) + { + lut_critical_outputs.erase(lut); + continue; + } + } + worklist.erase(lut); + updated_some = true; + } + log_assert(updated_some); + } + } + + // Invalidating LUT critical output sets is tricky, because increasing the depth of a LUT may take other, adjacent LUTs off the critical + // path to the output. Conservatively, if we increase depth of some LUT, every LUT in its input cone needs to have its critical output + // set invalidated, too. + pool<RTLIL::SigBit> invalidate_lut_critical_outputs(dict<RTLIL::SigBit, pool<RTLIL::SigBit>> &lut_critical_outputs, + pool<RTLIL::SigBit> worklist) + { + pool<RTLIL::SigBit> changed; + while (!worklist.empty()) + { + auto lut = worklist.pop(); + changed.insert(lut); + lut_critical_outputs.erase(lut); + for (auto lut_pred : lut_edges_bw[lut]) + { + if (lut_nodes[lut_pred] && !changed[lut_pred]) + { + changed.insert(lut_pred); + worklist.insert(lut_pred); + } + } + } + return changed; + } + + void check_lut_critical_outputs(const dict<RTLIL::SigBit, pool<RTLIL::SigBit>> &lut_critical_outputs) + { + dict<RTLIL::SigBit, pool<RTLIL::SigBit>> gold_lut_critical_outputs; + compute_lut_critical_outputs(gold_lut_critical_outputs); + for (auto lut_critical_output : lut_critical_outputs) + if (lut_nodes[lut_critical_output.first]) + log_assert(lut_critical_output.second == gold_lut_critical_outputs[lut_critical_output.first]); + } + + void update_lut_critical_outputs(dict<RTLIL::SigBit, pool<RTLIL::SigBit>> &lut_critical_outputs, + pool<RTLIL::SigBit> worklist = {}) + { + if (!worklist.empty()) + { + pool<RTLIL::SigBit> invalidated = invalidate_lut_critical_outputs(lut_critical_outputs, worklist); + compute_lut_critical_outputs(lut_critical_outputs, invalidated); + check_lut_critical_outputs(lut_critical_outputs); + } + else + compute_lut_critical_outputs(lut_critical_outputs); + } + + void update_breaking_node_potentials(dict<RTLIL::SigBit, dict<RTLIL::SigBit, int>> &potentials, + const dict<RTLIL::SigBit, pool<RTLIL::SigBit>> &lut_critical_outputs) + { + for (auto lut : lut_nodes) + { + if (potentials.count(lut)) + continue; + if (lut_gates[lut].size() == 1 || lut_slacks[lut] == 0) + continue; + + if (debug_relax) + log(" Computing potentials for LUT %s.\n", log_signal(lut)); + + for (auto lut_gate : lut_gates[lut]) + { + if (lut == lut_gate) + continue; + + if (debug_relax) + log(" Considering breaking node %s.\n", log_signal(lut_gate)); + + int r_ex, r_im, r_slk; + + auto cut_inputs = cut_lut_at_gate(lut, lut_gate); + pool<RTLIL::SigBit> gate_inputs = cut_inputs.first, other_inputs = cut_inputs.second; + if (gate_inputs.empty() && (int)other_inputs.size() == order) + { + if (debug_relax) + log(" Breaking would result in a (k+1)-LUT.\n"); + continue; + } + + pool<RTLIL::SigBit> elim_fanin_luts; + for (auto gate_input : gate_inputs) + { + if (lut_edges_fw[gate_input].size() == 1) + { + log_assert(lut_edges_fw[gate_input][lut]); + elim_fanin_luts.insert(gate_input); + } + } + if (debug_relax) + { + if (!lut_nodes[lut_gate]) + log(" Breaking requires a new LUT.\n"); + if (!gate_inputs.empty()) + { + log(" Breaking eliminates LUT inputs"); + for (auto gate_input : gate_inputs) + log(" %s", log_signal(gate_input)); + log(".\n"); + } + if (!elim_fanin_luts.empty()) + { + log(" Breaking eliminates fan-in LUTs"); + for (auto elim_fanin_lut : elim_fanin_luts) + log(" %s", log_signal(elim_fanin_lut)); + log(".\n"); + } + } + r_ex = (lut_nodes[lut_gate] ? 0 : -1) + elim_fanin_luts.size(); + + pool<pair<RTLIL::SigBit, RTLIL::SigBit>> maybe_mergeable_luts; + + // Try to merge LUTv with one of its successors. + RTLIL::SigBit last_lut_succ; + int fanout = 0; + for (auto lut_succ : lut_edges_fw[lut]) + { + if (lut_nodes[lut_succ]) + { + fanout++; + last_lut_succ = lut_succ; + } + } + if (fanout == 1) + maybe_mergeable_luts.insert({lut, last_lut_succ}); + + // Try to merge LUTv with one of its predecessors. + for (auto lut_pred : other_inputs) + { + int fanout = 0; + for (auto lut_pred_succ : lut_edges_fw[lut_pred]) + if (lut_nodes[lut_pred_succ] || lut_pred_succ == lut_gate) + fanout++; + if (fanout == 1) + maybe_mergeable_luts.insert({lut_pred, lut}); + } + + // Try to merge LUTw with one of its predecessors. + for (auto lut_gate_pred : lut_edges_bw[lut_gate]) + { + int fanout = 0; + for (auto lut_gate_pred_succ : lut_edges_fw[lut_gate_pred]) + if (lut_nodes[lut_gate_pred_succ] || lut_gate_pred_succ == lut_gate) + fanout++; + if (fanout == 1) + maybe_mergeable_luts.insert({lut_gate_pred, lut_gate}); + } + + r_im = 0; + for (auto maybe_mergeable_pair : maybe_mergeable_luts) + { + log_assert(lut_edges_fw[maybe_mergeable_pair.first][maybe_mergeable_pair.second]); + pool<RTLIL::SigBit> unique_inputs; + for (auto fst_lut_pred : lut_edges_bw[maybe_mergeable_pair.first]) + if (lut_nodes[fst_lut_pred]) + unique_inputs.insert(fst_lut_pred); + for (auto snd_lut_pred : lut_edges_bw[maybe_mergeable_pair.second]) + if (lut_nodes[snd_lut_pred]) + unique_inputs.insert(snd_lut_pred); + unique_inputs.erase(maybe_mergeable_pair.first); + if ((int)unique_inputs.size() <= order) + { + if (debug_relax) + log(" Breaking may allow merging %s and %s.\n", + log_signal(maybe_mergeable_pair.first), log_signal(maybe_mergeable_pair.second)); + r_im++; + } + } + + int lut_gate_depth; + if (lut_nodes[lut_gate]) + lut_gate_depth = lut_depths[lut_gate]; + else + { + lut_gate_depth = 0; + for (auto lut_gate_pred : lut_edges_bw[lut_gate]) + lut_gate_depth = max(lut_gate_depth, lut_depths[lut_gate_pred] + 1); + } + if (lut_depths[lut] >= lut_gate_depth + 1) + r_slk = 0; + else + { + int depth_delta = lut_gate_depth + 1 - lut_depths[lut]; + if (depth_delta > lut_slacks[lut]) + { + if (debug_relax) + log(" Breaking would increase depth by %d, which is more than available slack.\n", depth_delta); + continue; + } + + if (debug_relax) + { + log(" Breaking increases depth of LUT by %d.\n", depth_delta); + if (lut_critical_outputs.at(lut).size()) + { + log(" Breaking decreases slack of outputs"); + for (auto lut_critical_output : lut_critical_outputs.at(lut)) + { + log(" %s", log_signal(lut_critical_output)); + log_assert(lut_slacks[lut_critical_output] > 0); + } + log(".\n"); + } + } + r_slk = lut_critical_outputs.at(lut).size() * depth_delta; + } + + int p = 100 * (r_alpha * r_ex + r_beta * r_im + r_gamma) / (r_slk + 1); + if (debug_relax) + log(" Potential for breaking node %s: %d (Rex=%d, Rim=%d, Rslk=%d).\n", + log_signal(lut_gate), p, r_ex, r_im, r_slk); + potentials[lut][lut_gate] = p; + } + } + } + + bool relax_depth_for_bound(bool first, int depth_bound, dict<RTLIL::SigBit, pool<RTLIL::SigBit>> &lut_critical_outputs) + { + int initial_count = GetSize(lut_nodes); + + for (auto node : lut_nodes) + { + lut_slacks[node] = depth_bound - (lut_depths[node] + lut_altitudes[node]); + log_assert(lut_slacks[node] >= 0); + } + if (debug) + { + dump_dot_lut_graph(stringf("flowmap-relax-%d-initial.dot", depth_bound), GraphMode::Slack); + log(" Dumped initial slack graph to `flowmap-relax-%d-initial.dot`.\n", depth_bound); + } + + dict<RTLIL::SigBit, dict<RTLIL::SigBit, int>> potentials; + for (int break_num = 1; ; break_num++) + { + update_breaking_node_potentials(potentials, lut_critical_outputs); + + if (potentials.empty()) + { + 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"); + return true; + } + else + { + log(" Slack exhausted.\n"); + break; + } + } + + RTLIL::SigBit breaking_lut, breaking_gate; + int best_potential = INT_MIN; + for (auto lut_gate_potentials : potentials) + { + for (auto gate_potential : lut_gate_potentials.second) + { + if (gate_potential.second > best_potential) + { + breaking_lut = lut_gate_potentials.first; + breaking_gate = gate_potential.first; + best_potential = gate_potential.second; + } + } + } + log(" Breaking LUT %s to %s LUT %s (potential %d).\n", + log_signal(breaking_lut), lut_nodes[breaking_gate] ? "reuse" : "extract", log_signal(breaking_gate), best_potential); + + if (debug_relax) + log(" Removing breaking gate %s from LUT.\n", log_signal(breaking_gate)); + lut_gates[breaking_lut].erase(breaking_gate); + + auto cut_inputs = cut_lut_at_gate(breaking_lut, breaking_gate); + pool<RTLIL::SigBit> gate_inputs = cut_inputs.first, other_inputs = cut_inputs.second; + + pool<RTLIL::SigBit> worklist = lut_gates[breaking_lut]; + pool<RTLIL::SigBit> elim_gates = gate_inputs; + while (!worklist.empty()) + { + auto lut_gate = worklist.pop(); + bool all_gate_preds_elim = true; + for (auto lut_gate_pred : edges_bw[lut_gate]) + if (!elim_gates[lut_gate_pred]) + all_gate_preds_elim = false; + if (all_gate_preds_elim) + { + if (debug_relax) + log(" Removing gate %s from LUT.\n", log_signal(lut_gate)); + lut_gates[breaking_lut].erase(lut_gate); + for (auto lut_gate_succ : edges_fw[lut_gate]) + worklist.insert(lut_gate_succ); + } + } + log_assert(!lut_gates[breaking_lut].empty()); + + pool<RTLIL::SigBit> directly_affected_nodes = {breaking_lut}; + for (auto gate_input : gate_inputs) + { + if (debug_relax) + log(" Removing LUT edge %s -> %s.\n", log_signal(gate_input), log_signal(breaking_lut)); + remove_lut_edge(gate_input, breaking_lut, &directly_affected_nodes); + } + if (debug_relax) + log(" Adding LUT edge %s -> %s.\n", log_signal(breaking_gate), log_signal(breaking_lut)); + add_lut_edge(breaking_gate, breaking_lut, &directly_affected_nodes); + + if (debug_relax) + log(" Updating slack and potentials.\n"); + + pool<RTLIL::SigBit> indirectly_affected_nodes = {}; + update_lut_depths_altitudes(directly_affected_nodes, &indirectly_affected_nodes); + update_lut_critical_outputs(lut_critical_outputs, indirectly_affected_nodes); + for (auto node : indirectly_affected_nodes) + { + lut_slacks[node] = depth_bound - (lut_depths[node] + lut_altitudes[node]); + log_assert(lut_slacks[node] >= 0); + if (debug_relax) + log(" LUT %s now has depth %d and slack %d.\n", log_signal(node), lut_depths[node], lut_slacks[node]); + } + + worklist = indirectly_affected_nodes; + pool<RTLIL::SigBit> visited; + while (!worklist.empty()) + { + auto node = worklist.pop(); + visited.insert(node); + potentials.erase(node); + // We are invalidating the entire output cone of the gate IR node, not just of the LUT IR node. This is done to also invalidate + // all LUTs that could contain one of the indirectly affected nodes as a *part* of them, as they may not be in the output cone + // of any of the LUT IR nodes, e.g. if we have a LUT IR node A and node B as predecessors of node C, where node B includes all + // gates from node A. + for (auto node_succ : edges_fw[node]) + if (!visited[node_succ]) + worklist.insert(node_succ); + } + + if (debug) + { + dump_dot_lut_graph(stringf("flowmap-relax-%d-break-%d.dot", depth_bound, break_num), GraphMode::Slack); + log(" Dumped slack graph after break %d to `flowmap-relax-%d-break-%d.dot`.\n", break_num, depth_bound, break_num); + } + } + + return false; + } + + void optimize_area(int depth, int optarea) + { + dict<RTLIL::SigBit, pool<RTLIL::SigBit>> lut_critical_outputs; + update_lut_depths_altitudes(); + update_lut_critical_outputs(lut_critical_outputs); + + for (int depth_bound = depth; depth_bound <= depth + optarea; depth_bound++) + { + log("Relaxing with depth bound %d.\n", depth_bound); + bool fully_relaxed = relax_depth_for_bound(depth_bound == depth, depth_bound, lut_critical_outputs); + + if (fully_relaxed) + break; + } + } + + void pack_cells(int minlut) + { + ConstEval ce(module); + for (auto input_node : inputs) + ce.stop(input_node); + + pool<RTLIL::SigBit> mapped_nodes; + for (auto node : lut_nodes) + { + if (node_origins.count(node)) + { + auto origin = node_origins[node]; + if (origin.cell->getPort(origin.port).size() == 1) + log("Packing %s.%s.%s (%s).\n", + log_id(module), log_id(origin.cell), origin.port.c_str(), log_signal(node)); + else + log("Packing %s.%s.%s [%d] (%s).\n", + log_id(module), log_id(origin.cell), origin.port.c_str(), origin.offset, log_signal(node)); + } + else + { + log("Packing %s.%s.\n", log_id(module), log_signal(node)); + } + + for (auto gate_node : lut_gates[node]) + { + log_assert(node_origins.count(gate_node)); + + if (gate_node == node) + continue; + + auto gate_origin = node_origins[gate_node]; + if (gate_origin.cell->getPort(gate_origin.port).size() == 1) + log(" Packing %s.%s.%s (%s).\n", + log_id(module), log_id(gate_origin.cell), gate_origin.port.c_str(), log_signal(gate_node)); + else + log(" Packing %s.%s.%s [%d] (%s).\n", + log_id(module), log_id(gate_origin.cell), gate_origin.port.c_str(), gate_origin.offset, log_signal(gate_node)); + } + + vector<RTLIL::SigBit> input_nodes(lut_edges_bw[node].begin(), lut_edges_bw[node].end()); + RTLIL::Const lut_table(State::Sx, max(1 << input_nodes.size(), 1 << minlut)); + unsigned const mask = 1 << input_nodes.size(); + for (unsigned i = 0; i < mask; i++) + { + ce.push(); + for (size_t n = 0; n < input_nodes.size(); n++) + ce.set(input_nodes[n], ((i >> n) & 1) ? State::S1 : State::S0); + + RTLIL::SigSpec value = node, undef; + if (!ce.eval(value, undef)) + { + string env; + for (auto input_node : input_nodes) + env += stringf(" %s = %s\n", log_signal(input_node), log_signal(ce.values_map(input_node))); + log_error("Cannot evaluate %s because %s is not defined.\nEvaluation environment:\n%s", + log_signal(node), log_signal(undef), env.c_str()); + } + + lut_table[i] = value.as_bool() ? State::S1 : State::S0; + ce.pop(); + } + + RTLIL::SigSpec lut_a, lut_y = node; + for (auto input_node : input_nodes) + lut_a.append_bit(input_node); + lut_a.append(RTLIL::Const(State::Sx, minlut - input_nodes.size())); + + RTLIL::Cell *lut = module->addLut(NEW_ID, lut_a, lut_y, lut_table); + mapped_nodes.insert(node); + for (auto gate_node : lut_gates[node]) + { + auto gate_origin = node_origins[gate_node]; + lut->add_strpool_attribute(ID(src), gate_origin.cell->get_strpool_attribute(ID(src))); + packed_count++; + } + lut_count++; + lut_area += lut_table.size(); + + if ((int)input_nodes.size() >= minlut) + log(" Packed into a %d-LUT %s.%s.\n", GetSize(input_nodes), log_id(module), log_id(lut)); + else + 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) + { + auto origin = node_origins[node]; + RTLIL::SigSpec driver = origin.cell->getPort(origin.port); + driver[origin.offset] = module->addWire(NEW_ID); + origin.cell->setPort(origin.port, driver); + } + } + + FlowmapWorker(int order, int minlut, pool<IdString> cell_types, int r_alpha, int r_beta, int r_gamma, + bool relax, int optarea, bool debug, bool debug_relax, + RTLIL::Module *module) : + order(order), r_alpha(r_alpha), r_beta(r_beta), r_gamma(r_gamma), debug(debug), debug_relax(debug_relax), + module(module), sigmap(module), index(module) + { + log("Labeling cells.\n"); + discover_nodes(cell_types); + label_nodes(); + int depth = map_luts(); + + if (relax) + { + log("\n"); + log("Optimizing area.\n"); + optimize_area(depth, optarea); + } + + log("\n"); + log("Packing cells.\n"); + pack_cells(minlut); + } +}; + +static void split(std::vector<std::string> &tokens, const std::string &text, char sep) +{ + size_t start = 0, end = 0; + while ((end = text.find(sep, start)) != std::string::npos) { + tokens.push_back(text.substr(start, end - start)); + start = end + 1; + } + tokens.push_back(text.substr(start)); +} + +struct FlowmapPass : public Pass { + FlowmapPass() : Pass("flowmap", "pack LUTs with FlowMap") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" flowmap [options] [selection]\n"); + log("\n"); + log("This pass uses the FlowMap technology mapping algorithm to pack logic gates\n"); + log("into k-LUTs with optimal depth. It allows mapping any circuit elements that can\n"); + log("be evaluated with the `eval` pass, including cells with multiple output ports\n"); + log("and multi-bit input and output ports.\n"); + log("\n"); + log(" -maxlut k\n"); + log(" perform technology mapping for a k-LUT architecture. if not specified,\n"); + log(" defaults to 3.\n"); + log("\n"); + log(" -minlut n\n"); + log(" only produce n-input or larger LUTs. if not specified, defaults to 1.\n"); + log("\n"); + log(" -cells <cell>[,<cell>,...]\n"); + log(" map specified cells. if not specified, maps $_NOT_, $_AND_, $_OR_,\n"); + log(" $_XOR_ and $_MUX_, which are the outputs of the `simplemap` pass.\n"); + log("\n"); + log(" -relax\n"); + log(" perform depth relaxation and area minimization.\n"); + log("\n"); + log(" -r-alpha n, -r-beta n, -r-gamma n\n"); + log(" parameters of depth relaxation heuristic potential function.\n"); + log(" if not specified, alpha=8, beta=2, gamma=1.\n"); + log("\n"); + log(" -optarea n\n"); + log(" optimize for area by trading off at most n logic levels for fewer LUTs.\n"); + log(" n may be zero, to optimize for area without increasing depth.\n"); + log(" implies -relax.\n"); + log("\n"); + log(" -debug\n"); + log(" dump intermediate graphs.\n"); + log("\n"); + log(" -debug-relax\n"); + log(" explain decisions performed during depth relaxation.\n"); + log("\n"); + } + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + int order = 3; + int minlut = 1; + vector<string> cells; + bool relax = false; + int r_alpha = 8, r_beta = 2, r_gamma = 1; + int optarea = 0; + bool debug = false, debug_relax = false; + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + if (args[argidx] == "-maxlut" && argidx + 1 < args.size()) + { + order = atoi(args[++argidx].c_str()); + continue; + } + if (args[argidx] == "-minlut" && argidx + 1 < args.size()) + { + minlut = atoi(args[++argidx].c_str()); + continue; + } + if (args[argidx] == "-cells" && argidx + 1 < args.size()) + { + split(cells, args[++argidx], ','); + continue; + } + if (args[argidx] == "-relax") + { + relax = true; + continue; + } + if (args[argidx] == "-r-alpha" && argidx + 1 < args.size()) + { + r_alpha = atoi(args[++argidx].c_str()); + continue; + } + if (args[argidx] == "-r-beta" && argidx + 1 < args.size()) + { + r_beta = atoi(args[++argidx].c_str()); + continue; + } + if (args[argidx] == "-r-gamma" && argidx + 1 < args.size()) + { + r_gamma = atoi(args[++argidx].c_str()); + continue; + } + if (args[argidx] == "-optarea" && argidx + 1 < args.size()) + { + relax = true; + optarea = atoi(args[++argidx].c_str()); + continue; + } + if (args[argidx] == "-debug") + { + debug = true; + continue; + } + if (args[argidx] == "-debug-relax") + { + debug = debug_relax = true; + continue; + } + break; + } + extra_args(args, argidx, design); + + pool<IdString> cell_types; + if (!cells.empty()) + { + for (auto &cell : cells) + cell_types.insert(cell); + } + else + { + cell_types = {ID($_NOT_), ID($_AND_), ID($_OR_), ID($_XOR_), ID($_MUX_)}; + } + + const char *algo_r = relax ? "-r" : ""; + log_header(design, "Executing FLOWMAP pass (pack LUTs with FlowMap%s).\n", algo_r); + + int gate_count = 0, lut_count = 0, packed_count = 0; + int gate_area = 0, lut_area = 0; + for (auto module : design->selected_modules()) + { + FlowmapWorker worker(order, minlut, cell_types, r_alpha, r_beta, r_gamma, relax, optarea, debug, debug_relax, module); + gate_count += worker.gate_count; + lut_count += worker.lut_count; + packed_count += worker.packed_count; + gate_area += worker.gate_area; + lut_area += worker.lut_area; + } + + log("\n"); + log("Packed %d cells (%d of them duplicated) into %d LUTs.\n", packed_count, packed_count - gate_count, lut_count); + log("Solution takes %.1f%% of original gate area.\n", lut_area * 100.0 / gate_area); + } +} FlowmapPass; + +PRIVATE_NAMESPACE_END diff --git a/passes/techmap/hilomap.cc b/passes/techmap/hilomap.cc index 82cecac26..9ec651aef 100644 --- a/passes/techmap/hilomap.cc +++ b/passes/techmap/hilomap.cc @@ -55,7 +55,7 @@ void hilomap_worker(RTLIL::SigSpec &sig) struct HilomapPass : public Pass { HilomapPass() : Pass("hilomap", "technology mapping of constant hi- and/or lo-drivers") { } - virtual void help() + void help() YS_OVERRIDE { log("\n"); log(" hilomap [options] [selection]\n"); @@ -74,7 +74,7 @@ struct HilomapPass : public Pass { log(" each constant bit.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing HILOMAP pass (mapping to constant drivers).\n"); diff --git a/passes/techmap/insbuf.cc b/passes/techmap/insbuf.cc index aa81468dc..2173049b4 100644 --- a/passes/techmap/insbuf.cc +++ b/passes/techmap/insbuf.cc @@ -25,7 +25,7 @@ PRIVATE_NAMESPACE_BEGIN struct InsbufPass : public Pass { InsbufPass() : Pass("insbuf", "insert buffer cells for connected wires") { } - virtual void help() + void help() YS_OVERRIDE { log("\n"); log(" insbuf [options] [selection]\n"); @@ -37,7 +37,7 @@ struct InsbufPass : public Pass { log(" call to \"clean\" will remove all $_BUF_ in the design.)\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing INSBUF pass (insert buffer cells for connected wires).\n"); diff --git a/passes/techmap/iopadmap.cc b/passes/techmap/iopadmap.cc index 690ba87ed..c868b9a87 100644 --- a/passes/techmap/iopadmap.cc +++ b/passes/techmap/iopadmap.cc @@ -34,7 +34,7 @@ void split_portname_pair(std::string &port1, std::string &port2) struct IopadmapPass : public Pass { IopadmapPass() : Pass("iopadmap", "technology mapping of i/o pads (or buffers)") { } - virtual void help() + void help() YS_OVERRIDE { log("\n"); log(" iopadmap [options] [selection]\n"); @@ -64,6 +64,11 @@ struct IopadmapPass : public Pass { log(" of the tristate driver and the 2nd portname is the internal output\n"); log(" buffering the external signal.\n"); log("\n"); + log(" -ignore <celltype> <portname>[:<portname>]*\n"); + log(" Skips mapping inputs/outputs that are already connected to given\n"); + log(" ports of the given cell. Can be used multiple times. This is in\n"); + log(" addition to the cells specified as mapping targets.\n"); + log("\n"); log(" -widthparam <param_name>\n"); log(" Use the specified parameter name to set the port width.\n"); log("\n"); @@ -78,7 +83,7 @@ struct IopadmapPass : public Pass { log("Tristate PADS (-toutpad, -tinoutpad) always operate in -bits mode.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing IOPADMAP pass (mapping inputs/outputs to IO-PAD cells).\n"); @@ -88,6 +93,7 @@ struct IopadmapPass : public Pass { std::string toutpad_celltype, toutpad_portname, toutpad_portname2, toutpad_portname3; std::string tinoutpad_celltype, tinoutpad_portname, tinoutpad_portname2, tinoutpad_portname3, tinoutpad_portname4; std::string widthparam, nameparam; + pool<pair<IdString, IdString>> ignore; bool flag_bits = false; size_t argidx; @@ -127,6 +133,18 @@ struct IopadmapPass : public Pass { split_portname_pair(tinoutpad_portname3, tinoutpad_portname4); continue; } + if (arg == "-ignore" && argidx+2 < args.size()) { + std::string ignore_celltype = args[++argidx]; + std::string ignore_portname = args[++argidx]; + std::string ignore_portname2; + while (!ignore_portname.empty()) { + split_portname_pair(ignore_portname, ignore_portname2); + ignore.insert(make_pair(RTLIL::escape_id(ignore_celltype), RTLIL::escape_id(ignore_portname))); + + ignore_portname = ignore_portname2; + } + continue; + } if (arg == "-widthparam" && argidx+1 < args.size()) { widthparam = args[++argidx]; continue; @@ -143,6 +161,23 @@ struct IopadmapPass : public Pass { } extra_args(args, argidx, design); + if (!inpad_portname2.empty()) + ignore.insert(make_pair(RTLIL::escape_id(inpad_celltype), RTLIL::escape_id(inpad_portname2))); + if (!outpad_portname2.empty()) + ignore.insert(make_pair(RTLIL::escape_id(outpad_celltype), RTLIL::escape_id(outpad_portname2))); + if (!inoutpad_portname2.empty()) + ignore.insert(make_pair(RTLIL::escape_id(inoutpad_celltype), RTLIL::escape_id(inoutpad_portname2))); + if (!toutpad_portname3.empty()) + ignore.insert(make_pair(RTLIL::escape_id(toutpad_celltype), RTLIL::escape_id(toutpad_portname3))); + if (!tinoutpad_portname4.empty()) + ignore.insert(make_pair(RTLIL::escape_id(tinoutpad_celltype), RTLIL::escape_id(tinoutpad_portname4))); + + for (auto module : design->modules()) + if (module->get_blackbox_attribute()) + for (auto wire : module->wires()) + if (wire->get_bool_attribute("\\iopad_external_pin")) + ignore.insert(make_pair(module->name, wire->name)); + for (auto module : design->selected_modules()) { dict<IdString, pool<int>> skip_wires; @@ -150,28 +185,11 @@ struct IopadmapPass : public Pass { SigMap sigmap(module); for (auto cell : module->cells()) - { - if (cell->type == RTLIL::escape_id(inpad_celltype) && cell->hasPort(RTLIL::escape_id(inpad_portname2))) - for (auto bit : sigmap(cell->getPort(RTLIL::escape_id(inpad_portname2)))) - skip_wire_bits.insert(bit); - - if (cell->type == RTLIL::escape_id(outpad_celltype) && cell->hasPort(RTLIL::escape_id(outpad_portname2))) - for (auto bit : sigmap(cell->getPort(RTLIL::escape_id(outpad_portname2)))) + for (auto port : cell->connections()) + if (ignore.count(make_pair(cell->type, port.first))) + for (auto bit : sigmap(port.second)) skip_wire_bits.insert(bit); - if (cell->type == RTLIL::escape_id(inoutpad_celltype) && cell->hasPort(RTLIL::escape_id(inoutpad_portname2))) - for (auto bit : sigmap(cell->getPort(RTLIL::escape_id(inoutpad_portname2)))) - skip_wire_bits.insert(bit); - - if (cell->type == RTLIL::escape_id(toutpad_celltype) && cell->hasPort(RTLIL::escape_id(toutpad_portname3))) - for (auto bit : sigmap(cell->getPort(RTLIL::escape_id(toutpad_portname3)))) - skip_wire_bits.insert(bit); - - if (cell->type == RTLIL::escape_id(tinoutpad_celltype) && cell->hasPort(RTLIL::escape_id(tinoutpad_portname4))) - for (auto bit : sigmap(cell->getPort(RTLIL::escape_id(tinoutpad_portname4)))) - skip_wire_bits.insert(bit); - } - if (!toutpad_celltype.empty() || !tinoutpad_celltype.empty()) { dict<SigBit, pair<IdString, pool<IdString>>> tbuf_bits; @@ -179,8 +197,8 @@ struct IopadmapPass : public Pass { SigMap rewrites; for (auto cell : module->cells()) - if (cell->type == "$_TBUF_") { - SigBit bit = sigmap(cell->getPort("\\Y").as_bit()); + if (cell->type == ID($_TBUF_)) { + SigBit bit = sigmap(cell->getPort(ID::Y).as_bit()); tbuf_bits[bit].first = cell->name; } @@ -212,8 +230,8 @@ struct IopadmapPass : public Pass { if (tbuf_cell == nullptr) continue; - SigBit en_sig = tbuf_cell->getPort("\\E").as_bit(); - SigBit data_sig = tbuf_cell->getPort("\\A").as_bit(); + SigBit en_sig = tbuf_cell->getPort(ID(E)).as_bit(); + SigBit data_sig = tbuf_cell->getPort(ID::A).as_bit(); if (wire->port_input && !tinoutpad_celltype.empty()) { @@ -226,7 +244,7 @@ struct IopadmapPass : public Pass { cell->setPort(RTLIL::escape_id(tinoutpad_portname2), owire); cell->setPort(RTLIL::escape_id(tinoutpad_portname3), data_sig); cell->setPort(RTLIL::escape_id(tinoutpad_portname4), wire_bit); - cell->attributes["\\keep"] = RTLIL::Const(1); + cell->attributes[ID::keep] = RTLIL::Const(1); for (auto cn : tbuf_cache.second) { auto c = module->cell(cn); @@ -263,7 +281,7 @@ struct IopadmapPass : public Pass { cell->setPort(RTLIL::escape_id(toutpad_portname), en_sig); cell->setPort(RTLIL::escape_id(toutpad_portname2), data_sig); cell->setPort(RTLIL::escape_id(toutpad_portname3), wire_bit); - cell->attributes["\\keep"] = RTLIL::Const(1); + cell->attributes[ID::keep] = RTLIL::Const(1); for (auto cn : tbuf_cache.second) { auto c = module->cell(cn); @@ -390,7 +408,7 @@ struct IopadmapPass : public Pass { cell->parameters[RTLIL::escape_id(widthparam)] = RTLIL::Const(1); if (!nameparam.empty()) cell->parameters[RTLIL::escape_id(nameparam)] = RTLIL::Const(stringf("%s[%d]", RTLIL::id2cstr(wire->name), i)); - cell->attributes["\\keep"] = RTLIL::Const(1); + cell->attributes[ID::keep] = RTLIL::Const(1); } } else @@ -403,7 +421,7 @@ struct IopadmapPass : public Pass { cell->parameters[RTLIL::escape_id(widthparam)] = RTLIL::Const(wire->width); if (!nameparam.empty()) cell->parameters[RTLIL::escape_id(nameparam)] = RTLIL::Const(RTLIL::id2cstr(wire->name)); - cell->attributes["\\keep"] = RTLIL::Const(1); + cell->attributes[ID::keep] = RTLIL::Const(1); } wire->port_id = 0; diff --git a/passes/techmap/libparse.cc b/passes/techmap/libparse.cc index d3b1ff02f..349ccc115 100644 --- a/passes/techmap/libparse.cc +++ b/passes/techmap/libparse.cc @@ -24,6 +24,7 @@ #include <istream> #include <fstream> #include <iostream> +#include <sstream> #ifndef FILTERLIB #include "kernel/log.h" @@ -86,12 +87,14 @@ int LibertyParser::lexer(std::string &str) { int c; + // eat whitespace do { c = f.get(); } while (c == ' ' || c == '\t' || c == '\r'); + // search for identifiers, numbers, plus or minus. if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.') { - str = c; + str = static_cast<char>(c); while (1) { c = f.get(); if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.') @@ -111,6 +114,8 @@ int LibertyParser::lexer(std::string &str) } } + // if it wasn't an identifer, number of array range, + // maybe it's a string? if (c == '"') { str = ""; while (1) { @@ -125,9 +130,10 @@ int LibertyParser::lexer(std::string &str) return 'v'; } + // if it wasn't a string, perhaps it's a comment or a forward slash? if (c == '/') { c = f.get(); - if (c == '*') { + if (c == '*') { // start of '/*' block comment int last_c = 0; while (c > 0 && (last_c != '*' || c != '/')) { last_c = c; @@ -136,7 +142,7 @@ int LibertyParser::lexer(std::string &str) line++; } return lexer(str); - } else if (c == '/') { + } else if (c == '/') { // start of '//' line comment while (c > 0 && c != '\n') c = f.get(); line++; @@ -144,24 +150,31 @@ int LibertyParser::lexer(std::string &str) } f.unget(); // fprintf(stderr, "LEX: char >>/<<\n"); - return '/'; + return '/'; // a single '/' charater. } + // check for a backslash if (c == '\\') { - c = f.get(); + c = f.get(); if (c == '\r') c = f.get(); - if (c == '\n') + if (c == '\n') { + line++; return lexer(str); + } f.unget(); return '\\'; } + // check for a new line if (c == '\n') { line++; - return ';'; + return 'n'; } + // anything else, such as ';' will get passed + // through as literal items. + // if (c >= 32 && c < 255) // fprintf(stderr, "LEX: char >>%c<<\n", c); // else @@ -175,14 +188,39 @@ LibertyAst *LibertyParser::parse() int tok = lexer(str); - while (tok == ';') + // there are liberty files in the wild that + // have superfluous ';' at the end of + // a { ... }. We simply ignore a ';' here. + // and get to the next statement. + + while ((tok == 'n') || (tok == ';')) tok = lexer(str); if (tok == '}' || tok < 0) return NULL; - if (tok != 'v') - error(); + if (tok != 'v') { + std::string eReport; + switch(tok) + { + case 'n': + error("Unexpected newline."); + break; + case '[': + case ']': + case '}': + case '{': + case '\"': + case ':': + eReport = "Unexpected '"; + eReport += static_cast<char>(tok); + eReport += "'."; + error(eReport); + break; + default: + error(); + } + } LibertyAst *ast = new LibertyAst; ast->id = str; @@ -191,7 +229,9 @@ LibertyAst *LibertyParser::parse() { tok = lexer(str); - if (tok == ';') + // allow both ';' and new lines to + // terminate a statement. + if ((tok == ';') || (tok == 'n')) break; if (tok == ':' && ast->value.empty()) { @@ -207,7 +247,12 @@ LibertyAst *LibertyParser::parse() ast->value += str; tok = lexer(str); } - if (tok == ';') + + // In a liberty file, all key : value pairs should end in ';' + // However, there are some liberty files in the wild that + // just have a newline. We'll be kind and accept a newline + // instead of the ';' too.. + if ((tok == ';') || (tok == 'n')) break; else error(); @@ -222,8 +267,70 @@ LibertyAst *LibertyParser::parse() continue; if (tok == ')') break; - if (tok != 'v') - error(); + + // FIXME: the AST needs to be extended to store + // these vector ranges. + if (tok == '[') + { + // parse vector range [A] or [A:B] + std::string arg; + tok = lexer(arg); + if (tok != 'v') + { + // expected a vector array index + error("Expected a number."); + } + else + { + // fixme: check for number A + } + tok = lexer(arg); + // optionally check for : in case of [A:B] + // if it isn't we just expect ']' + // as we have [A] + if (tok == ':') + { + tok = lexer(arg); + if (tok != 'v') + { + // expected a vector array index + error("Expected a number."); + } + else + { + // fixme: check for number B + tok = lexer(arg); + } + } + // expect a closing bracket of array range + if (tok != ']') + { + error("Expected ']' on array range."); + } + continue; + } + if (tok != 'v') { + std::string eReport; + switch(tok) + { + case 'n': + error("Unexpected newline."); + break; + case '[': + case ']': + case '}': + case '{': + case '\"': + case ':': + eReport = "Unexpected '"; + eReport += static_cast<char>(tok); + eReport += "'."; + error(eReport); + break; + default: + error(); + } + } ast->args.push_back(arg); } continue; @@ -249,14 +356,31 @@ LibertyAst *LibertyParser::parse() void LibertyParser::error() { - log_error("Syntax error in line %d.\n", line); + log_error("Syntax error in liberty file on line %d.\n", line); +} + +void LibertyParser::error(const std::string &str) +{ + std::stringstream ss; + ss << "Syntax error in liberty file on line " << line << ".\n"; + ss << " " << str << "\n"; + log_error("%s", ss.str().c_str()); } #else void LibertyParser::error() { - fprintf(stderr, "Syntax error in line %d.\n", line); + fprintf(stderr, "Syntax error in liberty file on line %d.\n", line); + exit(1); +} + +void LibertyParser::error(const std::string &str) +{ + std::stringstream ss; + ss << "Syntax error in liberty file on line " << line << ".\n"; + ss << " " << str << "\n"; + printf("%s", ss.str().c_str()); exit(1); } @@ -264,21 +388,21 @@ void LibertyParser::error() #define CHECK_NV(result, check) \ do { \ - auto _R = (result); \ - if (!(_R check)) { \ - fprintf(stderr, "Error from '%s' (%ld %s) in %s:%d.\n", \ - #result, (long int)_R, #check, __FILE__, __LINE__); \ - abort(); \ - } \ + auto _R = (result); \ + if (!(_R check)) { \ + fprintf(stderr, "Error from '%s' (%ld %s) in %s:%d.\n", \ + #result, (long int)_R, #check, __FILE__, __LINE__); \ + abort(); \ + } \ } while(0) #define CHECK_COND(result) \ do { \ - if (!(result)) { \ - fprintf(stderr, "Error from '%s' in %s:%d.\n", \ - #result, __FILE__, __LINE__); \ - abort(); \ - } \ + if (!(result)) { \ + fprintf(stderr, "Error from '%s' in %s:%d.\n", \ + #result, __FILE__, __LINE__); \ + abort(); \ + } \ } while(0) /**** END: http://svn.clifford.at/tools/trunk/examples/check.h ****/ diff --git a/passes/techmap/libparse.h b/passes/techmap/libparse.h index cf6325570..c9ebd06c5 100644 --- a/passes/techmap/libparse.h +++ b/passes/techmap/libparse.h @@ -46,9 +46,17 @@ namespace Yosys LibertyAst *ast; LibertyParser(std::istream &f) : f(f), line(1), ast(parse()) {} ~LibertyParser() { if (ast) delete ast; } + + /* lexer return values: + 'v': identifier, string, array range [...] -> str holds the token string + 'n': newline + anything else is a single character. + */ int lexer(std::string &str); - LibertyAst *parse(); + + LibertyAst *parse(); void error(); + void error(const std::string &str); }; } diff --git a/passes/techmap/lut2mux.cc b/passes/techmap/lut2mux.cc index 2bb0bd8b4..c6618fc9d 100644 --- a/passes/techmap/lut2mux.cc +++ b/passes/techmap/lut2mux.cc @@ -25,14 +25,14 @@ PRIVATE_NAMESPACE_BEGIN int lut2mux(Cell *cell) { - SigSpec sig_a = cell->getPort("\\A"); - SigSpec sig_y = cell->getPort("\\Y"); - Const lut = cell->getParam("\\LUT"); + SigSpec sig_a = cell->getPort(ID::A); + SigSpec sig_y = cell->getPort(ID::Y); + Const lut = cell->getParam(ID(LUT)); int count = 1; if (GetSize(sig_a) == 1) { - cell->module->addMuxGate(NEW_ID, lut[0], lut[1], sig_a, sig_y); + cell->module->addMuxGate(NEW_ID, lut.extract(0)[0], lut.extract(1)[0], sig_a, sig_y); } else { @@ -56,7 +56,7 @@ int lut2mux(Cell *cell) struct Lut2muxPass : public Pass { Lut2muxPass() : Pass("lut2mux", "convert $lut to $_MUX_") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -65,7 +65,7 @@ struct Lut2muxPass : public Pass { log("This pass converts $lut cells to $_MUX_ gates.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing LUT2MUX pass (convert $lut to $_MUX_).\n"); @@ -81,7 +81,7 @@ struct Lut2muxPass : public Pass { for (auto module : design->selected_modules()) for (auto cell : module->selected_cells()) { - if (cell->type == "$lut") { + if (cell->type == ID($lut)) { IdString cell_name = cell->name; int count = lut2mux(cell); log("Converted %s.%s to %d MUX cells.\n", log_id(module), log_id(cell_name), count); diff --git a/passes/techmap/maccmap.cc b/passes/techmap/maccmap.cc index 32569d076..09f61927c 100644 --- a/passes/techmap/maccmap.cc +++ b/passes/techmap/maccmap.cc @@ -36,7 +36,7 @@ struct MaccmapWorker void add(RTLIL::SigBit bit, int position) { - if (position >= width || bit == RTLIL::S0) + if (position >= width || bit == State::S0) return; if (bits.at(position).count(bit)) { @@ -53,7 +53,7 @@ struct MaccmapWorker if (do_subtract) { a = module->Not(NEW_ID, a); - add(RTLIL::S1, 0); + add(State::S1, 0); } for (int i = 0; i < width; i++) @@ -80,7 +80,7 @@ struct MaccmapWorker else { add(module->And(NEW_ID, a, RTLIL::SigSpec(b[i], width)), false, do_subtract); - a = {a.extract(0, width-1), RTLIL::S0}; + a = {a.extract(0, width-1), State::S0}; } } @@ -88,10 +88,10 @@ struct MaccmapWorker { int start_index = 0, stop_index = GetSize(in1); - while (start_index < stop_index && in1[start_index] == RTLIL::S0 && in2[start_index] == RTLIL::S0 && in3[start_index] == RTLIL::S0) + while (start_index < stop_index && in1[start_index] == State::S0 && in2[start_index] == RTLIL::S0 && in3[start_index] == RTLIL::S0) start_index++; - while (start_index < stop_index && in1[stop_index-1] == RTLIL::S0 && in2[stop_index-1] == RTLIL::S0 && in3[stop_index-1] == RTLIL::S0) + while (start_index < stop_index && in1[stop_index-1] == State::S0 && in2[stop_index-1] == RTLIL::S0 && in3[stop_index-1] == RTLIL::S0) stop_index--; if (start_index == stop_index) @@ -111,13 +111,13 @@ struct MaccmapWorker RTLIL::Wire *w1 = module->addWire(NEW_ID, width); RTLIL::Wire *w2 = module->addWire(NEW_ID, width); - RTLIL::Cell *cell = module->addCell(NEW_ID, "$fa"); - cell->setParam("\\WIDTH", width); - cell->setPort("\\A", in1); - cell->setPort("\\B", in2); - cell->setPort("\\C", in3); - cell->setPort("\\Y", w1); - cell->setPort("\\X", w2); + RTLIL::Cell *cell = module->addCell(NEW_ID, ID($fa)); + cell->setParam(ID(WIDTH), width); + cell->setPort(ID::A, in1); + cell->setPort(ID::B, in2); + cell->setPort(ID(C), in3); + cell->setPort(ID::Y, w1); + cell->setPort(ID(X), w2); out1 = {out_zeros_msb, w1, out_zeros_lsb}; out2 = {out_zeros_msb, w2, out_zeros_lsb}; @@ -222,7 +222,7 @@ struct MaccmapWorker RTLIL::SigSpec in3 = summands[i+2]; RTLIL::SigSpec out1, out2; fulladd(in1, in2, in3, out1, out2); - RTLIL::SigBit extra_bit = RTLIL::S0; + RTLIL::SigBit extra_bit = State::S0; if (!tree_sum_bits.empty()) { extra_bit = tree_sum_bits.back(); tree_sum_bits.pop_back(); @@ -237,23 +237,23 @@ struct MaccmapWorker } - RTLIL::Cell *c = module->addCell(NEW_ID, "$alu"); - c->setPort("\\A", summands.front()); - c->setPort("\\B", summands.back()); - c->setPort("\\CI", RTLIL::S0); - c->setPort("\\BI", RTLIL::S0); - c->setPort("\\Y", module->addWire(NEW_ID, width)); - c->setPort("\\X", module->addWire(NEW_ID, width)); - c->setPort("\\CO", module->addWire(NEW_ID, width)); + RTLIL::Cell *c = module->addCell(NEW_ID, ID($alu)); + c->setPort(ID::A, summands.front()); + c->setPort(ID::B, summands.back()); + c->setPort(ID(CI), State::S0); + c->setPort(ID(BI), State::S0); + c->setPort(ID::Y, module->addWire(NEW_ID, width)); + c->setPort(ID(X), module->addWire(NEW_ID, width)); + c->setPort(ID(CO), module->addWire(NEW_ID, width)); c->fixup_parameters(); if (!tree_sum_bits.empty()) { - c->setPort("\\CI", tree_sum_bits.back()); + c->setPort(ID(CI), tree_sum_bits.back()); tree_sum_bits.pop_back(); } log_assert(tree_sum_bits.empty()); - return c->getPort("\\Y"); + return c->getPort(ID::Y); } }; @@ -264,17 +264,17 @@ extern void maccmap(RTLIL::Module *module, RTLIL::Cell *cell, bool unmap = false void maccmap(RTLIL::Module *module, RTLIL::Cell *cell, bool unmap) { - int width = GetSize(cell->getPort("\\Y")); + int width = GetSize(cell->getPort(ID::Y)); Macc macc; macc.from_cell(cell); RTLIL::SigSpec all_input_bits; - all_input_bits.append(cell->getPort("\\A")); - all_input_bits.append(cell->getPort("\\B")); + all_input_bits.append(cell->getPort(ID::A)); + all_input_bits.append(cell->getPort(ID::B)); if (all_input_bits.to_sigbit_set().count(RTLIL::Sx)) { - module->connect(cell->getPort("\\Y"), RTLIL::SigSpec(RTLIL::Sx, width)); + module->connect(cell->getPort(ID::Y), RTLIL::SigSpec(RTLIL::Sx, width)); return; } @@ -339,9 +339,9 @@ void maccmap(RTLIL::Module *module, RTLIL::Cell *cell, bool unmap) } if (summands.front().second) - module->addNeg(NEW_ID, summands.front().first, cell->getPort("\\Y")); + module->addNeg(NEW_ID, summands.front().first, cell->getPort(ID::Y)); else - module->connect(cell->getPort("\\Y"), summands.front().first); + module->connect(cell->getPort(ID::Y), summands.front().first); } else { @@ -356,7 +356,7 @@ void maccmap(RTLIL::Module *module, RTLIL::Cell *cell, bool unmap) for (auto &bit : macc.bit_ports) worker.add(bit, 0); - module->connect(cell->getPort("\\Y"), worker.synth()); + module->connect(cell->getPort(ID::Y), worker.synth()); } } @@ -365,7 +365,7 @@ PRIVATE_NAMESPACE_BEGIN struct MaccmapPass : public Pass { MaccmapPass() : Pass("maccmap", "mapping macc cells") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -375,7 +375,7 @@ struct MaccmapPass : public Pass { log("is used then the $macc cell is mapped to $add, $sub, etc. cells instead.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { bool unmap_mode = false; @@ -393,7 +393,7 @@ struct MaccmapPass : public Pass { for (auto mod : design->selected_modules()) for (auto cell : mod->selected_cells()) - if (cell->type == "$macc") { + if (cell->type == ID($macc)) { log("Mapping %s.%s (%s).\n", log_id(mod), log_id(cell), log_id(cell->type)); maccmap(mod, cell, unmap_mode); mod->remove(cell); diff --git a/passes/techmap/muxcover.cc b/passes/techmap/muxcover.cc index 1dc649587..5541b6122 100644 --- a/passes/techmap/muxcover.cc +++ b/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<SigBit> 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<SigBit> roots; @@ -85,13 +116,13 @@ struct MuxcoverWorker if (!cell->input(conn.first)) continue; for (auto bit : sigmap(conn.second)) { - if (used_once.count(bit) || cell->type != "$_MUX_" || conn.first == "\\S") + if (used_once.count(bit) || cell->type != ID($_MUX_) || conn.first == ID(S)) roots.insert(bit); used_once.insert(bit); } } - if (cell->type == "$_MUX_") - sig_to_mux[sigmap(cell->getPort("\\Y"))] = cell; + if (cell->type == ID($_MUX_)) + sig_to_mux[sigmap(cell->getPort(ID::Y))] = cell; } log(" Treeifying %d MUXes:\n", GetSize(sig_to_mux)); @@ -110,8 +141,8 @@ struct MuxcoverWorker if (sig_to_mux.count(bit) && (bit == rootsig || !roots.count(bit))) { Cell *c = sig_to_mux.at(bit); tree.muxes[bit] = c; - wavefront.insert(sigmap(c->getPort("\\A"))); - wavefront.insert(sigmap(c->getPort("\\B"))); + wavefront.insert(sigmap(c->getPort(ID::A))); + wavefront.insert(sigmap(c->getPort(ID::B))); } } @@ -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<SigBit, SigBit, SigBit> 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<SigBit> &bits) + { + for (auto bit : bits) + find_best_cover(tree, bit); + } + + int sum_best_covers(tree_t &tree, const vector<SigBit> &bits) + { + int sum = 0; + for (auto bit : pool<SigBit>(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); - - if (best_mux.cost > mux.cost) + find_best_covers(tree, mux.inputs); + log_debug(" Decode cost for mux8 at %s: %d\n", log_signal(bit), 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); - - if (best_mux.cost > mux.cost) + find_best_covers(tree, mux.inputs); + log_debug(" Decode cost for mux16 at %s: %d\n", log_signal(bit), 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; } } @@ -456,69 +516,69 @@ struct MuxcoverWorker if (GetSize(mux.inputs) == 2) { count_muxes_by_type[0]++; - Cell *cell = module->addCell(NEW_ID, "$_MUX_"); - cell->setPort("\\A", mux.inputs[0]); - cell->setPort("\\B", mux.inputs[1]); - cell->setPort("\\S", mux.selects[0]); - cell->setPort("\\Y", bit); + Cell *cell = module->addCell(NEW_ID, ID($_MUX_)); + cell->setPort(ID::A, mux.inputs[0]); + cell->setPort(ID::B, mux.inputs[1]); + cell->setPort(ID(S), mux.selects[0]); + cell->setPort(ID::Y, bit); return; } if (GetSize(mux.inputs) == 4) { count_muxes_by_type[1]++; - Cell *cell = module->addCell(NEW_ID, "$_MUX4_"); - cell->setPort("\\A", mux.inputs[0]); - cell->setPort("\\B", mux.inputs[1]); - cell->setPort("\\C", mux.inputs[2]); - cell->setPort("\\D", mux.inputs[3]); - cell->setPort("\\S", mux.selects[0]); - cell->setPort("\\T", mux.selects[1]); - cell->setPort("\\Y", bit); + Cell *cell = module->addCell(NEW_ID, ID($_MUX4_)); + cell->setPort(ID::A, mux.inputs[0]); + cell->setPort(ID::B, mux.inputs[1]); + cell->setPort(ID(C), mux.inputs[2]); + cell->setPort(ID(D), mux.inputs[3]); + cell->setPort(ID(S), mux.selects[0]); + cell->setPort(ID(T), mux.selects[1]); + cell->setPort(ID::Y, bit); return; } if (GetSize(mux.inputs) == 8) { count_muxes_by_type[2]++; - Cell *cell = module->addCell(NEW_ID, "$_MUX8_"); - cell->setPort("\\A", mux.inputs[0]); - cell->setPort("\\B", mux.inputs[1]); - cell->setPort("\\C", mux.inputs[2]); - cell->setPort("\\D", mux.inputs[3]); - cell->setPort("\\E", mux.inputs[4]); - cell->setPort("\\F", mux.inputs[5]); - cell->setPort("\\G", mux.inputs[6]); - cell->setPort("\\H", mux.inputs[7]); - cell->setPort("\\S", mux.selects[0]); - cell->setPort("\\T", mux.selects[1]); - cell->setPort("\\U", mux.selects[2]); - cell->setPort("\\Y", bit); + Cell *cell = module->addCell(NEW_ID, ID($_MUX8_)); + cell->setPort(ID::A, mux.inputs[0]); + cell->setPort(ID::B, mux.inputs[1]); + cell->setPort(ID(C), mux.inputs[2]); + cell->setPort(ID(D), mux.inputs[3]); + cell->setPort(ID(E), mux.inputs[4]); + cell->setPort(ID(F), mux.inputs[5]); + cell->setPort(ID(G), mux.inputs[6]); + cell->setPort(ID(H), mux.inputs[7]); + cell->setPort(ID(S), mux.selects[0]); + cell->setPort(ID(T), mux.selects[1]); + cell->setPort(ID(U), mux.selects[2]); + cell->setPort(ID::Y, bit); return; } if (GetSize(mux.inputs) == 16) { count_muxes_by_type[3]++; - Cell *cell = module->addCell(NEW_ID, "$_MUX16_"); - cell->setPort("\\A", mux.inputs[0]); - cell->setPort("\\B", mux.inputs[1]); - cell->setPort("\\C", mux.inputs[2]); - cell->setPort("\\D", mux.inputs[3]); - cell->setPort("\\E", mux.inputs[4]); - cell->setPort("\\F", mux.inputs[5]); - cell->setPort("\\G", mux.inputs[6]); - cell->setPort("\\H", mux.inputs[7]); - cell->setPort("\\I", mux.inputs[8]); - cell->setPort("\\J", mux.inputs[9]); - cell->setPort("\\K", mux.inputs[10]); - cell->setPort("\\L", mux.inputs[11]); - cell->setPort("\\M", mux.inputs[12]); - cell->setPort("\\N", mux.inputs[13]); - cell->setPort("\\O", mux.inputs[14]); - cell->setPort("\\P", mux.inputs[15]); - cell->setPort("\\S", mux.selects[0]); - cell->setPort("\\T", mux.selects[1]); - cell->setPort("\\U", mux.selects[2]); - cell->setPort("\\V", mux.selects[3]); - cell->setPort("\\Y", bit); + Cell *cell = module->addCell(NEW_ID, ID($_MUX16_)); + cell->setPort(ID::A, mux.inputs[0]); + cell->setPort(ID::B, mux.inputs[1]); + cell->setPort(ID(C), mux.inputs[2]); + cell->setPort(ID(D), mux.inputs[3]); + cell->setPort(ID(E), mux.inputs[4]); + cell->setPort(ID(F), mux.inputs[5]); + cell->setPort(ID(G), mux.inputs[6]); + cell->setPort(ID(H), mux.inputs[7]); + cell->setPort(ID(I), mux.inputs[8]); + cell->setPort(ID(J), mux.inputs[9]); + cell->setPort(ID(K), mux.inputs[10]); + cell->setPort(ID(L), mux.inputs[11]); + cell->setPort(ID(M), mux.inputs[12]); + cell->setPort(ID(N), mux.inputs[13]); + cell->setPort(ID(O), mux.inputs[14]); + cell->setPort(ID(P), mux.inputs[15]); + cell->setPort(ID(S), mux.selects[0]); + cell->setPort(ID(T), mux.selects[1]); + cell->setPort(ID(U), mux.selects[2]); + cell->setPort(ID(V), mux.selects[3]); + cell->setPort(ID::Y, bit); return; } @@ -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); @@ -561,7 +623,7 @@ struct MuxcoverWorker struct MuxcoverPass : public Pass { MuxcoverPass() : Pass("muxcover", "cover trees of MUX cells with wider MUXes") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -569,17 +631,32 @@ 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(" Cover $_MUX_ trees using the specified types of MUXes (with optional\n"); + log(" integer costs). If none of these options are given, the effect is the\n"); + log(" same as if all of them are.\n"); + log(" Default costs: $_MUX4_ = %d, $_MUX8_ = %d, \n", COST_MUX4, COST_MUX8); + log(" $_MUX16_ = %d\n", COST_MUX16); + log("\n"); + log(" -mux2=cost\n"); + log(" Use the specified cost for $_MUX_ cells when making covering decisions.\n"); + log(" Default cost: $_MUX_ = %d\n", COST_MUX2); + 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<N>_ to select from less\n"); + log(" than <N> different signals.\n"); + log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing MUXCOVER pass (mapping to wider MUXes).\n"); @@ -587,26 +664,57 @@ 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_mux2 = COST_MUX2; + 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() >= 6 && arg.compare(0,6,"-mux2=") == 0) { + cost_mux2 = atoi(arg.substr(6).c_str()); + continue; + } + if (arg.size() >= 5 && arg.compare(0,5,"-mux4") == 0) { 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.compare(0,5,"-mux8") == 0) { 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.compare(0,6,"-mux16") == 0) { use_mux16 = true; + if (arg.size() > 6) { + if (arg[6] != '=') break; + cost_mux16 = atoi(arg.substr(7).c_str()); + } + continue; + } + if (arg.size() >= 6 && arg.compare(0,6,"-dmux=") == 0) { + cost_dmux = atoi(arg.substr(6).c_str()); continue; } - if (args[argidx] == "-nodecode") { + if (arg == "-nodecode") { nodecode = true; continue; } + if (arg == "-nopartial") { + nopartial = true; + continue; + } break; } extra_args(args, argidx, design); @@ -623,7 +731,13 @@ 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_mux2 = cost_mux2; + 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/passes/techmap/nlutmap.cc b/passes/techmap/nlutmap.cc index f1a41cc3e..798d82248 100644 --- a/passes/techmap/nlutmap.cc +++ b/passes/techmap/nlutmap.cc @@ -82,10 +82,10 @@ struct NlutmapWorker for (auto cell : module->cells()) { - if (cell->type != "$lut" || mapped_cells.count(cell)) + if (cell->type != ID($lut) || mapped_cells.count(cell)) continue; - if (GetSize(cell->getPort("\\A")) == lut_size || lut_size == 2) + if (GetSize(cell->getPort(ID::A)) == lut_size || lut_size == 2) candidate_ratings[cell] = 0; for (auto &conn : cell->connections()) @@ -119,7 +119,7 @@ struct NlutmapWorker if (config.assert_mode) { for (auto cell : module->cells()) - if (cell->type == "$lut" && !mapped_cells.count(cell)) + if (cell->type == ID($lut) && !mapped_cells.count(cell)) log_error("Insufficient number of LUTs to map all logic cells!\n"); } @@ -129,7 +129,7 @@ struct NlutmapWorker struct NlutmapPass : public Pass { NlutmapPass() : Pass("nlutmap", "map to LUTs of different sizes") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -149,7 +149,7 @@ struct NlutmapPass : public Pass { log("to generic logic gates ($_AND_, etc.).\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { NlutmapConfig config; diff --git a/passes/techmap/pmuxtree.cc b/passes/techmap/pmuxtree.cc index c626dbcc5..31ab13cec 100644 --- a/passes/techmap/pmuxtree.cc +++ b/passes/techmap/pmuxtree.cc @@ -67,16 +67,16 @@ static SigSpec recursive_mux_generator(Module *module, const SigSpec &sig_data, struct PmuxtreePass : public Pass { PmuxtreePass() : Pass("pmuxtree", "transform $pmux cells to trees of $mux cells") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); - log(" pmuxtree [options] [selection]\n"); + log(" pmuxtree [selection]\n"); log("\n"); - log("This pass transforms $pmux cells to a trees of $mux cells.\n"); + log("This pass transforms $pmux cells to trees of $mux cells.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing PMUXTREE pass.\n"); @@ -89,21 +89,21 @@ struct PmuxtreePass : public Pass { for (auto module : design->selected_modules()) for (auto cell : module->selected_cells()) { - if (cell->type != "$pmux") + if (cell->type != ID($pmux)) continue; - SigSpec sig_data = cell->getPort("\\B"); - SigSpec sig_sel = cell->getPort("\\S"); + SigSpec sig_data = cell->getPort(ID::B); + SigSpec sig_sel = cell->getPort(ID(S)); - if (!cell->getPort("\\A").is_fully_undef()) { - sig_data.append(cell->getPort("\\A")); + if (!cell->getPort(ID::A).is_fully_undef()) { + sig_data.append(cell->getPort(ID::A)); SigSpec sig_sel_or = module->ReduceOr(NEW_ID, sig_sel); sig_sel.append(module->Not(NEW_ID, sig_sel_or)); } SigSpec result, result_or; result = recursive_mux_generator(module, sig_data, sig_sel, result_or); - module->connect(cell->getPort("\\Y"), result); + module->connect(cell->getPort(ID::Y), result); module->remove(cell); } } diff --git a/passes/techmap/shregmap.cc b/passes/techmap/shregmap.cc index 6936b499e..be00e5030 100644 --- a/passes/techmap/shregmap.cc +++ b/passes/techmap/shregmap.cc @@ -71,22 +71,22 @@ struct ShregmapTechGreenpak4 : ShregmapTech bool fixup(Cell *cell, dict<int, SigBit> &taps) { - auto D = cell->getPort("\\D"); - auto C = cell->getPort("\\C"); + auto D = cell->getPort(ID(D)); + auto C = cell->getPort(ID(C)); - auto newcell = cell->module->addCell(NEW_ID, "\\GP_SHREG"); - newcell->setPort("\\nRST", State::S1); - newcell->setPort("\\CLK", C); - newcell->setPort("\\IN", D); + auto newcell = cell->module->addCell(NEW_ID, ID(GP_SHREG)); + newcell->setPort(ID(nRST), State::S1); + newcell->setPort(ID(CLK), C); + newcell->setPort(ID(IN), D); int i = 0; for (auto tap : taps) { - newcell->setPort(i ? "\\OUTB" : "\\OUTA", tap.second); - newcell->setParam(i ? "\\OUTB_TAP" : "\\OUTA_TAP", tap.first + 1); + newcell->setPort(i ? ID(OUTB) : ID(OUTA), tap.second); + newcell->setParam(i ? ID(OUTB_TAP) : ID(OUTA_TAP), tap.first + 1); i++; } - cell->setParam("\\OUTA_INVERT", 0); + cell->setParam(ID(OUTA_INVERT), 0); return false; } }; @@ -112,14 +112,14 @@ struct ShregmapWorker { for (auto wire : module->wires()) { - if (wire->port_output || wire->get_bool_attribute("\\keep")) { + if (wire->port_output || wire->get_bool_attribute(ID::keep)) { for (auto bit : sigmap(wire)) sigbit_with_non_chain_users.insert(bit); } - if (wire->attributes.count("\\init")) { + if (wire->attributes.count(ID(init))) { SigSpec initsig = sigmap(wire); - Const initval = wire->attributes.at("\\init"); + Const initval = wire->attributes.at(ID(init)); for (int i = 0; i < GetSize(initsig) && i < GetSize(initval); i++) if (initval[i] == State::S0 && !opts.zinit) sigbit_init[initsig[i]] = false; @@ -130,7 +130,7 @@ struct ShregmapWorker for (auto cell : module->cells()) { - if (opts.ffcells.count(cell->type) && !cell->get_bool_attribute("\\keep")) + if (opts.ffcells.count(cell->type) && !cell->get_bool_attribute(ID::keep)) { IdString d_port = opts.ffcells.at(cell->type).first; IdString q_port = opts.ffcells.at(cell->type).second; @@ -140,10 +140,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; @@ -179,7 +191,7 @@ struct ShregmapWorker IdString q_port = opts.ffcells.at(c1->type).second; auto c1_conn = c1->connections(); - auto c2_conn = c1->connections(); + auto c2_conn = c2->connections(); c1_conn.erase(d_port); c1_conn.erase(q_port); @@ -307,7 +319,7 @@ struct ShregmapWorker initval.push_back(State::S0); remove_init.insert(bit); } - first_cell->setParam("\\INIT", initval); + first_cell->setParam(ID(INIT), initval); } if (opts.zinit) @@ -321,22 +333,22 @@ struct ShregmapWorker int param_clkpol = -1; int param_enpol = 2; - if (first_cell->type == "$_DFF_N_") param_clkpol = 0; - if (first_cell->type == "$_DFF_P_") param_clkpol = 1; + if (first_cell->type == ID($_DFF_N_)) param_clkpol = 0; + if (first_cell->type == ID($_DFF_P_)) param_clkpol = 1; - if (first_cell->type == "$_DFFE_NN_") param_clkpol = 0, param_enpol = 0; - if (first_cell->type == "$_DFFE_NP_") param_clkpol = 0, param_enpol = 1; - if (first_cell->type == "$_DFFE_PN_") param_clkpol = 1, param_enpol = 0; - if (first_cell->type == "$_DFFE_PP_") param_clkpol = 1, param_enpol = 1; + if (first_cell->type == ID($_DFFE_NN_)) param_clkpol = 0, param_enpol = 0; + if (first_cell->type == ID($_DFFE_NP_)) param_clkpol = 0, param_enpol = 1; + if (first_cell->type == ID($_DFFE_PN_)) param_clkpol = 1, param_enpol = 0; + if (first_cell->type == ID($_DFFE_PP_)) param_clkpol = 1, param_enpol = 1; log_assert(param_clkpol >= 0); - first_cell->setParam("\\CLKPOL", param_clkpol); - if (opts.ffe) first_cell->setParam("\\ENPOL", param_enpol); + first_cell->setParam(ID(CLKPOL), param_clkpol); + if (opts.ffe) first_cell->setParam(ID(ENPOL), param_enpol); } first_cell->type = shreg_cell_type_str; first_cell->setPort(q_port, last_cell->getPort(q_port)); - first_cell->setParam("\\DEPTH", depth); + first_cell->setParam(ID(DEPTH), depth); if (opts.tech != nullptr && !opts.tech->fixup(first_cell, taps_dict)) remove_cells.insert(first_cell); @@ -354,18 +366,18 @@ struct ShregmapWorker for (auto wire : module->wires()) { - if (wire->attributes.count("\\init") == 0) + if (wire->attributes.count(ID(init)) == 0) continue; SigSpec initsig = sigmap(wire); - Const &initval = wire->attributes.at("\\init"); + Const &initval = wire->attributes.at(ID(init)); for (int i = 0; i < GetSize(initsig) && i < GetSize(initval); i++) if (remove_init.count(initsig[i])) initval[i] = State::Sx; if (SigSpec(initval).is_fully_undef()) - wire->attributes.erase("\\init"); + wire->attributes.erase(ID(init)); } remove_cells.clear(); @@ -391,7 +403,7 @@ struct ShregmapWorker struct ShregmapPass : public Pass { ShregmapPass() : Pass("shregmap", "map shift registers") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -449,7 +461,7 @@ struct ShregmapPass : public Pass { log(" map to greenpak4 shift registers.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { ShregmapOptions opts; string clkpol, enpol; @@ -536,19 +548,19 @@ struct ShregmapPass : public Pass { bool en_neg = enpol == "neg" || enpol == "any" || enpol == "any_or_none"; if (clk_pos && en_none) - opts.ffcells["$_DFF_P_"] = make_pair(IdString("\\D"), IdString("\\Q")); + opts.ffcells[ID($_DFF_P_)] = make_pair(IdString(ID(D)), IdString(ID(Q))); if (clk_neg && en_none) - opts.ffcells["$_DFF_N_"] = make_pair(IdString("\\D"), IdString("\\Q")); + opts.ffcells[ID($_DFF_N_)] = make_pair(IdString(ID(D)), IdString(ID(Q))); if (clk_pos && en_pos) - opts.ffcells["$_DFFE_PP_"] = make_pair(IdString("\\D"), IdString("\\Q")); + opts.ffcells[ID($_DFFE_PP_)] = make_pair(IdString(ID(D)), IdString(ID(Q))); if (clk_pos && en_neg) - opts.ffcells["$_DFFE_PN_"] = make_pair(IdString("\\D"), IdString("\\Q")); + opts.ffcells[ID($_DFFE_PN_)] = make_pair(IdString(ID(D)), IdString(ID(Q))); if (clk_neg && en_pos) - opts.ffcells["$_DFFE_NP_"] = make_pair(IdString("\\D"), IdString("\\Q")); + opts.ffcells[ID($_DFFE_NP_)] = make_pair(IdString(ID(D)), IdString(ID(Q))); if (clk_neg && en_neg) - opts.ffcells["$_DFFE_NN_"] = make_pair(IdString("\\D"), IdString("\\Q")); + opts.ffcells[ID($_DFFE_NN_)] = make_pair(IdString(ID(D)), IdString(ID(Q))); if (en_pos || en_neg) opts.ffe = true; diff --git a/passes/techmap/simplemap.cc b/passes/techmap/simplemap.cc index c6b932bdc..91574f3c6 100644 --- a/passes/techmap/simplemap.cc +++ b/passes/techmap/simplemap.cc @@ -28,82 +28,82 @@ YOSYS_NAMESPACE_BEGIN void simplemap_not(RTLIL::Module *module, RTLIL::Cell *cell) { - RTLIL::SigSpec sig_a = cell->getPort("\\A"); - RTLIL::SigSpec sig_y = cell->getPort("\\Y"); + RTLIL::SigSpec sig_a = cell->getPort(ID::A); + RTLIL::SigSpec sig_y = cell->getPort(ID::Y); - sig_a.extend_u0(GetSize(sig_y), cell->parameters.at("\\A_SIGNED").as_bool()); + sig_a.extend_u0(GetSize(sig_y), cell->parameters.at(ID(A_SIGNED)).as_bool()); for (int i = 0; i < GetSize(sig_y); i++) { - RTLIL::Cell *gate = module->addCell(NEW_ID, "$_NOT_"); - gate->add_strpool_attribute("\\src", cell->get_strpool_attribute("\\src")); - gate->setPort("\\A", sig_a[i]); - gate->setPort("\\Y", sig_y[i]); + RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_NOT_)); + gate->add_strpool_attribute(ID(src), cell->get_strpool_attribute(ID(src))); + gate->setPort(ID::A, sig_a[i]); + gate->setPort(ID::Y, sig_y[i]); } } void simplemap_pos(RTLIL::Module *module, RTLIL::Cell *cell) { - RTLIL::SigSpec sig_a = cell->getPort("\\A"); - RTLIL::SigSpec sig_y = cell->getPort("\\Y"); + RTLIL::SigSpec sig_a = cell->getPort(ID::A); + RTLIL::SigSpec sig_y = cell->getPort(ID::Y); - sig_a.extend_u0(GetSize(sig_y), cell->parameters.at("\\A_SIGNED").as_bool()); + sig_a.extend_u0(GetSize(sig_y), cell->parameters.at(ID(A_SIGNED)).as_bool()); module->connect(RTLIL::SigSig(sig_y, sig_a)); } void simplemap_bitop(RTLIL::Module *module, RTLIL::Cell *cell) { - RTLIL::SigSpec sig_a = cell->getPort("\\A"); - RTLIL::SigSpec sig_b = cell->getPort("\\B"); - RTLIL::SigSpec sig_y = cell->getPort("\\Y"); + RTLIL::SigSpec sig_a = cell->getPort(ID::A); + RTLIL::SigSpec sig_b = cell->getPort(ID::B); + RTLIL::SigSpec sig_y = cell->getPort(ID::Y); - sig_a.extend_u0(GetSize(sig_y), cell->parameters.at("\\A_SIGNED").as_bool()); - sig_b.extend_u0(GetSize(sig_y), cell->parameters.at("\\B_SIGNED").as_bool()); + sig_a.extend_u0(GetSize(sig_y), cell->parameters.at(ID(A_SIGNED)).as_bool()); + sig_b.extend_u0(GetSize(sig_y), cell->parameters.at(ID(B_SIGNED)).as_bool()); - if (cell->type == "$xnor") + if (cell->type == ID($xnor)) { RTLIL::SigSpec sig_t = module->addWire(NEW_ID, GetSize(sig_y)); for (int i = 0; i < GetSize(sig_y); i++) { - RTLIL::Cell *gate = module->addCell(NEW_ID, "$_NOT_"); - gate->add_strpool_attribute("\\src", cell->get_strpool_attribute("\\src")); - gate->setPort("\\A", sig_t[i]); - gate->setPort("\\Y", sig_y[i]); + RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_NOT_)); + gate->add_strpool_attribute(ID(src), cell->get_strpool_attribute(ID(src))); + gate->setPort(ID::A, sig_t[i]); + gate->setPort(ID::Y, sig_y[i]); } sig_y = sig_t; } - std::string gate_type; - if (cell->type == "$and") gate_type = "$_AND_"; - if (cell->type == "$or") gate_type = "$_OR_"; - if (cell->type == "$xor") gate_type = "$_XOR_"; - if (cell->type == "$xnor") gate_type = "$_XOR_"; + IdString gate_type; + if (cell->type == ID($and)) gate_type = ID($_AND_); + if (cell->type == ID($or)) gate_type = ID($_OR_); + if (cell->type == ID($xor)) gate_type = ID($_XOR_); + if (cell->type == ID($xnor)) gate_type = ID($_XOR_); log_assert(!gate_type.empty()); for (int i = 0; i < GetSize(sig_y); i++) { RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type); - gate->add_strpool_attribute("\\src", cell->get_strpool_attribute("\\src")); - gate->setPort("\\A", sig_a[i]); - gate->setPort("\\B", sig_b[i]); - gate->setPort("\\Y", sig_y[i]); + gate->add_strpool_attribute(ID(src), cell->get_strpool_attribute(ID(src))); + gate->setPort(ID::A, sig_a[i]); + gate->setPort(ID::B, sig_b[i]); + gate->setPort(ID::Y, sig_y[i]); } } void simplemap_reduce(RTLIL::Module *module, RTLIL::Cell *cell) { - RTLIL::SigSpec sig_a = cell->getPort("\\A"); - RTLIL::SigSpec sig_y = cell->getPort("\\Y"); + RTLIL::SigSpec sig_a = cell->getPort(ID::A); + RTLIL::SigSpec sig_y = cell->getPort(ID::Y); if (sig_y.size() == 0) return; if (sig_a.size() == 0) { - if (cell->type == "$reduce_and") module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(1, sig_y.size()))); - if (cell->type == "$reduce_or") module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size()))); - if (cell->type == "$reduce_xor") module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size()))); - if (cell->type == "$reduce_xnor") module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(1, sig_y.size()))); - if (cell->type == "$reduce_bool") module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size()))); + if (cell->type == ID($reduce_and)) module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(1, sig_y.size()))); + if (cell->type == ID($reduce_or)) module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size()))); + if (cell->type == ID($reduce_xor)) module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size()))); + if (cell->type == ID($reduce_xnor)) module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(1, sig_y.size()))); + if (cell->type == ID($reduce_bool)) module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size()))); return; } @@ -112,12 +112,12 @@ void simplemap_reduce(RTLIL::Module *module, RTLIL::Cell *cell) sig_y = sig_y.extract(0, 1); } - std::string gate_type; - if (cell->type == "$reduce_and") gate_type = "$_AND_"; - if (cell->type == "$reduce_or") gate_type = "$_OR_"; - if (cell->type == "$reduce_xor") gate_type = "$_XOR_"; - if (cell->type == "$reduce_xnor") gate_type = "$_XOR_"; - if (cell->type == "$reduce_bool") gate_type = "$_OR_"; + IdString gate_type; + if (cell->type == ID($reduce_and)) gate_type = ID($_AND_); + if (cell->type == ID($reduce_or)) gate_type = ID($_OR_); + if (cell->type == ID($reduce_xor)) gate_type = ID($_XOR_); + if (cell->type == ID($reduce_xnor)) gate_type = ID($_XOR_); + if (cell->type == ID($reduce_bool)) gate_type = ID($_OR_); log_assert(!gate_type.empty()); RTLIL::Cell *last_output_cell = NULL; @@ -134,22 +134,22 @@ void simplemap_reduce(RTLIL::Module *module, RTLIL::Cell *cell) } RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type); - gate->add_strpool_attribute("\\src", cell->get_strpool_attribute("\\src")); - gate->setPort("\\A", sig_a[i]); - gate->setPort("\\B", sig_a[i+1]); - gate->setPort("\\Y", sig_t[i/2]); + gate->add_strpool_attribute(ID(src), cell->get_strpool_attribute(ID(src))); + gate->setPort(ID::A, sig_a[i]); + gate->setPort(ID::B, sig_a[i+1]); + gate->setPort(ID::Y, sig_t[i/2]); last_output_cell = gate; } sig_a = sig_t; } - if (cell->type == "$reduce_xnor") { + if (cell->type == ID($reduce_xnor)) { RTLIL::SigSpec sig_t = module->addWire(NEW_ID); - RTLIL::Cell *gate = module->addCell(NEW_ID, "$_NOT_"); - gate->add_strpool_attribute("\\src", cell->get_strpool_attribute("\\src")); - gate->setPort("\\A", sig_a); - gate->setPort("\\Y", sig_t); + RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_NOT_)); + gate->add_strpool_attribute(ID(src), cell->get_strpool_attribute(ID(src))); + gate->setPort(ID::A, sig_a); + gate->setPort(ID::Y, sig_t); last_output_cell = gate; sig_a = sig_t; } @@ -157,7 +157,7 @@ void simplemap_reduce(RTLIL::Module *module, RTLIL::Cell *cell) if (last_output_cell == NULL) { module->connect(RTLIL::SigSig(sig_y, sig_a)); } else { - last_output_cell->setPort("\\Y", sig_y); + last_output_cell->setPort(ID::Y, sig_y); } } @@ -174,26 +174,26 @@ static void logic_reduce(RTLIL::Module *module, RTLIL::SigSpec &sig, RTLIL::Cell continue; } - RTLIL::Cell *gate = module->addCell(NEW_ID, "$_OR_"); - gate->add_strpool_attribute("\\src", cell->get_strpool_attribute("\\src")); - gate->setPort("\\A", sig[i]); - gate->setPort("\\B", sig[i+1]); - gate->setPort("\\Y", sig_t[i/2]); + RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_OR_)); + gate->add_strpool_attribute(ID(src), cell->get_strpool_attribute(ID(src))); + gate->setPort(ID::A, sig[i]); + gate->setPort(ID::B, sig[i+1]); + gate->setPort(ID::Y, sig_t[i/2]); } sig = sig_t; } if (sig.size() == 0) - sig = RTLIL::SigSpec(0, 1); + sig = State::S0; } void simplemap_lognot(RTLIL::Module *module, RTLIL::Cell *cell) { - RTLIL::SigSpec sig_a = cell->getPort("\\A"); + RTLIL::SigSpec sig_a = cell->getPort(ID::A); logic_reduce(module, sig_a, cell); - RTLIL::SigSpec sig_y = cell->getPort("\\Y"); + RTLIL::SigSpec sig_y = cell->getPort(ID::Y); if (sig_y.size() == 0) return; @@ -203,21 +203,21 @@ void simplemap_lognot(RTLIL::Module *module, RTLIL::Cell *cell) sig_y = sig_y.extract(0, 1); } - RTLIL::Cell *gate = module->addCell(NEW_ID, "$_NOT_"); - gate->add_strpool_attribute("\\src", cell->get_strpool_attribute("\\src")); - gate->setPort("\\A", sig_a); - gate->setPort("\\Y", sig_y); + RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_NOT_)); + gate->add_strpool_attribute(ID(src), cell->get_strpool_attribute(ID(src))); + gate->setPort(ID::A, sig_a); + gate->setPort(ID::Y, sig_y); } void simplemap_logbin(RTLIL::Module *module, RTLIL::Cell *cell) { - RTLIL::SigSpec sig_a = cell->getPort("\\A"); + RTLIL::SigSpec sig_a = cell->getPort(ID::A); logic_reduce(module, sig_a, cell); - RTLIL::SigSpec sig_b = cell->getPort("\\B"); + RTLIL::SigSpec sig_b = cell->getPort(ID::B); logic_reduce(module, sig_b, cell); - RTLIL::SigSpec sig_y = cell->getPort("\\Y"); + RTLIL::SigSpec sig_y = cell->getPort(ID::Y); if (sig_y.size() == 0) return; @@ -227,41 +227,41 @@ void simplemap_logbin(RTLIL::Module *module, RTLIL::Cell *cell) sig_y = sig_y.extract(0, 1); } - std::string gate_type; - if (cell->type == "$logic_and") gate_type = "$_AND_"; - if (cell->type == "$logic_or") gate_type = "$_OR_"; + IdString gate_type; + if (cell->type == ID($logic_and)) gate_type = ID($_AND_); + if (cell->type == ID($logic_or)) gate_type = ID($_OR_); log_assert(!gate_type.empty()); RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type); - gate->add_strpool_attribute("\\src", cell->get_strpool_attribute("\\src")); - gate->setPort("\\A", sig_a); - gate->setPort("\\B", sig_b); - gate->setPort("\\Y", sig_y); + gate->add_strpool_attribute(ID(src), cell->get_strpool_attribute(ID(src))); + gate->setPort(ID::A, sig_a); + gate->setPort(ID::B, sig_b); + gate->setPort(ID::Y, sig_y); } void simplemap_eqne(RTLIL::Module *module, RTLIL::Cell *cell) { - RTLIL::SigSpec sig_a = cell->getPort("\\A"); - RTLIL::SigSpec sig_b = cell->getPort("\\B"); - RTLIL::SigSpec sig_y = cell->getPort("\\Y"); - bool is_signed = cell->parameters.at("\\A_SIGNED").as_bool(); - bool is_ne = cell->type == "$ne" || cell->type == "$nex"; + RTLIL::SigSpec sig_a = cell->getPort(ID::A); + RTLIL::SigSpec sig_b = cell->getPort(ID::B); + RTLIL::SigSpec sig_y = cell->getPort(ID::Y); + bool is_signed = cell->parameters.at(ID(A_SIGNED)).as_bool(); + bool is_ne = cell->type.in(ID($ne), ID($nex)); RTLIL::SigSpec xor_out = module->addWire(NEW_ID, max(GetSize(sig_a), GetSize(sig_b))); RTLIL::Cell *xor_cell = module->addXor(NEW_ID, sig_a, sig_b, xor_out, is_signed); - xor_cell->add_strpool_attribute("\\src", cell->get_strpool_attribute("\\src")); + xor_cell->add_strpool_attribute(ID(src), cell->get_strpool_attribute(ID(src))); simplemap_bitop(module, xor_cell); module->remove(xor_cell); RTLIL::SigSpec reduce_out = is_ne ? sig_y : module->addWire(NEW_ID); RTLIL::Cell *reduce_cell = module->addReduceOr(NEW_ID, xor_out, reduce_out); - reduce_cell->add_strpool_attribute("\\src", cell->get_strpool_attribute("\\src")); + reduce_cell->add_strpool_attribute(ID(src), cell->get_strpool_attribute(ID(src))); simplemap_reduce(module, reduce_cell); module->remove(reduce_cell); if (!is_ne) { RTLIL::Cell *not_cell = module->addLogicNot(NEW_ID, reduce_out, sig_y); - not_cell->add_strpool_attribute("\\src", cell->get_strpool_attribute("\\src")); + not_cell->add_strpool_attribute(ID(src), cell->get_strpool_attribute(ID(src))); simplemap_lognot(module, not_cell); module->remove(not_cell); } @@ -269,65 +269,65 @@ void simplemap_eqne(RTLIL::Module *module, RTLIL::Cell *cell) void simplemap_mux(RTLIL::Module *module, RTLIL::Cell *cell) { - RTLIL::SigSpec sig_a = cell->getPort("\\A"); - RTLIL::SigSpec sig_b = cell->getPort("\\B"); - RTLIL::SigSpec sig_y = cell->getPort("\\Y"); + RTLIL::SigSpec sig_a = cell->getPort(ID::A); + RTLIL::SigSpec sig_b = cell->getPort(ID::B); + RTLIL::SigSpec sig_y = cell->getPort(ID::Y); for (int i = 0; i < GetSize(sig_y); i++) { - RTLIL::Cell *gate = module->addCell(NEW_ID, "$_MUX_"); - gate->add_strpool_attribute("\\src", cell->get_strpool_attribute("\\src")); - gate->setPort("\\A", sig_a[i]); - gate->setPort("\\B", sig_b[i]); - gate->setPort("\\S", cell->getPort("\\S")); - gate->setPort("\\Y", sig_y[i]); + RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_MUX_)); + gate->add_strpool_attribute(ID(src), cell->get_strpool_attribute(ID(src))); + gate->setPort(ID::A, sig_a[i]); + gate->setPort(ID::B, sig_b[i]); + gate->setPort(ID(S), cell->getPort(ID(S))); + gate->setPort(ID::Y, sig_y[i]); } } void simplemap_tribuf(RTLIL::Module *module, RTLIL::Cell *cell) { - RTLIL::SigSpec sig_a = cell->getPort("\\A"); - RTLIL::SigSpec sig_e = cell->getPort("\\EN"); - RTLIL::SigSpec sig_y = cell->getPort("\\Y"); + RTLIL::SigSpec sig_a = cell->getPort(ID::A); + RTLIL::SigSpec sig_e = cell->getPort(ID(EN)); + RTLIL::SigSpec sig_y = cell->getPort(ID::Y); for (int i = 0; i < GetSize(sig_y); i++) { - RTLIL::Cell *gate = module->addCell(NEW_ID, "$_TBUF_"); - gate->add_strpool_attribute("\\src", cell->get_strpool_attribute("\\src")); - gate->setPort("\\A", sig_a[i]); - gate->setPort("\\E", sig_e); - gate->setPort("\\Y", sig_y[i]); + RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_TBUF_)); + gate->add_strpool_attribute(ID(src), cell->get_strpool_attribute(ID(src))); + gate->setPort(ID::A, sig_a[i]); + gate->setPort(ID(E), sig_e); + gate->setPort(ID::Y, sig_y[i]); } } void simplemap_lut(RTLIL::Module *module, RTLIL::Cell *cell) { - SigSpec lut_ctrl = cell->getPort("\\A"); - SigSpec lut_data = cell->getParam("\\LUT"); - lut_data.extend_u0(1 << cell->getParam("\\WIDTH").as_int()); + SigSpec lut_ctrl = cell->getPort(ID::A); + SigSpec lut_data = cell->getParam(ID(LUT)); + lut_data.extend_u0(1 << cell->getParam(ID(WIDTH)).as_int()); for (int idx = 0; GetSize(lut_data) > 1; idx++) { SigSpec sig_s = lut_ctrl[idx]; SigSpec new_lut_data = module->addWire(NEW_ID, GetSize(lut_data)/2); for (int i = 0; i < GetSize(lut_data); i += 2) { - RTLIL::Cell *gate = module->addCell(NEW_ID, "$_MUX_"); - gate->add_strpool_attribute("\\src", cell->get_strpool_attribute("\\src")); - gate->setPort("\\A", lut_data[i]); - gate->setPort("\\B", lut_data[i+1]); - gate->setPort("\\S", lut_ctrl[idx]); - gate->setPort("\\Y", new_lut_data[i/2]); + RTLIL::Cell *gate = module->addCell(NEW_ID, ID($_MUX_)); + gate->add_strpool_attribute(ID(src), cell->get_strpool_attribute(ID(src))); + gate->setPort(ID::A, lut_data[i]); + gate->setPort(ID::B, lut_data[i+1]); + gate->setPort(ID(S), lut_ctrl[idx]); + gate->setPort(ID::Y, new_lut_data[i/2]); } lut_data = new_lut_data; } - module->connect(cell->getPort("\\Y"), lut_data); + module->connect(cell->getPort(ID::Y), lut_data); } void simplemap_sop(RTLIL::Module *module, RTLIL::Cell *cell) { - SigSpec ctrl = cell->getPort("\\A"); - SigSpec table = cell->getParam("\\TABLE"); + SigSpec ctrl = cell->getPort(ID::A); + SigSpec table = cell->getParam(ID(TABLE)); - int width = cell->getParam("\\WIDTH").as_int(); - int depth = cell->getParam("\\DEPTH").as_int(); + int width = cell->getParam(ID(WIDTH)).as_int(); + int depth = cell->getParam(ID(DEPTH)).as_int(); table.extend_u0(2 * width * depth); SigSpec products; @@ -348,213 +348,213 @@ void simplemap_sop(RTLIL::Module *module, RTLIL::Cell *cell) products.append(GetSize(in) > 0 ? module->Eq(NEW_ID, in, pat) : State::S1); } - module->connect(cell->getPort("\\Y"), module->ReduceOr(NEW_ID, products)); + module->connect(cell->getPort(ID::Y), module->ReduceOr(NEW_ID, products)); } void simplemap_slice(RTLIL::Module *module, RTLIL::Cell *cell) { - int offset = cell->parameters.at("\\OFFSET").as_int(); - RTLIL::SigSpec sig_a = cell->getPort("\\A"); - RTLIL::SigSpec sig_y = cell->getPort("\\Y"); + int offset = cell->parameters.at(ID(OFFSET)).as_int(); + RTLIL::SigSpec sig_a = cell->getPort(ID::A); + RTLIL::SigSpec sig_y = cell->getPort(ID::Y); module->connect(RTLIL::SigSig(sig_y, sig_a.extract(offset, sig_y.size()))); } void simplemap_concat(RTLIL::Module *module, RTLIL::Cell *cell) { - RTLIL::SigSpec sig_ab = cell->getPort("\\A"); - sig_ab.append(cell->getPort("\\B")); - RTLIL::SigSpec sig_y = cell->getPort("\\Y"); + RTLIL::SigSpec sig_ab = cell->getPort(ID::A); + sig_ab.append(cell->getPort(ID::B)); + RTLIL::SigSpec sig_y = cell->getPort(ID::Y); module->connect(RTLIL::SigSig(sig_y, sig_ab)); } void simplemap_sr(RTLIL::Module *module, RTLIL::Cell *cell) { - int width = cell->parameters.at("\\WIDTH").as_int(); - char set_pol = cell->parameters.at("\\SET_POLARITY").as_bool() ? 'P' : 'N'; - char clr_pol = cell->parameters.at("\\CLR_POLARITY").as_bool() ? 'P' : 'N'; + int width = cell->parameters.at(ID(WIDTH)).as_int(); + char set_pol = cell->parameters.at(ID(SET_POLARITY)).as_bool() ? 'P' : 'N'; + char clr_pol = cell->parameters.at(ID(CLR_POLARITY)).as_bool() ? 'P' : 'N'; - RTLIL::SigSpec sig_s = cell->getPort("\\SET"); - RTLIL::SigSpec sig_r = cell->getPort("\\CLR"); - RTLIL::SigSpec sig_q = cell->getPort("\\Q"); + RTLIL::SigSpec sig_s = cell->getPort(ID(SET)); + RTLIL::SigSpec sig_r = cell->getPort(ID(CLR)); + RTLIL::SigSpec sig_q = cell->getPort(ID(Q)); std::string gate_type = stringf("$_SR_%c%c_", set_pol, clr_pol); for (int i = 0; i < width; i++) { RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type); - gate->add_strpool_attribute("\\src", cell->get_strpool_attribute("\\src")); - gate->setPort("\\S", sig_s[i]); - gate->setPort("\\R", sig_r[i]); - gate->setPort("\\Q", sig_q[i]); + gate->add_strpool_attribute(ID(src), cell->get_strpool_attribute(ID(src))); + gate->setPort(ID(S), sig_s[i]); + gate->setPort(ID(R), sig_r[i]); + gate->setPort(ID(Q), sig_q[i]); } } void simplemap_ff(RTLIL::Module *module, RTLIL::Cell *cell) { - int width = cell->parameters.at("\\WIDTH").as_int(); + int width = cell->parameters.at(ID(WIDTH)).as_int(); - RTLIL::SigSpec sig_d = cell->getPort("\\D"); - RTLIL::SigSpec sig_q = cell->getPort("\\Q"); + RTLIL::SigSpec sig_d = cell->getPort(ID(D)); + RTLIL::SigSpec sig_q = cell->getPort(ID(Q)); - std::string gate_type = "$_FF_"; + IdString gate_type = ID($_FF_); for (int i = 0; i < width; i++) { RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type); - gate->add_strpool_attribute("\\src", cell->get_strpool_attribute("\\src")); - gate->setPort("\\D", sig_d[i]); - gate->setPort("\\Q", sig_q[i]); + gate->add_strpool_attribute(ID(src), cell->get_strpool_attribute(ID(src))); + gate->setPort(ID(D), sig_d[i]); + gate->setPort(ID(Q), sig_q[i]); } } void simplemap_dff(RTLIL::Module *module, RTLIL::Cell *cell) { - int width = cell->parameters.at("\\WIDTH").as_int(); - char clk_pol = cell->parameters.at("\\CLK_POLARITY").as_bool() ? 'P' : 'N'; + int width = cell->parameters.at(ID(WIDTH)).as_int(); + char clk_pol = cell->parameters.at(ID(CLK_POLARITY)).as_bool() ? 'P' : 'N'; - RTLIL::SigSpec sig_clk = cell->getPort("\\CLK"); - RTLIL::SigSpec sig_d = cell->getPort("\\D"); - RTLIL::SigSpec sig_q = cell->getPort("\\Q"); + RTLIL::SigSpec sig_clk = cell->getPort(ID(CLK)); + RTLIL::SigSpec sig_d = cell->getPort(ID(D)); + RTLIL::SigSpec sig_q = cell->getPort(ID(Q)); - std::string gate_type = stringf("$_DFF_%c_", clk_pol); + IdString gate_type = stringf("$_DFF_%c_", clk_pol); for (int i = 0; i < width; i++) { RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type); - gate->add_strpool_attribute("\\src", cell->get_strpool_attribute("\\src")); - gate->setPort("\\C", sig_clk); - gate->setPort("\\D", sig_d[i]); - gate->setPort("\\Q", sig_q[i]); + gate->add_strpool_attribute(ID(src), cell->get_strpool_attribute(ID(src))); + gate->setPort(ID(C), sig_clk); + gate->setPort(ID(D), sig_d[i]); + gate->setPort(ID(Q), sig_q[i]); } } void simplemap_dffe(RTLIL::Module *module, RTLIL::Cell *cell) { - int width = cell->parameters.at("\\WIDTH").as_int(); - char clk_pol = cell->parameters.at("\\CLK_POLARITY").as_bool() ? 'P' : 'N'; - char en_pol = cell->parameters.at("\\EN_POLARITY").as_bool() ? 'P' : 'N'; + int width = cell->parameters.at(ID(WIDTH)).as_int(); + char clk_pol = cell->parameters.at(ID(CLK_POLARITY)).as_bool() ? 'P' : 'N'; + char en_pol = cell->parameters.at(ID(EN_POLARITY)).as_bool() ? 'P' : 'N'; - RTLIL::SigSpec sig_clk = cell->getPort("\\CLK"); - RTLIL::SigSpec sig_en = cell->getPort("\\EN"); - RTLIL::SigSpec sig_d = cell->getPort("\\D"); - RTLIL::SigSpec sig_q = cell->getPort("\\Q"); + RTLIL::SigSpec sig_clk = cell->getPort(ID(CLK)); + RTLIL::SigSpec sig_en = cell->getPort(ID(EN)); + RTLIL::SigSpec sig_d = cell->getPort(ID(D)); + RTLIL::SigSpec sig_q = cell->getPort(ID(Q)); - std::string gate_type = stringf("$_DFFE_%c%c_", clk_pol, en_pol); + IdString gate_type = stringf("$_DFFE_%c%c_", clk_pol, en_pol); for (int i = 0; i < width; i++) { RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type); - gate->add_strpool_attribute("\\src", cell->get_strpool_attribute("\\src")); - gate->setPort("\\C", sig_clk); - gate->setPort("\\E", sig_en); - gate->setPort("\\D", sig_d[i]); - gate->setPort("\\Q", sig_q[i]); + gate->add_strpool_attribute(ID(src), cell->get_strpool_attribute(ID(src))); + gate->setPort(ID(C), sig_clk); + gate->setPort(ID(E), sig_en); + gate->setPort(ID(D), sig_d[i]); + gate->setPort(ID(Q), sig_q[i]); } } void simplemap_dffsr(RTLIL::Module *module, RTLIL::Cell *cell) { - int width = cell->parameters.at("\\WIDTH").as_int(); - char clk_pol = cell->parameters.at("\\CLK_POLARITY").as_bool() ? 'P' : 'N'; - char set_pol = cell->parameters.at("\\SET_POLARITY").as_bool() ? 'P' : 'N'; - char clr_pol = cell->parameters.at("\\CLR_POLARITY").as_bool() ? 'P' : 'N'; + int width = cell->parameters.at(ID(WIDTH)).as_int(); + char clk_pol = cell->parameters.at(ID(CLK_POLARITY)).as_bool() ? 'P' : 'N'; + char set_pol = cell->parameters.at(ID(SET_POLARITY)).as_bool() ? 'P' : 'N'; + char clr_pol = cell->parameters.at(ID(CLR_POLARITY)).as_bool() ? 'P' : 'N'; - RTLIL::SigSpec sig_clk = cell->getPort("\\CLK"); - RTLIL::SigSpec sig_s = cell->getPort("\\SET"); - RTLIL::SigSpec sig_r = cell->getPort("\\CLR"); - RTLIL::SigSpec sig_d = cell->getPort("\\D"); - RTLIL::SigSpec sig_q = cell->getPort("\\Q"); + RTLIL::SigSpec sig_clk = cell->getPort(ID(CLK)); + RTLIL::SigSpec sig_s = cell->getPort(ID(SET)); + RTLIL::SigSpec sig_r = cell->getPort(ID(CLR)); + RTLIL::SigSpec sig_d = cell->getPort(ID(D)); + RTLIL::SigSpec sig_q = cell->getPort(ID(Q)); - std::string gate_type = stringf("$_DFFSR_%c%c%c_", clk_pol, set_pol, clr_pol); + IdString gate_type = stringf("$_DFFSR_%c%c%c_", clk_pol, set_pol, clr_pol); for (int i = 0; i < width; i++) { RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type); - gate->add_strpool_attribute("\\src", cell->get_strpool_attribute("\\src")); - gate->setPort("\\C", sig_clk); - gate->setPort("\\S", sig_s[i]); - gate->setPort("\\R", sig_r[i]); - gate->setPort("\\D", sig_d[i]); - gate->setPort("\\Q", sig_q[i]); + gate->add_strpool_attribute(ID(src), cell->get_strpool_attribute(ID(src))); + gate->setPort(ID(C), sig_clk); + gate->setPort(ID(S), sig_s[i]); + gate->setPort(ID(R), sig_r[i]); + gate->setPort(ID(D), sig_d[i]); + gate->setPort(ID(Q), sig_q[i]); } } void simplemap_adff(RTLIL::Module *module, RTLIL::Cell *cell) { - int width = cell->parameters.at("\\WIDTH").as_int(); - char clk_pol = cell->parameters.at("\\CLK_POLARITY").as_bool() ? 'P' : 'N'; - char rst_pol = cell->parameters.at("\\ARST_POLARITY").as_bool() ? 'P' : 'N'; + int width = cell->parameters.at(ID(WIDTH)).as_int(); + char clk_pol = cell->parameters.at(ID(CLK_POLARITY)).as_bool() ? 'P' : 'N'; + char rst_pol = cell->parameters.at(ID(ARST_POLARITY)).as_bool() ? 'P' : 'N'; - std::vector<RTLIL::State> rst_val = cell->parameters.at("\\ARST_VALUE").bits; + std::vector<RTLIL::State> rst_val = cell->parameters.at(ID(ARST_VALUE)).bits; while (int(rst_val.size()) < width) rst_val.push_back(RTLIL::State::S0); - RTLIL::SigSpec sig_clk = cell->getPort("\\CLK"); - RTLIL::SigSpec sig_rst = cell->getPort("\\ARST"); - RTLIL::SigSpec sig_d = cell->getPort("\\D"); - RTLIL::SigSpec sig_q = cell->getPort("\\Q"); + RTLIL::SigSpec sig_clk = cell->getPort(ID(CLK)); + RTLIL::SigSpec sig_rst = cell->getPort(ID(ARST)); + RTLIL::SigSpec sig_d = cell->getPort(ID(D)); + RTLIL::SigSpec sig_q = cell->getPort(ID(Q)); - std::string gate_type_0 = stringf("$_DFF_%c%c0_", clk_pol, rst_pol); - std::string gate_type_1 = stringf("$_DFF_%c%c1_", clk_pol, rst_pol); + IdString gate_type_0 = stringf("$_DFF_%c%c0_", clk_pol, rst_pol); + IdString gate_type_1 = stringf("$_DFF_%c%c1_", clk_pol, rst_pol); for (int i = 0; i < width; i++) { RTLIL::Cell *gate = module->addCell(NEW_ID, rst_val.at(i) == RTLIL::State::S1 ? gate_type_1 : gate_type_0); - gate->add_strpool_attribute("\\src", cell->get_strpool_attribute("\\src")); - gate->setPort("\\C", sig_clk); - gate->setPort("\\R", sig_rst); - gate->setPort("\\D", sig_d[i]); - gate->setPort("\\Q", sig_q[i]); + gate->add_strpool_attribute(ID(src), cell->get_strpool_attribute(ID(src))); + gate->setPort(ID(C), sig_clk); + gate->setPort(ID(R), sig_rst); + gate->setPort(ID(D), sig_d[i]); + gate->setPort(ID(Q), sig_q[i]); } } void simplemap_dlatch(RTLIL::Module *module, RTLIL::Cell *cell) { - int width = cell->parameters.at("\\WIDTH").as_int(); - char en_pol = cell->parameters.at("\\EN_POLARITY").as_bool() ? 'P' : 'N'; + int width = cell->parameters.at(ID(WIDTH)).as_int(); + char en_pol = cell->parameters.at(ID(EN_POLARITY)).as_bool() ? 'P' : 'N'; - RTLIL::SigSpec sig_en = cell->getPort("\\EN"); - RTLIL::SigSpec sig_d = cell->getPort("\\D"); - RTLIL::SigSpec sig_q = cell->getPort("\\Q"); + RTLIL::SigSpec sig_en = cell->getPort(ID(EN)); + RTLIL::SigSpec sig_d = cell->getPort(ID(D)); + RTLIL::SigSpec sig_q = cell->getPort(ID(Q)); - std::string gate_type = stringf("$_DLATCH_%c_", en_pol); + IdString gate_type = stringf("$_DLATCH_%c_", en_pol); for (int i = 0; i < width; i++) { RTLIL::Cell *gate = module->addCell(NEW_ID, gate_type); - gate->add_strpool_attribute("\\src", cell->get_strpool_attribute("\\src")); - gate->setPort("\\E", sig_en); - gate->setPort("\\D", sig_d[i]); - gate->setPort("\\Q", sig_q[i]); + gate->add_strpool_attribute(ID(src), cell->get_strpool_attribute(ID(src))); + gate->setPort(ID(E), sig_en); + gate->setPort(ID(D), sig_d[i]); + gate->setPort(ID(Q), sig_q[i]); } } void simplemap_get_mappers(std::map<RTLIL::IdString, void(*)(RTLIL::Module*, RTLIL::Cell*)> &mappers) { - mappers["$not"] = simplemap_not; - mappers["$pos"] = simplemap_pos; - mappers["$and"] = simplemap_bitop; - mappers["$or"] = simplemap_bitop; - mappers["$xor"] = simplemap_bitop; - mappers["$xnor"] = simplemap_bitop; - mappers["$reduce_and"] = simplemap_reduce; - mappers["$reduce_or"] = simplemap_reduce; - mappers["$reduce_xor"] = simplemap_reduce; - mappers["$reduce_xnor"] = simplemap_reduce; - mappers["$reduce_bool"] = simplemap_reduce; - mappers["$logic_not"] = simplemap_lognot; - mappers["$logic_and"] = simplemap_logbin; - mappers["$logic_or"] = simplemap_logbin; - mappers["$eq"] = simplemap_eqne; - mappers["$eqx"] = simplemap_eqne; - mappers["$ne"] = simplemap_eqne; - mappers["$nex"] = simplemap_eqne; - mappers["$mux"] = simplemap_mux; - mappers["$tribuf"] = simplemap_tribuf; - mappers["$lut"] = simplemap_lut; - mappers["$sop"] = simplemap_sop; - mappers["$slice"] = simplemap_slice; - mappers["$concat"] = simplemap_concat; - mappers["$sr"] = simplemap_sr; - mappers["$ff"] = simplemap_ff; - mappers["$dff"] = simplemap_dff; - mappers["$dffe"] = simplemap_dffe; - mappers["$dffsr"] = simplemap_dffsr; - mappers["$adff"] = simplemap_adff; - mappers["$dlatch"] = simplemap_dlatch; + mappers[ID($not)] = simplemap_not; + mappers[ID($pos)] = simplemap_pos; + mappers[ID($and)] = simplemap_bitop; + mappers[ID($or)] = simplemap_bitop; + mappers[ID($xor)] = simplemap_bitop; + mappers[ID($xnor)] = simplemap_bitop; + mappers[ID($reduce_and)] = simplemap_reduce; + mappers[ID($reduce_or)] = simplemap_reduce; + mappers[ID($reduce_xor)] = simplemap_reduce; + mappers[ID($reduce_xnor)] = simplemap_reduce; + mappers[ID($reduce_bool)] = simplemap_reduce; + mappers[ID($logic_not)] = simplemap_lognot; + mappers[ID($logic_and)] = simplemap_logbin; + mappers[ID($logic_or)] = simplemap_logbin; + mappers[ID($eq)] = simplemap_eqne; + mappers[ID($eqx)] = simplemap_eqne; + mappers[ID($ne)] = simplemap_eqne; + mappers[ID($nex)] = simplemap_eqne; + mappers[ID($mux)] = simplemap_mux; + mappers[ID($tribuf)] = simplemap_tribuf; + mappers[ID($lut)] = simplemap_lut; + mappers[ID($sop)] = simplemap_sop; + mappers[ID($slice)] = simplemap_slice; + mappers[ID($concat)] = simplemap_concat; + mappers[ID($sr)] = simplemap_sr; + mappers[ID($ff)] = simplemap_ff; + mappers[ID($dff)] = simplemap_dff; + mappers[ID($dffe)] = simplemap_dffe; + mappers[ID($dffsr)] = simplemap_dffsr; + mappers[ID($adff)] = simplemap_adff; + mappers[ID($dlatch)] = simplemap_dlatch; } void simplemap(RTLIL::Module *module, RTLIL::Cell *cell) @@ -575,7 +575,7 @@ PRIVATE_NAMESPACE_BEGIN struct SimplemapPass : public Pass { SimplemapPass() : Pass("simplemap", "mapping simple coarse-grain cells") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -590,7 +590,7 @@ struct SimplemapPass : public Pass { log(" $sr, $ff, $dff, $dffsr, $adff, $dlatch\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing SIMPLEMAP pass (map simple cells to gate primitives).\n"); extra_args(args, 1, design); @@ -599,7 +599,7 @@ struct SimplemapPass : public Pass { simplemap_get_mappers(mappers); for (auto mod : design->modules()) { - if (!design->selected(mod)) + if (!design->selected(mod) || mod->get_blackbox_attribute()) continue; std::vector<RTLIL::Cell*> cells = mod->cells(); for (auto cell : cells) { diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index 1908ae8b5..1d0362ad6 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -39,20 +39,20 @@ YOSYS_NAMESPACE_END USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN -void apply_prefix(std::string prefix, std::string &id) +void apply_prefix(IdString prefix, IdString &id) { if (id[0] == '\\') - id = prefix + "." + id.substr(1); + id = stringf("%s.%s", prefix.c_str(), id.c_str()+1); else - id = "$techmap" + prefix + "." + id; + id = stringf("$techmap%s.%s", prefix.c_str(), id.c_str()); } -void apply_prefix(std::string prefix, RTLIL::SigSpec &sig, RTLIL::Module *module) +void apply_prefix(IdString prefix, RTLIL::SigSpec &sig, RTLIL::Module *module) { vector<SigChunk> chunks = sig; for (auto &chunk : chunks) if (chunk.wire != NULL) { - std::string wire_name = chunk.wire->name.str(); + IdString wire_name = chunk.wire->name; apply_prefix(prefix, wire_name); log_assert(module->wires_.count(wire_name) > 0); chunk.wire = module->wires_[wire_name]; @@ -72,6 +72,8 @@ struct TechmapWorker pool<IdString> flatten_done_list; pool<Cell*> flatten_keep_list; + pool<string> log_msg_cache; + struct TechmapWireData { RTLIL::Wire *wire; RTLIL::SigSpec value; @@ -84,6 +86,7 @@ struct TechmapWorker bool flatten_mode; bool recursive_mode; bool autoproc_mode; + bool ignore_wb; TechmapWorker() { @@ -92,6 +95,7 @@ struct TechmapWorker flatten_mode = false; recursive_mode = false; autoproc_mode = false; + ignore_wb = false; } std::string constmap_tpl_name(SigMap &sigmap, RTLIL::Module *tpl, RTLIL::Cell *cell, bool verbose) @@ -141,8 +145,8 @@ struct TechmapWorker record.wire = it.second; record.value = it.second; result[p].push_back(record); - it.second->attributes["\\keep"] = RTLIL::Const(1); - it.second->attributes["\\_techmap_special_"] = RTLIL::Const(1); + it.second->attributes[ID::keep] = RTLIL::Const(1); + it.second->attributes[ID(_techmap_special_)] = RTLIL::Const(1); } } @@ -171,11 +175,11 @@ struct TechmapWorker } std::string orig_cell_name; - pool<string> extra_src_attrs = cell->get_strpool_attribute("\\src"); + pool<string> extra_src_attrs = cell->get_strpool_attribute(ID(src)); if (!flatten_mode) { for (auto &it : tpl->cells_) - if (it.first == "\\_TECHMAP_REPLACE_") { + if (it.first == ID(_TECHMAP_REPLACE_)) { orig_cell_name = cell->name.str(); module->rename(cell, stringf("$techmap%d", autoidx++) + cell->name.str()); break; @@ -185,36 +189,73 @@ struct TechmapWorker dict<IdString, IdString> memory_renames; for (auto &it : tpl->memories) { - std::string m_name = it.first.str(); - apply_prefix(cell->name.str(), m_name); + IdString m_name = it.first; + apply_prefix(cell->name, m_name); RTLIL::Memory *m = new RTLIL::Memory; m->name = m_name; m->width = it.second->width; m->start_offset = it.second->start_offset; m->size = it.second->size; m->attributes = it.second->attributes; - if (m->attributes.count("\\src")) - m->add_strpool_attribute("\\src", extra_src_attrs); + if (m->attributes.count(ID(src))) + m->add_strpool_attribute(ID(src), extra_src_attrs); module->memories[m->name] = m; memory_renames[it.first] = m->name; design->select(module, m); } std::map<RTLIL::IdString, RTLIL::IdString> positional_ports; + dict<Wire*, IdString> temp_renamed_wires; + pool<SigBit> autopurge_tpl_bits; - for (auto &it : tpl->wires_) { + for (auto &it : tpl->wires_) + { if (it.second->port_id > 0) - positional_ports[stringf("$%d", it.second->port_id)] = it.first; - std::string w_name = it.second->name.str(); - apply_prefix(cell->name.str(), w_name); - RTLIL::Wire *w = module->addWire(w_name, it.second); - w->port_input = false; - w->port_output = false; - w->port_id = 0; - if (it.second->get_bool_attribute("\\_techmap_special_")) - w->attributes.clear(); - if (w->attributes.count("\\src")) - w->add_strpool_attribute("\\src", extra_src_attrs); + { + IdString posportname = stringf("$%d", it.second->port_id); + positional_ports[posportname] = it.first; + + if (!flatten_mode && it.second->get_bool_attribute(ID(techmap_autopurge)) && + (!cell->hasPort(it.second->name) || !GetSize(cell->getPort(it.second->name))) && + (!cell->hasPort(posportname) || !GetSize(cell->getPort(posportname)))) + { + if (sigmaps.count(tpl) == 0) + sigmaps[tpl].set(tpl); + + for (auto bit : sigmaps.at(tpl)(it.second)) + if (bit.wire != nullptr) + autopurge_tpl_bits.insert(bit); + } + } + IdString w_name = it.second->name; + apply_prefix(cell->name, w_name); + RTLIL::Wire *w = module->wire(w_name); + if (w != nullptr) { + if (!flatten_mode || !w->get_bool_attribute(ID(hierconn))) { + temp_renamed_wires[w] = w->name; + module->rename(w, NEW_ID); + w = nullptr; + } else { + w->attributes.erase(ID(hierconn)); + if (GetSize(w) < GetSize(it.second)) { + log_warning("Widening signal %s.%s to match size of %s.%s (via %s.%s).\n", log_id(module), log_id(w), + log_id(tpl), log_id(it.second), log_id(module), log_id(cell)); + w->width = GetSize(it.second); + } + } + } + if (w == nullptr) { + w = module->addWire(w_name, it.second); + w->port_input = false; + w->port_output = false; + w->port_id = 0; + if (!flatten_mode) + w->attributes.erase(ID(techmap_autopurge)); + if (it.second->get_bool_attribute(ID(_techmap_special_))) + w->attributes.clear(); + if (w->attributes.count(ID(src))) + w->add_strpool_attribute(ID(src), extra_src_attrs); + } design->select(module, w); } @@ -239,7 +280,7 @@ struct TechmapWorker if (positional_ports.count(portname) > 0) portname = positional_ports.at(portname); if (tpl->wires_.count(portname) == 0 || tpl->wires_.at(portname)->port_id == 0) { - if (portname.substr(0, 1) == "$") + if (portname.begins_with("$")) log_error("Can't map port `%s' of cell `%s' to template `%s'!\n", portname.c_str(), cell->name.c_str(), tpl->name.c_str()); continue; } @@ -253,18 +294,18 @@ struct TechmapWorker if (w->port_output && !w->port_input) { c.first = it.second; c.second = RTLIL::SigSpec(w); - apply_prefix(cell->name.str(), c.second, module); + apply_prefix(cell->name, c.second, module); extra_connect.first = c.second; extra_connect.second = c.first; } else if (!w->port_output && w->port_input) { c.first = RTLIL::SigSpec(w); c.second = it.second; - apply_prefix(cell->name.str(), c.first, module); + apply_prefix(cell->name, c.first, module); extra_connect.first = c.first; extra_connect.second = c.second; } else { SigSpec sig_tpl = w, sig_tpl_pf = w, sig_mod = it.second; - apply_prefix(cell->name.str(), sig_tpl_pf, module); + apply_prefix(cell->name, sig_tpl_pf, module); for (int i = 0; i < GetSize(sig_tpl) && i < GetSize(sig_mod); i++) { if (tpl_written_bits.count(tpl_sigmap(sig_tpl[i]))) { c.first.append(sig_mod[i]); @@ -316,8 +357,14 @@ struct TechmapWorker } for (auto &attr : w->attributes) { - if (attr.first == "\\src") + if (attr.first == ID(src)) continue; + auto lhs = GetSize(extra_connect.first); + auto rhs = GetSize(extra_connect.second); + if (lhs > rhs) + extra_connect.first.remove(rhs, lhs-rhs); + else if (rhs > lhs) + extra_connect.second.remove(lhs, rhs-lhs); module->connect(extra_connect); break; } @@ -326,39 +373,59 @@ struct TechmapWorker for (auto &it : tpl->cells_) { - std::string c_name = it.second->name.str(); - bool techmap_replace_cell = (!flatten_mode) && (c_name == "\\_TECHMAP_REPLACE_"); + IdString c_name = it.second->name.str(); + bool techmap_replace_cell = (!flatten_mode) && (c_name == ID(_TECHMAP_REPLACE_)); if (techmap_replace_cell) c_name = orig_cell_name; else - apply_prefix(cell->name.str(), c_name); + apply_prefix(cell->name, c_name); RTLIL::Cell *c = module->addCell(c_name, it.second); design->select(module, c); - if (!flatten_mode && c->type.substr(0, 2) == "\\$") + if (!flatten_mode && c->type.begins_with("\\$")) c->type = c->type.substr(1); - for (auto &it2 : c->connections_) { - apply_prefix(cell->name.str(), it2.second, module); - port_signal_map.apply(it2.second); + vector<IdString> autopurge_ports; + + for (auto &it2 : c->connections_) + { + bool autopurge = false; + if (!autopurge_tpl_bits.empty()) { + autopurge = GetSize(it2.second) != 0; + for (auto &bit : sigmaps.at(tpl)(it2.second)) + if (!autopurge_tpl_bits.count(bit)) { + autopurge = false; + break; + } + } + + if (autopurge) { + autopurge_ports.push_back(it2.first); + } else { + apply_prefix(cell->name, it2.second, module); + port_signal_map.apply(it2.second); + } } - if (c->type == "$memrd" || c->type == "$memwr" || c->type == "$meminit") { - IdString memid = c->getParam("\\MEMID").decode_string(); + for (auto &it2 : autopurge_ports) + c->unsetPort(it2); + + if (c->type.in(ID($memrd), ID($memwr), ID($meminit))) { + IdString memid = c->getParam(ID(MEMID)).decode_string(); log_assert(memory_renames.count(memid) != 0); - c->setParam("\\MEMID", Const(memory_renames[memid].str())); + c->setParam(ID(MEMID), Const(memory_renames[memid].str())); } - if (c->type == "$mem") { - string memid = c->getParam("\\MEMID").decode_string(); - apply_prefix(cell->name.str(), memid); - c->setParam("\\MEMID", Const(memid)); + if (c->type == ID($mem)) { + IdString memid = c->getParam(ID(MEMID)).decode_string(); + apply_prefix(cell->name, memid); + c->setParam(ID(MEMID), Const(memid.c_str())); } - if (c->attributes.count("\\src")) - c->add_strpool_attribute("\\src", extra_src_attrs); + if (c->attributes.count(ID(src))) + c->add_strpool_attribute(ID(src), extra_src_attrs); if (techmap_replace_cell) for (auto attr : cell->attributes) @@ -376,6 +443,16 @@ struct TechmapWorker } module->remove(cell); + + for (auto &it : temp_renamed_wires) + { + Wire *w = it.first; + IdString name = it.second; + IdString altname = module->uniquify(name); + Wire *other_w = module->wire(name); + module->rename(other_w, altname); + module->rename(w, name); + } } bool techmap_module(RTLIL::Design *design, RTLIL::Module *module, RTLIL::Design *map, std::set<RTLIL::Cell*> &handled_cells, @@ -383,14 +460,27 @@ struct TechmapWorker { std::string mapmsg_prefix = in_recursion ? "Recursively mapping" : "Mapping"; - if (!design->selected(module)) + if (!design->selected(module) || module->get_blackbox_attribute(ignore_wb)) return false; bool log_continue = false; bool did_something = false; + LogMakeDebugHdl mkdebug; SigMap sigmap(module); + dict<SigBit, State> init_bits; + pool<SigBit> remove_init_bits; + + for (auto wire : module->wires()) { + if (wire->attributes.count("\\init")) { + Const value = wire->attributes.at("\\init"); + for (int i = 0; i < min(GetSize(value), GetSize(wire)); i++) + if (value[i] != State::Sx) + init_bits[sigmap(SigBit(wire, i))] = value[i]; + } + } + TopoSort<RTLIL::Cell*, RTLIL::IdString::compare_ptr_by_name<RTLIL::Cell>> cells; std::map<RTLIL::Cell*, std::set<RTLIL::SigBit>> cell_to_inbit; std::map<RTLIL::SigBit, std::set<RTLIL::Cell*>> outbit_to_cell; @@ -401,7 +491,7 @@ struct TechmapWorker continue; std::string cell_type = cell->type.str(); - if (in_recursion && cell_type.substr(0, 2) == "\\$") + if (in_recursion && cell->type.begins_with("\\$")) cell_type = cell_type.substr(1); if (celltypeMap.count(cell_type) == 0) { @@ -411,9 +501,9 @@ struct TechmapWorker } if (flatten_mode) { - bool keepit = cell->get_bool_attribute("\\keep_hierarchy"); + bool keepit = cell->get_bool_attribute(ID(keep_hierarchy)); for (auto &tpl_name : celltypeMap.at(cell_type)) - if (map->modules_[tpl_name]->get_bool_attribute("\\keep_hierarchy")) + if (map->modules_[tpl_name]->get_bool_attribute(ID(keep_hierarchy))) keepit = true; if (keepit) { if (!flatten_keep_list[cell]) { @@ -463,7 +553,7 @@ struct TechmapWorker std::string cell_type = cell->type.str(); - if (in_recursion && cell_type.substr(0, 2) == "\\$") + if (in_recursion && cell->type.begins_with("\\$")) cell_type = cell_type.substr(1); for (auto &tpl_name : celltypeMap.at(cell_type)) @@ -472,20 +562,20 @@ struct TechmapWorker RTLIL::Module *tpl = map->modules_[tpl_name]; std::map<RTLIL::IdString, RTLIL::Const> parameters(cell->parameters.begin(), cell->parameters.end()); - if (tpl->get_bool_attribute("\\blackbox")) + if (tpl->get_blackbox_attribute(ignore_wb)) continue; if (!flatten_mode) { std::string extmapper_name; - if (tpl->get_bool_attribute("\\techmap_simplemap")) + if (tpl->get_bool_attribute(ID(techmap_simplemap))) extmapper_name = "simplemap"; - if (tpl->get_bool_attribute("\\techmap_maccmap")) + if (tpl->get_bool_attribute(ID(techmap_maccmap))) extmapper_name = "maccmap"; - if (tpl->attributes.count("\\techmap_wrap")) + if (tpl->attributes.count(ID(techmap_wrap))) extmapper_name = "wrap"; if (!extmapper_name.empty()) @@ -500,7 +590,7 @@ struct TechmapWorker m_name += stringf(":%s=%s", log_id(c.first), log_signal(c.second)); if (extmapper_name == "wrap") - m_name += ":" + sha1(tpl->attributes.at("\\techmap_wrap").decode_string()); + m_name += ":" + sha1(tpl->attributes.at(ID(techmap_wrap)).decode_string()); RTLIL::Design *extmapper_design = extern_mode && !in_recursion ? design : tpl->design; RTLIL::Module *extmapper_module = extmapper_design->module(m_name); @@ -515,7 +605,7 @@ struct TechmapWorker int port_counter = 1; for (auto &c : extmapper_cell->connections_) { RTLIL::Wire *w = extmapper_module->addWire(c.first, GetSize(c.second)); - if (w->name == "\\Y" || w->name == "\\Q") + if (w->name.in(ID::Y, ID(Q))) w->port_output = true; else w->port_input = true; @@ -536,15 +626,16 @@ struct TechmapWorker if (extmapper_name == "maccmap") { log("Creating %s with maccmap.\n", log_id(extmapper_module)); - if (extmapper_cell->type != "$macc") + if (extmapper_cell->type != ID($macc)) log_error("The maccmap mapper can only map $macc (not %s) cells!\n", log_id(extmapper_cell->type)); maccmap(extmapper_module, extmapper_cell); extmapper_module->remove(extmapper_cell); } if (extmapper_name == "wrap") { - std::string cmd_string = tpl->attributes.at("\\techmap_wrap").decode_string(); + std::string cmd_string = tpl->attributes.at(ID(techmap_wrap)).decode_string(); log("Running \"%s\" on wrapper %s.\n", cmd_string.c_str(), log_id(extmapper_module)); + mkdebug.on(); Pass::call_on_module(extmapper_design, extmapper_module, cmd_string); log_continue = true; } @@ -558,11 +649,21 @@ struct TechmapWorker goto use_wrapper_tpl; } - log("%s %s.%s (%s) to %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(cell->type), log_id(extmapper_module)); + auto msg = stringf("Using extmapper %s for cells of type %s.", log_id(extmapper_module), log_id(cell->type)); + if (!log_msg_cache.count(msg)) { + log_msg_cache.insert(msg); + log("%s\n", msg.c_str()); + } + log_debug("%s %s.%s (%s) to %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(cell->type), log_id(extmapper_module)); } else { - log("%s %s.%s (%s) with %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(cell->type), extmapper_name.c_str()); + auto msg = stringf("Using extmapper %s for cells of type %s.", extmapper_name.c_str(), log_id(cell->type)); + if (!log_msg_cache.count(msg)) { + log_msg_cache.insert(msg); + log("%s\n", msg.c_str()); + } + log_debug("%s %s.%s (%s) with %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(cell->type), extmapper_name.c_str()); if (extmapper_name == "simplemap") { if (simplemap_mappers.count(cell->type) == 0) @@ -571,7 +672,7 @@ struct TechmapWorker } if (extmapper_name == "maccmap") { - if (cell->type != "$macc") + if (cell->type != ID($macc)) log_error("The maccmap mapper can only map $macc (not %s) cells!\n", log_id(cell->type)); maccmap(module, cell); } @@ -586,7 +687,7 @@ struct TechmapWorker } for (auto conn : cell->connections()) { - if (conn.first.substr(0, 1) == "$") + if (conn.first.begins_with("$")) continue; if (tpl->wires_.count(conn.first) > 0 && tpl->wires_.at(conn.first)->port_id > 0) continue; @@ -600,8 +701,8 @@ struct TechmapWorker continue; } - if (tpl->avail_parameters.count("\\_TECHMAP_CELLTYPE_") != 0) - parameters["\\_TECHMAP_CELLTYPE_"] = RTLIL::unescape_id(cell->type); + if (tpl->avail_parameters.count(ID(_TECHMAP_CELLTYPE_)) != 0) + parameters[ID(_TECHMAP_CELLTYPE_)] = RTLIL::unescape_id(cell->type); for (auto conn : cell->connections()) { if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONSTMSK_%s_", RTLIL::id2cstr(conn.first))) != 0) { @@ -617,6 +718,17 @@ struct TechmapWorker bit = RTLIL::SigBit(RTLIL::State::Sx); parameters[stringf("\\_TECHMAP_CONSTVAL_%s_", RTLIL::id2cstr(conn.first))] = RTLIL::SigSpec(v).as_const(); } + if (tpl->avail_parameters.count(stringf("\\_TECHMAP_WIREINIT_%s_", RTLIL::id2cstr(conn.first))) != 0) { + auto sig = sigmap(conn.second); + RTLIL::Const value(State::Sx, sig.size()); + for (int i = 0; i < sig.size(); i++) { + auto it = init_bits.find(sig[i]); + if (it != init_bits.end()) { + value[i] = it->second; + } + } + parameters[stringf("\\_TECHMAP_WIREINIT_%s_", RTLIL::id2cstr(conn.first))] = value; + } } int unique_bit_id_counter = 0; @@ -633,12 +745,15 @@ struct TechmapWorker unique_bit_id[bit] = unique_bit_id_counter++; } + // Find highest bit set int bits = 0; for (int i = 0; i < 32; i++) if (((unique_bit_id_counter-1) & (1 << i)) != 0) bits = i; - if (tpl->avail_parameters.count("\\_TECHMAP_BITS_CONNMAP_")) - parameters["\\_TECHMAP_BITS_CONNMAP_"] = bits; + // Increment index by one to get number of bits + bits++; + if (tpl->avail_parameters.count(ID(_TECHMAP_BITS_CONNMAP_))) + parameters[ID(_TECHMAP_BITS_CONNMAP_)] = bits; for (auto conn : cell->connections()) if (tpl->avail_parameters.count(stringf("\\_TECHMAP_CONNMAP_%s_", RTLIL::id2cstr(conn.first))) != 0) { @@ -660,6 +775,7 @@ struct TechmapWorker tpl = techmap_cache[key]; } else { if (parameters.size() != 0) { + mkdebug.on(); derived_name = tpl->derive(map, dict<RTLIL::IdString, RTLIL::Const>(parameters.begin(), parameters.end())); tpl = map->module(derived_name); log_continue = true; @@ -705,7 +821,7 @@ struct TechmapWorker for (auto &it : twd) { - if (it.first.substr(0, 12) != "_TECHMAP_DO_" || it.second.empty()) + if (it.first.compare(0, 12, "_TECHMAP_DO_") != 0 || it.second.empty()) continue; auto &data = it.second.front(); @@ -813,12 +929,25 @@ struct TechmapWorker TechmapWires twd = techmap_find_special_wires(tpl); for (auto &it : twd) { - if (it.first != "_TECHMAP_FAIL_" && it.first.substr(0, 12) != "_TECHMAP_DO_" && it.first.substr(0, 14) != "_TECHMAP_DONE_") + if (it.first != "_TECHMAP_FAIL_" && (it.first.substr(0, 20) != "_TECHMAP_REMOVEINIT_" || it.first[it.first.size()-1] != '_') && it.first.substr(0, 12) != "_TECHMAP_DO_" && it.first.substr(0, 14) != "_TECHMAP_DONE_") log_error("Techmap yielded unknown config wire %s.\n", it.first.c_str()); if (techmap_do_cache[tpl]) for (auto &it2 : it.second) if (!it2.value.is_fully_const()) log_error("Techmap yielded config wire %s with non-const value %s.\n", RTLIL::id2cstr(it2.wire->name), log_signal(it2.value)); + if (it.first.substr(0, 20) == "_TECHMAP_REMOVEINIT_" && techmap_do_cache[tpl]) { + for (auto &it2 : it.second) { + auto val = it2.value.as_const(); + auto wirename = RTLIL::escape_id(it.first.substr(20, it.first.size() - 20 - 1)); + auto it = cell->connections().find(wirename); + if (it != cell->connections().end()) { + auto sig = sigmap(it->second); + for (int i = 0; i < sig.size(); i++) + if (val[i] == State::S1) + remove_init_bits.insert(sig[i]); + } + } + } techmap_wire_names.erase(it.first); } @@ -829,6 +958,7 @@ struct TechmapWorker if (log_continue) { log_header(design, "Continuing TECHMAP pass.\n"); log_continue = false; + mkdebug.off(); } while (techmap_module(map, tpl, map, handled_cells, celltypeMap, true)) { } } @@ -840,6 +970,7 @@ struct TechmapWorker if (log_continue) { log_header(design, "Continuing TECHMAP pass.\n"); log_continue = false; + mkdebug.off(); } if (extern_mode && !in_recursion) @@ -852,20 +983,25 @@ struct TechmapWorker tpl->cloneInto(m); for (auto cell : m->cells()) { - if (cell->type.substr(0, 2) == "\\$") + if (cell->type.begins_with("\\$")) cell->type = cell->type.substr(1); } module_queue.insert(m); } - log("%s %s.%s to imported %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(m_name)); + log_debug("%s %s.%s to imported %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(m_name)); cell->type = m_name; cell->parameters.clear(); } else { - log("%s %s.%s using %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(tpl)); + auto msg = stringf("Using template %s for cells of type %s.", log_id(tpl), log_id(cell->type)); + if (!log_msg_cache.count(msg)) { + log_msg_cache.insert(msg); + log("%s\n", msg.c_str()); + } + log_debug("%s %s.%s (%s) using %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(cell->type), log_id(tpl)); techmap_module_worker(design, module, cell, tpl); cell = NULL; } @@ -880,9 +1016,29 @@ struct TechmapWorker handled_cells.insert(cell); } + if (!remove_init_bits.empty()) { + for (auto wire : module->wires()) + if (wire->attributes.count("\\init")) { + Const &value = wire->attributes.at("\\init"); + bool do_cleanup = true; + for (int i = 0; i < min(GetSize(value), GetSize(wire)); i++) { + SigBit bit = sigmap(SigBit(wire, i)); + if (remove_init_bits.count(bit)) + value[i] = State::Sx; + else if (value[i] != State::Sx) + do_cleanup = false; + } + if (do_cleanup) { + log("Removing init attribute from wire %s.%s.\n", log_id(module), log_id(wire)); + wire->attributes.erase("\\init"); + } + } + } + if (log_continue) { log_header(design, "Continuing TECHMAP pass.\n"); log_continue = false; + mkdebug.off(); } return did_something; @@ -891,7 +1047,7 @@ struct TechmapWorker struct TechmapPass : public Pass { TechmapPass() : Pass("techmap", "generic technology mapper") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -915,7 +1071,8 @@ struct TechmapPass : public Pass { log(" instead of inlining them.\n"); log("\n"); log(" -max_iter <number>\n"); - log(" only run the specified number of iterations.\n"); + log(" only run the specified number of iterations on each module.\n"); + log(" default: unlimited\n"); log("\n"); log(" -recursive\n"); log(" instead of the iterative breadth-first algorithm use a recursive\n"); @@ -925,6 +1082,9 @@ struct TechmapPass : public Pass { log(" -autoproc\n"); log(" Automatically call \"proc\" on implementations that contain processes.\n"); log("\n"); + log(" -wb\n"); + log(" Ignore the 'whitebox' attribute on cell implementations.\n"); + log("\n"); log(" -assert\n"); log(" this option will cause techmap to exit with an error if it can't map\n"); log(" a selected cell. only cell types that end on an underscore are accepted\n"); @@ -949,6 +1109,11 @@ struct TechmapPass : public Pass { log("will create a wrapper for the cell and then run the command string that the\n"); log("attribute is set to on the wrapper module.\n"); log("\n"); + log("When a port on a module in the map file has the 'techmap_autopurge' attribute\n"); + log("set, and that port is not connected in the instantiation that is mapped, then\n"); + log("then a cell port connected only to such wires will be omitted in the mapped\n"); + log("version of the circuit.\n"); + log("\n"); log("All wires in the modules from the map file matching the pattern _TECHMAP_*\n"); log("or *._TECHMAP_* are special wires that are used to pass instructions from\n"); log("the mapping module to the techmap command. At the moment the following special\n"); @@ -987,6 +1152,13 @@ struct TechmapPass : public Pass { log("\n"); log(" It is possible to combine both prefixes to 'RECURSION; CONSTMAP; '.\n"); log("\n"); + log(" _TECHMAP_REMOVEINIT_<port-name>_\n"); + log(" When this wire is set to a constant value, the init attribute of the wire(s)\n"); + log(" connected to this port will be consumed. This wire must have the same\n"); + log(" width as the given port, and for every bit that is set to 1 in the value,\n"); + log(" the corresponding init attribute bit will be changed to 1'bx. If all\n"); + log(" bits of an init attribute are left as x, it will be removed.\n"); + log("\n"); log("In addition to this special wires, techmap also supports special parameters in\n"); log("modules in the map file:\n"); log("\n"); @@ -1000,6 +1172,13 @@ struct TechmapPass : public Pass { log(" former has a 1-bit for each constant input bit and the latter has the\n"); log(" value for this bit. The unused bits of the latter are set to undef (x).\n"); log("\n"); + log(" _TECHMAP_WIREINIT_<port-name>_\n"); + log(" When a parameter with this name exists, it will be set to the initial\n"); + log(" value of the wire(s) connected to the given port, as specified by the init\n"); + log(" attribute. If the attribute doesn't exist, x will be filled for the\n"); + log(" missing bits. To remove the init attribute bits used, use the\n"); + log(" _TECHMAP_REMOVEINIT_*_ wires.\n"); + log("\n"); log(" _TECHMAP_BITS_CONNMAP_\n"); log(" _TECHMAP_CONNMAP_<port-name>_\n"); log(" For an N-bit port, the _TECHMAP_CONNMAP_<port-name>_ parameter, if it\n"); @@ -1022,7 +1201,7 @@ struct TechmapPass : public Pass { log("essentially techmap but using the design itself as map library).\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing TECHMAP pass (map to technology primitives).\n"); log_push(); @@ -1031,7 +1210,7 @@ struct TechmapPass : public Pass { simplemap_get_mappers(worker.simplemap_mappers); std::vector<std::string> map_files; - std::string verilog_frontend = "verilog -nooverwrite"; + std::string verilog_frontend = "verilog -nooverwrite -noblackbox"; int max_iter = -1; size_t argidx; @@ -1068,6 +1247,10 @@ struct TechmapPass : public Pass { worker.autoproc_mode = true; continue; } + if (args[argidx] == "-wb") { + worker.ignore_wb = true; + continue; + } break; } extra_args(args, argidx, design); @@ -1076,9 +1259,9 @@ struct TechmapPass : public Pass { if (map_files.empty()) { std::istringstream f(stdcells_code); Frontend::frontend_call(map, &f, "<techmap.v>", verilog_frontend); - } else + } else { for (auto &fn : map_files) - if (fn.substr(0, 1) == "%") { + if (fn.compare(0, 1, "%") == 0) { if (!saved_designs.count(fn.substr(1))) { delete map; log_cmd_error("Can't saved design `%s'.\n", fn.c_str()+1); @@ -1093,19 +1276,22 @@ struct TechmapPass : public Pass { yosys_input_files.insert(fn); if (f.fail()) log_cmd_error("Can't open map file `%s'\n", fn.c_str()); - Frontend::frontend_call(map, &f, fn, (fn.size() > 3 && fn.substr(fn.size()-3) == ".il") ? "ilang" : verilog_frontend); + Frontend::frontend_call(map, &f, fn, (fn.size() > 3 && fn.compare(fn.size()-3, std::string::npos, ".il") == 0 ? "ilang" : verilog_frontend)); } + } + + log_header(design, "Continuing TECHMAP pass.\n"); std::map<RTLIL::IdString, std::set<RTLIL::IdString, RTLIL::sort_by_id_str>> celltypeMap; for (auto &it : map->modules_) { - if (it.second->attributes.count("\\techmap_celltype") && !it.second->attributes.at("\\techmap_celltype").bits.empty()) { - char *p = strdup(it.second->attributes.at("\\techmap_celltype").decode_string().c_str()); + if (it.second->attributes.count(ID(techmap_celltype)) && !it.second->attributes.at(ID(techmap_celltype)).bits.empty()) { + char *p = strdup(it.second->attributes.at(ID(techmap_celltype)).decode_string().c_str()); for (char *q = strtok(p, " \t\r\n"); q; q = strtok(NULL, " \t\r\n")) celltypeMap[RTLIL::escape_id(q)].insert(it.first); free(p); } else { string module_name = it.first.str(); - if (module_name.substr(0, 2) == "\\$") + if (it.first.begins_with("\\$")) module_name = module_name.substr(1); celltypeMap[module_name].insert(it.first); } @@ -1119,15 +1305,16 @@ struct TechmapPass : public Pass { RTLIL::Module *module = *worker.module_queue.begin(); worker.module_queue.erase(module); + int module_max_iter = max_iter; bool did_something = true; std::set<RTLIL::Cell*> handled_cells; while (did_something) { did_something = false; - if (worker.techmap_module(design, module, map, handled_cells, celltypeMap, false)) - did_something = true; + if (worker.techmap_module(design, module, map, handled_cells, celltypeMap, false)) + did_something = true; if (did_something) module->check(); - if (max_iter > 0 && --max_iter == 0) + if (module_max_iter > 0 && --module_max_iter == 0) break; } } @@ -1141,11 +1328,11 @@ struct TechmapPass : public Pass { struct FlattenPass : public Pass { FlattenPass() : Pass("flatten", "flatten design") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); - log(" flatten [selection]\n"); + log(" flatten [options] [selection]\n"); log("\n"); log("This pass flattens the design by replacing cells by their implementation. This\n"); log("pass is very similar to the 'techmap' pass. The only difference is that this\n"); @@ -1154,17 +1341,29 @@ struct FlattenPass : public Pass { log("Cells and/or modules with the 'keep_hierarchy' attribute set will not be\n"); log("flattened by this command.\n"); log("\n"); + log(" -wb\n"); + log(" Ignore the 'whitebox' attribute on cell implementations.\n"); + log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing FLATTEN pass (flatten design).\n"); log_push(); - extra_args(args, 1, design); - TechmapWorker worker; worker.flatten_mode = true; + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + if (args[argidx] == "-wb") { + worker.ignore_wb = true; + continue; + } + break; + } + extra_args(args, argidx, design); + + std::map<RTLIL::IdString, std::set<RTLIL::IdString, RTLIL::sort_by_id_str>> celltypeMap; for (auto module : design->modules()) celltypeMap[module->name].insert(module->name); @@ -1172,7 +1371,7 @@ struct FlattenPass : public Pass { RTLIL::Module *top_mod = NULL; if (design->full_selection()) for (auto mod : design->modules()) - if (mod->get_bool_attribute("\\top")) + if (mod->get_bool_attribute(ID(top))) top_mod = mod; std::set<RTLIL::Cell*> handled_cells; @@ -1190,6 +1389,7 @@ struct FlattenPass : public Pass { } } + log_suppressed(); log("No more expansions possible.\n"); if (top_mod != NULL) @@ -1209,7 +1409,7 @@ struct FlattenPass : public Pass { dict<RTLIL::IdString, RTLIL::Module*> new_modules; for (auto mod : vector<Module*>(design->modules())) - if (used_modules[mod->name] || mod->get_bool_attribute("\\blackbox")) { + if (used_modules[mod->name] || mod->get_blackbox_attribute(worker.ignore_wb)) { new_modules[mod->name] = mod; } else { log("Deleting now unused module %s.\n", log_id(mod)); diff --git a/passes/techmap/tribuf.cc b/passes/techmap/tribuf.cc index 03629082c..41fdc8f3d 100644 --- a/passes/techmap/tribuf.cc +++ b/passes/techmap/tribuf.cc @@ -63,38 +63,38 @@ struct TribufWorker { for (auto cell : module->selected_cells()) { - if (cell->type == "$tribuf") - tribuf_cells[sigmap(cell->getPort("\\Y"))].push_back(cell); + if (cell->type == ID($tribuf)) + tribuf_cells[sigmap(cell->getPort(ID::Y))].push_back(cell); - if (cell->type == "$_TBUF_") - tribuf_cells[sigmap(cell->getPort("\\Y"))].push_back(cell); + if (cell->type == ID($_TBUF_)) + tribuf_cells[sigmap(cell->getPort(ID::Y))].push_back(cell); - if (cell->type.in("$mux", "$_MUX_")) + if (cell->type.in(ID($mux), ID($_MUX_))) { - IdString en_port = cell->type == "$mux" ? "\\EN" : "\\E"; - IdString tri_type = cell->type == "$mux" ? "$tribuf" : "$_TBUF_"; + IdString en_port = cell->type == ID($mux) ? ID(EN) : ID(E); + IdString tri_type = cell->type == ID($mux) ? ID($tribuf) : ID($_TBUF_); - if (is_all_z(cell->getPort("\\A")) && is_all_z(cell->getPort("\\B"))) { + if (is_all_z(cell->getPort(ID::A)) && is_all_z(cell->getPort(ID::B))) { module->remove(cell); continue; } - if (is_all_z(cell->getPort("\\A"))) { - cell->setPort("\\A", cell->getPort("\\B")); - cell->setPort(en_port, cell->getPort("\\S")); - cell->unsetPort("\\B"); - cell->unsetPort("\\S"); + if (is_all_z(cell->getPort(ID::A))) { + cell->setPort(ID::A, cell->getPort(ID::B)); + cell->setPort(en_port, cell->getPort(ID(S))); + cell->unsetPort(ID::B); + cell->unsetPort(ID(S)); cell->type = tri_type; - tribuf_cells[sigmap(cell->getPort("\\Y"))].push_back(cell); + tribuf_cells[sigmap(cell->getPort(ID::Y))].push_back(cell); continue; } - if (is_all_z(cell->getPort("\\B"))) { - cell->setPort(en_port, module->Not(NEW_ID, cell->getPort("\\S"))); - cell->unsetPort("\\B"); - cell->unsetPort("\\S"); + if (is_all_z(cell->getPort(ID::B))) { + cell->setPort(en_port, module->Not(NEW_ID, cell->getPort(ID(S)))); + cell->unsetPort(ID::B); + cell->unsetPort(ID(S)); cell->type = tri_type; - tribuf_cells[sigmap(cell->getPort("\\Y"))].push_back(cell); + tribuf_cells[sigmap(cell->getPort(ID::Y))].push_back(cell); continue; } } @@ -118,11 +118,11 @@ struct TribufWorker { SigSpec pmux_b, pmux_s; for (auto cell : it.second) { - if (cell->type == "$tribuf") - pmux_s.append(cell->getPort("\\EN")); + if (cell->type == ID($tribuf)) + pmux_s.append(cell->getPort(ID(EN))); else - pmux_s.append(cell->getPort("\\E")); - pmux_b.append(cell->getPort("\\A")); + pmux_s.append(cell->getPort(ID(E))); + pmux_b.append(cell->getPort(ID::A)); module->remove(cell); } @@ -139,7 +139,7 @@ struct TribufWorker { struct TribufPass : public Pass { TribufPass() : Pass("tribuf", "infer tri-state buffers") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -156,7 +156,7 @@ struct TribufPass : public Pass { log(" to non-tristate logic. this option implies -merge.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { TribufConfig config; diff --git a/passes/techmap/zinit.cc b/passes/techmap/zinit.cc index a577e1235..ac3d4ed4a 100644 --- a/passes/techmap/zinit.cc +++ b/passes/techmap/zinit.cc @@ -25,7 +25,7 @@ PRIVATE_NAMESPACE_BEGIN struct ZinitPass : public Pass { ZinitPass() : Pass("zinit", "add inverters so all FF are zero-initialized") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -37,7 +37,7 @@ struct ZinitPass : public Pass { log(" also add zero initialization to uninitialized FFs\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { bool all_mode = false; @@ -46,7 +46,7 @@ struct ZinitPass : public Pass { size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { - if (args[argidx] == "-singleton") { + if (args[argidx] == "-all") { all_mode = true; continue; } @@ -62,12 +62,12 @@ struct ZinitPass : public Pass { for (auto wire : module->selected_wires()) { - if (wire->attributes.count("\\init") == 0) + if (wire->attributes.count(ID(init)) == 0) continue; SigSpec wirebits = sigmap(wire); - Const initval = wire->attributes.at("\\init"); - wire->attributes.erase("\\init"); + Const initval = wire->attributes.at(ID(init)); + wire->attributes.erase(ID(init)); for (int i = 0; i < GetSize(wirebits) && i < GetSize(initval); i++) { @@ -90,12 +90,12 @@ struct ZinitPass : public Pass { } pool<IdString> dff_types = { - "$ff", "$dff", "$dffe", "$dffsr", "$adff", - "$_FF_", "$_DFFE_NN_", "$_DFFE_NP_", "$_DFFE_PN_", "$_DFFE_PP_", - "$_DFFSR_NNN_", "$_DFFSR_NNP_", "$_DFFSR_NPN_", "$_DFFSR_NPP_", - "$_DFFSR_PNN_", "$_DFFSR_PNP_", "$_DFFSR_PPN_", "$_DFFSR_PPP_", - "$_DFF_N_", "$_DFF_NN0_", "$_DFF_NN1_", "$_DFF_NP0_", "$_DFF_NP1_", - "$_DFF_P_", "$_DFF_PN0_", "$_DFF_PN1_", "$_DFF_PP0_", "$_DFF_PP1_" + ID($ff), ID($dff), ID($dffe), ID($dffsr), ID($adff), + ID($_FF_), ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_), + ID($_DFFSR_NNN_), ID($_DFFSR_NNP_), ID($_DFFSR_NPN_), ID($_DFFSR_NPP_), + ID($_DFFSR_PNN_), ID($_DFFSR_PNP_), ID($_DFFSR_PPN_), ID($_DFFSR_PPP_), + ID($_DFF_N_), ID($_DFF_NN0_), ID($_DFF_NN1_), ID($_DFF_NP0_), ID($_DFF_NP1_), + ID($_DFF_P_), ID($_DFF_PN0_), ID($_DFF_PN1_), ID($_DFF_PP0_), ID($_DFF_PP1_) }; for (auto cell : module->selected_cells()) @@ -103,8 +103,8 @@ struct ZinitPass : public Pass { if (!dff_types.count(cell->type)) continue; - SigSpec sig_d = sigmap(cell->getPort("\\D")); - SigSpec sig_q = sigmap(cell->getPort("\\Q")); + SigSpec sig_d = sigmap(cell->getPort(ID(D))); + SigSpec sig_q = sigmap(cell->getPort(ID(Q))); if (GetSize(sig_d) < 1 || GetSize(sig_q) < 1) continue; @@ -120,14 +120,14 @@ struct ZinitPass : public Pass { } Wire *initwire = module->addWire(NEW_ID, GetSize(initval)); - initwire->attributes["\\init"] = initval; + initwire->attributes[ID(init)] = initval; for (int i = 0; i < GetSize(initwire); i++) if (initval.bits.at(i) == State::S1) { sig_d[i] = module->NotGate(NEW_ID, sig_d[i]); module->addNotGate(NEW_ID, SigSpec(initwire, i), sig_q[i]); - initwire->attributes["\\init"].bits.at(i) = State::S0; + initwire->attributes[ID(init)].bits.at(i) = State::S0; } else { @@ -137,8 +137,8 @@ struct ZinitPass : public Pass { log("FF init value for cell %s (%s): %s = %s\n", log_id(cell), log_id(cell->type), log_signal(sig_q), log_signal(initval)); - cell->setPort("\\D", sig_d); - cell->setPort("\\Q", initwire); + cell->setPort(ID(D), sig_d); + cell->setPort(ID(Q), initwire); } for (auto &it : initbits) diff --git a/passes/tests/flowmap/flow.v b/passes/tests/flowmap/flow.v new file mode 100644 index 000000000..297ef910e --- /dev/null +++ b/passes/tests/flowmap/flow.v @@ -0,0 +1,22 @@ +// Exact reproduction of Figure 2(a) from 10.1109/43.273754. +module top(...); + input a,b,c,d,e,f; + wire nA = b&c; + wire A = !nA; + wire nB = c|d; + wire B = !nB; + wire nC = e&f; + wire C = !nC; + wire D = A|B; + wire E = a&D; + wire nF = D&C; + wire F = !nF; + wire nG = F|B; + wire G = !nG; + wire H = a&F; + wire I = E|G; + wire J = G&C; + wire np = H&I; + output p = !np; + output q = A|J; +endmodule diff --git a/passes/tests/flowmap/flowp.v b/passes/tests/flowmap/flowp.v new file mode 100644 index 000000000..2fb40ffa4 --- /dev/null +++ b/passes/tests/flowmap/flowp.v @@ -0,0 +1,16 @@ +// Like flow.v, but results in a network identical to Figure 2(b). +module top(...); + input a,b,c,d,e,f; + wire A = b&c; + wire B = c|d; + wire C = e&f; + wire D = A|B; + wire E = a&D; + wire F = D&C; + wire G = F|B; + wire H = a&F; + wire I = E|G; + wire J = G&C; + output p = H&I; + output q = A|J; +endmodule diff --git a/passes/tests/flowmap/pack1.v b/passes/tests/flowmap/pack1.v new file mode 100644 index 000000000..9454edf3c --- /dev/null +++ b/passes/tests/flowmap/pack1.v @@ -0,0 +1,11 @@ +// Exact reproduction of Figure 3(a) from 10.1109/92.285741. +module top(...); + input a,b,c,d,e,f,g,h; + wire x = !(c|d); + wire y = !(e&f); + wire u = !(a&b); + wire v = !(x|y); + wire w = !(g&h); + output s = !(u|v); + output t = !(v|w); +endmodule diff --git a/passes/tests/flowmap/pack1p.v b/passes/tests/flowmap/pack1p.v new file mode 100644 index 000000000..fdb278833 --- /dev/null +++ b/passes/tests/flowmap/pack1p.v @@ -0,0 +1,11 @@ +// Like pack1.v, but results in a simpler network. +module top(...); + input a,b,c,d,e,f,g,h; + wire x = c|d; + wire y = e&f; + wire u = a&b; + wire v = x|y; + wire w = g&h; + output s = u|v; + output t = v|w; +endmodule diff --git a/passes/tests/flowmap/pack2.v b/passes/tests/flowmap/pack2.v new file mode 100644 index 000000000..445e4afb0 --- /dev/null +++ b/passes/tests/flowmap/pack2.v @@ -0,0 +1,15 @@ +// Exact reproduction of Figure 4(a) from 10.1109/92.285741. +module top(...); + (* $flowmap_level=1 *) input a; + (* $flowmap_level=1 *) input b; + (* $flowmap_level=2 *) input c; + (* $flowmap_level=1 *) input d; + (* $flowmap_level=3 *) input e; + (* $flowmap_level=1 *) input f; + wire u = !(a&b); + wire w = !(c|d); + wire v = !(u|w); + wire n0 = !(w&e); + wire n1 = !(n0|f); + output n2 = !(v&n1); +endmodule diff --git a/passes/tests/flowmap/pack2p.v b/passes/tests/flowmap/pack2p.v new file mode 100644 index 000000000..d4b41733d --- /dev/null +++ b/passes/tests/flowmap/pack2p.v @@ -0,0 +1,15 @@ +// Like pack2.v, but results in a simpler network. +module top(...); + (* $flowmap_level=1 *) input a; + (* $flowmap_level=1 *) input b; + (* $flowmap_level=2 *) input c; + (* $flowmap_level=1 *) input d; + (* $flowmap_level=3 *) input e; + (* $flowmap_level=1 *) input f; + wire u = a&b; + wire w = c|d; + wire v = u|w; + wire n0 = w&e; + wire n1 = n0|f; + output n2 = v&n1; +endmodule diff --git a/passes/tests/flowmap/pack3.v b/passes/tests/flowmap/pack3.v new file mode 100644 index 000000000..06147a1aa --- /dev/null +++ b/passes/tests/flowmap/pack3.v @@ -0,0 +1,15 @@ +// Exact reproduction of Figure 5(a) (bottom) from 10.1109/92.285741. +module top(...); + input a,b,c,d,e,f,g,h,i,j; + wire x = !(a&b); + wire y = !(c|d); + wire z = !(e|f); + wire n0 = !(g&h); + wire n1 = !(i|j); + wire w = !(x&y); + wire n2 = !(z&n0); + wire n3 = !(n0|n1); + wire n4 = !(n2|n3); + wire v = !(w|n5); + output u = !(w&v); +endmodule diff --git a/passes/tests/flowmap/pack3p.v b/passes/tests/flowmap/pack3p.v new file mode 100644 index 000000000..bc6ac1757 --- /dev/null +++ b/passes/tests/flowmap/pack3p.v @@ -0,0 +1,15 @@ +// Like pack2.v, but results in a simpler network. +module top(...); + input a,b,c,d,e,f,g,h,i,j; + wire x = a&b; + wire y = c|d; + wire z = e|f; + wire n0 = g&h; + wire n1 = i|j; + wire w = x&y; + wire n2 = z&n0; + wire n3 = n0|n1; + wire n4 = n2|n3; + wire v = w|n5; + output u = w&v; +endmodule diff --git a/passes/tests/test_abcloop.cc b/passes/tests/test_abcloop.cc index 09cb41954..5d5466afe 100644 --- a/passes/tests/test_abcloop.cc +++ b/passes/tests/test_abcloop.cc @@ -244,7 +244,7 @@ static void test_abcloop() struct TestAbcloopPass : public Pass { TestAbcloopPass() : Pass("test_abcloop", "automatically test handling of loops in abc command") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -259,7 +259,7 @@ struct TestAbcloopPass : public Pass { log(" use this value as rng seed value (default = unix time).\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design*) + void execute(std::vector<std::string> args, RTLIL::Design*) YS_OVERRIDE { int num_iter = 100; xorshift32_state = 0; diff --git a/passes/tests/test_autotb.cc b/passes/tests/test_autotb.cc index cb31056f4..a5ac3130f 100644 --- a/passes/tests/test_autotb.cc +++ b/passes/tests/test_autotb.cc @@ -324,7 +324,7 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter, int s struct TestAutotbBackend : public Backend { TestAutotbBackend() : Backend("=test_autotb", "generate simple test benches") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -345,11 +345,14 @@ struct TestAutotbBackend : public Backend { log("value after initialization. This can e.g. be used to force a reset signal\n"); log("low in order to explore more inner states in a state machine.\n"); log("\n"); + log("The attribute 'gentb_skip' can be attached to modules to suppress testbench\n"); + log("generation.\n"); + log("\n"); log(" -n <int>\n"); log(" number of iterations the test bench should run (default = 1000)\n"); log("\n"); } - virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) + void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { int num_iter = 1000; int seed = 0; diff --git a/passes/tests/test_cell.cc b/passes/tests/test_cell.cc index 47b6bdf23..88116eeec 100644 --- a/passes/tests/test_cell.cc +++ b/passes/tests/test_cell.cc @@ -43,7 +43,7 @@ static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type, RTLIL::Cell *cell = module->addCell("\\UUT", cell_type); RTLIL::Wire *wire; - if (cell_type == "$mux" || cell_type == "$pmux") + if (cell_type.in("$mux", "$pmux")) { int width = 1 + xorshift32(8); int swidth = cell_type == "$mux" ? 1 : 1 + xorshift32(8); @@ -186,7 +186,7 @@ static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type, RTLIL::SigSpec config; for (int i = 0; i < (1 << width); i++) - config.append(xorshift32(2) ? RTLIL::S1 : RTLIL::S0); + config.append(xorshift32(2) ? State::S1 : State::S0); cell->setParam("\\LUT", config.as_const()); } @@ -209,16 +209,16 @@ static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type, for (int i = 0; i < width*depth; i++) switch (xorshift32(3)) { case 0: - config.append(RTLIL::S1); - config.append(RTLIL::S0); + config.append(State::S1); + config.append(State::S0); break; case 1: - config.append(RTLIL::S0); - config.append(RTLIL::S1); + config.append(State::S0); + config.append(State::S1); break; case 2: - config.append(RTLIL::S0); - config.append(RTLIL::S0); + config.append(State::S0); + config.append(State::S0); break; } @@ -264,7 +264,7 @@ static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type, cell->setPort("\\Y", wire); } - if (muxdiv && (cell_type == "$div" || cell_type == "$mod")) { + if (muxdiv && cell_type.in("$div", "$mod")) { auto b_not_zero = module->ReduceBool(NEW_ID, cell->getPort("\\B")); auto div_out = module->addWire(NEW_ID, GetSize(cell->getPort("\\Y"))); module->addMux(NEW_ID, RTLIL::SigSpec(0, GetSize(div_out)), div_out, b_not_zero, cell->getPort("\\Y")); @@ -308,18 +308,18 @@ static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type, case 0: n = xorshift32(GetSize(sig) + 1); for (int i = 0; i < n; i++) - sig[i] = xorshift32(2) == 1 ? RTLIL::S1 : RTLIL::S0; + sig[i] = xorshift32(2) == 1 ? State::S1 : State::S0; break; case 1: n = xorshift32(GetSize(sig) + 1); for (int i = n; i < GetSize(sig); i++) - sig[i] = xorshift32(2) == 1 ? RTLIL::S1 : RTLIL::S0; + sig[i] = xorshift32(2) == 1 ? State::S1 : State::S0; break; case 2: n = xorshift32(GetSize(sig)); m = xorshift32(GetSize(sig)); for (int i = min(n, m); i < max(n, m); i++) - sig[i] = xorshift32(2) == 1 ? RTLIL::S1 : RTLIL::S0; + sig[i] = xorshift32(2) == 1 ? State::S1 : State::S0; break; } @@ -491,7 +491,7 @@ static void run_eval_test(RTLIL::Design *design, bool verbose, bool nosat, std:: RTLIL::Const in_value; for (int i = 0; i < GetSize(gold_wire); i++) - in_value.bits.push_back(xorshift32(2) ? RTLIL::S1 : RTLIL::S0); + in_value.bits.push_back(xorshift32(2) ? State::S1 : State::S0); if (xorshift32(4) == 0) { int inv_chance = 1 + xorshift32(8); @@ -591,11 +591,11 @@ static void run_eval_test(RTLIL::Design *design, bool verbose, bool nosat, std:: } for (int i = 0; i < GetSize(out_sig); i++) { - if (out_val[i] != RTLIL::S0 && out_val[i] != RTLIL::S1) + if (out_val[i] != State::S0 && out_val[i] != State::S1) continue; - if (out_val[i] == RTLIL::S0 && sat1_model_value.at(i) == false) + if (out_val[i] == State::S0 && sat1_model_value.at(i) == false) continue; - if (out_val[i] == RTLIL::S1 && sat1_model_value.at(i) == true) + if (out_val[i] == State::S1 && sat1_model_value.at(i) == true) continue; log_error("Mismatch in sat model 1 (no undef modeling) output!\n"); } @@ -627,12 +627,12 @@ static void run_eval_test(RTLIL::Design *design, bool verbose, bool nosat, std:: for (int i = 0; i < GetSize(out_sig); i++) { if (sat2_model_value.at(GetSize(out_sig) + i)) { - if (out_val[i] != RTLIL::S0 && out_val[i] != RTLIL::S1) + if (out_val[i] != State::S0 && out_val[i] != State::S1) continue; } else { - if (out_val[i] == RTLIL::S0 && sat2_model_value.at(i) == false) + if (out_val[i] == State::S0 && sat2_model_value.at(i) == false) continue; - if (out_val[i] == RTLIL::S1 && sat2_model_value.at(i) == true) + if (out_val[i] == State::S1 && sat2_model_value.at(i) == true) continue; } log_error("Mismatch in sat model 2 (undef modeling) output!\n"); @@ -652,7 +652,7 @@ static void run_eval_test(RTLIL::Design *design, bool verbose, bool nosat, std:: struct TestCellPass : public Pass { TestCellPass() : Pass("test_cell", "automatically test the implementation of a cell type") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -712,7 +712,7 @@ struct TestCellPass : public Pass { log(" create a Verilog test bench to test simlib and write_verilog\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design*) + void execute(std::vector<std::string> args, RTLIL::Design*) YS_OVERRIDE { int num_iter = 100; std::string techmap_cmd = "techmap -assert"; @@ -872,7 +872,7 @@ struct TestCellPass : public Pass { continue; } - if (args[argidx].substr(0, 1) == "/") { + if (args[argidx].compare(0, 1, "/") == 0) { std::vector<std::string> new_selected_cell_types; for (auto it : selected_cell_types) if (it != args[argidx].substr(1)) diff --git a/techlibs/achronix/speedster22i/cells_map.v b/techlibs/achronix/speedster22i/cells_map.v index 95f5d59c5..9f647cbef 100755 --- a/techlibs/achronix/speedster22i/cells_map.v +++ b/techlibs/achronix/speedster22i/cells_map.v @@ -32,7 +32,7 @@ endmodule // > end buffers < // > Look-Up table < -// > VT: I still think Achronix folks would have choosen a better \ +// > VT: I still think Achronix folks would have chosen a better \ // > logic architecture. // LUT Map module \$lut (A, Y); @@ -43,30 +43,30 @@ module \$lut (A, Y); generate if (WIDTH == 1) begin // VT: This is not consistent and ACE will complain: assign Y = ~A[0]; - LUT4 #(.lut_function({4{LUT}})) _TECHMAP_REPLACE_ + LUT4 #(.lut_function({4{LUT}})) _TECHMAP_REPLACE_ (.dout(Y), .din0(A[0]), .din1(1'b0), .din2(1'b0), .din3(1'b0)); end else if (WIDTH == 2) begin - LUT4 #(.lut_function({4{LUT}})) _TECHMAP_REPLACE_ + LUT4 #(.lut_function({4{LUT}})) _TECHMAP_REPLACE_ (.dout(Y), .din0(A[0]), .din1(A[1]), .din2(1'b0), .din3(1'b0)); end else if(WIDTH == 3) begin - LUT4 #(.lut_function({2{LUT}})) _TECHMAP_REPLACE_ + LUT4 #(.lut_function({2{LUT}})) _TECHMAP_REPLACE_ (.dout(Y), .din0(A[0]), .din1(A[1]), .din2(A[2]), .din3(1'b0)); end else if(WIDTH == 4) begin - LUT4 #(.lut_function(LUT)) _TECHMAP_REPLACE_ + LUT4 #(.lut_function(LUT)) _TECHMAP_REPLACE_ (.dout(Y), .din0(A[0]), .din1(A[1]), .din2(A[2]), .din3(A[3])); end else wire _TECHMAP_FAIL_ = 1; endgenerate -endmodule +endmodule // > end LUT < // > Flops < // DFF flop module \$_DFF_P_ (input D, C, output Q); - DFF _TECHMAP_REPLACE_ + DFF _TECHMAP_REPLACE_ (.q(Q), .d(D), .ck(C)); -endmodule +endmodule diff --git a/techlibs/achronix/speedster22i/cells_sim.v b/techlibs/achronix/speedster22i/cells_sim.v index da23fed7e..a0c60b4be 100755 --- a/techlibs/achronix/speedster22i/cells_sim.v +++ b/techlibs/achronix/speedster22i/cells_sim.v @@ -30,7 +30,7 @@ endmodule module PADOUT (output padout, input padin, input oe); assign padout = padin; assign oe = oe; -endmodule +endmodule module LUT4 (output dout, input din0, din1, din2, din3); @@ -61,19 +61,19 @@ reg [1:0] s1; end endfunction -always @(dataa_w or datab_w or datac_w or datad_w or cin_w) begin +always @(dataa_w or datab_w or datac_w or datad_w) begin combout_rt = lut_data(lut_function, dataa_w, datab_w, datac_w, datad_w); end assign dout = combout_rt & 1'b1; -endmodule +endmodule module DFF (output q, input d, ck); reg q; always @(posedge ck) q <= d; - + endmodule diff --git a/techlibs/achronix/synth_achronix.cc b/techlibs/achronix/synth_achronix.cc index 7f4503070..626860d9c 100755 --- a/techlibs/achronix/synth_achronix.cc +++ b/techlibs/achronix/synth_achronix.cc @@ -28,7 +28,7 @@ PRIVATE_NAMESPACE_BEGIN struct SynthAchronixPass : public ScriptPass { SynthAchronixPass() : ScriptPass("synth_achronix", "synthesis for Acrhonix Speedster22i FPGAs.") { } - virtual void help() YS_OVERRIDE + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -63,7 +63,7 @@ struct SynthAchronixPass : public ScriptPass { string top_opt, family_opt, vout_file; bool retime, flatten; - virtual void clear_flags() YS_OVERRIDE + void clear_flags() YS_OVERRIDE { top_opt = "-auto-top"; vout_file = ""; @@ -71,7 +71,7 @@ struct SynthAchronixPass : public ScriptPass { flatten = true; } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { string run_from, run_to; clear_flags(); @@ -95,8 +95,8 @@ struct SynthAchronixPass : public ScriptPass { run_to = args[argidx].substr(pos+1); continue; } - if (args[argidx] == "-flatten") { - flatten = true; + if (args[argidx] == "-noflatten") { + flatten = false; continue; } if (args[argidx] == "-retime") { @@ -108,7 +108,7 @@ struct SynthAchronixPass : public ScriptPass { extra_args(args, argidx, design); if (!design->full_selection()) - log_cmd_error("This comannd only operates on fully selected designs!\n"); + log_cmd_error("This command only operates on fully selected designs!\n"); log_header(design, "Executing SYNTH_ACHRONIX pass.\n"); log_push(); @@ -118,7 +118,7 @@ struct SynthAchronixPass : public ScriptPass { log_pop(); } - virtual void script() YS_OVERRIDE + void script() YS_OVERRIDE { if (check_label("begin")) { diff --git a/techlibs/anlogic/Makefile.inc b/techlibs/anlogic/Makefile.inc new file mode 100644 index 000000000..9426b5ca5 --- /dev/null +++ b/techlibs/anlogic/Makefile.inc @@ -0,0 +1,12 @@ + +OBJS += techlibs/anlogic/synth_anlogic.o +OBJS += techlibs/anlogic/anlogic_eqn.o +OBJS += techlibs/anlogic/anlogic_fixcarry.o + +$(eval $(call add_share_file,share/anlogic,techlibs/anlogic/cells_map.v)) +$(eval $(call add_share_file,share/anlogic,techlibs/anlogic/arith_map.v)) +$(eval $(call add_share_file,share/anlogic,techlibs/anlogic/cells_sim.v)) +$(eval $(call add_share_file,share/anlogic,techlibs/anlogic/eagle_bb.v)) +$(eval $(call add_share_file,share/anlogic,techlibs/anlogic/drams.txt)) +$(eval $(call add_share_file,share/anlogic,techlibs/anlogic/drams_map.v)) +$(eval $(call add_share_file,share/anlogic,techlibs/anlogic/dram_init_16x4.vh)) diff --git a/techlibs/anlogic/anlogic_eqn.cc b/techlibs/anlogic/anlogic_eqn.cc new file mode 100644 index 000000000..070d39a20 --- /dev/null +++ b/techlibs/anlogic/anlogic_eqn.cc @@ -0,0 +1,113 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2018 Miodrag Milanovic <miodrag@symbioticeda.com> + * + * 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 AnlogicEqnPass : public Pass { + AnlogicEqnPass() : Pass("anlogic_eqn", "Anlogic: Calculate equations for luts") { } + void help() YS_OVERRIDE + { + log("\n"); + log(" anlogic_eqn [selection]\n"); + log("\n"); + log("Calculate equations for luts since bitstream generator depends on it.\n"); + log("\n"); + } + + Const init2eqn(Const init, int inputs) + { + std::string init_bits = init.as_string(); + const char* names[] = { "A" , "B", "C", "D", "E", "F" }; + + std::string eqn; + int width = (int)pow(2,inputs); + for(int i=0;i<width;i++) + { + if (init_bits[width-1-i]=='1') + { + eqn += "("; + for(int j=0;j<inputs;j++) + { + if (i & (1<<j)) + eqn += names[j]; + else + eqn += std::string("~") + names[j]; + + if (j!=(inputs-1)) eqn += "*"; + } + eqn += ")+"; + } + } + if (eqn.empty()) return Const("0"); + eqn = eqn.substr(0, eqn.length()-1); + return Const(eqn); + } + + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + log_header(design, "Executing ANLOGIC_EQN pass (calculate equations for luts).\n"); + + extra_args(args, args.size(), design); + + int cnt = 0; + for (auto module : design->selected_modules()) + { + for (auto cell : module->selected_cells()) + { + if (cell->type == "\\AL_MAP_LUT1") + { + cell->setParam("\\EQN", init2eqn(cell->getParam("\\INIT"),1)); + cnt++; + } + if (cell->type == "\\AL_MAP_LUT2") + { + cell->setParam("\\EQN", init2eqn(cell->getParam("\\INIT"),2)); + cnt++; + } + if (cell->type == "\\AL_MAP_LUT3") + { + cell->setParam("\\EQN", init2eqn(cell->getParam("\\INIT"),3)); + cnt++; + } + if (cell->type == "\\AL_MAP_LUT4") + { + cell->setParam("\\EQN", init2eqn(cell->getParam("\\INIT"),4)); + cnt++; + } + if (cell->type == "\\AL_MAP_LUT5") + { + cell->setParam("\\EQN", init2eqn(cell->getParam("\\INIT"),5)); + cnt++; + } + if (cell->type == "\\AL_MAP_LUT6") + { + cell->setParam("\\EQN", init2eqn(cell->getParam("\\INIT"),6)); + cnt++; + } + } + } + log_header(design, "Updated %d of AL_MAP_LUT* elements with equation.\n", cnt); + } +} AnlogicEqnPass; + +PRIVATE_NAMESPACE_END diff --git a/techlibs/anlogic/anlogic_fixcarry.cc b/techlibs/anlogic/anlogic_fixcarry.cc new file mode 100644 index 000000000..87164d375 --- /dev/null +++ b/techlibs/anlogic/anlogic_fixcarry.cc @@ -0,0 +1,130 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2019 Miodrag Milanovic <miodrag@symbioticeda.com> + * + * 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 + +static SigBit get_bit_or_zero(const SigSpec &sig) +{ + if (GetSize(sig) == 0) + return State::S0; + return sig[0]; +} + +static void fix_carry_chain(Module *module) +{ + SigMap sigmap(module); + + pool<SigBit> ci_bits; + dict<SigBit, SigBit> mapping_bits; + + for (auto cell : module->cells()) + { + if (cell->type == "\\AL_MAP_ADDER") { + if (cell->getParam("\\ALUTYPE") != Const("ADD")) continue; + SigBit bit_i0 = get_bit_or_zero(cell->getPort("\\a")); + SigBit bit_i1 = get_bit_or_zero(cell->getPort("\\b")); + if (bit_i0 == State::S0 && bit_i1== State::S0) { + SigBit bit_ci = get_bit_or_zero(cell->getPort("\\c")); + SigSpec o = cell->getPort("\\o"); + if (GetSize(o) == 2) { + SigBit bit_o = o[0]; + ci_bits.insert(bit_ci); + mapping_bits[bit_ci] = bit_o; + } + } + } + } + vector<Cell*> adders_to_fix_cells; + for (auto cell : module->cells()) + { + if (cell->type == "\\AL_MAP_ADDER") { + if (cell->getParam("\\ALUTYPE") != Const("ADD")) continue; + SigBit bit_ci = get_bit_or_zero(cell->getPort("\\c")); + SigBit bit_i0 = get_bit_or_zero(cell->getPort("\\a")); + SigBit bit_i1 = get_bit_or_zero(cell->getPort("\\b")); + SigBit canonical_bit = sigmap(bit_ci); + if (!ci_bits.count(canonical_bit)) + continue; + if (bit_i0 == State::S0 && bit_i1== State::S0) + continue; + + adders_to_fix_cells.push_back(cell); + log("Found %s cell named %s with invalid 'c' signal.\n", log_id(cell->type), log_id(cell)); + } + } + + for (auto cell : adders_to_fix_cells) + { + SigBit bit_ci = get_bit_or_zero(cell->getPort("\\c")); + SigBit canonical_bit = sigmap(bit_ci); + auto bit = mapping_bits.at(canonical_bit); + log("Fixing %s cell named %s breaking carry chain.\n", log_id(cell->type), log_id(cell)); + Cell *c = module->addCell(NEW_ID, "\\AL_MAP_ADDER"); + SigBit new_bit = module->addWire(NEW_ID); + SigBit dummy_bit = module->addWire(NEW_ID); + SigSpec bits; + bits.append(dummy_bit); + bits.append(new_bit); + c->setParam("\\ALUTYPE", Const("ADD_CARRY")); + c->setPort("\\a", bit); + c->setPort("\\b", State::S0); + c->setPort("\\c", State::S0); + c->setPort("\\o", bits); + + cell->setPort("\\c", new_bit); + } + +} + +struct AnlogicCarryFixPass : public Pass { + AnlogicCarryFixPass() : Pass("anlogic_fixcarry", "Anlogic: fix carry chain") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" anlogic_fixcarry [options] [selection]\n"); + log("\n"); + log("Add Anlogic adders to fix carry chain if needed.\n"); + log("\n"); + } + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + log_header(design, "Executing anlogic_fixcarry pass (fix invalid carry chain).\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + break; + } + extra_args(args, argidx, design); + + Module *module = design->top_module(); + + if (module == nullptr) + log_cmd_error("No top module found.\n"); + + fix_carry_chain(module); + } +} AnlogicCarryFixPass; + +PRIVATE_NAMESPACE_END diff --git a/techlibs/anlogic/arith_map.v b/techlibs/anlogic/arith_map.v new file mode 100644 index 000000000..1186543da --- /dev/null +++ b/techlibs/anlogic/arith_map.v @@ -0,0 +1,84 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2018 Miodrag Milanovic <miodrag@symbioticeda.com> + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * + * 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. + * + */ + +(* techmap_celltype = "$alu" *) +module _80_anlogic_alu (A, B, CI, BI, X, Y, CO); + parameter A_SIGNED = 0; + parameter B_SIGNED = 0; + parameter A_WIDTH = 1; + parameter B_WIDTH = 1; + parameter Y_WIDTH = 1; + + input [A_WIDTH-1:0] A; + input [B_WIDTH-1:0] B; + output [Y_WIDTH-1:0] X, Y; + + input CI, BI; + output [Y_WIDTH-1:0] CO; + + wire CIx; + wire [Y_WIDTH-1:0] COx; + + wire _TECHMAP_FAIL_ = Y_WIDTH <= 2; + + wire [Y_WIDTH-1:0] A_buf, B_buf; + \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf)); + \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf)); + + wire [Y_WIDTH-1:0] AA = A_buf; + wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; + wire [Y_WIDTH-1:0] C = { COx, CIx }; + + wire dummy; + AL_MAP_ADDER #( + .ALUTYPE("ADD_CARRY")) + adder_cin ( + .a(CI), + .b(1'b0), + .c(1'b0), + .o({CIx, dummy}) + ); + + genvar i; + generate for (i = 0; i < Y_WIDTH; i = i + 1) begin: slice + AL_MAP_ADDER #( + .ALUTYPE("ADD") + ) adder_i ( + .a(AA[i]), + .b(BB[i]), + .c(C[i]), + .o({COx[i],Y[i]}) + ); + + wire cout; + AL_MAP_ADDER #( + .ALUTYPE("ADD")) + adder_cout ( + .a(1'b0), + .b(1'b0), + .c(COx[i]), + .o({cout, CO[i]}) + ); + end: slice + endgenerate + + /* End implementation */ + assign X = AA ^ BB; +endmodule diff --git a/techlibs/anlogic/cells_map.v b/techlibs/anlogic/cells_map.v new file mode 100644 index 000000000..cfc743a4b --- /dev/null +++ b/techlibs/anlogic/cells_map.v @@ -0,0 +1,61 @@ +module \$_DFF_N_ (input D, C, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'bx), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(1'b1), .sr(1'b0)); endmodule +module \$_DFF_P_ (input D, C, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'bx), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(1'b1), .sr(1'b0)); endmodule + +module \$_DFFE_NN_ (input D, C, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'bx), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(E), .sr(1'b0)); endmodule +module \$_DFFE_NP_ (input D, C, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'bx), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(E), .sr(1'b0)); endmodule +module \$_DFFE_PN_ (input D, C, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'bx), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(E), .sr(1'b0)); endmodule +module \$_DFFE_PP_ (input D, C, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'bx), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(E), .sr(1'b0)); endmodule + +module \$_DFF_NN0_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b0), .SRMUX("INV"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(1'b1), .sr(R)); endmodule +module \$_DFF_NN1_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b1), .SRMUX("INV"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(1'b1), .sr(R)); endmodule +module \$_DFF_NP0_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b0), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(1'b1), .sr(R)); endmodule +module \$_DFF_NP1_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b1), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(1'b1), .sr(R)); endmodule +module \$_DFF_PN0_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b0), .SRMUX("INV"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C) , .ce(1'b1), .sr(R)); endmodule +module \$_DFF_PN1_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b1), .SRMUX("INV"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(1'b1), .sr(R)); endmodule +module \$_DFF_PP0_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b0), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(1'b1), .sr(R)); endmodule +module \$_DFF_PP1_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b1), .SRMUX("SR"), . SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(1'b1), .sr(R)); endmodule + +module \$_DLATCH_N_ (E, D, Q); + wire [1023:0] _TECHMAP_DO_ = "simplemap; opt"; + input E, D; + output Q = !E ? D : Q; +endmodule + +module \$_DLATCH_P_ (E, D, Q); + wire [1023:0] _TECHMAP_DO_ = "simplemap; opt"; + input E, D; + output Q = E ? D : Q; +endmodule + +`ifndef NO_LUT +module \$lut (A, Y); + parameter WIDTH = 0; + parameter LUT = 0; + + input [WIDTH-1:0] A; + output Y; + + generate + if (WIDTH == 1) begin + AL_MAP_LUT1 #(.EQN(""),.INIT(LUT)) _TECHMAP_REPLACE_ (.o(Y), .a(A[0])); + end else + if (WIDTH == 2) begin + AL_MAP_LUT2 #(.EQN(""),.INIT(LUT)) _TECHMAP_REPLACE_ (.o(Y), .a(A[0]), .b(A[1])); + end else + if (WIDTH == 3) begin + AL_MAP_LUT3 #(.EQN(""),.INIT(LUT)) _TECHMAP_REPLACE_ (.o(Y), .a(A[0]), .b(A[1]), .c(A[2])); + end else + if (WIDTH == 4) begin + AL_MAP_LUT4 #(.EQN(""),.INIT(LUT)) _TECHMAP_REPLACE_ (.o(Y), .a(A[0]), .b(A[1]), .c(A[2]), .d(A[3])); + end else + if (WIDTH == 5) begin + AL_MAP_LUT5 #(.EQN(""),.INIT(LUT)) _TECHMAP_REPLACE_ (.o(Y), .a(A[0]), .b(A[1]), .c(A[2]), .d(A[3]), .e(A[4])); + end else + if (WIDTH == 6) begin + AL_MAP_LUT6 #(.EQN(""),.INIT(LUT)) _TECHMAP_REPLACE_ (.o(Y), .a(A[0]), .b(A[1]), .c(A[2]), .d(A[3]), .e(A[4]), .f(A[5])); + end else begin + wire _TECHMAP_FAIL_ = 1; + end + endgenerate +endmodule +`endif diff --git a/techlibs/anlogic/cells_sim.v b/techlibs/anlogic/cells_sim.v new file mode 100644 index 000000000..0fba43572 --- /dev/null +++ b/techlibs/anlogic/cells_sim.v @@ -0,0 +1,192 @@ +module AL_MAP_SEQ ( + output reg q, + input ce, + input clk, + input sr, + input d +); + parameter DFFMODE = "FF"; //FF,LATCH + parameter REGSET = "RESET"; //RESET/SET + parameter SRMUX = "SR"; //SR/INV + parameter SRMODE = "SYNC"; //SYNC/ASYNC + + wire clk_ce; + assign clk_ce = ce ? clk : 1'b0; + + wire srmux; + generate + case (SRMUX) + "SR": assign srmux = sr; + "INV": assign srmux = ~sr; + default: assign srmux = sr; + endcase + endgenerate + + wire regset; + generate + case (REGSET) + "RESET": assign regset = 1'b0; + "SET": assign regset = 1'b1; + default: assign regset = 1'b0; + endcase + endgenerate + + initial q = regset; + + generate + if (DFFMODE == "FF") + begin + if (SRMODE == "ASYNC") + begin + always @(posedge clk_ce, posedge srmux) + if (srmux) + q <= regset; + else + q <= d; + end + else + begin + always @(posedge clk_ce) + if (srmux) + q <= regset; + else + q <= d; + end + end + else + begin + // DFFMODE == "LATCH" + if (SRMODE == "ASYNC") + begin + always @(clk_ce, srmux) + if (srmux) + q <= regset; + else + q <= d; + end + else + begin + always @(clk_ce) + if (srmux) + q <= regset; + else + q <= d; + end + end + endgenerate +endmodule + +module AL_MAP_LUT1 ( + output o, + input a +); + parameter [1:0] INIT = 2'h0; + parameter EQN = "(A)"; + + assign o = a ? INIT[1] : INIT[0]; +endmodule + +module AL_MAP_LUT2 ( + output o, + input a, + input b +); + parameter [3:0] INIT = 4'h0; + parameter EQN = "(A)"; + + wire [1:0] s1 = b ? INIT[ 3:2] : INIT[1:0]; + assign o = a ? s1[1] : s1[0]; +endmodule + +module AL_MAP_LUT3 ( + output o, + input a, + input b, + input c +); + parameter [7:0] INIT = 8'h0; + parameter EQN = "(A)"; + + wire [3:0] s2 = c ? INIT[ 7:4] : INIT[3:0]; + wire [1:0] s1 = b ? s2[ 3:2] : s2[1:0]; + assign o = a ? s1[1] : s1[0]; +endmodule + +module AL_MAP_LUT4 ( + output o, + input a, + input b, + input c, + input d +); + parameter [15:0] INIT = 16'h0; + parameter EQN = "(A)"; + + wire [7:0] s3 = d ? INIT[15:8] : INIT[7:0]; + wire [3:0] s2 = c ? s3[ 7:4] : s3[3:0]; + wire [1:0] s1 = b ? s2[ 3:2] : s2[1:0]; + assign o = a ? s1[1] : s1[0]; +endmodule + +module AL_MAP_LUT5 ( + output o, + input a, + input b, + input c, + input d, + input e +); + parameter [31:0] INIT = 32'h0; + parameter EQN = "(A)"; + assign o = INIT >> {e, d, c, b, a}; +endmodule + + +module AL_MAP_LUT6 ( + output o, + input a, + input b, + input c, + input d, + input e, + input f +); + parameter [63:0] INIT = 64'h0; + parameter EQN = "(A)"; + assign o = INIT >> {f, e, d, c, b, a}; +endmodule + +module AL_MAP_ALU2B ( + input cin, + input a0, b0, c0, d0, + input a1, b1, c1, d1, + output s0, s1, cout +); + parameter [15:0] INIT0 = 16'h0000; + parameter [15:0] INIT1 = 16'h0000; + parameter FUNC0 = "NO"; + parameter FUNC1 = "NO"; +endmodule + +module AL_MAP_ADDER ( + input a, + input b, + input c, + output [1:0] o +); + parameter ALUTYPE = "ADD"; + + generate + case (ALUTYPE) + "ADD": assign o = a + b + c; + "SUB": assign o = a - b - c; + "A_LE_B": assign o = a - b - c; + + "ADD_CARRY": assign o = { a, 1'b0 }; + "SUB_CARRY": assign o = { ~a, 1'b0 }; + "A_LE_B_CARRY": assign o = { a, 1'b0 }; + default: assign o = a + b + c; + endcase + endgenerate + +endmodule diff --git a/techlibs/anlogic/dram_init_16x4.vh b/techlibs/anlogic/dram_init_16x4.vh new file mode 100644 index 000000000..32fb1578c --- /dev/null +++ b/techlibs/anlogic/dram_init_16x4.vh @@ -0,0 +1,16 @@ +.INIT_D0({INIT[15*4+0], INIT[14*4+0], INIT[13*4+0], INIT[12*4+0], + INIT[11*4+0], INIT[10*4+0], INIT[9*4+0], INIT[8*4+0], + INIT[7*4+0], INIT[6*4+0], INIT[5*4+0], INIT[4*4+0], + INIT[3*4+0], INIT[2*4+0], INIT[1*4+0], INIT[0*4+0]}), +.INIT_D1({INIT[15*4+1], INIT[14*4+1], INIT[13*4+1], INIT[12*4+1], + INIT[11*4+1], INIT[10*4+1], INIT[9*4+1], INIT[8*4+1], + INIT[7*4+1], INIT[6*4+1], INIT[5*4+1], INIT[4*4+1], + INIT[3*4+1], INIT[2*4+1], INIT[1*4+1], INIT[0*4+1]}), +.INIT_D2({INIT[15*4+2], INIT[14*4+2], INIT[13*4+2], INIT[12*4+2], + INIT[11*4+2], INIT[10*4+2], INIT[9*4+2], INIT[8*4+2], + INIT[7*4+2], INIT[6*4+2], INIT[5*4+2], INIT[4*4+2], + INIT[3*4+2], INIT[2*4+2], INIT[1*4+2], INIT[0*4+2]}), +.INIT_D3({INIT[15*4+3], INIT[14*4+3], INIT[13*4+3], INIT[12*4+3], + INIT[11*4+3], INIT[10*4+3], INIT[9*4+3], INIT[8*4+3], + INIT[7*4+3], INIT[6*4+3], INIT[5*4+3], INIT[4*4+3], + INIT[3*4+3], INIT[2*4+3], INIT[1*4+3], INIT[0*4+3]}) diff --git a/techlibs/anlogic/drams.txt b/techlibs/anlogic/drams.txt new file mode 100644 index 000000000..4e903c0a2 --- /dev/null +++ b/techlibs/anlogic/drams.txt @@ -0,0 +1,16 @@ +bram $__ANLOGIC_DRAM16X4 + init 1 + abits 4 + dbits 4 + groups 2 + ports 1 1 + wrmode 0 1 + enable 0 1 + transp 0 0 + clocks 0 1 + clkpol 0 1 +endbram + +match $__ANLOGIC_DRAM16X4 + make_outreg +endmatch diff --git a/techlibs/anlogic/drams_map.v b/techlibs/anlogic/drams_map.v new file mode 100644 index 000000000..084e2a25f --- /dev/null +++ b/techlibs/anlogic/drams_map.v @@ -0,0 +1,22 @@ +module \$__ANLOGIC_DRAM16X4 (CLK1, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN); + parameter [63:0]INIT = 64'bx; + input CLK1; + + input [3:0] A1ADDR; + output [3:0] A1DATA; + + input [3:0] B1ADDR; + input [3:0] B1DATA; + input B1EN; + + EG_LOGIC_DRAM16X4 #( + `include "dram_init_16x4.vh" + ) _TECHMAP_REPLACE_ ( + .di(B1DATA), + .waddr(B1ADDR), + .wclk(CLK1), + .we(B1EN), + .raddr(A1ADDR), + .do(A1DATA) + ); +endmodule diff --git a/techlibs/anlogic/eagle_bb.v b/techlibs/anlogic/eagle_bb.v new file mode 100644 index 000000000..7cbec331a --- /dev/null +++ b/techlibs/anlogic/eagle_bb.v @@ -0,0 +1,1028 @@ +// Anlogic Eagle - Blackbox cells +// FIXME: Create sim models + +(* blackbox *) +module EG_LOGIC_BUF( + output o, + input i +); +endmodule + +(* blackbox *) +module EG_LOGIC_BUFG( + output o, + input i +); +endmodule + +(* blackbox *) +module EG_LOGIC_BUFIO( + input clki, + input rst, + input coe, + output clko, + output clkdiv1, + output clkdivx +); + parameter GSR = "DISABLE"; + parameter DIV = 2; + parameter STOPCLK = "DISABLE"; +endmodule + +(* blackbox *) +module EG_LOGIC_BUFGMUX( + output o, + input i0, + input i1, + input s +); + parameter INIT_OUT = "0"; + parameter PRESELECT_I0 = "TRUE"; + parameter PRESELECT_I1 = "FALSE"; +endmodule + +(* blackbox *) +module EG_LOGIC_MBOOT( + input rebootn, + input [7:0] dynamic_addr +); + parameter ADDR_SOURCE_SEL = "STATIC"; + parameter STATIC_ADDR = 8'b00000000; +endmodule + +(* blackbox *) +module EG_LOGIC_DNA( + output dout, + input clk, + input din, + input shift_en +); +endmodule + +(* blackbox *) +module EG_LOGIC_GCTRL( + output done, + output highz +); +endmodule + +(* blackbox *) +module EG_LOGIC_GSRN( + input gsrn, + input sync_clk +); + parameter GSRN_SYNC_SEL = "DISABLE"; + parameter USR_GSRN_EN = "DISABLE"; +endmodule + +(* blackbox *) +module EG_LOGIC_CCLK( + output cclk, + input en +); + parameter FREQ = "4.5"; +endmodule + +(* blackbox *) +module EG_LOGIC_IDELAY( + output o, + input i +); + parameter INDEL = 0; +endmodule + +(* blackbox *) +module EG_LOGIC_IDDR( + output q1, + output q0, + input clk, + input d, + input rst +); + parameter ASYNCRST = "ENABLE"; + parameter PIPEMODE = "PIPED"; +endmodule + +(* blackbox *) +module EG_LOGIC_ODDR( + output q, + input clk, + input d1, + input d0, + input rst +); + parameter ASYNCRST = "ENABLE"; +endmodule + +(* blackbox *) +module EG_LOGIC_IDDRx2( + output q3, + output q2, + output q1, + output q0, + input pclk, + input sclk, + input d, + input rst +); + parameter ASYNCRST = "ENABLE"; +endmodule + +(* blackbox *) +module EG_LOGIC_ODELAY( + output o, + input i +); + parameter OUTDEL = 0; +endmodule + +(* blackbox *) +module EG_LOGIC_ODDRx2( + output q, + input pclk, + input sclk, + input d3, + input d2, + input d1, + input d0, + input rst +); + parameter ASYNCRST = "ENABLE"; +endmodule + +(* blackbox *) +module EG_LOGIC_ODDRx2l( + output q, + input sclk, + input d3, + input d2, + input d1, + input d0, + input rst +); + parameter ASYNCRST = "ENABLE"; +endmodule + +(* blackbox *) +module EG_LOGIC_FIFO( + input rst, + input [DATA_WIDTH_W-1:0] di, + output [DATA_WIDTH_R-1:0] do, + input clkw, + input we, + input clkr, + input re, + input ore, + input [2:0] csw, + input [2:0] csr, + output empty_flag, + output aempty_flag, + output full_flag, + output afull_flag +); + parameter DATA_WIDTH_W = 9; + parameter DATA_WIDTH_R = DATA_WIDTH_W; + parameter DATA_DEPTH_W = 1024; + parameter DATA_DEPTH_R = DATA_WIDTH_W * DATA_DEPTH_W / DATA_WIDTH_R; + parameter MODE = "FIFO8K"; + parameter REGMODE_W = "NOREG"; + parameter REGMODE_R = "NOREG"; + parameter E = 0; + parameter AE = 6; + parameter AF = DATA_DEPTH_W - 6; + parameter F = DATA_DEPTH_W; + parameter GSR = "DISABLE"; + parameter RESETMODE = "ASYNC"; + parameter ASYNC_RESET_RELEASE = "SYNC"; + parameter ENDIAN = "LITTLE"; +endmodule + +(* blackbox *) +module EG_LOGIC_DRAM( + input [DATA_WIDTH_W-1:0] di, + input [ADDR_WIDTH_W-1:0] waddr, + input wclk, + input we, + output [DATA_WIDTH_R-1:0] do, + input [ADDR_WIDTH_R-1:0] raddr +); + parameter DATA_WIDTH_W = 9; + parameter ADDR_WIDTH_W = 10; + parameter DATA_DEPTH_W = 2 ** ADDR_WIDTH_W; + parameter DATA_WIDTH_R = 9; + parameter ADDR_WIDTH_R = 10; + parameter DATA_DEPTH_R = 2 ** ADDR_WIDTH_R; + parameter INIT_FILE = "NONE"; +endmodule + +(* blackbox *) +module EG_LOGIC_DRAM16X4( + input [3:0] di, + input [3:0] waddr, + input wclk, + input we, + input [3:0]raddr, + output [3:0]do +); + parameter INIT_D0=16'h0000; + parameter INIT_D1=16'h0000; + parameter INIT_D2=16'h0000; + parameter INIT_D3=16'h0000; +endmodule + +(* blackbox *) +module EG_LOGIC_MULT( + output [OUTPUT_WIDTH-1:0] p, + input [INPUT_WIDTH_A-1:0] a, + input [INPUT_WIDTH_B-1:0] b, + input cea, + input ceb, + input cepd, + input clk, + input rstan, + input rstbn, + input rstpdn +); + parameter INPUT_WIDTH_A = 18; + parameter INPUT_WIDTH_B = 18; + parameter OUTPUT_WIDTH = 36; + parameter INPUTFORMAT = "SIGNED"; + parameter INPUTREGA = "ENABLE"; + parameter INPUTREGB = "ENABLE"; + parameter OUTPUTREG = "ENABLE"; + parameter SRMODE = "ASYNC"; + parameter IMPLEMENT = "AUTO"; +endmodule + +(* blackbox *) +module EG_LOGIC_SEQ_DIV( + input clk, + input rst, + input start, + input [NUMER_WIDTH-1:0] numer, + input [DENOM_WIDTH-1:0] denom, + output [NUMER_WIDTH-1:0] quotient, + output [DENOM_WIDTH-1:0] remain, + output done +); + parameter NUMER_WIDTH = 16; + parameter DENOM_WIDTH = 16; +endmodule + +(* blackbox *) +module EG_PHY_BRAM( + output [8:0] doa, + output [8:0] dob, + input [8:0] dia, + input [8:0] dib, + input [2:0] csa, + input [2:0] csb, + input cea, + input ocea, + input clka, + input wea, + input rsta, + input ceb, + input oceb, + input clkb, + input web, + input rstb, + input [12:0] addra, + input [12:0] addrb +); + parameter MODE = "DP8K"; + parameter DATA_WIDTH_A = "9"; + parameter DATA_WIDTH_B = "9"; + parameter READBACK = "OFF"; + parameter REGMODE_A = "NOREG"; + parameter REGMODE_B = "NOREG"; + parameter WRITEMODE_A = "NORMAL"; + parameter WRITEMODE_B = "NORMAL"; + parameter GSR = "ENABLE"; + parameter RESETMODE = "SYNC"; + parameter ASYNC_RESET_RELEASE = "SYNC"; + parameter CEAMUX = "SIG"; + parameter CEBMUX = "SIG"; + parameter OCEAMUX = "SIG"; + parameter OCEBMUX = "SIG"; + parameter RSTAMUX = "SIG"; + parameter RSTBMUX = "SIG"; + parameter CLKAMUX = "SIG"; + parameter CLKBMUX = "SIG"; + parameter WEAMUX = "SIG"; + parameter WEBMUX = "SIG"; + parameter CSA0 = "SIG" ; + parameter CSA1 = "SIG" ; + parameter CSA2 = "SIG" ; + parameter CSB0 = "SIG" ; + parameter CSB1 = "SIG" ; + parameter CSB2 = "SIG" ; + parameter INIT_FILE = "NONE"; + parameter INITP_00 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INITP_01 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INITP_02 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INITP_03 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_00 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_01 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_02 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_03 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_04 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_05 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_06 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_07 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_08 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_09 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_0A = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_0B = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_0C = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_0D = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_0E = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_0F = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_10 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_11 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_12 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_13 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_14 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_15 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_16 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_17 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_18 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_19 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_1A = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_1B = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_1C = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_1D = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_1E = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_1F = 256'h0000000000000000000000000000000000000000000000000000000000000000; +endmodule + +(* blackbox *) +module EG_PHY_BRAM32K( + output [15:0] doa, + output [15:0] dob, + input [15:0] dia, + input [15:0] dib, + input [10:0] addra, + input [10:0] addrb, + input bytea, + input bytewea, + input byteb, + input byteweb, + input csa, + input wea, + input csb, + input web, + input clka, + input rsta, + input clkb, + input rstb, + input ocea, + input oceb +); + parameter MODE = "DP16K"; + parameter DATA_WIDTH_A = "16"; + parameter DATA_WIDTH_B = "16"; + parameter REGMODE_A = "NOREG"; + parameter REGMODE_B = "NOREG"; + parameter WRITEMODE_A = "NORMAL"; + parameter WRITEMODE_B = "NORMAL"; + parameter SRMODE = "SYNC"; + parameter CSAMUX = "SIG"; + parameter CSBMUX = "SIG"; + parameter OCEAMUX = "SIG"; + parameter OCEBMUX = "SIG"; + parameter RSTAMUX = "SIG"; + parameter RSTBMUX = "SIG"; + parameter CLKAMUX = "SIG"; + parameter CLKBMUX = "SIG"; + parameter WEAMUX = "SIG"; + parameter WEBMUX = "SIG"; + parameter READBACK = "OFF"; + parameter INIT_FILE = ""; + parameter INIT_00 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_01 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_02 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_03 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_04 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_05 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_06 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_07 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_08 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_09 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_0A = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_0B = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_0C = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_0D = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_0E = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_0F = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_10 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_11 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_12 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_13 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_14 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_15 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_16 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_17 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_18 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_19 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_1A = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_1B = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_1C = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_1D = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_1E = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_1F = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_20 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_21 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_22 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_23 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_24 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_25 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_26 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_27 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_28 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_29 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_2A = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_2B = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_2C = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_2D = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_2E = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_2F = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_30 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_31 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_32 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_33 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_34 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_35 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_36 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_37 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_38 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_39 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_3A = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_3B = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_3C = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_3D = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_3E = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_3F = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_40 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_41 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_42 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_43 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_44 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_45 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_46 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_47 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_48 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_49 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_4A = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_4B = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_4C = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_4D = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_4E = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_4F = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_50 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_51 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_52 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_53 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_54 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_55 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_56 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_57 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_58 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_59 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_5A = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_5B = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_5C = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_5D = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_5E = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_5F = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_60 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_61 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_62 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_63 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_64 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_65 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_66 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_67 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_68 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_69 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_6A = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_6B = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_6C = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_6D = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_6E = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_6F = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_70 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_71 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_72 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_73 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_74 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_75 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_76 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_77 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_78 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_79 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_7A = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_7B = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_7C = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_7D = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_7E = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_7F = 256'h0000000000000000000000000000000000000000000000000000000000000000; +endmodule + +(* blackbox *) +module EG_PHY_FIFO( + input [8:0] dia, + input [8:0] dib, + input [2:0] csr, + input [2:0] csw, + input we, + input re, + input clkw, + input clkr, + input rst, + input rprst, + input orea, + input oreb, + output [8:0] dob, + output [8:0] doa, + output empty_flag, + output aempty_flag, + output afull_flag, + output full_flag +); + parameter MODE = "FIFO8K"; + parameter DATA_WIDTH_A = "18"; + parameter DATA_WIDTH_B = "18"; + parameter READBACK = "OFF"; + parameter REGMODE_A = "NOREG"; + parameter REGMODE_B = "NOREG"; + parameter [13:0] AE = 14'b00000001100000; + parameter [13:0] AF = 14'b01111110010000; + parameter [13:0] F = 14'b01111111110000; + parameter [13:0] AEP1 = 14'b00000001110000; + parameter [13:0] AFM1 = 14'b01111110000000; + parameter [13:0] FM1 = 14'b01111111100000; + parameter [4:0] E = 5'b00000; + parameter [5:0] EP1 = 6'b010000; + parameter GSR = "ENABLE"; + parameter RESETMODE = "ASYNC"; + parameter ASYNC_RESET_RELEASE = "SYNC"; + parameter CEA = "SIG"; + parameter CEB = "SIG"; + parameter OCEA = "SIG"; + parameter OCEB = "SIG"; + parameter RSTA = "SIG"; + parameter RSTB = "SIG"; + parameter CLKA = "SIG"; + parameter CLKB = "SIG"; + parameter WEA = "SIG"; + parameter WEB = "SIG"; + parameter CSA0 = "SIG"; + parameter CSA1 = "SIG"; + parameter CSA2 = "SIG"; + parameter CSB0 = "SIG"; + parameter CSB1 = "SIG"; + parameter CSB2 = "SIG"; +endmodule + +(* blackbox *) +module EG_PHY_MULT18( + output [17:0] acout, + output [17:0] bcout, + output [35:0] p, + input signeda, + input signedb, + input [17:0] a, + input [17:0] b, + input [17:0] acin, + input [17:0] bcin, + input cea, + input ceb, + input cepd, + input clk, + input rstan, + input rstbn, + input rstpdn, + input sourcea, + input sourceb +); + parameter INPUTREGA = "ENABLE"; + parameter INPUTREGB = "ENABLE"; + parameter OUTPUTREG = "ENABLE"; + parameter SRMODE = "ASYNC"; + parameter MODE = "MULT18X18C"; + parameter CEAMUX = "SIG"; + parameter CEBMUX = "SIG"; + parameter CEPDMUX = "SIG"; + parameter RSTANMUX = "SIG"; + parameter RSTBNMUX = "SIG"; + parameter RSTPDNMUX = "SIG"; + parameter CLKMUX = "SIG"; + parameter SIGNEDAMUX = "SIG"; + parameter SIGNEDBMUX = "SIG"; + parameter SOURCEAMUX = "SIG"; + parameter SOURCEBMUX = "SIG"; +endmodule + +(* blackbox *) +module EG_PHY_GCLK( + input clki, + output clko +); +endmodule + +(* blackbox *) +module EG_PHY_IOCLK( + input clki, + input stop, + output clko +); + parameter STOPCLK = "DISABLE"; +endmodule + +(* blackbox *) +module EG_PHY_CLKDIV( + output clkdiv1, + output clkdivx, + input clki, + input rst, + input rls +); + parameter GSR = "DISABLE"; + parameter DIV = 2; +endmodule + +(* blackbox *) +module EG_PHY_CONFIG( + output jrstn, + output [1:0] jrti, + output jshift, + output jtck, + output jtdi, + output jupdate, + output [1:0] jscanen, + output jtms, + input [1:0] jtdo, + input [7:0] jtag8_ipa, + input [7:0] jtag8_ipb, + output done, + output highz, + output cclk, + input cclk_en, + input gsrn_sync_clk, + input usr_gsrn, + output dna_dout, + input dna_clk, + input dna_din, + input dna_shift_en, + input mboot_rebootn, + input [7:0] mboot_dynamic_addr +); + parameter MBOOT_AUTO_SEL = "DISABLE"; + parameter ADDR_SOURCE_SEL = "STATIC"; + parameter STATIC_ADDR = 8'b0; + parameter DONE_PERSISTN = "ENABLE"; + parameter INIT_PERSISTN = "ENABLE"; + parameter PROGRAMN_PERSISTN = "DISABLE"; + parameter JTAG_PERSISTN = "DISABLE"; + parameter GSRN_SYNC_SEL = "DISABLE"; + parameter FREQ = "2.5"; + parameter USR_GSRN_EN = "DISABLE"; +endmodule + +(* blackbox *) +module EG_PHY_OSC( + input osc_dis, + output osc_clk +); + parameter STDBY = "DISABLE"; +endmodule + +(* blackbox *) +module EG_PHY_PWRMNT( + output pwr_dwn_n, + input sel_pwr, + input pwr_mnt_pd +); + parameter MNT_LVL = 0; +endmodule + +(* blackbox *) +module EG_PHY_DDR_8M_16( + input clk, + input clk_n, + input ras_n, + input cas_n, + input we_n, + input cs_n, + input [11:0] addr, + input [1:0] ba, + inout [15:0] dq, + input ldqs, + input udqs, + input ldm, + input udm, + input cke +); +endmodule + +(* blackbox *) +module EG_PHY_SDRAM_2M_32( + input clk, + input ras_n, + input cas_n, + input we_n, + input [10:0] addr, + input [1:0] ba, + inout [31:0] dq, + input cs_n, + input dm0, + input dm1, + input dm2, + input dm3, + input cke +); +endmodule + +(* blackbox *) +module EG_PHY_PAD( + input ipad, + output opad, + inout bpad, + input rst, + input ce, + input isclk, + input ipclk, + input osclk, + input opclk, + input ts, + input [3:0] do, + output di, + output [3:0] diq +); + parameter DEDCLK = "DISABLE"; + parameter GSR = "ENABLE"; + parameter SRMODE = "SYNC"; + parameter TSMUX = "1"; + parameter INSCLKMUX = "0"; + parameter INPCLKMUX = "CLK"; + parameter INCEMUX = "CE"; + parameter INRSTMUX = "0"; + parameter IN_REGSET = "RESET"; + parameter IN_DFFMODE = "NONE"; + parameter IDDRMODE = "OFF"; + parameter IDDRPIPEMODE = "NONE"; + parameter INDELMUX = "NODEL"; + parameter INDEL = 0; + parameter OUTSCLKMUX = "0"; + parameter OUTPCLKMUX = "CLK"; + parameter OUTCEMUX = "CE"; + parameter OUTRSTMUX = "0"; + parameter DO_REGSET = "RESET"; + parameter DO_DFFMODE = "NONE"; + parameter ODDRMODE = "OFF"; + parameter OUTDELMUX = "NODEL"; + parameter OUTDEL = 0; + parameter TO_REGSET = "RESET"; + parameter TO_DFFMODE = "NONE"; + parameter MODE = "IN"; + parameter DRIVE = "NONE"; + parameter IOTYPE = "LVCMOS25"; +endmodule + +(* blackbox *) +module EG_PHY_MSLICE( + input [1:0] a, + input [1:0] b, + input [1:0] c, + input [1:0] d, + input [1:0] mi, + input clk, + input ce, + input sr, + input fci, + output [1:0] f, + output [1:0] fx, + output [1:0] q, + output fco, + input dpram_mode, + input [1:0] dpram_di, + input dpram_we, + input dpram_wclk, + input [3:0] dpram_waddr +); + parameter INIT_LUT0 = 16'h0000; + parameter INIT_LUT1 = 16'h0000; + parameter MODE = "LOGIC"; + parameter ALUTYPE = "ADD"; + parameter MSFXMUX = "OFF"; + parameter GSR = "ENABLE"; + parameter TESTMODE = "OFF"; + parameter CEMUX = "CE"; + parameter SRMUX = "SR"; + parameter CLKMUX = "CLK"; + parameter SRMODE = "ASYNC"; + parameter DFFMODE = "FF"; + parameter REG0_SD = "MI"; + parameter REG1_SD = "MI"; + parameter REG0_REGSET = "SET"; + parameter REG1_REGSET = "SET"; +endmodule + +(* blackbox *) +module EG_PHY_LSLICE( + input [1:0] a, + input [1:0] b, + input [1:0] c, + input [1:0] d, + input [1:0] e, + input [1:0] mi, + input clk, + input ce, + input sr, + input fci, + output [1:0] f, + output [1:0] fx, + output [1:0] q, + output fco, + output [3:0] dpram_di, + output [3:0] dpram_waddr, + output dpram_wclk, + output dpram_we, + output dpram_mode +); + parameter INIT_LUTF0 = 16'h0000; + parameter INIT_LUTG0 = 16'h0000; + parameter INIT_LUTF1 = 16'h0000; + parameter INIT_LUTG1 = 16'h0000; + parameter MODE = "LOGIC"; + parameter GSR = "ENABLE"; + parameter TESTMODE = "OFF"; + parameter CEMUX = "1"; + parameter SRMUX = "SR"; + parameter CLKMUX = "CLK"; + parameter SRMODE = "ASYNC"; + parameter DFFMODE = "FF"; + parameter REG0_SD = "MI"; + parameter REG1_SD = "MI"; + parameter REG0_REGSET = "SET"; + parameter REG1_REGSET = "SET"; + parameter DEMUX0 = "D"; + parameter DEMUX1 = "D"; + parameter CMIMUX0 = "C"; + parameter CMIMUX1 = "C"; + parameter LSFMUX0 = "LUTF"; + parameter LSFXMUX0 = "LUTG"; + parameter LSFMUX1 = "LUTF"; + parameter LSFXMUX1 = "LUTG"; +endmodule + +(* blackbox *) +module EG_PHY_PLL( + output [4:0] clkc, + output extlock, + input stdby, + input refclk, + input fbclk, + input reset, + output psdone, + input psclk, + input psdown, + input psstep, + input [2:0] psclksel, + output [7:0] do, + input dclk, + input dcs, + input dwe, + input [7:0] di, + input [5:0] daddr +); + parameter DYNCFG = "DISABLE"; + parameter IF_ESCLKSTSW = "DISABLE"; + parameter REFCLK_SEL = "INTERNAL"; + parameter FIN = "100.0000"; + parameter REFCLK_DIV = 1; + parameter FBCLK_DIV = 1; + parameter CLKC0_DIV = 1; + parameter CLKC1_DIV = 1; + parameter CLKC2_DIV = 1; + parameter CLKC3_DIV = 1; + parameter CLKC4_DIV = 1; + parameter CLKC0_ENABLE = "DISABLE"; + parameter CLKC1_ENABLE = "DISABLE"; + parameter CLKC2_ENABLE = "DISABLE"; + parameter CLKC3_ENABLE = "DISABLE"; + parameter CLKC4_ENABLE = "DISABLE"; + parameter CLKC0_DIV2_ENABLE = "DISABLE"; + parameter CLKC1_DIV2_ENABLE = "DISABLE"; + parameter CLKC2_DIV2_ENABLE = "DISABLE"; + parameter CLKC3_DIV2_ENABLE = "DISABLE"; + parameter CLKC4_DIV2_ENABLE = "DISABLE"; + parameter FEEDBK_MODE = "NORMAL"; + parameter FEEDBK_PATH = "VCO_PHASE_0"; + parameter STDBY_ENABLE = "ENABLE"; + parameter CLKC0_FPHASE = 0; + parameter CLKC1_FPHASE = 0; + parameter CLKC2_FPHASE = 0; + parameter CLKC3_FPHASE = 0; + parameter CLKC4_FPHASE = 0; + parameter CLKC0_CPHASE = 1; + parameter CLKC1_CPHASE = 1; + parameter CLKC2_CPHASE = 1; + parameter CLKC3_CPHASE = 1; + parameter CLKC4_CPHASE = 1; + parameter GMC_GAIN = 7; + parameter GMC_TEST = 14; + parameter ICP_CURRENT = 14; + parameter KVCO = 7; + parameter LPF_CAPACITOR = 3; + parameter LPF_RESISTOR = 1; + parameter PLLRST_ENA = "ENABLE"; + parameter PLLMRST_ENA = "DISABLE"; + parameter PLLC2RST_ENA = "DISABLE"; + parameter PLLC34RST_ENA = "DISABLE"; + parameter PREDIV_MUXC0 = "VCO"; + parameter PREDIV_MUXC1 = "VCO"; + parameter PREDIV_MUXC2 = "VCO"; + parameter PREDIV_MUXC3 = "VCO"; + parameter PREDIV_MUXC4 = "VCO"; + parameter ODIV_MUXC0 = "DIV"; + parameter ODIV_MUXC1 = "DIV"; + parameter ODIV_MUXC2 = "DIV"; + parameter ODIV_MUXC3 = "DIV"; + parameter ODIV_MUXC4 = "DIV"; + parameter FREQ_LOCK_ACCURACY = 2; + parameter PLL_LOCK_MODE = 0; + parameter INTFB_WAKE = "DISABLE"; + parameter DPHASE_SOURCE = "DISABLE"; + parameter VCO_NORESET = "DISABLE"; + parameter STDBY_VCO_ENA = "DISABLE"; + parameter NORESET = "DISABLE"; + parameter SYNC_ENABLE = "ENABLE"; + parameter DERIVE_PLL_CLOCKS = "DISABLE"; + parameter GEN_BASIC_CLOCK = "DISABLE"; +endmodule + +(* blackbox *) +module EG_LOGIC_BRAM( + output [DATA_WIDTH_A-1:0] doa, + output [DATA_WIDTH_B-1:0] dob, + input [DATA_WIDTH_A-1:0] dia, + input [DATA_WIDTH_B-1:0] dib, + input cea, + input ocea, + input clka, + input wea, + input rsta, + input ceb, + input oceb, + input clkb, + input web, + input rstb, + input [BYTE_A - 1 : 0] bea, + input [BYTE_B - 1 : 0] beb, + input [ADDR_WIDTH_A-1:0] addra, + input [ADDR_WIDTH_B-1:0] addrb +); + parameter DATA_WIDTH_A = 9; + parameter DATA_WIDTH_B = DATA_WIDTH_A; + parameter ADDR_WIDTH_A = 10; + parameter ADDR_WIDTH_B = ADDR_WIDTH_A; + parameter DATA_DEPTH_A = 2 ** ADDR_WIDTH_A; + parameter DATA_DEPTH_B = 2 ** ADDR_WIDTH_B; + parameter BYTE_ENABLE = 0; + parameter BYTE_A = BYTE_ENABLE == 0 ? 1 : DATA_WIDTH_A / BYTE_ENABLE; + parameter BYTE_B = BYTE_ENABLE == 0 ? 1 : DATA_WIDTH_B / BYTE_ENABLE; + parameter MODE = "DP"; + parameter REGMODE_A = "NOREG"; + parameter REGMODE_B = "NOREG"; + parameter WRITEMODE_A = "NORMAL"; + parameter WRITEMODE_B = "NORMAL"; + parameter RESETMODE = "SYNC"; + parameter DEBUGGABLE = "NO"; + parameter PACKABLE = "NO"; + parameter FORCE_KEEP = "OFF"; + parameter INIT_FILE = "NONE"; + parameter FILL_ALL = "NONE"; + parameter IMPLEMENT = "9K"; +endmodule + +(* blackbox *) +module EG_PHY_ADC( + input clk, + input pd, + input [2:0] s, + input soc, + output eoc, + output [11:0] dout +); + parameter CH0 = "DISABLE"; + parameter CH1 = "DISABLE"; + parameter CH2 = "DISABLE"; + parameter CH3 = "DISABLE"; + parameter CH4 = "DISABLE"; + parameter CH5 = "DISABLE"; + parameter CH6 = "DISABLE"; + parameter CH7 = "DISABLE"; + parameter VREF = "DISABLE"; +endmodule diff --git a/techlibs/anlogic/synth_anlogic.cc b/techlibs/anlogic/synth_anlogic.cc new file mode 100644 index 000000000..b87fc8566 --- /dev/null +++ b/techlibs/anlogic/synth_anlogic.cc @@ -0,0 +1,218 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2018 Miodrag Milanovic <miodrag@symbioticeda.com> + * Copyright (C) 2018 Clifford Wolf <clifford@clifford.at> + * + * 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/register.h" +#include "kernel/celltypes.h" +#include "kernel/rtlil.h" +#include "kernel/log.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct SynthAnlogicPass : public ScriptPass +{ + SynthAnlogicPass() : ScriptPass("synth_anlogic", "synthesis for Anlogic FPGAs") { } + + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" synth_anlogic [options]\n"); + log("\n"); + log("This command runs synthesis for Anlogic FPGAs.\n"); + log("\n"); + log(" -top <module>\n"); + log(" use the specified module as top module\n"); + log("\n"); + log(" -edif <file>\n"); + log(" write the design to the specified EDIF file. writing of an output file\n"); + log(" is omitted if this parameter is not specified.\n"); + log("\n"); + log(" -json <file>\n"); + log(" write the design to the specified JSON file. writing of an output file\n"); + log(" is omitted if this parameter is not specified.\n"); + log("\n"); + log(" -run <from_label>:<to_label>\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"); + log(" synonymous to the end of the command list.\n"); + log("\n"); + log(" -noflatten\n"); + log(" do not flatten design before synthesis\n"); + log("\n"); + log(" -retime\n"); + log(" run 'abc' with -dff option\n"); + log("\n"); + log("\n"); + log("The following commands are executed by this synthesis command:\n"); + help_script(); + log("\n"); + } + + string top_opt, edif_file, json_file; + bool flatten, retime; + + void clear_flags() YS_OVERRIDE + { + top_opt = "-auto-top"; + edif_file = ""; + json_file = ""; + flatten = true; + retime = false; + } + + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + string run_from, run_to; + clear_flags(); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + if (args[argidx] == "-top" && argidx+1 < args.size()) { + top_opt = "-top " + args[++argidx]; + continue; + } + if (args[argidx] == "-edif" && argidx+1 < args.size()) { + edif_file = args[++argidx]; + continue; + } + if (args[argidx] == "-json" && argidx+1 < args.size()) { + json_file = args[++argidx]; + continue; + } + if (args[argidx] == "-run" && argidx+1 < args.size()) { + size_t pos = args[argidx+1].find(':'); + if (pos == std::string::npos) + break; + run_from = args[++argidx].substr(0, pos); + run_to = args[argidx].substr(pos+1); + continue; + } + if (args[argidx] == "-noflatten") { + flatten = false; + continue; + } + if (args[argidx] == "-retime") { + retime = true; + continue; + } + break; + } + extra_args(args, argidx, design); + + if (!design->full_selection()) + log_cmd_error("This command only operates on fully selected designs!\n"); + + log_header(design, "Executing SYNTH_ANLOGIC pass.\n"); + log_push(); + + run_script(design, run_from, run_to); + + log_pop(); + } + + void script() YS_OVERRIDE + { + if (check_label("begin")) + { + run("read_verilog -lib +/anlogic/cells_sim.v +/anlogic/eagle_bb.v"); + run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str())); + } + + if (flatten && check_label("flatten", "(unless -noflatten)")) + { + run("proc"); + run("flatten"); + run("tribuf -logic"); + run("deminout"); + } + + if (check_label("coarse")) + { + run("synth -run coarse"); + } + + if (check_label("dram")) + { + run("memory_bram -rules +/anlogic/drams.txt"); + run("techmap -map +/anlogic/drams_map.v"); + run("setundef -zero -params t:EG_LOGIC_DRAM16X4"); + } + + if (check_label("fine")) + { + run("opt -fast -mux_undef -undriven -fine"); + run("memory_map"); + run("opt -undriven -fine"); + run("techmap -map +/techmap.v -map +/anlogic/arith_map.v"); + if (retime || help_mode) + run("abc -dff", "(only if -retime)"); + } + + if (check_label("map_ffs")) + { + run("dffsr2dff"); + run("techmap -D NO_LUT -map +/anlogic/cells_map.v"); + run("dffinit -strinit SET RESET -ff AL_MAP_SEQ q REGSET -noreinit"); + run("opt_expr -mux_undef"); + run("simplemap"); + } + + if (check_label("map_luts")) + { + run("abc -lut 4:6"); + run("clean"); + } + + if (check_label("map_cells")) + { + run("techmap -map +/anlogic/cells_map.v"); + run("clean"); + } + + if (check_label("map_anlogic")) + { + run("anlogic_fixcarry"); + run("anlogic_eqn"); + } + + if (check_label("check")) + { + run("hierarchy -check"); + run("stat"); + run("check -noinit"); + } + + if (check_label("edif")) + { + if (!edif_file.empty() || help_mode) + run(stringf("write_edif %s", help_mode ? "<file-name>" : edif_file.c_str())); + } + + if (check_label("json")) + { + if (!json_file.empty() || help_mode) + run(stringf("write_json %s", help_mode ? "<file-name>" : json_file.c_str())); + } + } +} SynthAnlogicPass; + +PRIVATE_NAMESPACE_END diff --git a/techlibs/common/Makefile.inc b/techlibs/common/Makefile.inc index ab961ac0b..de94798af 100644 --- a/techlibs/common/Makefile.inc +++ b/techlibs/common/Makefile.inc @@ -25,5 +25,7 @@ $(eval $(call add_share_file,share,techlibs/common/techmap.v)) $(eval $(call add_share_file,share,techlibs/common/pmux2mux.v)) $(eval $(call add_share_file,share,techlibs/common/adff2dff.v)) $(eval $(call add_share_file,share,techlibs/common/dff2ff.v)) +$(eval $(call add_share_file,share,techlibs/common/gate2lut.v)) +$(eval $(call add_share_file,share,techlibs/common/cmp2lut.v)) $(eval $(call add_share_file,share,techlibs/common/cells.lib)) - +$(eval $(call add_share_file,share,techlibs/common/dummy.box)) diff --git a/techlibs/common/cmp2lut.v b/techlibs/common/cmp2lut.v new file mode 100644 index 000000000..0d0757767 --- /dev/null +++ b/techlibs/common/cmp2lut.v @@ -0,0 +1,105 @@ +// Certain arithmetic operations between a signal of width n and a constant can be directly mapped +// to a single k-LUT (where n <= k). This is preferable to normal alumacc techmapping process +// because for many targets, arithmetic techmapping creates hard logic (such as carry cells) which often +// cannot be optimized further. +// +// TODO: Currently, only comparisons with 1-bit output are mapped. Potentially, all arithmetic cells +// with n <= k inputs should be techmapped in this way, because this shortens the critical path +// from n to 1 by avoiding carry chains. + +(* techmap_celltype = "$eq $ne $lt $le $gt $ge" *) +module _90_lut_cmp_ (A, B, Y); + +parameter A_SIGNED = 0; +parameter B_SIGNED = 0; +parameter A_WIDTH = 0; +parameter B_WIDTH = 0; +parameter Y_WIDTH = 0; + +input [A_WIDTH-1:0] A; +input [B_WIDTH-1:0] B; +output [Y_WIDTH-1:0] Y; + +parameter _TECHMAP_CELLTYPE_ = ""; + +parameter _TECHMAP_CONSTMSK_A_ = 0; +parameter _TECHMAP_CONSTVAL_A_ = 0; +parameter _TECHMAP_CONSTMSK_B_ = 0; +parameter _TECHMAP_CONSTVAL_B_ = 0; + +function automatic [(1 << `LUT_WIDTH)-1:0] gen_lut; + input integer width; + input integer operation; + input integer swap; + input integer sign; + input integer operand; + integer n, i_var, i_cst, lhs, rhs, o_bit; + begin + gen_lut = width'b0; + for (n = 0; n < (1 << width); n++) begin + if (sign) + i_var = n[width-1:0]; + else + i_var = n; + i_cst = operand; + if (swap) begin + lhs = i_cst; + rhs = i_var; + end else begin + lhs = i_var; + rhs = i_cst; + end + if (operation == 0) + o_bit = (lhs < rhs); + if (operation == 1) + o_bit = (lhs <= rhs); + if (operation == 2) + o_bit = (lhs > rhs); + if (operation == 3) + o_bit = (lhs >= rhs); + if (operation == 4) + o_bit = (lhs == rhs); + if (operation == 5) + o_bit = (lhs != rhs); + gen_lut = gen_lut | (o_bit << n); + end + end +endfunction + +generate + if (_TECHMAP_CELLTYPE_ == "$lt") + localparam operation = 0; + if (_TECHMAP_CELLTYPE_ == "$le") + localparam operation = 1; + if (_TECHMAP_CELLTYPE_ == "$gt") + localparam operation = 2; + if (_TECHMAP_CELLTYPE_ == "$ge") + localparam operation = 3; + if (_TECHMAP_CELLTYPE_ == "$eq") + localparam operation = 4; + if (_TECHMAP_CELLTYPE_ == "$ne") + localparam operation = 5; + + if (A_WIDTH > `LUT_WIDTH || B_WIDTH > `LUT_WIDTH || Y_WIDTH != 1) + wire _TECHMAP_FAIL_ = 1; + else if (&_TECHMAP_CONSTMSK_B_) + \$lut #( + .WIDTH(A_WIDTH), + .LUT({ gen_lut(A_WIDTH, operation, 0, A_SIGNED && B_SIGNED, _TECHMAP_CONSTVAL_B_) }) + ) _TECHMAP_REPLACE_ ( + .A(A), + .Y(Y) + ); + else if (&_TECHMAP_CONSTMSK_A_) + \$lut #( + .WIDTH(B_WIDTH), + .LUT({ gen_lut(B_WIDTH, operation, 1, A_SIGNED && B_SIGNED, _TECHMAP_CONSTVAL_A_) }) + ) _TECHMAP_REPLACE_ ( + .A(B), + .Y(Y) + ); + else + wire _TECHMAP_FAIL_ = 1; +endgenerate + +endmodule diff --git a/techlibs/common/dummy.box b/techlibs/common/dummy.box new file mode 100644 index 000000000..0c18070a0 --- /dev/null +++ b/techlibs/common/dummy.box @@ -0,0 +1 @@ +(dummy) 1 0 0 0 diff --git a/techlibs/common/gate2lut.v b/techlibs/common/gate2lut.v new file mode 100644 index 000000000..99c123f4a --- /dev/null +++ b/techlibs/common/gate2lut.v @@ -0,0 +1,87 @@ +(* techmap_celltype = "$_NOT_" *) +module _90_lut_not (A, Y); + input A; + output Y; + + wire [`LUT_WIDTH-1:0] AA; + assign AA = {A}; + + \$lut #( + .WIDTH(`LUT_WIDTH), + .LUT(4'b01) + ) lut ( + .A(AA), + .Y(Y) + ); +endmodule + +(* techmap_celltype = "$_OR_" *) +module _90_lut_or (A, B, Y); + input A, B; + output Y; + + wire [`LUT_WIDTH-1:0] AA; + assign AA = {B, A}; + + \$lut #( + .WIDTH(`LUT_WIDTH), + .LUT(4'b1110) + ) lut ( + .A(AA), + .Y(Y) + ); +endmodule + +(* techmap_celltype = "$_AND_" *) +module _90_lut_and (A, B, Y); + input A, B; + output Y; + + wire [`LUT_WIDTH-1:0] AA; + assign AA = {B, A}; + + \$lut #( + .WIDTH(`LUT_WIDTH), + .LUT(4'b1000) + ) lut ( + .A(AA), + .Y(Y) + ); +endmodule + +(* techmap_celltype = "$_XOR_" *) +module _90_lut_xor (A, B, Y); + input A, B; + output Y; + + wire [`LUT_WIDTH-1:0] AA; + assign AA = {B, A}; + + \$lut #( + .WIDTH(`LUT_WIDTH), + .LUT(4'b0110) + ) lut ( + .A(AA), + .Y(Y) + ); +endmodule + +(* techmap_celltype = "$_MUX_" *) +module _90_lut_mux (A, B, S, Y); + input A, B, S; + output Y; + + wire [`LUT_WIDTH-1:0] AA; + assign AA = {S, B, A}; + + \$lut #( + .WIDTH(`LUT_WIDTH), + // A 1010 1010 + // B 1100 1100 + // S 1111 0000 + .LUT(8'b_1100_1010) + ) lut ( + .A(AA), + .Y(Y) + ); +endmodule diff --git a/techlibs/common/prep.cc b/techlibs/common/prep.cc index cc977f97e..cdd21c3b3 100644 --- a/techlibs/common/prep.cc +++ b/techlibs/common/prep.cc @@ -29,7 +29,7 @@ struct PrepPass : public ScriptPass { PrepPass() : ScriptPass("prep", "generic synthesis script") { } - virtual void help() YS_OVERRIDE + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -81,7 +81,7 @@ struct PrepPass : public ScriptPass string top_module, fsm_opts; bool autotop, flatten, ifxmode, memxmode, nomemmode, nokeepdc, nordff; - virtual void clear_flags() YS_OVERRIDE + void clear_flags() YS_OVERRIDE { top_module.clear(); @@ -94,7 +94,7 @@ struct PrepPass : public ScriptPass nordff = true; } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { string run_from, run_to; @@ -153,7 +153,7 @@ struct PrepPass : public ScriptPass extra_args(args, argidx, design); if (!design->full_selection()) - log_cmd_error("This comannd only operates on fully selected designs!\n"); + log_cmd_error("This command only operates on fully selected designs!\n"); log_header(design, "Executing PREP pass.\n"); log_push(); @@ -163,7 +163,7 @@ struct PrepPass : public ScriptPass log_pop(); } - virtual void script() YS_OVERRIDE + void script() YS_OVERRIDE { if (check_label("begin")) @@ -195,9 +195,11 @@ struct PrepPass : public ScriptPass run(nokeepdc ? "opt" : "opt -keepdc"); if (!ifxmode) { if (help_mode) - run("wreduce [-memx]"); - else + run("wreduce -keepdc [-memx]"); + else if (nokeepdc) run(memxmode ? "wreduce -memx" : "wreduce"); + else + run(memxmode ? "wreduce -keepdc -memx" : "wreduce -keepdc"); } if (!nomemmode) { run(string("memory_dff") + (help_mode ? " [-nordff]" : nordff ? " -nordff" : "")); diff --git a/techlibs/common/simcells.v b/techlibs/common/simcells.v index 937512e7c..64720e598 100644 --- a/techlibs/common/simcells.v +++ b/techlibs/common/simcells.v @@ -230,6 +230,25 @@ endmodule // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| //- +//- $_NMUX_ (A, B, S, Y) +//- +//- A 2-input inverting MUX gate. +//- +//- Truth table: A B S | Y +//- -------+--- +//- 0 - 0 | 1 +//- 1 - 0 | 0 +//- - 0 1 | 1 +//- - 1 1 | 0 +//- +module \$_NMUX_ (A, B, S, Y); +input A, B, S; +output Y; +assign Y = S ? !B : !A; +endmodule + +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- //- $_MUX4_ (A, B, C, D, S, T, Y) //- //- A 4-input MUX gate. @@ -465,7 +484,7 @@ endmodule //- //- $_SR_NP_ (S, R, Q) //- -//- A set-reset latch with negative polarity SET and positive polarioty RESET. +//- A set-reset latch with negative polarity SET and positive polarity RESET. //- //- Truth table: S R | Q //- -----+--- @@ -489,7 +508,7 @@ endmodule //- //- $_SR_PN_ (S, R, Q) //- -//- A set-reset latch with positive polarity SET and negative polarioty RESET. +//- A set-reset latch with positive polarity SET and negative polarity RESET. //- //- Truth table: S R | Q //- -----+--- diff --git a/techlibs/common/simlib.v b/techlibs/common/simlib.v index 8e43fe058..7845a3fed 100644 --- a/techlibs/common/simlib.v +++ b/techlibs/common/simlib.v @@ -532,14 +532,26 @@ endmodule // -------------------------------------------------------- +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- +//- $lcu (P, G, CI, CO) +//- +//- Lookahead carry unit +//- A building block dedicated to fast computation of carry-bits used in binary +//- arithmetic operations. By replacing the ripple carry structure used in full-adder +//- blocks, the more significant bits of the sum can be expected to be computed more +//- quickly. +//- Typically created during `techmap` of $alu cells (see the "_90_alu" rule in +//- +/techmap.v). module \$lcu (P, G, CI, CO); parameter WIDTH = 1; -input [WIDTH-1:0] P, G; -input CI; +input [WIDTH-1:0] P; // Propagate +input [WIDTH-1:0] G; // Generate +input CI; // Carry-in -output reg [WIDTH-1:0] CO; +output reg [WIDTH-1:0] CO; // Carry-out integer i; always @* begin @@ -555,6 +567,17 @@ endmodule // -------------------------------------------------------- +// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| +//- +//- $alu (A, B, CI, BI, X, Y, CO) +//- +//- Arithmetic logic unit. +//- A building block supporting both binary addition/subtraction operations, and +//- indirectly, comparison operations. +//- Typically created by the `alumacc` pass, which transforms: +//- $add, $sub, $lt, $le, $ge, $gt, $eq, $eqx, $ne, $nex +//- cells into this $alu cell. +//- module \$alu (A, B, CI, BI, X, Y, CO); parameter A_SIGNED = 0; @@ -563,12 +586,16 @@ parameter A_WIDTH = 1; parameter B_WIDTH = 1; parameter Y_WIDTH = 1; -input [A_WIDTH-1:0] A; -input [B_WIDTH-1:0] B; -output [Y_WIDTH-1:0] X, Y; +input [A_WIDTH-1:0] A; // Input operand +input [B_WIDTH-1:0] B; // Input operand +output [Y_WIDTH-1:0] X; // A xor B (sign-extended, optional B inversion, + // used in combination with + // reduction-AND for $eq/$ne ops) +output [Y_WIDTH-1:0] Y; // Sum -input CI, BI; -output [Y_WIDTH-1:0] CO; +input CI; // Carry-in (set for $sub) +input BI; // Invert-B (set for $sub) +output [Y_WIDTH-1:0] CO; // Carry-out wire [Y_WIDTH-1:0] AA, BB; @@ -584,6 +611,7 @@ endgenerate wire y_co_undef = ^{A, A, B, B, CI, CI, BI, BI}; assign X = AA ^ BB; +// Full adder assign Y = (AA + BB + CI) ^ {Y_WIDTH{y_co_undef}}; function get_carry; @@ -1271,6 +1299,181 @@ endmodule // -------------------------------------------------------- +module \$specify2 (EN, SRC, DST); + +parameter FULL = 0; +parameter SRC_WIDTH = 1; +parameter DST_WIDTH = 1; + +parameter SRC_DST_PEN = 0; +parameter SRC_DST_POL = 0; + +parameter T_RISE_MIN = 0; +parameter T_RISE_TYP = 0; +parameter T_RISE_MAX = 0; + +parameter T_FALL_MIN = 0; +parameter T_FALL_TYP = 0; +parameter T_FALL_MAX = 0; + +input EN; +input [SRC_WIDTH-1:0] SRC; +input [DST_WIDTH-1:0] DST; + +localparam SD = SRC_DST_PEN ? (SRC_DST_POL ? 1 : 2) : 0; + +`ifdef SIMLIB_SPECIFY +specify + if (EN && SD==0 && !FULL) (SRC => DST) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && SD==0 && FULL) (SRC *> DST) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && SD==1 && !FULL) (SRC +=> DST) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && SD==1 && FULL) (SRC +*> DST) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && SD==2 && !FULL) (SRC -=> DST) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && SD==2 && FULL) (SRC -*> DST) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); +endspecify +`endif + +endmodule + +// -------------------------------------------------------- + +module \$specify3 (EN, SRC, DST, DAT); + +parameter FULL = 0; +parameter SRC_WIDTH = 1; +parameter DST_WIDTH = 1; + +parameter EDGE_EN = 0; +parameter EDGE_POL = 0; + +parameter SRC_DST_PEN = 0; +parameter SRC_DST_POL = 0; + +parameter DAT_DST_PEN = 0; +parameter DAT_DST_POL = 0; + +parameter T_RISE_MIN = 0; +parameter T_RISE_TYP = 0; +parameter T_RISE_MAX = 0; + +parameter T_FALL_MIN = 0; +parameter T_FALL_TYP = 0; +parameter T_FALL_MAX = 0; + +input EN; +input [SRC_WIDTH-1:0] SRC; +input [DST_WIDTH-1:0] DST, DAT; + +localparam ED = EDGE_EN ? (EDGE_POL ? 1 : 2) : 0; +localparam SD = SRC_DST_PEN ? (SRC_DST_POL ? 1 : 2) : 0; +localparam DD = DAT_DST_PEN ? (DAT_DST_POL ? 1 : 2) : 0; + +`ifdef SIMLIB_SPECIFY +specify + // DD=0 + + if (EN && DD==0 && SD==0 && ED==0 && !FULL) ( SRC => (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==0 && SD==0 && ED==0 && FULL) ( SRC *> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==0 && SD==0 && ED==1 && !FULL) (posedge SRC => (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==0 && SD==0 && ED==1 && FULL) (posedge SRC *> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==0 && SD==0 && ED==2 && !FULL) (negedge SRC => (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==0 && SD==0 && ED==2 && FULL) (negedge SRC *> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + + if (EN && DD==0 && SD==1 && ED==0 && !FULL) ( SRC +=> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==0 && SD==1 && ED==0 && FULL) ( SRC +*> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==0 && SD==1 && ED==1 && !FULL) (posedge SRC +=> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==0 && SD==1 && ED==1 && FULL) (posedge SRC +*> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==0 && SD==1 && ED==2 && !FULL) (negedge SRC +=> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==0 && SD==1 && ED==2 && FULL) (negedge SRC +*> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + + if (EN && DD==0 && SD==2 && ED==0 && !FULL) ( SRC -=> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==0 && SD==2 && ED==0 && FULL) ( SRC -*> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==0 && SD==2 && ED==1 && !FULL) (posedge SRC -=> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==0 && SD==2 && ED==1 && FULL) (posedge SRC -*> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==0 && SD==2 && ED==2 && !FULL) (negedge SRC -=> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==0 && SD==2 && ED==2 && FULL) (negedge SRC -*> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + + // DD=1 + + if (EN && DD==1 && SD==0 && ED==0 && !FULL) ( SRC => (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==1 && SD==0 && ED==0 && FULL) ( SRC *> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==1 && SD==0 && ED==1 && !FULL) (posedge SRC => (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==1 && SD==0 && ED==1 && FULL) (posedge SRC *> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==1 && SD==0 && ED==2 && !FULL) (negedge SRC => (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==1 && SD==0 && ED==2 && FULL) (negedge SRC *> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + + if (EN && DD==1 && SD==1 && ED==0 && !FULL) ( SRC +=> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==1 && SD==1 && ED==0 && FULL) ( SRC +*> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==1 && SD==1 && ED==1 && !FULL) (posedge SRC +=> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==1 && SD==1 && ED==1 && FULL) (posedge SRC +*> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==1 && SD==1 && ED==2 && !FULL) (negedge SRC +=> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==1 && SD==1 && ED==2 && FULL) (negedge SRC +*> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + + if (EN && DD==1 && SD==2 && ED==0 && !FULL) ( SRC -=> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==1 && SD==2 && ED==0 && FULL) ( SRC -*> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==1 && SD==2 && ED==1 && !FULL) (posedge SRC -=> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==1 && SD==2 && ED==1 && FULL) (posedge SRC -*> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==1 && SD==2 && ED==2 && !FULL) (negedge SRC -=> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==1 && SD==2 && ED==2 && FULL) (negedge SRC -*> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + + // DD=2 + + if (EN && DD==2 && SD==0 && ED==0 && !FULL) ( SRC => (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==2 && SD==0 && ED==0 && FULL) ( SRC *> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==2 && SD==0 && ED==1 && !FULL) (posedge SRC => (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==2 && SD==0 && ED==1 && FULL) (posedge SRC *> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==2 && SD==0 && ED==2 && !FULL) (negedge SRC => (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==2 && SD==0 && ED==2 && FULL) (negedge SRC *> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + + if (EN && DD==2 && SD==1 && ED==0 && !FULL) ( SRC +=> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==2 && SD==1 && ED==0 && FULL) ( SRC +*> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==2 && SD==1 && ED==1 && !FULL) (posedge SRC +=> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==2 && SD==1 && ED==1 && FULL) (posedge SRC +*> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==2 && SD==1 && ED==2 && !FULL) (negedge SRC +=> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==2 && SD==1 && ED==2 && FULL) (negedge SRC +*> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + + if (EN && DD==2 && SD==2 && ED==0 && !FULL) ( SRC -=> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==2 && SD==2 && ED==0 && FULL) ( SRC -*> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==2 && SD==2 && ED==1 && !FULL) (posedge SRC -=> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==2 && SD==2 && ED==1 && FULL) (posedge SRC -*> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==2 && SD==2 && ED==2 && !FULL) (negedge SRC -=> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==2 && SD==2 && ED==2 && FULL) (negedge SRC -*> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); +endspecify +`endif + +endmodule + +// -------------------------------------------------------- + +module \$specrule (EN_SRC, EN_DST, SRC, DST); + +parameter TYPE = ""; +parameter T_LIMIT = 0; +parameter T_LIMIT2 = 0; + +parameter SRC_WIDTH = 1; +parameter DST_WIDTH = 1; + +parameter SRC_PEN = 0; +parameter SRC_POL = 0; + +parameter DST_PEN = 0; +parameter DST_POL = 0; + +input EN_SRC, EN_DST; +input [SRC_WIDTH-1:0] SRC; +input [DST_WIDTH-1:0] DST; + +`ifdef SIMLIB_SPECIFY +specify + // TBD +endspecify +`endif + +endmodule + +// -------------------------------------------------------- + module \$assert (A, EN); input A, EN; @@ -1863,4 +2066,5 @@ end endmodule `endif + // -------------------------------------------------------- diff --git a/techlibs/common/synth.cc b/techlibs/common/synth.cc index 4ca34839e..a176357a7 100644 --- a/techlibs/common/synth.cc +++ b/techlibs/common/synth.cc @@ -29,7 +29,7 @@ struct SynthPass : public ScriptPass { SynthPass() : ScriptPass("synth", "generic synthesis script") { } - virtual void help() YS_OVERRIDE + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -51,6 +51,9 @@ struct SynthPass : public ScriptPass log(" -encfile <file>\n"); log(" passed to 'fsm_recode' via 'fsm'\n"); log("\n"); + log(" -lut <k>\n"); + log(" perform synthesis for a k-LUT architecture.\n"); + log("\n"); log(" -nofsm\n"); log(" do not run FSM optimization\n"); log("\n"); @@ -72,16 +75,20 @@ struct SynthPass : public ScriptPass log(" from label is synonymous to 'begin', and empty to label is\n"); log(" synonymous to the end of the command list.\n"); log("\n"); + log(" -abc9\n"); + log(" use new ABC9 flow (EXPERIMENTAL)\n"); + log("\n"); log("\n"); log("The following commands are executed by this synthesis command:\n"); help_script(); log("\n"); } - string top_module, fsm_opts, memory_opts; + string top_module, fsm_opts, memory_opts, abc; bool autotop, flatten, noalumacc, nofsm, noabc, noshare; + int lut; - virtual void clear_flags() YS_OVERRIDE + void clear_flags() YS_OVERRIDE { top_module.clear(); fsm_opts.clear(); @@ -89,13 +96,15 @@ struct SynthPass : public ScriptPass autotop = false; flatten = false; + lut = 0; noalumacc = false; nofsm = false; noabc = false; noshare = false; + abc = "abc"; } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { string run_from, run_to; clear_flags(); @@ -130,6 +139,10 @@ struct SynthPass : public ScriptPass flatten = true; continue; } + if (args[argidx] == "-lut") { + lut = atoi(args[++argidx].c_str()); + continue; + } if (args[argidx] == "-nofsm") { nofsm = true; continue; @@ -150,12 +163,19 @@ struct SynthPass : public ScriptPass noshare = true; continue; } + if (args[argidx] == "-abc9") { + abc = "abc9"; + continue; + } break; } extra_args(args, argidx, design); if (!design->full_selection()) - log_cmd_error("This comannd only operates on fully selected designs!\n"); + log_cmd_error("This command only operates on fully selected designs!\n"); + + if (abc == "abc9" && !lut) + log_cmd_error("ABC9 flow only supported for FPGA synthesis (using '-lut' option)\n"); log_header(design, "Executing SYNTH pass.\n"); log_push(); @@ -165,7 +185,7 @@ struct SynthPass : public ScriptPass log_pop(); } - virtual void script() YS_OVERRIDE + void script() YS_OVERRIDE { if (check_label("begin")) { @@ -186,19 +206,25 @@ struct SynthPass : public ScriptPass { run("proc"); if (help_mode || flatten) - run("flatten", "(if -flatten)"); + run("flatten", " (if -flatten)"); run("opt_expr"); run("opt_clean"); run("check"); run("opt"); run("wreduce"); + run("peepopt"); + run("opt_clean"); + if (help_mode) + run("techmap -map +/cmp2lut.v", " (if -lut)"); + else + run(stringf("techmap -map +/cmp2lut.v -D LUT_WIDTH=%d", lut)); if (!noalumacc) - run("alumacc"); + run("alumacc", " (unless -noalumacc)"); if (!noshare) - run("share"); + run("share", " (unless -noshare)"); run("opt"); if (!nofsm) - run("fsm" + fsm_opts); + run("fsm" + fsm_opts, " (unless -nofsm)"); run("opt -fast"); run("memory -nomap" + memory_opts); run("opt_clean"); @@ -210,12 +236,33 @@ struct SynthPass : public ScriptPass run("memory_map"); run("opt -full"); run("techmap"); + if (help_mode) + { + run("techmap -map +/gate2lut.v", "(if -noabc and -lut)"); + run("clean; opt_lut", " (if -noabc and -lut)"); + } + else if (noabc && lut) + { + run(stringf("techmap -map +/gate2lut.v -D LUT_WIDTH=%d", lut)); + run("clean; opt_lut"); + } run("opt -fast"); if (!noabc) { #ifdef YOSYS_ENABLE_ABC - run("abc -fast"); - run("opt -fast"); + if (help_mode) + { + run(abc + " -fast", " (unless -noabc, unless -lut)"); + run(abc + " -fast -lut k", "(unless -noabc, if -lut)"); + } + else + { + if (lut) + run(stringf("%s -fast -lut %d", abc.c_str(), lut)); + else + run(abc + " -fast"); + } + run("opt -fast", " (unless -noabc)"); #endif } } diff --git a/techlibs/coolrunner2/coolrunner2_sop.cc b/techlibs/coolrunner2/coolrunner2_sop.cc index 431e0a127..de0cbb29d 100644 --- a/techlibs/coolrunner2/coolrunner2_sop.cc +++ b/techlibs/coolrunner2/coolrunner2_sop.cc @@ -25,7 +25,7 @@ PRIVATE_NAMESPACE_BEGIN struct Coolrunner2SopPass : public Pass { Coolrunner2SopPass() : Pass("coolrunner2_sop", "break $sop cells into ANDTERM/ORTERM cells") { } - virtual void help() + void help() YS_OVERRIDE { log("\n"); log(" coolrunner2_sop [options] [selection]\n"); @@ -33,7 +33,7 @@ struct Coolrunner2SopPass : public Pass { log("Break $sop cells into ANDTERM/ORTERM cells.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing COOLRUNNER2_SOP pass (break $sop cells into ANDTERM/ORTERM cells).\n"); extra_args(args, 1, design); @@ -60,10 +60,8 @@ struct Coolrunner2SopPass : public Pass { dict<SigBit, pool<tuple<Cell*, std::string>>> special_pterms_inv; for (auto cell : module->selected_cells()) { - if (cell->type == "\\FDCP" || cell->type == "\\FDCP_N" || cell->type == "\\FDDCP" || - cell->type == "\\FTCP" || cell->type == "\\FTCP_N" || cell->type == "\\FTDCP" || - cell->type == "\\FDCPE" || cell->type == "\\FDCPE_N" || cell->type == "\\FDDCPE" || - cell->type == "\\LDCP" || cell->type == "\\LDCP_N") + if (cell->type.in("\\FDCP", "\\FDCP_N", "\\FDDCP", "\\FTCP", "\\FTCP_N", "\\FTDCP", + "\\FDCPE", "\\FDCPE_N", "\\FDDCPE", "\\LDCP", "\\LDCP_N")) { if (cell->hasPort("\\PRE")) special_pterms_no_inv[sigmap(cell->getPort("\\PRE")[0])].insert( @@ -257,10 +255,8 @@ struct Coolrunner2SopPass : public Pass { pool<SigBit> sig_fed_by_ff; for (auto cell : module->selected_cells()) { - if (cell->type == "\\FDCP" || cell->type == "\\FDCP_N" || cell->type == "\\FDDCP" || - cell->type == "\\LDCP" || cell->type == "\\LDCP_N" || - cell->type == "\\FTCP" || cell->type == "\\FTCP_N" || cell->type == "\\FTDCP" || - cell->type == "\\FDCPE" || cell->type == "\\FDCPE_N" || cell->type == "\\FDDCPE") + if (cell->type.in("\\FDCP", "\\FDCP_N", "\\FDDCP", "\\LDCP", "\\LDCP_N", + "\\FTCP", "\\FTCP_N", "\\FTDCP", "\\FDCPE", "\\FDCPE_N", "\\FDDCPE")) { auto output = sigmap(cell->getPort("\\Q")[0]); sig_fed_by_ff.insert(output); @@ -270,13 +266,11 @@ struct Coolrunner2SopPass : public Pass { // Look at all the FF inputs for (auto cell : module->selected_cells()) { - if (cell->type == "\\FDCP" || cell->type == "\\FDCP_N" || cell->type == "\\FDDCP" || - cell->type == "\\LDCP" || cell->type == "\\LDCP_N" || - cell->type == "\\FTCP" || cell->type == "\\FTCP_N" || cell->type == "\\FTDCP" || - cell->type == "\\FDCPE" || cell->type == "\\FDCPE_N" || cell->type == "\\FDDCPE") + if (cell->type.in("\\FDCP", "\\FDCP_N", "\\FDDCP", "\\LDCP", "\\LDCP_N", + "\\FTCP", "\\FTCP_N", "\\FTDCP", "\\FDCPE", "\\FDCPE_N", "\\FDDCPE")) { SigBit input; - if (cell->type == "\\FTCP" || cell->type == "\\FTCP_N" || cell->type == "\\FTDCP") + if (cell->type.in("\\FTCP", "\\FTCP_N", "\\FTDCP")) input = sigmap(cell->getPort("\\T")[0]); else input = sigmap(cell->getPort("\\D")[0]); @@ -300,7 +294,7 @@ struct Coolrunner2SopPass : public Pass { xor_cell->setPort("\\IN_PTC", and_to_xor_wire); xor_cell->setPort("\\OUT", xor_to_ff_wire); - if (cell->type == "\\FTCP" || cell->type == "\\FTCP_N" || cell->type == "\\FTDCP") + if (cell->type.in("\\FTCP", "\\FTCP_N", "\\FTDCP")) cell->setPort("\\T", xor_to_ff_wire); else cell->setPort("\\D", xor_to_ff_wire); diff --git a/techlibs/coolrunner2/synth_coolrunner2.cc b/techlibs/coolrunner2/synth_coolrunner2.cc index 2e94c3449..21bbcaef4 100644 --- a/techlibs/coolrunner2/synth_coolrunner2.cc +++ b/techlibs/coolrunner2/synth_coolrunner2.cc @@ -29,7 +29,7 @@ struct SynthCoolrunner2Pass : public ScriptPass { SynthCoolrunner2Pass() : ScriptPass("synth_coolrunner2", "synthesis for Xilinx Coolrunner-II CPLDs") { } - virtual void help() YS_OVERRIDE + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -66,7 +66,7 @@ struct SynthCoolrunner2Pass : public ScriptPass string top_opt, json_file; bool flatten, retime; - virtual void clear_flags() YS_OVERRIDE + void clear_flags() YS_OVERRIDE { top_opt = "-auto-top"; json_file = ""; @@ -74,7 +74,7 @@ struct SynthCoolrunner2Pass : public ScriptPass retime = false; } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { string run_from, run_to; clear_flags(); @@ -111,7 +111,7 @@ struct SynthCoolrunner2Pass : public ScriptPass extra_args(args, argidx, design); if (!design->full_selection()) - log_cmd_error("This comannd only operates on fully selected designs!\n"); + log_cmd_error("This command only operates on fully selected designs!\n"); log_header(design, "Executing SYNTH_COOLRUNNER2 pass.\n"); log_push(); @@ -121,7 +121,7 @@ struct SynthCoolrunner2Pass : public ScriptPass log_pop(); } - virtual void script() YS_OVERRIDE + void script() YS_OVERRIDE { if (check_label("begin")) { @@ -129,7 +129,7 @@ struct SynthCoolrunner2Pass : public ScriptPass run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str())); } - if (check_label("flatten", "(unless -noflatten)") && flatten) + if (flatten && check_label("flatten", "(unless -noflatten)")) { run("proc"); run("flatten"); diff --git a/techlibs/easic/synth_easic.cc b/techlibs/easic/synth_easic.cc index e17138f3a..dd9e3dab7 100644 --- a/techlibs/easic/synth_easic.cc +++ b/techlibs/easic/synth_easic.cc @@ -29,7 +29,7 @@ struct SynthEasicPass : public ScriptPass { SynthEasicPass() : ScriptPass("synth_easic", "synthesis for eASIC platform") { } - virtual void help() YS_OVERRIDE + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -67,7 +67,7 @@ struct SynthEasicPass : public ScriptPass string top_opt, vlog_file, etools_path; bool flatten, retime; - virtual void clear_flags() YS_OVERRIDE + void clear_flags() YS_OVERRIDE { top_opt = "-auto-top"; vlog_file = ""; @@ -76,7 +76,7 @@ struct SynthEasicPass : public ScriptPass retime = false; } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { string run_from, run_to; clear_flags(); @@ -117,7 +117,7 @@ struct SynthEasicPass : public ScriptPass extra_args(args, argidx, design); if (!design->full_selection()) - log_cmd_error("This comannd only operates on fully selected designs!\n"); + log_cmd_error("This command only operates on fully selected designs!\n"); log_header(design, "Executing SYNTH_EASIC pass.\n"); log_push(); @@ -127,7 +127,7 @@ struct SynthEasicPass : public ScriptPass log_pop(); } - virtual void script() YS_OVERRIDE + void script() YS_OVERRIDE { string phys_clk_lib = stringf("%s/data_ruby28/design_libs/logical/timing/gp/n3x_phys_clk_0v893ff125c.lib", etools_path.c_str()); string logic_lut_lib = stringf("%s/data_ruby28/design_libs/logical/timing/gp/n3x_logic_lut_0v893ff125c.lib", etools_path.c_str()); diff --git a/techlibs/ecp5/.gitignore b/techlibs/ecp5/.gitignore new file mode 100644 index 000000000..54c329735 --- /dev/null +++ b/techlibs/ecp5/.gitignore @@ -0,0 +1,9 @@ +bram_init_1_2_4.vh +bram_init_9_18_36.vh +brams_init.mk +bram_conn_1.vh +bram_conn_2.vh +bram_conn_4.vh +bram_conn_9.vh +bram_conn_18.vh +brams_connect.mk diff --git a/techlibs/ecp5/Makefile.inc b/techlibs/ecp5/Makefile.inc new file mode 100644 index 000000000..9efb6347f --- /dev/null +++ b/techlibs/ecp5/Makefile.inc @@ -0,0 +1,54 @@ + +OBJS += techlibs/ecp5/synth_ecp5.o techlibs/ecp5/ecp5_ffinit.o \ + techlibs/ecp5/ecp5_gsr.o + +$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_ff.vh)) +$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_io.vh)) +$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_map.v)) +$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_sim.v)) +$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_bb.v)) +$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/lutrams_map.v)) +$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/lutram.txt)) +$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/brams_map.v)) +$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/bram.txt)) +$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/arith_map.v)) +$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/latches_map.v)) + +$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc_map.v)) +$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc_unmap.v)) +$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc_model.v)) +$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc_5g.box)) +$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc_5g.lut)) +$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/abc_5g_nowide.lut)) + +EXTRA_OBJS += techlibs/ecp5/brams_init.mk techlibs/ecp5/brams_connect.mk +.SECONDARY: techlibs/ecp5/brams_init.mk techlibs/ecp5/brams_connect.mk + +techlibs/ecp5/brams_init.mk: techlibs/ecp5/brams_init.py + $(Q) mkdir -p techlibs/ecp5 + $(P) python3 $< + $(Q) touch $@ + +techlibs/ecp5/brams_connect.mk: techlibs/ecp5/brams_connect.py + $(Q) mkdir -p techlibs/ecp5 + $(P) python3 $< + $(Q) touch $@ + + +techlibs/ecp5/bram_init_1_2_4.vh: techlibs/ecp5/brams_init.mk +techlibs/ecp5/bram_init_9_18_36.vh: techlibs/ecp5/brams_init.mk + +techlibs/ecp5/bram_conn_1.vh: techlibs/ecp5/brams_connect.mk +techlibs/ecp5/bram_conn_2.vh: techlibs/ecp5/brams_connect.mk +techlibs/ecp5/bram_conn_4.vh: techlibs/ecp5/brams_connect.mk +techlibs/ecp5/bram_conn_9.vh: techlibs/ecp5/brams_connect.mk +techlibs/ecp5/bram_conn_18.vh: techlibs/ecp5/brams_connect.mk + +$(eval $(call add_gen_share_file,share/ecp5,techlibs/ecp5/bram_init_1_2_4.vh)) +$(eval $(call add_gen_share_file,share/ecp5,techlibs/ecp5/bram_init_9_18_36.vh)) + +$(eval $(call add_gen_share_file,share/ecp5,techlibs/ecp5/bram_conn_1.vh)) +$(eval $(call add_gen_share_file,share/ecp5,techlibs/ecp5/bram_conn_2.vh)) +$(eval $(call add_gen_share_file,share/ecp5,techlibs/ecp5/bram_conn_4.vh)) +$(eval $(call add_gen_share_file,share/ecp5,techlibs/ecp5/bram_conn_9.vh)) +$(eval $(call add_gen_share_file,share/ecp5,techlibs/ecp5/bram_conn_18.vh)) diff --git a/techlibs/ecp5/abc_5g.box b/techlibs/ecp5/abc_5g.box new file mode 100644 index 000000000..a336b4a85 --- /dev/null +++ b/techlibs/ecp5/abc_5g.box @@ -0,0 +1,43 @@ +# NB: Inputs/Outputs must be ordered alphabetically +# (with exceptions for carry in/out) + +# Box 1 : CCU2C (2xCARRY + 2xLUT4) +# Outputs: S0, S1, COUT +# (NB: carry chain input/output must be last +# input/output and bus has been moved +# there overriding the otherwise +# alphabetical ordering) +# name ID w/b ins outs +CCU2C 1 1 9 3 + +#A0 A1 B0 B1 C0 C1 D0 D1 CIN +379 - 379 - 275 - 141 - 257 +630 379 630 379 526 275 392 141 273 +516 516 516 516 412 412 278 278 43 + +# Box 2 : TRELLIS_DPR16X4_COMB (16x4 dist ram) +# Outputs: DO0, DO1, DO2, DO3 +# name ID w/b ins outs +$__ABC_DPR16X4_COMB 2 0 8 4 + +#A0 A1 A2 A3 RAD0 RAD1 RAD2 RAD3 +0 0 0 0 141 379 275 379 +0 0 0 0 141 379 275 379 +0 0 0 0 141 379 275 379 +0 0 0 0 141 379 275 379 + +# Box 3 : PFUMX (MUX2) +# Outputs: Z +# name ID w/b ins outs +PFUMX 3 1 3 1 + +#ALUT BLUT C0 +98 98 151 + +# Box 4 : L6MUX21 (MUX2) +# Outputs: Z +# name ID w/b ins outs +L6MUX21 4 1 3 1 + +#D0 D1 SD +140 141 148 diff --git a/techlibs/ecp5/abc_5g.lut b/techlibs/ecp5/abc_5g.lut new file mode 100644 index 000000000..e8aa9b35d --- /dev/null +++ b/techlibs/ecp5/abc_5g.lut @@ -0,0 +1,25 @@ +# ECP5-5G LUT library for ABC +# Note that ECP5 architecture assigns difference +# in LUT input delay to interconnect, so this is +# considered too + + +# Simple LUTs +# area D C B A +1 1 141 +2 1 141 275 +3 1 141 275 379 +4 1 141 275 379 379 + +# LUT5 = 2x LUT4 + PFUMX +# area M0 D C B A +5 2 151 239 373 477 477 + +# LUT6 = 2x LUT5 + MUX2 +# area M1 M0 D C B A +6 4 148 292 380 514 618 618 + +# LUT7 = 2x LUT6 + MUX2 +# area M2 M1 M0 D C B A +7 8 148 289 433 521 655 759 759 + diff --git a/techlibs/ecp5/abc_5g_nowide.lut b/techlibs/ecp5/abc_5g_nowide.lut new file mode 100644 index 000000000..60352d892 --- /dev/null +++ b/techlibs/ecp5/abc_5g_nowide.lut @@ -0,0 +1,12 @@ +# ECP5-5G LUT library for ABC +# Note that ECP5 architecture assigns difference +# in LUT input delay to interconnect, so this is +# considered too + + +# Simple LUTs +# area D C B A +1 1 141 +2 1 141 275 +3 1 141 275 379 +4 1 141 275 379 379 diff --git a/techlibs/ecp5/abc_map.v b/techlibs/ecp5/abc_map.v new file mode 100644 index 000000000..ffd25f06d --- /dev/null +++ b/techlibs/ecp5/abc_map.v @@ -0,0 +1,24 @@ +// --------------------------------------- + +module TRELLIS_DPR16X4 ( + input [3:0] DI, + input [3:0] WAD, + input WRE, + input WCK, + input [3:0] RAD, + output [3:0] DO +); + parameter WCKMUX = "WCK"; + parameter WREMUX = "WRE"; + parameter [63:0] INITVAL = 64'h0000000000000000; + wire [3:0] \$DO ; + + TRELLIS_DPR16X4 #( + .WCKMUX(WCKMUX), .WREMUX(WREMUX), .INITVAL(INITVAL) + ) _TECHMAP_REPLACE_ ( + .DI(DI), .WAD(WAD), .WRE(WRE), .WCK(WCK), + .RAD(RAD), .DO(\$DO ) + ); + + \$__ABC_DPR16X4_COMB do (.A(\$DO ), .S(RAD), .Y(DO)); +endmodule diff --git a/techlibs/ecp5/abc_model.v b/techlibs/ecp5/abc_model.v new file mode 100644 index 000000000..56a733b75 --- /dev/null +++ b/techlibs/ecp5/abc_model.v @@ -0,0 +1,5 @@ +// --------------------------------------- + +(* abc_box_id=2 *) +module \$__ABC_DPR16X4_COMB (input [3:0] A, S, output [3:0] Y); +endmodule diff --git a/techlibs/ecp5/abc_unmap.v b/techlibs/ecp5/abc_unmap.v new file mode 100644 index 000000000..d43cdd93f --- /dev/null +++ b/techlibs/ecp5/abc_unmap.v @@ -0,0 +1,5 @@ +// --------------------------------------- + +module \$__ABC_DPR16X4_COMB (input [3:0] A, S, output [3:0] Y); + assign Y = A; +endmodule diff --git a/techlibs/ecp5/arith_map.v b/techlibs/ecp5/arith_map.v new file mode 100644 index 000000000..17bde0497 --- /dev/null +++ b/techlibs/ecp5/arith_map.v @@ -0,0 +1,80 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * Copyright (C) 2018 David Shah <dave@ds0.me> + * + * 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. + * + */ + +(* techmap_celltype = "$alu" *) +module _80_ecp5_alu (A, B, CI, BI, X, Y, CO); + parameter A_SIGNED = 0; + parameter B_SIGNED = 0; + parameter A_WIDTH = 1; + parameter B_WIDTH = 1; + parameter Y_WIDTH = 1; + + input [A_WIDTH-1:0] A; + input [B_WIDTH-1:0] B; + output [Y_WIDTH-1:0] X, Y; + + input CI, BI; + output [Y_WIDTH-1:0] CO; + + wire _TECHMAP_FAIL_ = Y_WIDTH <= 4; + + wire [Y_WIDTH-1:0] A_buf, B_buf; + \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf)); + \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf)); + + function integer round_up2; + input integer N; + begin + round_up2 = ((N + 1) / 2) * 2; + end + endfunction + + localparam Y_WIDTH2 = round_up2(Y_WIDTH); + + 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'b1001011010101010), + .INIT1(16'b1001011010101010), + .INJECT1_0("NO"), + .INJECT1_1("NO") + ) ccu2c_i ( + .CIN(C[i]), + .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]) + ); + + assign CO[i] = (AA[i] && BB[i]) || (C[i] && (AA[i] || BB[i])); + if (i+1 < Y_WIDTH) begin + assign CO[i+1] = FCO[i]; + assign Y[i+1] = Y1[i]; + end + end endgenerate + + assign X = AA ^ BB; +endmodule diff --git a/techlibs/ecp5/bram.txt b/techlibs/ecp5/bram.txt new file mode 100644 index 000000000..f223a42b8 --- /dev/null +++ b/techlibs/ecp5/bram.txt @@ -0,0 +1,29 @@ +bram $__ECP5_DP16KD + init 1 + + abits 10 @a10d18 + dbits 18 @a10d18 + abits 11 @a11d9 + dbits 9 @a11d9 + abits 12 @a12d4 + dbits 4 @a12d4 + abits 13 @a13d2 + dbits 2 @a13d2 + abits 14 @a14d1 + dbits 1 @a14d1 + + groups 2 + ports 1 1 + wrmode 1 0 + enable 2 1 @a10d18 + enable 1 1 @a11d9 @a12d4 @a13d2 @a14d1 + transp 0 2 + clocks 2 3 + clkpol 2 3 +endbram + +match $__ECP5_DP16KD + min bits 2048 + min efficiency 5 + shuffle_enable B +endmatch diff --git a/techlibs/ecp5/brams_connect.py b/techlibs/ecp5/brams_connect.py new file mode 100755 index 000000000..f86dcfcf0 --- /dev/null +++ b/techlibs/ecp5/brams_connect.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python3 + +def write_bus_ports(f, ada_bits, adb_bits, dia_bits, dob_bits): + ada_conn = [".ADA%d(%s)" % (i, ada_bits[i]) for i in range(len(ada_bits))] + adb_conn = [".ADB%d(%s)" % (i, adb_bits[i]) for i in range(len(adb_bits))] + dia_conn = [".DIA%d(%s)" % (i, dia_bits[i]) for i in range(len(dia_bits))] + dob_conn = [".DOB%d(%s)" % (i, dob_bits[i]) for i in range(len(dob_bits))] + print(" %s," % ", ".join(ada_conn), file=f) + print(" %s," % ", ".join(adb_conn), file=f) + print(" %s," % ", ".join(dia_conn), file=f) + print(" %s," % ", ".join(dob_conn), file=f) + +with open("techlibs/ecp5/bram_conn_1.vh", "w") as f: + ada_bits = ["A1ADDR[%d]" % i for i in range(14)] + adb_bits = ["B1ADDR[%d]" % i for i in range(14)] + dia_bits = ["A1DATA[0]"] + ["1'b0" for i in range(17)] + dob_bits = ["B1DATA[0]"] + write_bus_ports(f, ada_bits, adb_bits, dia_bits, dob_bits) + +with open("techlibs/ecp5/bram_conn_2.vh", "w") as f: + ada_bits = ["1'b0"] + ["A1ADDR[%d]" % i for i in range(13)] + adb_bits = ["1'b0"] + ["B1ADDR[%d]" % i for i in range(13)] + dia_bits = ["A1DATA[%d]" % i for i in range(2)] + ["1'b0" for i in range(16)] + dob_bits = ["B1DATA[%d]" % i for i in range(2)] + write_bus_ports(f, ada_bits, adb_bits, dia_bits, dob_bits) + +with open("techlibs/ecp5/bram_conn_4.vh", "w") as f: + ada_bits = ["1'b0", "1'b0"] + ["A1ADDR[%d]" % i for i in range(12)] + adb_bits = ["1'b0", "1'b0"] + ["B1ADDR[%d]" % i for i in range(12)] + dia_bits = ["A1DATA[%d]" % i for i in range(4)] + ["1'b0" for i in range(14)] + dob_bits = ["B1DATA[%d]" % i for i in range(4)] + write_bus_ports(f, ada_bits, adb_bits, dia_bits, dob_bits) + +with open("techlibs/ecp5/bram_conn_9.vh", "w") as f: + ada_bits = ["1'b0", "1'b0", "1'b0"] + ["A1ADDR[%d]" % i for i in range(11)] + adb_bits = ["1'b0", "1'b0", "1'b0"] + ["B1ADDR[%d]" % i for i in range(11)] + dia_bits = ["A1DATA[%d]" % i for i in range(9)] + ["1'b0" for i in range(9)] + dob_bits = ["B1DATA[%d]" % i for i in range(9)] + write_bus_ports(f, ada_bits, adb_bits, dia_bits, dob_bits) + +with open("techlibs/ecp5/bram_conn_18.vh", "w") as f: + ada_bits = ["A1EN[0]", "A1EN[1]", "1'b0", "1'b0"] + ["A1ADDR[%d]" % i for i in range(10)] + adb_bits = ["1'b0", "1'b0", "1'b0", "1'b0"] + ["B1ADDR[%d]" % i for i in range(10)] + dia_bits = ["A1DATA[%d]" % i for i in range(18)] + dob_bits = ["B1DATA[%d]" % i for i in range(18)] + write_bus_ports(f, ada_bits, adb_bits, dia_bits, dob_bits) diff --git a/techlibs/ecp5/brams_init.py b/techlibs/ecp5/brams_init.py new file mode 100755 index 000000000..96a47bdcd --- /dev/null +++ b/techlibs/ecp5/brams_init.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 +with open("techlibs/ecp5/bram_init_1_2_4.vh", "w") as f: + for i in range(0, 0x40): + init_snippets = [] + for j in range(32): + init_snippets.append("INIT[%4d*8 +: 8]" % (32 * i + j)) + init_snippets.append("3'b000" if (j % 2 == 1) else "1'b0") + init_snippets = list(reversed(init_snippets)) + for k in range(8, 64, 8): + init_snippets[k] = "\n " + init_snippets[k] + print(".INITVAL_%02X({%s})," % (i, ", ".join(init_snippets)), file=f) + +with open("techlibs/ecp5/bram_init_9_18_36.vh", "w") as f: + for i in range(0, 0x40): + init_snippets = [] + for j in range(16): + init_snippets.append("INIT[%3d*18 +: 18]" % (16 * i + j)) + init_snippets.append("2'b00") + init_snippets = list(reversed(init_snippets)) + for k in range(8, 32, 8): + init_snippets[k] = "\n " + init_snippets[k] + print(".INITVAL_%02X({%s})," % (i, ", ".join(init_snippets)), file=f) diff --git a/techlibs/ecp5/brams_map.v b/techlibs/ecp5/brams_map.v new file mode 100644 index 000000000..0353cbadb --- /dev/null +++ b/techlibs/ecp5/brams_map.v @@ -0,0 +1,115 @@ +module \$__ECP5_DP16KD (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN); + parameter CFG_ABITS = 10; + parameter CFG_DBITS = 18; + parameter CFG_ENABLE_A = 2; + + parameter CLKPOL2 = 1; + parameter CLKPOL3 = 1; + parameter [18431:0] INIT = 18432'bx; + parameter TRANSP2 = 0; + + input CLK2; + input CLK3; + + input [CFG_ABITS-1:0] A1ADDR; + input [CFG_DBITS-1:0] A1DATA; + input [CFG_ENABLE_A-1:0] A1EN; + + input [CFG_ABITS-1:0] B1ADDR; + output [CFG_DBITS-1:0] B1DATA; + input B1EN; + + localparam CLKAMUX = CLKPOL2 ? "CLKA" : "INV"; + localparam CLKBMUX = CLKPOL3 ? "CLKB" : "INV"; + + localparam WRITEMODE_A = TRANSP2 ? "WRITETHROUGH" : "READBEFOREWRITE"; + + generate if (CFG_DBITS == 1) begin + DP16KD #( + `include "bram_init_1_2_4.vh" + .DATA_WIDTH_A(1), + .DATA_WIDTH_B(1), + .CLKAMUX(CLKAMUX), + .CLKBMUX(CLKBMUX), + .WRITEMODE_A(WRITEMODE_A), + .WRITEMODE_B("READBEFOREWRITE"), + .GSR("AUTO") + ) _TECHMAP_REPLACE_ ( + `include "bram_conn_1.vh" + .CLKA(CLK2), .CLKB(CLK3), + .WEA(|A1EN), .CEA(1'b1), .OCEA(1'b1), + .WEB(1'b0), .CEB(B1EN), .OCEB(1'b1), + .RSTA(1'b0), .RSTB(1'b0) + ); + end else if (CFG_DBITS == 2) begin + DP16KD #( + `include "bram_init_1_2_4.vh" + .DATA_WIDTH_A(2), + .DATA_WIDTH_B(2), + .CLKAMUX(CLKAMUX), + .CLKBMUX(CLKBMUX), + .WRITEMODE_A(WRITEMODE_A), + .WRITEMODE_B("READBEFOREWRITE"), + .GSR("AUTO") + ) _TECHMAP_REPLACE_ ( + `include "bram_conn_2.vh" + .CLKA(CLK2), .CLKB(CLK3), + .WEA(|A1EN), .CEA(1'b1), .OCEA(1'b1), + .WEB(1'b0), .CEB(B1EN), .OCEB(1'b1), + .RSTA(1'b0), .RSTB(1'b0) + ); + end else if (CFG_DBITS <= 4) begin + DP16KD #( + `include "bram_init_1_2_4.vh" + .DATA_WIDTH_A(4), + .DATA_WIDTH_B(4), + .CLKAMUX(CLKAMUX), + .CLKBMUX(CLKBMUX), + .WRITEMODE_A(WRITEMODE_A), + .WRITEMODE_B("READBEFOREWRITE"), + .GSR("AUTO") + ) _TECHMAP_REPLACE_ ( + `include "bram_conn_4.vh" + .CLKA(CLK2), .CLKB(CLK3), + .WEA(|A1EN), .CEA(1'b1), .OCEA(1'b1), + .WEB(1'b0), .CEB(B1EN), .OCEB(1'b1), + .RSTA(1'b0), .RSTB(1'b0) + ); + end else if (CFG_DBITS <= 9) begin + DP16KD #( + `include "bram_init_9_18_36.vh" + .DATA_WIDTH_A(9), + .DATA_WIDTH_B(9), + .CLKAMUX(CLKAMUX), + .CLKBMUX(CLKBMUX), + .WRITEMODE_A(WRITEMODE_A), + .WRITEMODE_B("READBEFOREWRITE"), + .GSR("AUTO") + ) _TECHMAP_REPLACE_ ( + `include "bram_conn_9.vh" + .CLKA(CLK2), .CLKB(CLK3), + .WEA(|A1EN), .CEA(1'b1), .OCEA(1'b1), + .WEB(1'b0), .CEB(B1EN), .OCEB(1'b1), + .RSTA(1'b0), .RSTB(1'b0) + ); + end else if (CFG_DBITS <= 18) begin + DP16KD #( + `include "bram_init_9_18_36.vh" + .DATA_WIDTH_A(18), + .DATA_WIDTH_B(18), + .CLKAMUX(CLKAMUX), + .CLKBMUX(CLKBMUX), + .WRITEMODE_A(WRITEMODE_A), + .WRITEMODE_B("READBEFOREWRITE"), + .GSR("AUTO") + ) _TECHMAP_REPLACE_ ( + `include "bram_conn_18.vh" + .CLKA(CLK2), .CLKB(CLK3), + .WEA(|A1EN), .CEA(1'b1), .OCEA(1'b1), + .WEB(1'b0), .CEB(B1EN), .OCEB(1'b1), + .RSTA(1'b0), .RSTB(1'b0) + ); + end else begin + wire TECHMAP_FAIL = 1'b1; + end endgenerate +endmodule diff --git a/techlibs/ecp5/cells_bb.v b/techlibs/ecp5/cells_bb.v new file mode 100644 index 000000000..8557053b6 --- /dev/null +++ b/techlibs/ecp5/cells_bb.v @@ -0,0 +1,686 @@ +// ECP5 Blackbox cells +// FIXME: Create sim models + +(* blackbox *) +module MULT18X18D( + input A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, + input B0, B1, B2, B3, B4, B5, B6, B7, B8, B9, B10, B11, B12, B13, B14, B15, B16, B17, + input C0, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13, C14, C15, C16, C17, + input SIGNEDA, SIGNEDB, SOURCEA, SOURCEB, + input CLK0, CLK1, CLK2, CLK3, + input CE0, CE1, CE2, CE3, + input RST0, RST1, RST2, RST3, + input SRIA0, SRIA1, SRIA2, SRIA3, SRIA4, SRIA5, SRIA6, SRIA7, SRIA8, SRIA9, SRIA10, SRIA11, SRIA12, SRIA13, SRIA14, SRIA15, SRIA16, SRIA17, + input SRIB0, SRIB1, SRIB2, SRIB3, SRIB4, SRIB5, SRIB6, SRIB7, SRIB8, SRIB9, SRIB10, SRIB11, SRIB12, SRIB13, SRIB14, SRIB15, SRIB16, SRIB17, + output SROA0, SROA1, SROA2, SROA3, SROA4, SROA5, SROA6, SROA7, SROA8, SROA9, SROA10, SROA11, SROA12, SROA13, SROA14, SROA15, SROA16, SROA17, + output SROB0, SROB1, SROB2, SROB3, SROB4, SROB5, SROB6, SROB7, SROB8, SROB9, SROB10, SROB11, SROB12, SROB13, SROB14, SROB15, SROB16, SROB17, + output ROA0, ROA1, ROA2, ROA3, ROA4, ROA5, ROA6, ROA7, ROA8, ROA9, ROA10, ROA11, ROA12, ROA13, ROA14, ROA15, ROA16, ROA17, + output ROB0, ROB1, ROB2, ROB3, ROB4, ROB5, ROB6, ROB7, ROB8, ROB9, ROB10, ROB11, ROB12, ROB13, ROB14, ROB15, ROB16, ROB17, + output ROC0, ROC1, ROC2, ROC3, ROC4, ROC5, ROC6, ROC7, ROC8, ROC9, ROC10, ROC11, ROC12, ROC13, ROC14, ROC15, ROC16, ROC17, + output P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, P33, P34, P35, + output SIGNEDP +); + parameter REG_INPUTA_CLK = "NONE"; + parameter REG_INPUTA_CE = "CE0"; + parameter REG_INPUTA_RST = "RST0"; + parameter REG_INPUTB_CLK = "NONE"; + parameter REG_INPUTB_CE = "CE0"; + parameter REG_INPUTB_RST = "RST0"; + parameter REG_INPUTC_CLK = "NONE"; + parameter REG_PIPELINE_CLK = "NONE"; + parameter REG_PIPELINE_CE = "CE0"; + parameter REG_PIPELINE_RST = "RST0"; + parameter REG_OUTPUT_CLK = "NONE"; + parameter [127:0] CLK0_DIV = "ENABLED"; + parameter [127:0] CLK1_DIV = "ENABLED"; + parameter [127:0] CLK2_DIV = "ENABLED"; + parameter [127:0] CLK3_DIV = "ENABLED"; + parameter [127:0] GSR = "ENABLED"; + parameter [127:0] SOURCEB_MODE = "B_SHIFT"; + parameter [127:0] RESETMODE = "SYNC"; +endmodule + +(* blackbox *) +module ALU54B( + input CLK0, CLK1, CLK2, CLK3, + input CE0, CE1, CE2, CE3, + input RST0, RST1, RST2, RST3, + input SIGNEDIA, SIGNEDIB, SIGNEDCIN, + input A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24, A25, A26, A27, A28, A29, A30, A31, A32, A33, A34, A35, + input B0, B1, B2, B3, B4, B5, B6, B7, B8, B9, B10, B11, B12, B13, B14, B15, B16, B17, B18, B19, B20, B21, B22, B23, B24, B25, B26, B27, B28, B29, B30, B31, B32, B33, B34, B35, + input C0, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12, C13, C14, C15, C16, C17, C18, C19, C20, C21, C22, C23, C24, C25, C26, C27, C28, C29, C30, C31, C32, C33, C34, C35, C36, C37, C38, C39, C40, C41, C42, C43, C44, C45, C46, C47, C48, C49, C50, C51, C52, C53, + input CFB0, CFB1, CFB2, CFB3, CFB4, CFB5, CFB6, CFB7, CFB8, CFB9, CFB10, CFB11, CFB12, CFB13, CFB14, CFB15, CFB16, CFB17, CFB18, CFB19, CFB20, CFB21, CFB22, CFB23, CFB24, CFB25, CFB26, CFB27, CFB28, CFB29, CFB30, CFB31, CFB32, CFB33, CFB34, CFB35, CFB36, CFB37, CFB38, CFB39, CFB40, CFB41, CFB42, CFB43, CFB44, CFB45, CFB46, CFB47, CFB48, CFB49, CFB50, CFB51, CFB52, CFB53, + input MA0, MA1, MA2, MA3, MA4, MA5, MA6, MA7, MA8, MA9, MA10, MA11, MA12, MA13, MA14, MA15, MA16, MA17, MA18, MA19, MA20, MA21, MA22, MA23, MA24, MA25, MA26, MA27, MA28, MA29, MA30, MA31, MA32, MA33, MA34, MA35, + input MB0, MB1, MB2, MB3, MB4, MB5, MB6, MB7, MB8, MB9, MB10, MB11, MB12, MB13, MB14, MB15, MB16, MB17, MB18, MB19, MB20, MB21, MB22, MB23, MB24, MB25, MB26, MB27, MB28, MB29, MB30, MB31, MB32, MB33, MB34, MB35, + input CIN0, CIN1, CIN2, CIN3, CIN4, CIN5, CIN6, CIN7, CIN8, CIN9, CIN10, CIN11, CIN12, CIN13, CIN14, CIN15, CIN16, CIN17, CIN18, CIN19, CIN20, CIN21, CIN22, CIN23, CIN24, CIN25, CIN26, CIN27, CIN28, CIN29, CIN30, CIN31, CIN32, CIN33, CIN34, CIN35, CIN36, CIN37, CIN38, CIN39, CIN40, CIN41, CIN42, CIN43, CIN44, CIN45, CIN46, CIN47, CIN48, CIN49, CIN50, CIN51, CIN52, CIN53, + input OP0, OP1, OP2, OP3, OP4, OP5, OP6, OP7, OP8, OP9, OP10, + output R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R15, R16, R17, R18, R19, R20, R21, R22, R23, R24, R25, R26, R27, R28, R29, R30, R31, R32, R33, R34, R35, R36, R37, R38, R39, R40, R41, R42, R43, R44, R45, R46, R47, R48, R49, R50, R51, R52, R53, + output CO0, CO1, CO2, CO3, CO4, CO5, CO6, CO7, CO8, CO9, CO10, CO11, CO12, CO13, CO14, CO15, CO16, CO17, CO18, CO19, CO20, CO21, CO22, CO23, CO24, CO25, CO26, CO27, CO28, CO29, CO30, CO31, CO32, CO33, CO34, CO35, CO36, CO37, CO38, CO39, CO40, CO41, CO42, CO43, CO44, CO45, CO46, CO47, CO48, CO49, CO50, CO51, CO52, CO53, + output EQZ, EQZM, EQOM, EQPAT, EQPATB, + output OVER, UNDER, OVERUNDER, + output SIGNEDR +); + parameter REG_INPUTC0_CLK = "NONE"; + parameter REG_INPUTC1_CLK = "NONE"; + parameter REG_OPCODEOP0_0_CLK = "NONE"; + parameter REG_OPCODEOP0_0_CE = "CE0"; + parameter REG_OPCODEOP0_0_RST = "RST0"; + parameter REG_OPCODEOP1_0_CLK = "NONE"; + parameter REG_OPCODEOP0_1_CLK = "NONE"; + parameter REG_OPCODEOP0_1_CE = "CE0"; + parameter REG_OPCODEOP0_1_RST = "RST0"; + parameter REG_OPCODEIN_0_CLK = "NONE"; + parameter REG_OPCODEIN_0_CE = "CE0"; + parameter REG_OPCODEIN_0_RST = "RST0"; + parameter REG_OPCODEIN_1_CLK = "NONE"; + parameter REG_OPCODEIN_1_CE = "CE0"; + parameter REG_OPCODEIN_1_RST = "RST0"; + parameter REG_OUTPUT0_CLK = "NONE"; + parameter REG_OUTPUT1_CLK = "NONE"; + parameter REG_FLAG_CLK = "NONE"; + parameter [127:0] MCPAT_SOURCE = "STATIC"; + parameter [127:0] MASKPAT_SOURCE = "STATIC"; + parameter MASK01 = "0x00000000000000"; + parameter [127:0] CLK0_DIV = "ENABLED"; + parameter [127:0] CLK1_DIV = "ENABLED"; + parameter [127:0] CLK2_DIV = "ENABLED"; + parameter [127:0] CLK3_DIV = "ENABLED"; + parameter MCPAT = "0x00000000000000"; + parameter MASKPAT = "0x00000000000000"; + parameter RNDPAT = "0x00000000000000"; + parameter [127:0] GSR = "ENABLED"; + parameter [127:0] RESETMODE = "SYNC"; + parameter FORCE_ZERO_BARREL_SHIFT = "DISABLED"; + parameter LEGACY = "DISABLED"; +endmodule + +(* blackbox *) +module EHXPLLL ( + input CLKI, CLKFB, + input PHASESEL1, PHASESEL0, PHASEDIR, PHASESTEP, PHASELOADREG, + input STDBY, PLLWAKESYNC, + input RST, ENCLKOP, ENCLKOS, ENCLKOS2, ENCLKOS3, + output CLKOP, CLKOS, CLKOS2, CLKOS3, + output LOCK, INTLOCK, + output REFCLK, CLKINTFB +); + parameter CLKI_DIV = 1; + parameter CLKFB_DIV = 1; + parameter CLKOP_DIV = 8; + parameter CLKOS_DIV = 8; + parameter CLKOS2_DIV = 8; + parameter CLKOS3_DIV = 8; + parameter CLKOP_ENABLE = "ENABLED"; + parameter CLKOS_ENABLE = "DISABLED"; + parameter CLKOS2_ENABLE = "DISABLED"; + parameter CLKOS3_ENABLE = "DISABLED"; + parameter CLKOP_CPHASE = 0; + parameter CLKOS_CPHASE = 0; + parameter CLKOS2_CPHASE = 0; + parameter CLKOS3_CPHASE = 0; + parameter CLKOP_FPHASE = 0; + parameter CLKOS_FPHASE = 0; + parameter CLKOS2_FPHASE = 0; + parameter CLKOS3_FPHASE = 0; + parameter FEEDBK_PATH = "CLKOP"; + parameter CLKOP_TRIM_POL = "RISING"; + parameter CLKOP_TRIM_DELAY = 0; + parameter CLKOS_TRIM_POL = "RISING"; + parameter CLKOS_TRIM_DELAY = 0; + parameter OUTDIVIDER_MUXA = "DIVA"; + parameter OUTDIVIDER_MUXB = "DIVB"; + parameter OUTDIVIDER_MUXC = "DIVC"; + parameter OUTDIVIDER_MUXD = "DIVD"; + parameter PLL_LOCK_MODE = 0; + parameter PLL_LOCK_DELAY = 200; + parameter STDBY_ENABLE = "DISABLED"; + parameter REFIN_RESET = "DISABLED"; + parameter SYNC_ENABLE = "DISABLED"; + parameter INT_LOCK_STICKY = "ENABLED"; + parameter DPHASE_SOURCE = "DISABLED"; + parameter PLLRST_ENA = "DISABLED"; + parameter INTFB_WAKE = "DISABLED"; +endmodule + +(* blackbox *) +module DTR( + input STARTPULSE, + output DTROUT7, DTROUT6, DTROUT5, DTROUT4, DTROUT3, DTROUT2, DTROUT1, DTROUT0 +); +endmodule + +(* blackbox *) +module OSCG( + output OSC +); +parameter DIV = 128; +endmodule + +(* blackbox *) (* keep *) +module USRMCLK( + input USRMCLKI, USRMCLKTS, + output USRMCLKO +); +endmodule + +(* blackbox *) (* keep *) +module JTAGG( + input TCK, TMS, TDI, JTDO2, JTDO1, + output TDO, JTDI, JTCK, JRTI2, JRTI1, + output JSHIFT, JUPDATE, JRSTN, JCE2, JCE1 +); +parameter ER1 = "ENABLED"; +parameter ER2 = "ENABLED"; +endmodule + +(* blackbox *) +module DELAYF( + input A, LOADN, MOVE, DIRECTION, + output Z, CFLAG +); + parameter DEL_MODE = "USER_DEFINED"; + parameter DEL_VALUE = 0; +endmodule + +(* blackbox *) +module DELAYG( + input A, + output Z +); + parameter DEL_MODE = "USER_DEFINED"; + parameter DEL_VALUE = 0; +endmodule + +(* blackbox *) +module IDDRX1F( + input D, SCLK, RST, + output Q0, Q1 +); + parameter GSR = "ENABLED"; +endmodule + +(* blackbox *) +module IDDRX2F( + input D, SCLK, ECLK, RST, + output Q0, Q1, Q2, Q3 +); + parameter GSR = "ENABLED"; +endmodule + +(* blackbox *) +module IDDR71B( + input D, SCLK, ECLK, RST, ALIGNWD, + output Q0, Q1, Q2, Q3, Q4, Q5, Q6 +); + parameter GSR = "ENABLED"; +endmodule + +(* blackbox *) +module IDDRX2DQA( + input D, DQSR90, ECLK, SCLK, RST, + input RDPNTR2, RDPNTR1, RDPNTR0, WRPNTR2, WRPNTR1, WRPNTR0, + output Q0, Q1, Q2, Q3, QWL +); + parameter GSR = "ENABLED"; +endmodule + +(* blackbox *) +module ODDRX1F( + input SCLK, RST, D0, D1, + output Q +); + parameter GSR = "ENABLED"; +endmodule + +(* blackbox *) +module ODDRX2F( + input SCLK, ECLK, RST, D0, D1, D2, D3, + output Q +); + parameter GSR = "ENABLED"; +endmodule + +(* blackbox *) +module ODDR71B( + input SCLK, ECLK, RST, D0, D1, D2, D3, D4, D5, D6, + output Q +); + parameter GSR = "ENABLED"; +endmodule + +(* blackbox *) +module OSHX2A( + input D0, D1, RST, ECLK, SCLK, + output Q +); + parameter GSR = "ENABLED"; +endmodule + +(* blackbox *) +module ODDRX2DQA( + input D0, D1, D2, D3, RST, ECLK, SCLK, DQSW270, + output Q +); + parameter GSR = "ENABLED"; +endmodule + +(* blackbox *) +module ODDRX2DQSB( + input D0, D1, D2, D3, RST, ECLK, SCLK, DQSW, + output Q +); + parameter GSR = "ENABLED"; +endmodule + +(* blackbox *) +module TSHX2DQA( + input T0, T1, SCLK, ECLK, DQSW270, RST, + output Q +); + parameter GSR = "ENABLED"; + parameter REGSET = "SET"; +endmodule + +(* blackbox *) +module TSHX2DQSA( + input T0, T1, SCLK, ECLK, DQSW, RST, + output Q +); + parameter GSR = "ENABLED"; + parameter REGSET = "SET"; +endmodule + +(* blackbox *) +module DQSBUFM( + input DQSI, READ1, READ0, READCLKSEL2, READCLKSEL1, READCLKSEL0, DDRDEL, + input ECLK, SCLK, + input DYNDELAY7, DYNDELAY6, DYNDELAY5, DYNDELAY4, + input DYNDELAY3, DYNDELAY2, DYNDELAY1, DYNDELAY0, + input RST, RDLOADN, RDMOVE, RDDIRECTION, WRLOADN, WRMOVE, WRDIRECTION, PAUSE, + output DQSR90, DQSW, DQSW270, + output RDPNTR2, RDPNTR1, RDPNTR0, WRPNTR2, WRPNTR1, WRPNTR0, + output DATAVALID, BURSTDET, RDCFLAG, WRCFLAG +); + parameter DQS_LI_DEL_ADJ = "FACTORYONLY"; + parameter DQS_LI_DEL_VAL = 0; + parameter DQS_LO_DEL_ADJ = "FACTORYONLY"; + parameter DQS_LO_DEL_VAL = 0; + parameter GSR = "ENABLED"; +endmodule + +(* blackbox *) +module DDRDLLA( + input CLK, RST, UDDCNTLN, FREEZE, + output LOCK, DDRDEL, DCNTL7, DCNTL6, DCNTL5, DCNTL4, DCNTL3, DCNTL2, DCNTL1, DCNTL0 +); + parameter FORCE_MAX_DELAY = "NO"; + parameter GSR = "ENABLED"; +endmodule + +(* blackbox *) +module CLKDIVF( + input CLKI, RST, ALIGNWD, + output CDIVX +); + parameter GSR = "DISABLED"; + parameter DIV = "2.0"; +endmodule + +(* blackbox *) +module ECLKSYNCB( + input ECLKI, STOP, + output ECLKO +); +endmodule + +(* blackbox *) +module DCCA( + input CLKI, CE, + output CLKO +); +endmodule + +(* blackbox *) (* keep *) +module DCUA( + input CH0_HDINP, CH1_HDINP, CH0_HDINN, CH1_HDINN, + input D_TXBIT_CLKP_FROM_ND, D_TXBIT_CLKN_FROM_ND, D_SYNC_ND, D_TXPLL_LOL_FROM_ND, + input CH0_RX_REFCLK, CH1_RX_REFCLK, CH0_FF_RXI_CLK, CH1_FF_RXI_CLK, CH0_FF_TXI_CLK, CH1_FF_TXI_CLK, CH0_FF_EBRD_CLK, CH1_FF_EBRD_CLK, + input CH0_FF_TX_D_0, CH1_FF_TX_D_0, CH0_FF_TX_D_1, CH1_FF_TX_D_1, CH0_FF_TX_D_2, CH1_FF_TX_D_2, CH0_FF_TX_D_3, CH1_FF_TX_D_3, + input CH0_FF_TX_D_4, CH1_FF_TX_D_4, CH0_FF_TX_D_5, CH1_FF_TX_D_5, CH0_FF_TX_D_6, CH1_FF_TX_D_6, CH0_FF_TX_D_7, CH1_FF_TX_D_7, + input CH0_FF_TX_D_8, CH1_FF_TX_D_8, CH0_FF_TX_D_9, CH1_FF_TX_D_9, CH0_FF_TX_D_10, CH1_FF_TX_D_10, CH0_FF_TX_D_11, CH1_FF_TX_D_11, + input CH0_FF_TX_D_12, CH1_FF_TX_D_12, CH0_FF_TX_D_13, CH1_FF_TX_D_13, CH0_FF_TX_D_14, CH1_FF_TX_D_14, CH0_FF_TX_D_15, CH1_FF_TX_D_15, + input CH0_FF_TX_D_16, CH1_FF_TX_D_16, CH0_FF_TX_D_17, CH1_FF_TX_D_17, CH0_FF_TX_D_18, CH1_FF_TX_D_18, CH0_FF_TX_D_19, CH1_FF_TX_D_19, + input CH0_FF_TX_D_20, CH1_FF_TX_D_20, CH0_FF_TX_D_21, CH1_FF_TX_D_21, CH0_FF_TX_D_22, CH1_FF_TX_D_22, CH0_FF_TX_D_23, CH1_FF_TX_D_23, + input CH0_FFC_EI_EN, CH1_FFC_EI_EN, CH0_FFC_PCIE_DET_EN, CH1_FFC_PCIE_DET_EN, CH0_FFC_PCIE_CT, CH1_FFC_PCIE_CT, CH0_FFC_SB_INV_RX, CH1_FFC_SB_INV_RX, + input CH0_FFC_ENABLE_CGALIGN, CH1_FFC_ENABLE_CGALIGN, CH0_FFC_SIGNAL_DETECT, CH1_FFC_SIGNAL_DETECT, CH0_FFC_FB_LOOPBACK, CH1_FFC_FB_LOOPBACK, CH0_FFC_SB_PFIFO_LP, CH1_FFC_SB_PFIFO_LP, + input CH0_FFC_PFIFO_CLR, CH1_FFC_PFIFO_CLR, CH0_FFC_RATE_MODE_RX, CH1_FFC_RATE_MODE_RX, CH0_FFC_RATE_MODE_TX, CH1_FFC_RATE_MODE_TX, CH0_FFC_DIV11_MODE_RX, CH1_FFC_DIV11_MODE_RX, CH0_FFC_RX_GEAR_MODE, CH1_FFC_RX_GEAR_MODE, CH0_FFC_TX_GEAR_MODE, CH1_FFC_TX_GEAR_MODE, + input CH0_FFC_DIV11_MODE_TX, CH1_FFC_DIV11_MODE_TX, CH0_FFC_LDR_CORE2TX_EN, CH1_FFC_LDR_CORE2TX_EN, CH0_FFC_LANE_TX_RST, CH1_FFC_LANE_TX_RST, CH0_FFC_LANE_RX_RST, CH1_FFC_LANE_RX_RST, + input CH0_FFC_RRST, CH1_FFC_RRST, CH0_FFC_TXPWDNB, CH1_FFC_TXPWDNB, CH0_FFC_RXPWDNB, CH1_FFC_RXPWDNB, CH0_LDR_CORE2TX, CH1_LDR_CORE2TX, + input D_SCIWDATA0, D_SCIWDATA1, D_SCIWDATA2, D_SCIWDATA3, D_SCIWDATA4, D_SCIWDATA5, D_SCIWDATA6, D_SCIWDATA7, + input D_SCIADDR0, D_SCIADDR1, D_SCIADDR2, D_SCIADDR3, D_SCIADDR4, D_SCIADDR5, D_SCIENAUX, D_SCISELAUX, + input CH0_SCIEN, CH1_SCIEN, CH0_SCISEL, CH1_SCISEL, D_SCIRD, D_SCIWSTN, D_CYAWSTN, D_FFC_SYNC_TOGGLE, + input D_FFC_DUAL_RST, D_FFC_MACRO_RST, D_FFC_MACROPDB, D_FFC_TRST, CH0_FFC_CDR_EN_BITSLIP, CH1_FFC_CDR_EN_BITSLIP, D_SCAN_ENABLE, D_SCAN_IN_0, + input D_SCAN_IN_1, D_SCAN_IN_2, D_SCAN_IN_3, D_SCAN_IN_4, D_SCAN_IN_5, D_SCAN_IN_6, D_SCAN_IN_7, D_SCAN_MODE, + input D_SCAN_RESET, D_CIN0, D_CIN1, D_CIN2, D_CIN3, D_CIN4, D_CIN5, D_CIN6,D_CIN7, D_CIN8, D_CIN9, D_CIN10, D_CIN11, + output CH0_HDOUTP, CH1_HDOUTP, CH0_HDOUTN, CH1_HDOUTN, D_TXBIT_CLKP_TO_ND, D_TXBIT_CLKN_TO_ND, D_SYNC_PULSE2ND, D_TXPLL_LOL_TO_ND, + output CH0_FF_RX_F_CLK, CH1_FF_RX_F_CLK, CH0_FF_RX_H_CLK, CH1_FF_RX_H_CLK, CH0_FF_TX_F_CLK, CH1_FF_TX_F_CLK, CH0_FF_TX_H_CLK, CH1_FF_TX_H_CLK, + output CH0_FF_RX_PCLK, CH1_FF_RX_PCLK, CH0_FF_TX_PCLK, CH1_FF_TX_PCLK, CH0_FF_RX_D_0, CH1_FF_RX_D_0, CH0_FF_RX_D_1, CH1_FF_RX_D_1, + output CH0_FF_RX_D_2, CH1_FF_RX_D_2, CH0_FF_RX_D_3, CH1_FF_RX_D_3, CH0_FF_RX_D_4, CH1_FF_RX_D_4, CH0_FF_RX_D_5, CH1_FF_RX_D_5, + output CH0_FF_RX_D_6, CH1_FF_RX_D_6, CH0_FF_RX_D_7, CH1_FF_RX_D_7, CH0_FF_RX_D_8, CH1_FF_RX_D_8, CH0_FF_RX_D_9, CH1_FF_RX_D_9, + output CH0_FF_RX_D_10, CH1_FF_RX_D_10, CH0_FF_RX_D_11, CH1_FF_RX_D_11, CH0_FF_RX_D_12, CH1_FF_RX_D_12, CH0_FF_RX_D_13, CH1_FF_RX_D_13, + output CH0_FF_RX_D_14, CH1_FF_RX_D_14, CH0_FF_RX_D_15, CH1_FF_RX_D_15, CH0_FF_RX_D_16, CH1_FF_RX_D_16, CH0_FF_RX_D_17, CH1_FF_RX_D_17, + output CH0_FF_RX_D_18, CH1_FF_RX_D_18, CH0_FF_RX_D_19, CH1_FF_RX_D_19, CH0_FF_RX_D_20, CH1_FF_RX_D_20, CH0_FF_RX_D_21, CH1_FF_RX_D_21, + output CH0_FF_RX_D_22, CH1_FF_RX_D_22, CH0_FF_RX_D_23, CH1_FF_RX_D_23, CH0_FFS_PCIE_DONE, CH1_FFS_PCIE_DONE, CH0_FFS_PCIE_CON, CH1_FFS_PCIE_CON, + output CH0_FFS_RLOS, CH1_FFS_RLOS, CH0_FFS_LS_SYNC_STATUS, CH1_FFS_LS_SYNC_STATUS, CH0_FFS_CC_UNDERRUN, CH1_FFS_CC_UNDERRUN, CH0_FFS_CC_OVERRUN, CH1_FFS_CC_OVERRUN, + output CH0_FFS_RXFBFIFO_ERROR, CH1_FFS_RXFBFIFO_ERROR, CH0_FFS_TXFBFIFO_ERROR, CH1_FFS_TXFBFIFO_ERROR, CH0_FFS_RLOL, CH1_FFS_RLOL, CH0_FFS_SKP_ADDED, CH1_FFS_SKP_ADDED, + output CH0_FFS_SKP_DELETED, CH1_FFS_SKP_DELETED, CH0_LDR_RX2CORE, CH1_LDR_RX2CORE, D_SCIRDATA0, D_SCIRDATA1, D_SCIRDATA2, D_SCIRDATA3, + output D_SCIRDATA4, D_SCIRDATA5, D_SCIRDATA6, D_SCIRDATA7, D_SCIINT, D_SCAN_OUT_0, D_SCAN_OUT_1, D_SCAN_OUT_2, D_SCAN_OUT_3, D_SCAN_OUT_4, D_SCAN_OUT_5, D_SCAN_OUT_6, D_SCAN_OUT_7, + output D_COUT0, D_COUT1, D_COUT2, D_COUT3, D_COUT4, D_COUT5, D_COUT6, D_COUT7, D_COUT8, D_COUT9, D_COUT10, D_COUT11, D_COUT12, D_COUT13, D_COUT14, D_COUT15, D_COUT16, D_COUT17, D_COUT18, D_COUT19, + + input D_REFCLKI, + output D_FFS_PLOL +); + parameter CH0_AUTO_CALIB_EN = "0b0"; + parameter CH0_AUTO_FACQ_EN = "0b0"; + parameter CH0_BAND_THRESHOLD = "0b000000"; + parameter CH0_CALIB_CK_MODE = "0b0"; + parameter CH0_CC_MATCH_1 = "0b0000000000"; + parameter CH0_CC_MATCH_2 = "0b0000000000"; + parameter CH0_CC_MATCH_3 = "0b0000000000"; + parameter CH0_CC_MATCH_4 = "0b0000000000"; + parameter CH0_CDR_CNT4SEL = "0b00"; + parameter CH0_CDR_CNT8SEL = "0b00"; + parameter CH0_CTC_BYPASS = "0b0"; + parameter CH0_DCOATDCFG = "0b00"; + parameter CH0_DCOATDDLY = "0b00"; + parameter CH0_DCOBYPSATD = "0b0"; + parameter CH0_DCOCALDIV = "0b000"; + parameter CH0_DCOCTLGI = "0b000"; + parameter CH0_DCODISBDAVOID = "0b0"; + parameter CH0_DCOFLTDAC = "0b00"; + parameter CH0_DCOFTNRG = "0b000"; + parameter CH0_DCOIOSTUNE = "0b000"; + parameter CH0_DCOITUNE = "0b00"; + parameter CH0_DCOITUNE4LSB = "0b000"; + parameter CH0_DCOIUPDNX2 = "0b0"; + parameter CH0_DCONUOFLSB = "0b000"; + parameter CH0_DCOSCALEI = "0b00"; + parameter CH0_DCOSTARTVAL = "0b000"; + parameter CH0_DCOSTEP = "0b00"; + parameter CH0_DEC_BYPASS = "0b0"; + parameter CH0_ENABLE_CG_ALIGN = "0b0"; + parameter CH0_ENC_BYPASS = "0b0"; + parameter CH0_FF_RX_F_CLK_DIS = "0b0"; + parameter CH0_FF_RX_H_CLK_EN = "0b0"; + parameter CH0_FF_TX_F_CLK_DIS = "0b0"; + parameter CH0_FF_TX_H_CLK_EN = "0b0"; + parameter CH0_GE_AN_ENABLE = "0b0"; + parameter CH0_INVERT_RX = "0b0"; + parameter CH0_INVERT_TX = "0b0"; + parameter CH0_LDR_CORE2TX_SEL = "0b0"; + parameter CH0_LDR_RX2CORE_SEL = "0b0"; + parameter CH0_LEQ_OFFSET_SEL = "0b0"; + parameter CH0_LEQ_OFFSET_TRIM = "0b000"; + parameter CH0_LSM_DISABLE = "0b0"; + parameter CH0_MATCH_2_ENABLE = "0b0"; + parameter CH0_MATCH_4_ENABLE = "0b0"; + parameter CH0_MIN_IPG_CNT = "0b00"; + parameter CH0_PCIE_EI_EN = "0b0"; + parameter CH0_PCIE_MODE = "0b0"; + parameter CH0_PCS_DET_TIME_SEL = "0b00"; + parameter CH0_PDEN_SEL = "0b0"; + parameter CH0_PRBS_ENABLE = "0b0"; + parameter CH0_PRBS_LOCK = "0b0"; + parameter CH0_PRBS_SELECTION = "0b0"; + parameter CH0_RATE_MODE_RX = "0b0"; + parameter CH0_RATE_MODE_TX = "0b0"; + parameter CH0_RCV_DCC_EN = "0b0"; + parameter CH0_REG_BAND_OFFSET = "0b0000"; + parameter CH0_REG_BAND_SEL = "0b000000"; + parameter CH0_REG_IDAC_EN = "0b0"; + parameter CH0_REG_IDAC_SEL = "0b0000000000"; + parameter CH0_REQ_EN = "0b0"; + parameter CH0_REQ_LVL_SET = "0b00"; + parameter CH0_RIO_MODE = "0b0"; + parameter CH0_RLOS_SEL = "0b0"; + parameter CH0_RPWDNB = "0b0"; + parameter CH0_RTERM_RX = "0b00000"; + parameter CH0_RTERM_TX = "0b00000"; + parameter CH0_RXIN_CM = "0b00"; + parameter CH0_RXTERM_CM = "0b00"; + parameter CH0_RX_DCO_CK_DIV = "0b000"; + parameter CH0_RX_DIV11_SEL = "0b0"; + parameter CH0_RX_GEAR_BYPASS = "0b0"; + parameter CH0_RX_GEAR_MODE = "0b0"; + parameter CH0_RX_LOS_CEQ = "0b00"; + parameter CH0_RX_LOS_EN = "0b0"; + parameter CH0_RX_LOS_HYST_EN = "0b0"; + parameter CH0_RX_LOS_LVL = "0b000"; + parameter CH0_RX_RATE_SEL = "0b0000"; + parameter CH0_RX_SB_BYPASS = "0b0"; + parameter CH0_SB_BYPASS = "0b0"; + parameter CH0_SEL_SD_RX_CLK = "0b0"; + parameter CH0_TDRV_DAT_SEL = "0b00"; + parameter CH0_TDRV_POST_EN = "0b0"; + parameter CH0_TDRV_PRE_EN = "0b0"; + parameter CH0_TDRV_SLICE0_CUR = "0b000"; + parameter CH0_TDRV_SLICE0_SEL = "0b00"; + parameter CH0_TDRV_SLICE1_CUR = "0b000"; + parameter CH0_TDRV_SLICE1_SEL = "0b00"; + parameter CH0_TDRV_SLICE2_CUR = "0b00"; + parameter CH0_TDRV_SLICE2_SEL = "0b00"; + parameter CH0_TDRV_SLICE3_CUR = "0b00"; + parameter CH0_TDRV_SLICE3_SEL = "0b00"; + parameter CH0_TDRV_SLICE4_CUR = "0b00"; + parameter CH0_TDRV_SLICE4_SEL = "0b00"; + parameter CH0_TDRV_SLICE5_CUR = "0b00"; + parameter CH0_TDRV_SLICE5_SEL = "0b00"; + parameter CH0_TPWDNB = "0b0"; + parameter CH0_TX_CM_SEL = "0b00"; + parameter CH0_TX_DIV11_SEL = "0b0"; + parameter CH0_TX_GEAR_BYPASS = "0b0"; + parameter CH0_TX_GEAR_MODE = "0b0"; + parameter CH0_TX_POST_SIGN = "0b0"; + parameter CH0_TX_PRE_SIGN = "0b0"; + parameter CH0_UC_MODE = "0b0"; + parameter CH0_UDF_COMMA_A = "0b0000000000"; + parameter CH0_UDF_COMMA_B = "0b0000000000"; + parameter CH0_UDF_COMMA_MASK = "0b0000000000"; + parameter CH0_WA_BYPASS = "0b0"; + parameter CH0_WA_MODE = "0b0"; + parameter CH1_AUTO_CALIB_EN = "0b0"; + parameter CH1_AUTO_FACQ_EN = "0b0"; + parameter CH1_BAND_THRESHOLD = "0b000000"; + parameter CH1_CALIB_CK_MODE = "0b0"; + parameter CH1_CC_MATCH_1 = "0b0000000000"; + parameter CH1_CC_MATCH_2 = "0b0000000000"; + parameter CH1_CC_MATCH_3 = "0b0000000000"; + parameter CH1_CC_MATCH_4 = "0b0000000000"; + parameter CH1_CDR_CNT4SEL = "0b00"; + parameter CH1_CDR_CNT8SEL = "0b00"; + parameter CH1_CTC_BYPASS = "0b0"; + parameter CH1_DCOATDCFG = "0b00"; + parameter CH1_DCOATDDLY = "0b00"; + parameter CH1_DCOBYPSATD = "0b0"; + parameter CH1_DCOCALDIV = "0b000"; + parameter CH1_DCOCTLGI = "0b000"; + parameter CH1_DCODISBDAVOID = "0b0"; + parameter CH1_DCOFLTDAC = "0b00"; + parameter CH1_DCOFTNRG = "0b000"; + parameter CH1_DCOIOSTUNE = "0b000"; + parameter CH1_DCOITUNE = "0b00"; + parameter CH1_DCOITUNE4LSB = "0b000"; + parameter CH1_DCOIUPDNX2 = "0b0"; + parameter CH1_DCONUOFLSB = "0b000"; + parameter CH1_DCOSCALEI = "0b00"; + parameter CH1_DCOSTARTVAL = "0b000"; + parameter CH1_DCOSTEP = "0b00"; + parameter CH1_DEC_BYPASS = "0b0"; + parameter CH1_ENABLE_CG_ALIGN = "0b0"; + parameter CH1_ENC_BYPASS = "0b0"; + parameter CH1_FF_RX_F_CLK_DIS = "0b0"; + parameter CH1_FF_RX_H_CLK_EN = "0b0"; + parameter CH1_FF_TX_F_CLK_DIS = "0b0"; + parameter CH1_FF_TX_H_CLK_EN = "0b0"; + parameter CH1_GE_AN_ENABLE = "0b0"; + parameter CH1_INVERT_RX = "0b0"; + parameter CH1_INVERT_TX = "0b0"; + parameter CH1_LDR_CORE2TX_SEL = "0b0"; + parameter CH1_LDR_RX2CORE_SEL = "0b0"; + parameter CH1_LEQ_OFFSET_SEL = "0b0"; + parameter CH1_LEQ_OFFSET_TRIM = "0b000"; + parameter CH1_LSM_DISABLE = "0b0"; + parameter CH1_MATCH_2_ENABLE = "0b0"; + parameter CH1_MATCH_4_ENABLE = "0b0"; + parameter CH1_MIN_IPG_CNT = "0b00"; + parameter CH1_PCIE_EI_EN = "0b0"; + parameter CH1_PCIE_MODE = "0b0"; + parameter CH1_PCS_DET_TIME_SEL = "0b00"; + parameter CH1_PDEN_SEL = "0b0"; + parameter CH1_PRBS_ENABLE = "0b0"; + parameter CH1_PRBS_LOCK = "0b0"; + parameter CH1_PRBS_SELECTION = "0b0"; + parameter CH1_RATE_MODE_RX = "0b0"; + parameter CH1_RATE_MODE_TX = "0b0"; + parameter CH1_RCV_DCC_EN = "0b0"; + parameter CH1_REG_BAND_OFFSET = "0b0000"; + parameter CH1_REG_BAND_SEL = "0b000000"; + parameter CH1_REG_IDAC_EN = "0b0"; + parameter CH1_REG_IDAC_SEL = "0b0000000000"; + parameter CH1_REQ_EN = "0b0"; + parameter CH1_REQ_LVL_SET = "0b00"; + parameter CH1_RIO_MODE = "0b0"; + parameter CH1_RLOS_SEL = "0b0"; + parameter CH1_RPWDNB = "0b0"; + parameter CH1_RTERM_RX = "0b00000"; + parameter CH1_RTERM_TX = "0b00000"; + parameter CH1_RXIN_CM = "0b00"; + parameter CH1_RXTERM_CM = "0b00"; + parameter CH1_RX_DCO_CK_DIV = "0b000"; + parameter CH1_RX_DIV11_SEL = "0b0"; + parameter CH1_RX_GEAR_BYPASS = "0b0"; + parameter CH1_RX_GEAR_MODE = "0b0"; + parameter CH1_RX_LOS_CEQ = "0b00"; + parameter CH1_RX_LOS_EN = "0b0"; + parameter CH1_RX_LOS_HYST_EN = "0b0"; + parameter CH1_RX_LOS_LVL = "0b000"; + parameter CH1_RX_RATE_SEL = "0b0000"; + parameter CH1_RX_SB_BYPASS = "0b0"; + parameter CH1_SB_BYPASS = "0b0"; + parameter CH1_SEL_SD_RX_CLK = "0b0"; + parameter CH1_TDRV_DAT_SEL = "0b00"; + parameter CH1_TDRV_POST_EN = "0b0"; + parameter CH1_TDRV_PRE_EN = "0b0"; + parameter CH1_TDRV_SLICE0_CUR = "0b000"; + parameter CH1_TDRV_SLICE0_SEL = "0b00"; + parameter CH1_TDRV_SLICE1_CUR = "0b000"; + parameter CH1_TDRV_SLICE1_SEL = "0b00"; + parameter CH1_TDRV_SLICE2_CUR = "0b00"; + parameter CH1_TDRV_SLICE2_SEL = "0b00"; + parameter CH1_TDRV_SLICE3_CUR = "0b00"; + parameter CH1_TDRV_SLICE3_SEL = "0b00"; + parameter CH1_TDRV_SLICE4_CUR = "0b00"; + parameter CH1_TDRV_SLICE4_SEL = "0b00"; + parameter CH1_TDRV_SLICE5_CUR = "0b00"; + parameter CH1_TDRV_SLICE5_SEL = "0b00"; + parameter CH1_TPWDNB = "0b0"; + parameter CH1_TX_CM_SEL = "0b00"; + parameter CH1_TX_DIV11_SEL = "0b0"; + parameter CH1_TX_GEAR_BYPASS = "0b0"; + parameter CH1_TX_GEAR_MODE = "0b0"; + parameter CH1_TX_POST_SIGN = "0b0"; + parameter CH1_TX_PRE_SIGN = "0b0"; + parameter CH1_UC_MODE = "0b0"; + parameter CH1_UDF_COMMA_A = "0b0000000000"; + parameter CH1_UDF_COMMA_B = "0b0000000000"; + parameter CH1_UDF_COMMA_MASK = "0b0000000000"; + parameter CH1_WA_BYPASS = "0b0"; + parameter CH1_WA_MODE = "0b0"; + parameter D_BITCLK_FROM_ND_EN = "0b0"; + parameter D_BITCLK_LOCAL_EN = "0b0"; + parameter D_BITCLK_ND_EN = "0b0"; + parameter D_BUS8BIT_SEL = "0b0"; + parameter D_CDR_LOL_SET = "0b00"; + parameter D_CMUSETBIASI = "0b00"; + parameter D_CMUSETI4CPP = "0b0000"; + parameter D_CMUSETI4CPZ = "0b0000"; + parameter D_CMUSETI4VCO = "0b00"; + parameter D_CMUSETICP4P = "0b00"; + parameter D_CMUSETICP4Z = "0b000"; + parameter D_CMUSETINITVCT = "0b00"; + parameter D_CMUSETISCL4VCO = "0b000"; + parameter D_CMUSETP1GM = "0b000"; + parameter D_CMUSETP2AGM = "0b000"; + parameter D_CMUSETZGM = "0b000"; + parameter D_DCO_CALIB_TIME_SEL = "0b00"; + parameter D_HIGH_MARK = "0b0000"; + parameter D_IB_PWDNB = "0b0"; + parameter D_ISETLOS = "0b00000000"; + parameter D_LOW_MARK = "0b0000"; + parameter D_MACROPDB = "0b0"; + parameter D_PD_ISET = "0b00"; + parameter D_PLL_LOL_SET = "0b00"; + parameter D_REFCK_MODE = "0b000"; + parameter D_REQ_ISET = "0b000"; + parameter D_RG_EN = "0b0"; + parameter D_RG_SET = "0b00"; + parameter D_SETICONST_AUX = "0b00"; + parameter D_SETICONST_CH = "0b00"; + parameter D_SETIRPOLY_AUX = "0b00"; + parameter D_SETIRPOLY_CH = "0b00"; + parameter D_SETPLLRC = "0b000000"; + parameter D_SYNC_LOCAL_EN = "0b0"; + parameter D_SYNC_ND_EN = "0b0"; + parameter D_TXPLL_PWDNB = "0b0"; + parameter D_TX_VCO_CK_DIV = "0b000"; + parameter D_XGE_MODE = "0b0"; + +// These parameters don't do anything but are +// needed for compatibility with Diamond + parameter D_TX_MAX_RATE = "2.5"; + parameter D_RX_MAX_RATE = "2.5"; + parameter CH0_TXAMPLITUDE = "0d1300"; + parameter CH1_TXAMPLITUDE = "0d1300"; + parameter CH0_PROTOCOL = "8B10B"; + parameter CH1_PROTOCOL = "8B10B"; + parameter CH0_CDR_MAX_RATE = "2.5"; + parameter CH1_CDR_MAX_RATE = "2.5"; +endmodule + +(* blackbox *) +module EXTREFB ( + input REFCLKP, REFCLKN, + output REFCLKO +); + parameter REFCK_PWDNB = "0b0"; + parameter REFCK_RTERM = "0b0"; + parameter REFCK_DCBIAS_EN = "0b0"; +endmodule + +(* blackbox *) +module PCSCLKDIV ( + input CLKI, RST, SEL2, SEL1, SEL0, + output CDIV1, CDIVX +); + parameter GSR = "DISABLED"; +endmodule + +// Note: this module is not marked keep as we want it swept away in synth (sim use only) +(* blackbox *) +module PUR ( + input PUR +); + parameter RST_PULSE = 1; +endmodule + +(* blackbox, keep *) +module GSR ( + input GSR +); +endmodule + +(* blackbox, keep *) +module SGSR ( + input GSR, CLK +); +endmodule
\ No newline at end of file diff --git a/techlibs/ecp5/cells_ff.vh b/techlibs/ecp5/cells_ff.vh new file mode 100644 index 000000000..0c9689ebd --- /dev/null +++ b/techlibs/ecp5/cells_ff.vh @@ -0,0 +1,40 @@ +// Diamond flip-flops +module FD1P3AX(input D, SP, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(0), .CE(SP), .DI(D), .Q(Q)); endmodule +module FD1P3AY(input D, SP, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(0), .CE(SP), .DI(D), .Q(Q)); endmodule +module FD1P3BX(input PD, D, SP, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule +module FD1P3DX(input CD, D, SP, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule +module FD1P3IX(input CD, D, SP, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule +module FD1P3JX(input PD, D, SP, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule +module FD1S3AX(input D, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(0), .DI(D), .Q(Q)); endmodule +module FD1S3AY(input D, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(0), .DI(D), .Q(Q)); endmodule +module FD1S3BX(input PD, D, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .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); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .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); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .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); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule + +// TODO: Diamond latches +// 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 registers +module IFS1P3BX(input PD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .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); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .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); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .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); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .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); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .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); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .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); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .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); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .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 diff --git a/techlibs/ecp5/cells_io.vh b/techlibs/ecp5/cells_io.vh new file mode 100644 index 000000000..02e66e8a5 --- /dev/null +++ b/techlibs/ecp5/cells_io.vh @@ -0,0 +1,14 @@ +// 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 olvds (.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 diff --git a/techlibs/ecp5/cells_map.v b/techlibs/ecp5/cells_map.v new file mode 100644 index 000000000..71ae9237b --- /dev/null +++ b/techlibs/ecp5/cells_map.v @@ -0,0 +1,163 @@ +module \$_DFF_N_ (input D, C, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(1'b0), .DI(D), .Q(Q)); endmodule +module \$_DFF_P_ (input D, C, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(1'b0), .DI(D), .Q(Q)); endmodule + +module \$_DFFE_NN_ (input D, C, E, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("INV"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); endmodule +module \$_DFFE_PN_ (input D, C, E, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("INV"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); endmodule + +module \$_DFFE_NP_ (input D, C, E, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); endmodule +module \$_DFFE_PP_ (input D, C, E, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); endmodule + +module \$_DFF_NN0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule +module \$_DFF_NN1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule +module \$_DFF_PN0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule +module \$_DFF_PN1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule + +module \$_DFF_NP0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule +module \$_DFF_NP1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule +module \$_DFF_PP0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule +module \$_DFF_PP1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule + +module \$__DFFS_NN0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule +module \$__DFFS_NN1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule +module \$__DFFS_PN0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule +module \$__DFFS_PN1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!R), .DI(D), .Q(Q)); endmodule + +module \$__DFFS_NP0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule +module \$__DFFS_NP1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule +module \$__DFFS_PP0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule +module \$__DFFS_PP1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule + +module \$__DFFE_NN0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule +module \$__DFFE_NN1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule +module \$__DFFE_PN0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule +module \$__DFFE_PN1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule + +module \$__DFFE_NP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule +module \$__DFFE_NP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule +module \$__DFFE_PP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule +module \$__DFFE_PP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule + +module \$__DFFSE_NN0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule +module \$__DFFSE_NN1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(!R), .DI(D), .Q(Q)); endmodule +module \$__DFFSE_PN0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .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_PN1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .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 + +module \$__DFFSE_NP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule +module \$__DFFSE_NP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule +module \$__DFFSE_PP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .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("AUTO"), .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 + +`include "cells_ff.vh" +`include "cells_io.vh" + +`ifndef NO_LUT +module \$lut (A, Y); + parameter WIDTH = 0; + parameter LUT = 0; + + input [WIDTH-1:0] A; + output Y; + + // Need to swap input ordering, and fix init accordingly, + // to match ABC's expectation of LUT inputs in non-decreasing + // delay order + localparam P_WIDTH = WIDTH < 4 ? 4 : WIDTH; + function [P_WIDTH-1:0] permute_index; + input [P_WIDTH-1:0] i; + integer j; + begin + permute_index = 0; + for (j = 0; j < P_WIDTH; j = j + 1) + permute_index[P_WIDTH-1 - j] = i[j]; + end + endfunction + + function [2**P_WIDTH-1:0] permute_init; + integer i; + begin + permute_init = 0; + for (i = 0; i < 2**P_WIDTH; i = i + 1) + permute_init[i] = LUT[permute_index(i)]; + end + endfunction + + parameter [2**P_WIDTH-1:0] P_LUT = permute_init(); + + generate + if (WIDTH == 1) begin + LUT4 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.Z(Y), + .A(1'b0), .B(1'b0), .C(1'b0), .D(A[0])); + end else + if (WIDTH == 2) begin + LUT4 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.Z(Y), + .A(1'b0), .B(1'b0), .C(A[1]), .D(A[0])); + end else + if (WIDTH == 3) begin + LUT4 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.Z(Y), + .A(1'b0), .B(A[2]), .C(A[1]), .D(A[0])); + end else + if (WIDTH == 4) begin + LUT4 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.Z(Y), + .A(A[3]), .B(A[2]), .C(A[1]), .D(A[0])); + `ifndef NO_PFUMUX + end else + if (WIDTH == 5) begin + wire f0, f1; + LUT4 #(.INIT(P_LUT[15: 0])) lut0 (.Z(f0), + .A(A[4]), .B(A[3]), .C(A[2]), .D(A[1])); + LUT4 #(.INIT(P_LUT[31:16])) lut1 (.Z(f1), + .A(A[4]), .B(A[3]), .C(A[2]), .D(A[1])); + PFUMX mux5(.ALUT(f1), .BLUT(f0), .C0(A[0]), .Z(Y)); + end else + if (WIDTH == 6) begin + wire f0, f1, f2, f3, g0, g1; + LUT4 #(.INIT(P_LUT[15: 0])) lut0 (.Z(f0), + .A(A[5]), .B(A[4]), .C(A[3]), .D(A[2])); + LUT4 #(.INIT(P_LUT[31:16])) lut1 (.Z(f1), + .A(A[5]), .B(A[4]), .C(A[3]), .D(A[2])); + + LUT4 #(.INIT(P_LUT[47:32])) lut2 (.Z(f2), + .A(A[5]), .B(A[4]), .C(A[3]), .D(A[2])); + LUT4 #(.INIT(P_LUT[63:48])) lut3 (.Z(f3), + .A(A[5]), .B(A[4]), .C(A[3]), .D(A[2])); + + PFUMX mux50(.ALUT(f1), .BLUT(f0), .C0(A[1]), .Z(g0)); + PFUMX mux51(.ALUT(f3), .BLUT(f2), .C0(A[1]), .Z(g1)); + L6MUX21 mux6 (.D0(g0), .D1(g1), .SD(A[0]), .Z(Y)); + end else + if (WIDTH == 7) begin + wire f0, f1, f2, f3, f4, f5, f6, f7, g0, g1, g2, g3, h0, h1; + LUT4 #(.INIT(P_LUT[15: 0])) lut0 (.Z(f0), + .A(A[6]), .B(A[5]), .C(A[4]), .D(A[3])); + LUT4 #(.INIT(P_LUT[31:16])) lut1 (.Z(f1), + .A(A[6]), .B(A[5]), .C(A[4]), .D(A[3])); + + LUT4 #(.INIT(P_LUT[47:32])) lut2 (.Z(f2), + .A(A[6]), .B(A[5]), .C(A[4]), .D(A[3])); + LUT4 #(.INIT(P_LUT[63:48])) lut3 (.Z(f3), + .A(A[6]), .B(A[5]), .C(A[4]), .D(A[3])); + + LUT4 #(.INIT(P_LUT[79:64])) lut4 (.Z(f4), + .A(A[6]), .B(A[5]), .C(A[4]), .D(A[3])); + LUT4 #(.INIT(P_LUT[95:80])) lut5 (.Z(f5), + .A(A[6]), .B(A[5]), .C(A[4]), .D(A[3])); + + LUT4 #(.INIT(P_LUT[111: 96])) lut6 (.Z(f6), + .A(A[6]), .B(A[5]), .C(A[4]), .D(A[3])); + LUT4 #(.INIT(P_LUT[127:112])) lut7 (.Z(f7), + .A(A[6]), .B(A[5]), .C(A[4]), .D(A[3])); + + PFUMX mux50(.ALUT(f1), .BLUT(f0), .C0(A[2]), .Z(g0)); + PFUMX mux51(.ALUT(f3), .BLUT(f2), .C0(A[2]), .Z(g1)); + PFUMX mux52(.ALUT(f5), .BLUT(f4), .C0(A[2]), .Z(g2)); + PFUMX mux53(.ALUT(f7), .BLUT(f6), .C0(A[2]), .Z(g3)); + L6MUX21 mux60 (.D0(g0), .D1(g1), .SD(A[1]), .Z(h0)); + L6MUX21 mux61 (.D0(g2), .D1(g3), .SD(A[1]), .Z(h1)); + L6MUX21 mux7 (.D0(h0), .D1(h1), .SD(A[0]), .Z(Y)); + `endif + end else begin + wire _TECHMAP_FAIL_ = 1; + end + endgenerate +endmodule +`endif diff --git a/techlibs/ecp5/cells_sim.v b/techlibs/ecp5/cells_sim.v new file mode 100644 index 000000000..db77dc127 --- /dev/null +++ b/techlibs/ecp5/cells_sim.v @@ -0,0 +1,699 @@ +// --------------------------------------- + +module LUT4(input A, B, C, D, output Z); + parameter [15:0] INIT = 16'h0000; + wire [7:0] s3 = D ? INIT[15:8] : INIT[7:0]; + wire [3:0] s2 = C ? s3[ 7:4] : s3[3:0]; + wire [1:0] s1 = B ? s2[ 3:2] : s2[1:0]; + assign Z = A ? s1[1] : s1[0]; +endmodule + +// --------------------------------------- +(* abc_box_id=4, lib_whitebox *) +module L6MUX21 (input D0, D1, SD, output Z); + assign Z = SD ? D1 : D0; +endmodule + +// --------------------------------------- +(* abc_box_id=1, lib_whitebox *) +module CCU2C( + (* abc_carry *) + input CIN, + input A0, B0, C0, D0, A1, B1, C1, D1, + output S0, S1, + (* abc_carry *) + output COUT +); + parameter [15:0] INIT0 = 16'h0000; + parameter [15:0] INIT1 = 16'h0000; + parameter INJECT1_0 = "YES"; + parameter INJECT1_1 = "YES"; + + // First half + wire LUT4_0, LUT2_0; +`ifdef _ABC + assign LUT4_0 = INIT0[{D0, C0, B0, A0}]; + assign LUT2_0 = INIT0[{2'b00, B0, A0}]; +`else + LUT4 #(.INIT(INIT0)) lut4_0(.A(A0), .B(B0), .C(C0), .D(D0), .Z(LUT4_0)); + LUT2 #(.INIT(INIT0[3:0])) lut2_0(.A(A0), .B(B0), .Z(LUT2_0)); +`endif + wire gated_cin_0 = (INJECT1_0 == "YES") ? 1'b0 : CIN; + assign S0 = LUT4_0 ^ gated_cin_0; + + wire gated_lut2_0 = (INJECT1_0 == "YES") ? 1'b0 : LUT2_0; + wire cout_0 = (~LUT4_0 & gated_lut2_0) | (LUT4_0 & CIN); + + // Second half + wire LUT4_1, LUT2_1; +`ifdef _ABC + assign LUT4_1 = INIT1[{D1, C1, B1, A1}]; + assign LUT2_1 = INIT1[{2'b00, B1, A1}]; +`else + LUT4 #(.INIT(INIT1)) lut4_1(.A(A1), .B(B1), .C(C1), .D(D1), .Z(LUT4_1)); + LUT2 #(.INIT(INIT1[3:0])) lut2_1(.A(A1), .B(B1), .Z(LUT2_1)); +`endif + wire gated_cin_1 = (INJECT1_1 == "YES") ? 1'b0 : cout_0; + assign S1 = LUT4_1 ^ gated_cin_1; + + wire gated_lut2_1 = (INJECT1_1 == "YES") ? 1'b0 : LUT2_1; + assign COUT = (~LUT4_1 & gated_lut2_1) | (LUT4_1 & cout_0); + +endmodule + +// --------------------------------------- + +module TRELLIS_RAM16X2 ( + input DI0, DI1, + input WAD0, WAD1, WAD2, WAD3, + input WRE, WCK, + input RAD0, RAD1, RAD2, RAD3, + output DO0, DO1 +); + parameter WCKMUX = "WCK"; + parameter WREMUX = "WRE"; + parameter INITVAL_0 = 16'h0000; + parameter INITVAL_1 = 16'h0000; + + reg [1:0] mem[15:0]; + + integer i; + initial begin + for (i = 0; i < 16; i = i + 1) + mem[i] <= {INITVAL_1[i], INITVAL_0[i]}; + end + + wire muxwck = (WCKMUX == "INV") ? ~WCK : WCK; + + reg muxwre; + always @(*) + case (WREMUX) + "1": muxwre = 1'b1; + "0": muxwre = 1'b0; + "INV": muxwre = ~WRE; + default: muxwre = WRE; + endcase + + + always @(posedge muxwck) + if (muxwre) + mem[{WAD3, WAD2, WAD1, WAD0}] <= {DI1, DI0}; + + assign {DO1, DO0} = mem[{RAD3, RAD2, RAD1, RAD0}]; +endmodule + +// --------------------------------------- +(* abc_box_id=3, lib_whitebox *) +module PFUMX (input ALUT, BLUT, C0, output Z); + assign Z = C0 ? ALUT : BLUT; +endmodule + +// --------------------------------------- +module TRELLIS_DPR16X4 ( + input [3:0] DI, + input [3:0] WAD, + input WRE, + input WCK, + input [3:0] RAD, + /* (* abc_arrival=<TODO> *) */ + output [3:0] DO +); + parameter WCKMUX = "WCK"; + parameter WREMUX = "WRE"; + parameter [63:0] INITVAL = 64'h0000000000000000; + + reg [3:0] mem[15:0]; + + integer i; + initial begin + for (i = 0; i < 16; i = i + 1) + mem[i] <= {INITVAL[i+3], INITVAL[i+2], INITVAL[i+1], INITVAL[i]}; + end + + wire muxwck = (WCKMUX == "INV") ? ~WCK : WCK; + + reg muxwre; + always @(*) + case (WREMUX) + "1": muxwre = 1'b1; + "0": muxwre = 1'b0; + "INV": muxwre = ~WRE; + default: muxwre = WRE; + endcase + + always @(posedge muxwck) + if (muxwre) + mem[WAD] <= DI; + + assign DO = mem[RAD]; +endmodule + +// --------------------------------------- + +module DPR16X4C ( + input [3:0] DI, + input WCK, WRE, + input [3:0] RAD, + input [3:0] WAD, + output [3:0] DO +); + // For legacy Lattice compatibility, INITIVAL is a hex + // string rather than a numeric parameter + parameter INITVAL = "0x0000000000000000"; + + function [63:0] convert_initval; + input [143:0] hex_initval; + reg done; + reg [63:0] temp; + reg [7:0] char; + integer i; + begin + done = 1'b0; + temp = 0; + for (i = 0; i < 16; i = i + 1) begin + if (!done) begin + char = hex_initval[8*i +: 8]; + if (char == "x") begin + done = 1'b1; + end else begin + if (char >= "0" && char <= "9") + temp[4*i +: 4] = char - "0"; + else if (char >= "A" && char <= "F") + temp[4*i +: 4] = 10 + char - "A"; + else if (char >= "a" && char <= "f") + temp[4*i +: 4] = 10 + char - "a"; + end + end + end + convert_initval = temp; + end + endfunction + + localparam conv_initval = convert_initval(INITVAL); + + reg [3:0] ram[0:15]; + integer i; + initial begin + for (i = 0; i < 15; i = i + 1) begin + ram[i] <= conv_initval[4*i +: 4]; + end + end + + always @(posedge WCK) + if (WRE) + ram[WAD] <= DI; + + assign DO = ram[RAD]; + +endmodule + +// --------------------------------------- + +module LUT2(input A, B, output Z); + parameter [3:0] INIT = 4'h0; + wire [1:0] s1 = B ? INIT[ 3:2] : INIT[1:0]; + assign Z = A ? s1[1] : s1[0]; +endmodule + +// --------------------------------------- + +module TRELLIS_FF(input CLK, LSR, CE, DI, M, output reg Q); + parameter GSR = "ENABLED"; + parameter [127:0] CEMUX = "1"; + parameter CLKMUX = "CLK"; + parameter LSRMUX = "LSR"; + parameter SRMODE = "LSR_OVER_CE"; + parameter REGSET = "RESET"; + parameter [127:0] LSRMODE = "LSR"; + + wire muxce; + generate + case (CEMUX) + "1": assign muxce = 1'b1; + "0": assign muxce = 1'b0; + "INV": assign muxce = ~CE; + default: assign muxce = CE; + endcase + endgenerate + + wire muxlsr = (LSRMUX == "INV") ? ~LSR : LSR; + wire muxclk = (CLKMUX == "INV") ? ~CLK : CLK; + wire srval; + generate + if (LSRMODE == "PRLD") + assign srval = M; + else + assign srval = (REGSET == "SET") ? 1'b1 : 1'b0; + endgenerate + + initial Q = srval; + + generate + if (SRMODE == "ASYNC") begin + always @(posedge muxclk, posedge muxlsr) + if (muxlsr) + Q <= srval; + else if (muxce) + Q <= DI; + end else begin + always @(posedge muxclk) + if (muxlsr) + Q <= srval; + else if (muxce) + Q <= DI; + end + endgenerate +endmodule + +// --------------------------------------- +(* keep *) +module TRELLIS_IO( + inout B, + input I, + input T, + output O +); + parameter DIR = "INPUT"; + reg T_pd; + always @(*) if (T === 1'bz) T_pd <= 1'b0; else T_pd <= T; + + generate + if (DIR == "INPUT") begin + assign B = 1'bz; + assign O = B; + end else if (DIR == "OUTPUT") begin + assign B = T_pd ? 1'bz : I; + assign O = 1'bx; + end else if (DIR == "BIDIR") begin + assign B = T_pd ? 1'bz : I; + assign O = B; + end else begin + ERROR_UNKNOWN_IO_MODE error(); + end + endgenerate + +endmodule + +// --------------------------------------- + +module INV(input A, output Z); + assign Z = !A; +endmodule + +// --------------------------------------- + +module TRELLIS_SLICE( + input A0, B0, C0, D0, + input A1, B1, C1, D1, + input M0, M1, + input FCI, FXA, FXB, + + input CLK, LSR, CE, + input DI0, DI1, + + input WD0, WD1, + input WAD0, WAD1, WAD2, WAD3, + input WRE, WCK, + + output F0, Q0, + output F1, Q1, + output FCO, OFX0, OFX1, + + output WDO0, WDO1, WDO2, WDO3, + output WADO0, WADO1, WADO2, WADO3 +); + + parameter MODE = "LOGIC"; + parameter GSR = "ENABLED"; + parameter SRMODE = "LSR_OVER_CE"; + parameter [127:0] CEMUX = "1"; + parameter CLKMUX = "CLK"; + parameter LSRMUX = "LSR"; + parameter LUT0_INITVAL = 16'h0000; + parameter LUT1_INITVAL = 16'h0000; + parameter REG0_SD = "0"; + parameter REG1_SD = "0"; + parameter REG0_REGSET = "RESET"; + parameter REG1_REGSET = "RESET"; + parameter REG0_LSRMODE = "LSR"; + parameter REG1_LSRMODE = "LSR"; + parameter [127:0] CCU2_INJECT1_0 = "NO"; + parameter [127:0] CCU2_INJECT1_1 = "NO"; + parameter WREMUX = "WRE"; + parameter WCKMUX = "WCK"; + + parameter A0MUX = "A0"; + parameter A1MUX = "A1"; + parameter B0MUX = "B0"; + parameter B1MUX = "B1"; + parameter C0MUX = "C0"; + parameter C1MUX = "C1"; + parameter D0MUX = "D0"; + parameter D1MUX = "D1"; + + wire A0m, B0m, C0m, D0m; + wire A1m, B1m, C1m, D1m; + + generate + if (A0MUX == "1") assign A0m = 1'b1; else assign A0m = A0; + if (B0MUX == "1") assign B0m = 1'b1; else assign B0m = B0; + if (C0MUX == "1") assign C0m = 1'b1; else assign C0m = C0; + if (D0MUX == "1") assign D0m = 1'b1; else assign D0m = D0; + if (A1MUX == "1") assign A1m = 1'b1; else assign A1m = A1; + if (B1MUX == "1") assign B1m = 1'b1; else assign B1m = B1; + if (C1MUX == "1") assign C1m = 1'b1; else assign C1m = C1; + if (D1MUX == "1") assign D1m = 1'b1; else assign D1m = D1; + + endgenerate + + function [15:0] permute_initval; + input [15:0] initval; + integer i; + begin + for (i = 0; i < 16; i = i + 1) begin + permute_initval[{i[0], i[2], i[1], i[3]}] = initval[i]; + end + end + endfunction + + generate + if (MODE == "LOGIC") begin + // LUTs + LUT4 #( + .INIT(LUT0_INITVAL) + ) lut4_0 ( + .A(A0m), .B(B0m), .C(C0m), .D(D0m), + .Z(F0) + ); + LUT4 #( + .INIT(LUT1_INITVAL) + ) lut4_1 ( + .A(A1m), .B(B1m), .C(C1m), .D(D1m), + .Z(F1) + ); + // LUT expansion muxes + PFUMX lut5_mux (.ALUT(F1), .BLUT(F0), .C0(M0), .Z(OFX0)); + L6MUX21 lutx_mux (.D0(FXA), .D1(FXB), .SD(M1), .Z(OFX1)); + end else if (MODE == "CCU2") begin + CCU2C #( + .INIT0(LUT0_INITVAL), + .INIT1(LUT1_INITVAL), + .INJECT1_0(CCU2_INJECT1_0), + .INJECT1_1(CCU2_INJECT1_1) + ) ccu2c_i ( + .CIN(FCI), + .A0(A0m), .B0(B0m), .C0(C0m), .D0(D0m), + .A1(A1m), .B1(B1m), .C1(C1m), .D1(D1m), + .S0(F0), .S1(F1), + .COUT(FCO) + ); + end else if (MODE == "RAMW") begin + assign WDO0 = C1m; + assign WDO1 = A1m; + assign WDO2 = D1m; + assign WDO3 = B1m; + assign WADO0 = D0m; + assign WADO1 = B0m; + assign WADO2 = C0m; + assign WADO3 = A0m; + end else if (MODE == "DPRAM") begin + TRELLIS_RAM16X2 #( + .INITVAL_0(permute_initval(LUT0_INITVAL)), + .INITVAL_1(permute_initval(LUT1_INITVAL)), + .WREMUX(WREMUX) + ) ram_i ( + .DI0(WD0), .DI1(WD1), + .WAD0(WAD0), .WAD1(WAD1), .WAD2(WAD2), .WAD3(WAD3), + .WRE(WRE), .WCK(WCK), + .RAD0(D0m), .RAD1(B0m), .RAD2(C0m), .RAD3(A0m), + .DO0(F0), .DO1(F1) + ); + // TODO: confirm RAD and INITVAL ordering + // DPRAM mode contract? +`ifdef FORMAL + always @(*) begin + assert(A0m==A1m); + assert(B0m==B1m); + assert(C0m==C1m); + assert(D0m==D1m); + end +`endif + end else begin + ERROR_UNKNOWN_SLICE_MODE error(); + end + endgenerate + + // FF input selection muxes + wire muxdi0 = (REG0_SD == "1") ? DI0 : M0; + wire muxdi1 = (REG1_SD == "1") ? DI1 : M1; + // Flipflops + TRELLIS_FF #( + .GSR(GSR), + .CEMUX(CEMUX), + .CLKMUX(CLKMUX), + .LSRMUX(LSRMUX), + .SRMODE(SRMODE), + .REGSET(REG0_REGSET), + .LSRMODE(REG0_LSRMODE) + ) ff_0 ( + .CLK(CLK), .LSR(LSR), .CE(CE), + .DI(muxdi0), .M(M0), + .Q(Q0) + ); + TRELLIS_FF #( + .GSR(GSR), + .CEMUX(CEMUX), + .CLKMUX(CLKMUX), + .LSRMUX(LSRMUX), + .SRMODE(SRMODE), + .REGSET(REG1_REGSET), + .LSRMODE(REG1_LSRMODE) + ) ff_1 ( + .CLK(CLK), .LSR(LSR), .CE(CE), + .DI(muxdi1), .M(M1), + .Q(Q1) + ); +endmodule + +(* blackbox *) +module DP16KD( + input DIA17, DIA16, DIA15, DIA14, DIA13, DIA12, DIA11, DIA10, DIA9, DIA8, DIA7, DIA6, DIA5, DIA4, DIA3, DIA2, DIA1, DIA0, + input ADA13, ADA12, ADA11, ADA10, ADA9, ADA8, ADA7, ADA6, ADA5, ADA4, ADA3, ADA2, ADA1, ADA0, + input CEA, OCEA, CLKA, WEA, RSTA, + input CSA2, CSA1, CSA0, + output DOA17, DOA16, DOA15, DOA14, DOA13, DOA12, DOA11, DOA10, DOA9, DOA8, DOA7, DOA6, DOA5, DOA4, DOA3, DOA2, DOA1, DOA0, + + input DIB17, DIB16, DIB15, DIB14, DIB13, DIB12, DIB11, DIB10, DIB9, DIB8, DIB7, DIB6, DIB5, DIB4, DIB3, DIB2, DIB1, DIB0, + input ADB13, ADB12, ADB11, ADB10, ADB9, ADB8, ADB7, ADB6, ADB5, ADB4, ADB3, ADB2, ADB1, ADB0, + input CEB, OCEB, CLKB, WEB, RSTB, + input CSB2, CSB1, CSB0, + output DOB17, DOB16, DOB15, DOB14, DOB13, DOB12, DOB11, DOB10, DOB9, DOB8, DOB7, DOB6, DOB5, DOB4, DOB3, DOB2, DOB1, DOB0 +); + parameter DATA_WIDTH_A = 18; + parameter DATA_WIDTH_B = 18; + + parameter REGMODE_A = "NOREG"; + parameter REGMODE_B = "NOREG"; + + parameter RESETMODE = "SYNC"; + parameter ASYNC_RESET_RELEASE = "SYNC"; + + parameter CSDECODE_A = "0b000"; + parameter CSDECODE_B = "0b000"; + + parameter WRITEMODE_A = "NORMAL"; + parameter WRITEMODE_B = "NORMAL"; + + parameter DIA17MUX = "DIA17"; + parameter DIA16MUX = "DIA16"; + parameter DIA15MUX = "DIA15"; + parameter DIA14MUX = "DIA14"; + parameter DIA13MUX = "DIA13"; + parameter DIA12MUX = "DIA12"; + parameter DIA11MUX = "DIA11"; + parameter DIA10MUX = "DIA10"; + parameter DIA9MUX = "DIA9"; + parameter DIA8MUX = "DIA8"; + parameter DIA7MUX = "DIA7"; + parameter DIA6MUX = "DIA6"; + parameter DIA5MUX = "DIA5"; + parameter DIA4MUX = "DIA4"; + parameter DIA3MUX = "DIA3"; + parameter DIA2MUX = "DIA2"; + parameter DIA1MUX = "DIA1"; + parameter DIA0MUX = "DIA0"; + parameter ADA13MUX = "ADA13"; + parameter ADA12MUX = "ADA12"; + parameter ADA11MUX = "ADA11"; + parameter ADA10MUX = "ADA10"; + parameter ADA9MUX = "ADA9"; + parameter ADA8MUX = "ADA8"; + parameter ADA7MUX = "ADA7"; + parameter ADA6MUX = "ADA6"; + parameter ADA5MUX = "ADA5"; + parameter ADA4MUX = "ADA4"; + parameter ADA3MUX = "ADA3"; + parameter ADA2MUX = "ADA2"; + parameter ADA1MUX = "ADA1"; + parameter ADA0MUX = "ADA0"; + parameter CEAMUX = "CEA"; + parameter OCEAMUX = "OCEA"; + parameter CLKAMUX = "CLKA"; + parameter WEAMUX = "WEA"; + parameter RSTAMUX = "RSTA"; + parameter CSA2MUX = "CSA2"; + parameter CSA1MUX = "CSA1"; + parameter CSA0MUX = "CSA0"; + parameter DOA17MUX = "DOA17"; + parameter DOA16MUX = "DOA16"; + parameter DOA15MUX = "DOA15"; + parameter DOA14MUX = "DOA14"; + parameter DOA13MUX = "DOA13"; + parameter DOA12MUX = "DOA12"; + parameter DOA11MUX = "DOA11"; + parameter DOA10MUX = "DOA10"; + parameter DOA9MUX = "DOA9"; + parameter DOA8MUX = "DOA8"; + parameter DOA7MUX = "DOA7"; + parameter DOA6MUX = "DOA6"; + parameter DOA5MUX = "DOA5"; + parameter DOA4MUX = "DOA4"; + parameter DOA3MUX = "DOA3"; + parameter DOA2MUX = "DOA2"; + parameter DOA1MUX = "DOA1"; + parameter DOA0MUX = "DOA0"; + parameter DIB17MUX = "DIB17"; + parameter DIB16MUX = "DIB16"; + parameter DIB15MUX = "DIB15"; + parameter DIB14MUX = "DIB14"; + parameter DIB13MUX = "DIB13"; + parameter DIB12MUX = "DIB12"; + parameter DIB11MUX = "DIB11"; + parameter DIB10MUX = "DIB10"; + parameter DIB9MUX = "DIB9"; + parameter DIB8MUX = "DIB8"; + parameter DIB7MUX = "DIB7"; + parameter DIB6MUX = "DIB6"; + parameter DIB5MUX = "DIB5"; + parameter DIB4MUX = "DIB4"; + parameter DIB3MUX = "DIB3"; + parameter DIB2MUX = "DIB2"; + parameter DIB1MUX = "DIB1"; + parameter DIB0MUX = "DIB0"; + parameter ADB13MUX = "ADB13"; + parameter ADB12MUX = "ADB12"; + parameter ADB11MUX = "ADB11"; + parameter ADB10MUX = "ADB10"; + parameter ADB9MUX = "ADB9"; + parameter ADB8MUX = "ADB8"; + parameter ADB7MUX = "ADB7"; + parameter ADB6MUX = "ADB6"; + parameter ADB5MUX = "ADB5"; + parameter ADB4MUX = "ADB4"; + parameter ADB3MUX = "ADB3"; + parameter ADB2MUX = "ADB2"; + parameter ADB1MUX = "ADB1"; + parameter ADB0MUX = "ADB0"; + parameter CEBMUX = "CEB"; + parameter OCEBMUX = "OCEB"; + parameter CLKBMUX = "CLKB"; + parameter WEBMUX = "WEB"; + parameter RSTBMUX = "RSTB"; + parameter CSB2MUX = "CSB2"; + parameter CSB1MUX = "CSB1"; + parameter CSB0MUX = "CSB0"; + parameter DOB17MUX = "DOB17"; + parameter DOB16MUX = "DOB16"; + parameter DOB15MUX = "DOB15"; + parameter DOB14MUX = "DOB14"; + parameter DOB13MUX = "DOB13"; + parameter DOB12MUX = "DOB12"; + parameter DOB11MUX = "DOB11"; + parameter DOB10MUX = "DOB10"; + parameter DOB9MUX = "DOB9"; + parameter DOB8MUX = "DOB8"; + parameter DOB7MUX = "DOB7"; + parameter DOB6MUX = "DOB6"; + parameter DOB5MUX = "DOB5"; + parameter DOB4MUX = "DOB4"; + parameter DOB3MUX = "DOB3"; + parameter DOB2MUX = "DOB2"; + parameter DOB1MUX = "DOB1"; + parameter DOB0MUX = "DOB0"; + + parameter WID = 0; + + parameter GSR = "ENABLED"; + + parameter INITVAL_00 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_01 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_02 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_03 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_04 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_05 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_06 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_07 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_08 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_09 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_10 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_11 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_12 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_13 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_14 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_15 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_16 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_17 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_18 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_19 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_20 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_21 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_22 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_23 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_24 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_25 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_26 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_27 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_28 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_29 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_2A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_2B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_2C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_2D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_2E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_2F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_30 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_31 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_32 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_33 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_34 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_35 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_36 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_37 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_38 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_39 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_3A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_3B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_3C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_3D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_3E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_3F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; +endmodule + +`ifndef NO_INCLUDES + +`include "cells_ff.vh" +`include "cells_io.vh" + +`endif diff --git a/techlibs/ecp5/ecp5_ffinit.cc b/techlibs/ecp5/ecp5_ffinit.cc new file mode 100644 index 000000000..dbd16cac9 --- /dev/null +++ b/techlibs/ecp5/ecp5_ffinit.cc @@ -0,0 +1,203 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * Copyright (C) 2018-19 David Shah <david@symbioticeda.com> + * + * 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 Ecp5FfinitPass : public Pass { + Ecp5FfinitPass() : Pass("ecp5_ffinit", "ECP5: handle FF init values") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" ecp5_ffinit [options] [selection]\n"); + log("\n"); + log("Remove init values for FF output signals when equal to reset value.\n"); + log("If reset is not used, set the reset value to the init value, otherwise\n"); + log("unmap out the reset (if not an async reset).\n"); + } + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + log_header(design, "Executing ECP5_FFINIT pass (implement FF init values).\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + // if (args[argidx] == "-singleton") { + // singleton_mode = true; + // continue; + // } + break; + } + extra_args(args, argidx, design); + + for (auto module : design->selected_modules()) + { + log("Handling FF init values in %s.\n", log_id(module)); + + SigMap sigmap(module); + pool<Wire*> init_wires; + dict<SigBit, State> initbits; + dict<SigBit, SigBit> initbit_to_wire; + pool<SigBit> handled_initbits; + + for (auto wire : module->selected_wires()) + { + if (wire->attributes.count("\\init") == 0) + continue; + + SigSpec wirebits = sigmap(wire); + Const initval = wire->attributes.at("\\init"); + init_wires.insert(wire); + + for (int i = 0; i < GetSize(wirebits) && i < GetSize(initval); i++) + { + SigBit bit = wirebits[i]; + State val = initval[i]; + + if (val != State::S0 && val != State::S1) + continue; + + if (initbits.count(bit)) { + if (initbits.at(bit) != val) { + log_warning("Conflicting init values for signal %s (%s = %s, %s = %s).\n", + log_signal(bit), log_signal(SigBit(wire, i)), log_signal(val), + log_signal(initbit_to_wire[bit]), log_signal(initbits.at(bit))); + initbits.at(bit) = State::Sx; + } + continue; + } + + initbits[bit] = val; + initbit_to_wire[bit] = SigBit(wire, i); + } + } + for (auto cell : module->selected_cells()) + { + if (cell->type != "\\TRELLIS_FF") + continue; + SigSpec sig_d = cell->getPort("\\DI"); + SigSpec sig_q = cell->getPort("\\Q"); + SigSpec sig_lsr = cell->getPort("\\LSR"); + + if (GetSize(sig_d) < 1 || GetSize(sig_q) < 1) + continue; + + SigBit bit_d = sigmap(sig_d[0]); + SigBit bit_q = sigmap(sig_q[0]); + + std::string regset = "RESET"; + if (cell->hasParam("\\REGSET")) + regset = cell->getParam("\\REGSET").decode_string(); + State resetState; + if (regset == "SET") + resetState = State::S1; + else if (regset == "RESET") + resetState = State::S0; + else + log_error("FF cell %s has illegal REGSET value %s.\n", + log_id(cell), regset.c_str()); + + if (!initbits.count(bit_q)) + continue; + + State val = initbits.at(bit_q); + + if (val == State::Sx) + continue; + + log("FF init value for cell %s (%s): %s = %c\n", log_id(cell), log_id(cell->type), + log_signal(bit_q), val != State::S0 ? '1' : '0'); + // Initval is the same as the reset state. Matches hardware, nowt more to do + if (val == resetState) { + handled_initbits.insert(bit_q); + continue; + } + + if (GetSize(sig_lsr) >= 1 && sig_lsr[0] != State::S0) { + std::string srmode = "LSR_OVER_CE"; + if (cell->hasParam("\\SRMODE")) + srmode = cell->getParam("\\SRMODE").decode_string(); + if (srmode == "ASYNC") { + log("Async reset value %c for FF cell %s inconsistent with init value %c.\n", + resetState != State::S0 ? '1' : '0', log_id(cell), val != State::S0 ? '1' : '0'); + } else { + SigBit bit_lsr = sigmap(sig_lsr[0]); + Wire *new_bit_d = module->addWire(NEW_ID); + if (resetState == State::S0) { + module->addAndnotGate(NEW_ID, bit_d, bit_lsr, new_bit_d); + } else { + module->addOrGate(NEW_ID, bit_d, bit_lsr, new_bit_d); + } + + cell->setPort("\\DI", new_bit_d); + cell->setPort("\\LSR", State::S0); + + if(cell->hasPort("\\CE")) { + std::string cemux = "CE"; + if (cell->hasParam("\\CEMUX")) + cemux = cell->getParam("\\CEMUX").decode_string(); + SigSpec sig_ce = cell->getPort("\\CE"); + if (GetSize(sig_ce) >= 1) { + SigBit bit_ce = sigmap(sig_ce[0]); + Wire *new_bit_ce = module->addWire(NEW_ID); + if (cemux == "INV") + module->addAndnotGate(NEW_ID, bit_ce, bit_lsr, new_bit_ce); + else + module->addOrGate(NEW_ID, bit_ce, bit_lsr, new_bit_ce); + cell->setPort("\\CE", new_bit_ce); + } + } + cell->setParam("\\REGSET", val != State::S0 ? Const("SET") : Const("RESET")); + handled_initbits.insert(bit_q); + } + } else { + cell->setParam("\\REGSET", val != State::S0 ? Const("SET") : Const("RESET")); + handled_initbits.insert(bit_q); + } + } + + for (auto wire : init_wires) + { + if (wire->attributes.count("\\init") == 0) + continue; + + SigSpec wirebits = sigmap(wire); + Const &initval = wire->attributes.at("\\init"); + bool remove_attribute = true; + + for (int i = 0; i < GetSize(wirebits) && i < GetSize(initval); i++) { + if (handled_initbits.count(wirebits[i])) + initval[i] = State::Sx; + else if (initval[i] != State::Sx) + remove_attribute = false; + } + + if (remove_attribute) + wire->attributes.erase("\\init"); + } + } + } +} Ecp5FfinitPass; + +PRIVATE_NAMESPACE_END diff --git a/techlibs/ecp5/ecp5_gsr.cc b/techlibs/ecp5/ecp5_gsr.cc new file mode 100644 index 000000000..2bc714b6f --- /dev/null +++ b/techlibs/ecp5/ecp5_gsr.cc @@ -0,0 +1,135 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * Copyright (C) 2019 David Shah <david@symbioticeda.com> + * + * 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 Ecp5GsrPass : public Pass { + Ecp5GsrPass() : Pass("ecp5_gsr", "ECP5: handle GSR") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" ecp5_gsr [options] [selection]\n"); + log("\n"); + log("Trim active low async resets connected to GSR and resolve GSR parameter,\n"); + log("if a GSR or SGSR primitive is used in the design.\n"); + log("\n"); + log("If any cell has the GSR parameter set to \"AUTO\", this will be resolved\n"); + log("to \"ENABLED\" if a GSR primitive is present and the (* nogsr *) attribute\n"); + log("is not set, otherwise it will be resolved to \"DISABLED\".\n"); + log("\n"); + } + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + log_header(design, "Executing ECP5_GSR pass (implement FF init values).\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + // if (args[argidx] == "-singleton") { + // singleton_mode = true; + // continue; + // } + break; + } + extra_args(args, argidx, design); + + for (auto module : design->selected_modules()) + { + log("Handling GSR in %s.\n", log_id(module)); + + SigMap sigmap(module); + + SigBit gsr; + bool found_gsr = false; + + for (auto cell : module->selected_cells()) + { + if (cell->type != ID(GSR) && cell->type != ID(SGSR)) + continue; + if (found_gsr) + log_error("Found more than one GSR or SGSR cell in module %s.\n", log_id(module)); + found_gsr = true; + SigSpec sig_gsr = cell->getPort(ID(GSR)); + if (GetSize(sig_gsr) < 1) + log_error("GSR cell %s has disconnected GSR input.\n", log_id(cell)); + gsr = sigmap(sig_gsr[0]); + } + + // Resolve GSR parameter + + for (auto cell : module->selected_cells()) + { + if (!cell->hasParam(ID(GSR)) || cell->getParam(ID(GSR)).decode_string() != "AUTO") + continue; + + bool gsren = found_gsr; + if (cell->get_bool_attribute("\\nogsr")) + gsren = false; + cell->setParam(ID(GSR), gsren ? Const("ENABLED") : Const("DISABLED")); + + } + + if (!found_gsr) + continue; + + // For finding active low FF inputs + pool<SigBit> inverted_gsr; + + log_debug("GSR net in module %s is %s.\n", log_id(module), log_signal(gsr)); + for (auto cell : module->selected_cells()) + { + if (cell->type != ID($_NOT_)) + continue; + SigSpec sig_a = cell->getPort(ID(A)), sig_y = cell->getPort(ID(Y)); + if (GetSize(sig_a) < 1 || GetSize(sig_y) < 1) + continue; + SigBit a = sigmap(sig_a[0]); + if (a == gsr) + inverted_gsr.insert(sigmap(sig_y[0])); + } + + for (auto cell : module->selected_cells()) + { + if (cell->type != ID(TRELLIS_FF)) + continue; + if (!cell->hasParam(ID(GSR)) || cell->getParam(ID(GSR)).decode_string() != "ENABLED") + continue; + if (!cell->hasParam(ID(SRMODE)) || cell->getParam(ID(SRMODE)).decode_string() != "ASYNC") + continue; + SigSpec sig_lsr = cell->getPort(ID(LSR)); + if (GetSize(sig_lsr) < 1) + continue; + SigBit lsr = sigmap(sig_lsr[0]); + if (!inverted_gsr.count(lsr)) + continue; + cell->setParam(ID(SRMODE), Const("LSR_OVER_CE")); + cell->unsetPort(ID(LSR)); + } + + } + } +} Ecp5GsrPass; + +PRIVATE_NAMESPACE_END diff --git a/techlibs/ecp5/latches_map.v b/techlibs/ecp5/latches_map.v new file mode 100644 index 000000000..c28f88cf7 --- /dev/null +++ b/techlibs/ecp5/latches_map.v @@ -0,0 +1,11 @@ +module \$_DLATCH_N_ (E, D, Q); + wire [1023:0] _TECHMAP_DO_ = "simplemap; opt"; + input E, D; + output Q = !E ? D : Q; +endmodule + +module \$_DLATCH_P_ (E, D, Q); + wire [1023:0] _TECHMAP_DO_ = "simplemap; opt"; + input E, D; + output Q = E ? D : Q; +endmodule diff --git a/techlibs/ecp5/lutram.txt b/techlibs/ecp5/lutram.txt new file mode 100644 index 000000000..b94357429 --- /dev/null +++ b/techlibs/ecp5/lutram.txt @@ -0,0 +1,17 @@ +bram $__TRELLIS_DPR16X4 + init 1 + abits 4 + dbits 4 + groups 2 + ports 1 1 + wrmode 0 1 + enable 0 1 + transp 0 0 + clocks 0 1 + clkpol 0 2 +endbram + +match $__TRELLIS_DPR16X4 + make_outreg + min wports 1 +endmatch diff --git a/techlibs/ecp5/lutrams_map.v b/techlibs/ecp5/lutrams_map.v new file mode 100644 index 000000000..3b3de831f --- /dev/null +++ b/techlibs/ecp5/lutrams_map.v @@ -0,0 +1,28 @@ +module \$__TRELLIS_DPR16X4 (CLK1, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN); + parameter [63:0] INIT = 64'bx; + parameter CLKPOL2 = 1; + input CLK1; + + input [3:0] A1ADDR; + output [3:0] A1DATA; + + input [3:0] B1ADDR; + input [3:0] B1DATA; + input B1EN; + + localparam WCKMUX = CLKPOL2 ? "WCK" : "INV"; + + TRELLIS_DPR16X4 #( + .INITVAL(INIT), + .WCKMUX(WCKMUX), + .WREMUX("WRE") + ) _TECHMAP_REPLACE_ ( + .RAD(A1ADDR), + .DO(A1DATA), + + .WAD(B1ADDR), + .DI(B1DATA), + .WCK(CLK1), + .WRE(B1EN) + ); +endmodule diff --git a/techlibs/ecp5/synth_ecp5.cc b/techlibs/ecp5/synth_ecp5.cc new file mode 100644 index 000000000..2593546e0 --- /dev/null +++ b/techlibs/ecp5/synth_ecp5.cc @@ -0,0 +1,351 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * Copyright (C) 2018 David Shah <dave@ds0.me> + * + * 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/register.h" +#include "kernel/celltypes.h" +#include "kernel/rtlil.h" +#include "kernel/log.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct SynthEcp5Pass : public ScriptPass +{ + SynthEcp5Pass() : ScriptPass("synth_ecp5", "synthesis for ECP5 FPGAs") { } + + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" synth_ecp5 [options]\n"); + log("\n"); + log("This command runs synthesis for ECP5 FPGAs.\n"); + log("\n"); + log(" -top <module>\n"); + log(" use the specified module as top module\n"); + log("\n"); + log(" -blif <file>\n"); + log(" write the design to the specified BLIF file. writing of an output file\n"); + log(" is omitted if this parameter is not specified.\n"); + log("\n"); + log(" -edif <file>\n"); + log(" write the design to the specified EDIF file. writing of an output file\n"); + log(" is omitted if this parameter is not specified.\n"); + log("\n"); + log(" -json <file>\n"); + log(" write the design to the specified JSON file. writing of an output file\n"); + log(" is omitted if this parameter is not specified.\n"); + log("\n"); + log(" -run <from_label>:<to_label>\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"); + log(" synonymous to the end of the command list.\n"); + log("\n"); + log(" -noflatten\n"); + log(" do not flatten design before synthesis\n"); + log("\n"); + log(" -retime\n"); + log(" run 'abc' with -dff option\n"); + log("\n"); + log(" -noccu2\n"); + log(" do not use CCU2 cells in output netlist\n"); + log("\n"); + log(" -nodffe\n"); + log(" do not use flipflops with CE in output netlist\n"); + log("\n"); + log(" -nobram\n"); + log(" do not use block RAM cells in output netlist\n"); + log("\n"); + log(" -nolutram\n"); + log(" do not use LUT RAM cells in output netlist\n"); + log("\n"); + log(" -nowidelut\n"); + log(" do not use PFU muxes to implement LUTs larger than LUT4s\n"); + log("\n"); + log(" -abc2\n"); + log(" run two passes of 'abc' for slightly improved logic density\n"); + log("\n"); + log(" -abc9\n"); + log(" use new ABC9 flow (EXPERIMENTAL)\n"); + log("\n"); + log(" -vpr\n"); + log(" generate an output netlist (and BLIF file) suitable for VPR\n"); + log(" (this feature is experimental and incomplete)\n"); + log("\n"); + log("\n"); + log("The following commands are executed by this synthesis command:\n"); + help_script(); + log("\n"); + } + + string top_opt, blif_file, edif_file, json_file; + bool noccu2, nodffe, nobram, nolutram, nowidelut, flatten, retime, abc2, abc9, vpr; + + void clear_flags() YS_OVERRIDE + { + top_opt = "-auto-top"; + blif_file = ""; + edif_file = ""; + json_file = ""; + noccu2 = false; + nodffe = false; + nobram = false; + nolutram = false; + nowidelut = false; + flatten = true; + retime = false; + abc2 = false; + vpr = false; + abc9 = false; + } + + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + string run_from, run_to; + clear_flags(); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + if (args[argidx] == "-top" && argidx+1 < args.size()) { + top_opt = "-top " + args[++argidx]; + continue; + } + if (args[argidx] == "-blif" && argidx+1 < args.size()) { + blif_file = args[++argidx]; + continue; + } + if (args[argidx] == "-edif" && argidx+1 < args.size()) { + edif_file = args[++argidx]; + continue; + } + if (args[argidx] == "-json" && argidx+1 < args.size()) { + json_file = args[++argidx]; + continue; + } + if (args[argidx] == "-run" && argidx+1 < args.size()) { + size_t pos = args[argidx+1].find(':'); + if (pos == std::string::npos) + break; + run_from = args[++argidx].substr(0, pos); + run_to = args[argidx].substr(pos+1); + continue; + } + if (args[argidx] == "-flatten") { + flatten = true; + continue; + } + if (args[argidx] == "-noflatten") { + flatten = false; + continue; + } + if (args[argidx] == "-retime") { + retime = true; + continue; + } + if (args[argidx] == "-noccu2") { + noccu2 = true; + continue; + } + if (args[argidx] == "-nodffe") { + nodffe = true; + continue; + } + if (args[argidx] == "-nobram") { + nobram = true; + continue; + } + if (args[argidx] == "-nolutram" || /*deprecated alias*/ args[argidx] == "-nodram") { + nolutram = true; + continue; + } + if (args[argidx] == "-nowidelut" || /*deprecated alias*/ args[argidx] == "-nomux") { + nowidelut = true; + continue; + } + if (args[argidx] == "-abc2") { + abc2 = true; + continue; + } + if (args[argidx] == "-vpr") { + vpr = true; + continue; + } + if (args[argidx] == "-abc9") { + abc9 = true; + continue; + } + break; + } + extra_args(args, argidx, design); + + if (!design->full_selection()) + log_cmd_error("This command only operates on fully selected designs!\n"); + + if (abc9 && retime) + log_cmd_error("-retime option not currently compatible with -abc9!\n"); + + log_header(design, "Executing SYNTH_ECP5 pass.\n"); + log_push(); + + run_script(design, run_from, run_to); + + log_pop(); + } + + void script() YS_OVERRIDE + { + if (check_label("begin")) + { + run("read_verilog -D_ABC -lib +/ecp5/cells_sim.v +/ecp5/cells_bb.v"); + run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str())); + } + + if (flatten && check_label("flatten", "(unless -noflatten)")) + { + run("proc"); + run("flatten"); + run("tribuf -logic"); + run("deminout"); + } + + if (check_label("coarse")) + { + run("synth -run coarse"); + } + + if (!nobram && check_label("map_bram", "(skip if -nobram)")) + { + run("memory_bram -rules +/ecp5/bram.txt"); + run("techmap -map +/ecp5/brams_map.v"); + } + + if (!nolutram && check_label("map_lutram", "(skip if -nolutram)")) + { + run("memory_bram -rules +/ecp5/lutram.txt"); + run("techmap -map +/ecp5/lutrams_map.v"); + } + + if (check_label("map_ffram")) + { + run("opt -fast -mux_undef -undriven -fine"); + run("memory_map"); + run("opt -undriven -fine"); + } + + if (check_label("map_gates")) + { + if (noccu2) + run("techmap"); + else + run("techmap -map +/techmap.v -map +/ecp5/arith_map.v"); + if (retime || help_mode) + run("abc -dff", "(only if -retime)"); + } + + if (check_label("map_ffs")) + { + run("dffsr2dff"); + run("dff2dffs"); + run("opt_clean"); + if (!nodffe) + run("dff2dffe -direct-match $_DFF_* -direct-match $__DFFS_*"); + run("techmap -D NO_LUT -map +/ecp5/cells_map.v"); + run("opt_expr -undriven -mux_undef"); + run("simplemap"); + run("ecp5_ffinit"); + run("ecp5_gsr"); + run("opt_clean"); + } + + if (check_label("map_luts")) + { + if (abc2 || help_mode) { + run("abc", " (only if -abc2)"); + } + std::string techmap_args = "-map +/ecp5/latches_map.v"; + if (abc9) + techmap_args += " -map +/ecp5/abc_map.v -max_iter 1"; + run("techmap " + techmap_args); + + if (abc9) { + if (nowidelut) + run("abc9 -lut +/ecp5/abc_5g_nowide.lut -box +/ecp5/abc_5g.box -W 200"); + else + run("abc9 -lut +/ecp5/abc_5g.lut -box +/ecp5/abc_5g.box -W 200"); + run("techmap -map +/ecp5/abc_unmap.v"); + } else { + if (nowidelut) + run("abc -lut 4 -dress"); + else + run("abc -lut 4:7 -dress"); + } + run("clean"); + } + + if (check_label("map_cells")) + { + if (vpr) + run("techmap -D NO_LUT -map +/ecp5/cells_map.v"); + else + run("techmap -map +/ecp5/cells_map.v", "(with -D NO_LUT in vpr mode)"); + + run("clean"); + } + + if (check_label("check")) + { + run("hierarchy -check"); + run("stat"); + run("check -noinit"); + } + + if (check_label("blif")) + { + if (!blif_file.empty() || help_mode) { + if (vpr || help_mode) { + run(stringf("opt_clean -purge"), + " (vpr mode)"); + run(stringf("write_blif -attr -cname -conn -param %s", + help_mode ? "<file-name>" : blif_file.c_str()), + " (vpr mode)"); + } + if (!vpr) + run(stringf("write_blif -gates -attr -param %s", + help_mode ? "<file-name>" : blif_file.c_str()), + " (non-vpr mode)"); + } + } + + if (check_label("edif")) + { + if (!edif_file.empty() || help_mode) + run(stringf("write_edif %s", help_mode ? "<file-name>" : edif_file.c_str())); + } + + if (check_label("json")) + { + if (!json_file.empty() || help_mode) + run(stringf("write_json %s", help_mode ? "<file-name>" : json_file.c_str())); + } + } +} SynthEcp5Pass; + +PRIVATE_NAMESPACE_END diff --git a/techlibs/ecp5/tests/.gitignore b/techlibs/ecp5/tests/.gitignore new file mode 100644 index 000000000..0e18132cc --- /dev/null +++ b/techlibs/ecp5/tests/.gitignore @@ -0,0 +1 @@ +work_* diff --git a/techlibs/ecp5/tests/test_diamond_ffs.py b/techlibs/ecp5/tests/test_diamond_ffs.py new file mode 100644 index 000000000..1ed85ce8b --- /dev/null +++ b/techlibs/ecp5/tests/test_diamond_ffs.py @@ -0,0 +1,82 @@ +import os +import subprocess + +if not os.path.exists("work_ff"): + os.mkdir("work_ff") + +modules = [] + +with open("../cells_ff.vh", "r") as f: + with open("work_ff/cells_ff_gate.v", "w") as g: + for line in f: + if not line.startswith("module"): + g.write(line) + continue + else: + spidx = line.find(" ") + bridx = line.find("(") + modname = line[spidx+1 : bridx] + g.write("module %s_gate" % modname) + g.write(line[bridx:]) + inpidx = line.find("input ") + outpidx = line.find(", output") + modules.append((modname, [x.strip() for x in line[inpidx+6:outpidx].split(",")])) + +with open("work_ff/testbench.v", "w") as f: + print(""" +`timescale 1ns/ 1ps + +module testbench; +reg pur = 0, clk, rst, cen, d; + +// Needed for Diamond sim models +GSR GSR_INST (.GSR(1'b1)); +PUR PUR_INST (.PUR(pur)); + + +initial begin + $dumpfile("work_ff/ffs.vcd"); + $dumpvars(0, testbench); + #5; + pur = 1; + #95; + repeat (2500) begin + {clk, rst, cen, d} = $random; + #10; + check_outputs; + #1; + end + $finish; +end + """, file=f) + + for modname, inputs in modules: + print(" wire %s_gold_q, %s_gate_q;" % (modname, modname), file=f) + portconns = [] + for inp in inputs: + if inp in ("SCLK", "CK"): + portconns.append(".%s(clk)" % inp) + elif inp in ("CD", "PD"): + portconns.append(".%s(rst)" % inp) + elif inp == "SP": + portconns.append(".%s(cen)" % inp) + elif inp == "D": + portconns.append(".%s(d)" % inp) + else: + assert False + portconns.append(".Q(%s_gold_q)" % modname) + print(" %s %s_gold_i (%s);" % (modname, modname, ", ".join(portconns)), file=f) + portconns[-1] = (".Q(%s_gate_q)" % modname) + print(" %s_gate %s_gate_i (%s);" % (modname, modname, ", ".join(portconns)), file=f) + print("", file=f) + print(" task check_outputs;", file=f) + print(" begin", file=f) + print(" if (%s_gold_q != %s_gate_q) $display(\"MISMATCH at %%1t: %s_gold_q=%%b, %s_gate_q=%%b\", $time, %s_gold_q, %s_gate_q);" % + (modname, modname, modname, modname, modname, modname), file=f) + print(" end", file=f) + print(" endtask", file=f) + print("endmodule", file=f) + +diamond_models = "/usr/local/diamond/3.10_x64/cae_library/simulation/verilog/ecp5u" +subprocess.call(["iverilog", "-s", "testbench", "-o", "work_ff/testbench", "-Dmixed_hdl", "-DNO_INCLUDES", "-y", diamond_models, "work_ff/cells_ff_gate.v", "../cells_sim.v", "work_ff/testbench.v"]) +subprocess.call(["vvp", "work_ff/testbench"]) diff --git a/techlibs/efinix/Makefile.inc b/techlibs/efinix/Makefile.inc new file mode 100644 index 000000000..5013f7fc1 --- /dev/null +++ b/techlibs/efinix/Makefile.inc @@ -0,0 +1,10 @@ + +OBJS += techlibs/efinix/synth_efinix.o +OBJS += techlibs/efinix/efinix_gbuf.o +OBJS += techlibs/efinix/efinix_fixcarry.o + +$(eval $(call add_share_file,share/efinix,techlibs/efinix/cells_map.v)) +$(eval $(call add_share_file,share/efinix,techlibs/efinix/arith_map.v)) +$(eval $(call add_share_file,share/efinix,techlibs/efinix/cells_sim.v)) +$(eval $(call add_share_file,share/efinix,techlibs/efinix/brams_map.v)) +$(eval $(call add_share_file,share/efinix,techlibs/efinix/bram.txt)) diff --git a/techlibs/efinix/arith_map.v b/techlibs/efinix/arith_map.v new file mode 100644 index 000000000..178f57bc5 --- /dev/null +++ b/techlibs/efinix/arith_map.v @@ -0,0 +1,79 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2018 Miodrag Milanovic <miodrag@symbioticeda.com> + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * + * 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. + * + */ + +(* techmap_celltype = "$alu" *) +module _80_efinix_alu (A, B, CI, BI, X, Y, CO); + parameter A_SIGNED = 0; + parameter B_SIGNED = 0; + parameter A_WIDTH = 1; + parameter B_WIDTH = 1; + parameter Y_WIDTH = 1; + + input [A_WIDTH-1:0] A; + input [B_WIDTH-1:0] B; + output [Y_WIDTH-1:0] X, Y; + + input CI, BI; + output [Y_WIDTH-1:0] CO; + + wire CIx; + wire [Y_WIDTH-1:0] COx; + + wire _TECHMAP_FAIL_ = Y_WIDTH <= 2; + + wire [Y_WIDTH-1:0] A_buf, B_buf; + \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf)); + \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf)); + + wire [Y_WIDTH-1:0] AA = A_buf; + wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; + wire [Y_WIDTH-1:0] C = { COx, CIx }; + + EFX_ADD #(.I0_POLARITY(1'b1),.I1_POLARITY(1'b1)) + adder_cin ( + .I0(CI), + .I1(1'b1), + .CI(1'b0), + .CO(CIx) + ); + + genvar i; + generate for (i = 0; i < Y_WIDTH; i = i + 1) begin: slice + EFX_ADD #(.I0_POLARITY(1'b1),.I1_POLARITY(1'b1)) + adder_i ( + .I0(AA[i]), + .I1(BB[i]), + .CI(C[i]), + .O(Y[i]), + .CO(COx[i]) + ); + EFX_ADD #(.I0_POLARITY(1'b1),.I1_POLARITY(1'b1)) + adder_cout ( + .I0(1'b0), + .I1(1'b0), + .CI(COx[i]), + .O(CO[i]) + ); + end: slice + endgenerate + + /* End implementation */ + assign X = AA ^ BB; +endmodule
\ No newline at end of file diff --git a/techlibs/efinix/bram.txt b/techlibs/efinix/bram.txt new file mode 100644 index 000000000..0b3fd9308 --- /dev/null +++ b/techlibs/efinix/bram.txt @@ -0,0 +1,32 @@ +bram $__EFINIX_5K + init 1 + + abits 8 @a8d16 + dbits 16 @a8d16 + abits 9 @a9d8 + dbits 8 @a9d8 + abits 10 @a10d4 + dbits 4 @a10d4 + abits 11 @a11d2 + dbits 2 @a11d2 + abits 12 @a12d1 + dbits 1 @a12d1 + abits 8 @a8d20 + dbits 20 @a8d20 + abits 9 @a9d10 + dbits 10 @a9d10 + + groups 2 + ports 1 1 + wrmode 1 0 + enable 1 1 + transp 0 2 + clocks 2 3 + clkpol 2 3 +endbram + +match $__EFINIX_5K + min bits 256 + min efficiency 5 + shuffle_enable B +endmatch diff --git a/techlibs/efinix/brams_map.v b/techlibs/efinix/brams_map.v new file mode 100644 index 000000000..6786ae769 --- /dev/null +++ b/techlibs/efinix/brams_map.v @@ -0,0 +1,65 @@ +module \$__EFINIX_5K (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN); + parameter CFG_ABITS = 8; + parameter CFG_DBITS = 20; + parameter CFG_ENABLE_A = 1; + + parameter CLKPOL2 = 1; + parameter CLKPOL3 = 1; + parameter [5119:0] INIT = 5119'bx; + parameter TRANSP2 = 0; + + input CLK2; + input CLK3; + + input [CFG_ABITS-1:0] A1ADDR; + input [CFG_DBITS-1:0] A1DATA; + input [CFG_ENABLE_A-1:0] A1EN; + + input [CFG_ABITS-1:0] B1ADDR; + output [CFG_DBITS-1:0] B1DATA; + input B1EN; + + localparam WRITEMODE_A = TRANSP2 ? "WRITE_FIRST" : "READ_FIRST"; + + EFX_RAM_5K #( + .READ_WIDTH(CFG_DBITS), + .WRITE_WIDTH(CFG_DBITS), + .OUTPUT_REG(1'b0), + .RCLK_POLARITY(1'b1), + .RE_POLARITY(1'b1), + .WCLK_POLARITY(1'b1), + .WE_POLARITY(1'b1), + .WCLKE_POLARITY(1'b1), + .WRITE_MODE(WRITEMODE_A), + .INIT_0(INIT[ 0*256 +: 256]), + .INIT_1(INIT[ 1*256 +: 256]), + .INIT_2(INIT[ 2*256 +: 256]), + .INIT_3(INIT[ 3*256 +: 256]), + .INIT_4(INIT[ 4*256 +: 256]), + .INIT_5(INIT[ 5*256 +: 256]), + .INIT_6(INIT[ 6*256 +: 256]), + .INIT_7(INIT[ 7*256 +: 256]), + .INIT_8(INIT[ 8*256 +: 256]), + .INIT_9(INIT[ 9*256 +: 256]), + .INIT_A(INIT[10*256 +: 256]), + .INIT_B(INIT[11*256 +: 256]), + .INIT_C(INIT[12*256 +: 256]), + .INIT_D(INIT[13*256 +: 256]), + .INIT_E(INIT[14*256 +: 256]), + .INIT_F(INIT[15*256 +: 256]), + .INIT_10(INIT[16*256 +: 256]), + .INIT_11(INIT[17*256 +: 256]), + .INIT_12(INIT[18*256 +: 256]), + .INIT_13(INIT[19*256 +: 256]) + ) _TECHMAP_REPLACE_ ( + .WDATA(A1DATA), + .WADDR(A1ADDR), + .WE(A1EN), + .WCLK(CLK2), + .WCLKE(1'b1), + .RDATA(B1DATA), + .RADDR(B1ADDR), + .RE(B1EN), + .RCLK(CLK3) + ); +endmodule diff --git a/techlibs/efinix/cells_map.v b/techlibs/efinix/cells_map.v new file mode 100644 index 000000000..0aeab1902 --- /dev/null +++ b/techlibs/efinix/cells_map.v @@ -0,0 +1,45 @@ +module \$_DFF_N_ (input D, C, output Q); EFX_FF #(.CLK_POLARITY(1'b0), .CE_POLARITY(1'b1), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b1), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(1'b0), .Q(Q)); endmodule +module \$_DFF_P_ (input D, C, output Q); EFX_FF #(.CLK_POLARITY(1'b1), .CE_POLARITY(1'b1), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b1), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(1'b0), .Q(Q)); endmodule + +module \$_DFFE_NN_ (input D, C, E, output Q); EFX_FF #(.CLK_POLARITY(1'b0), .CE_POLARITY(1'b0), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b1), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(E), .CLK(C), .SR(1'b0), .Q(Q)); endmodule +module \$_DFFE_NP_ (input D, C, E, output Q); EFX_FF #(.CLK_POLARITY(1'b0), .CE_POLARITY(1'b1), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b1), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(E), .CLK(C), .SR(1'b0), .Q(Q)); endmodule + +module \$_DFFE_PN_ (input D, C, E, output Q); EFX_FF #(.CLK_POLARITY(1'b1), .CE_POLARITY(1'b0), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b1), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(E), .CLK(C), .SR(1'b0), .Q(Q)); endmodule +module \$_DFFE_PP_ (input D, C, E, output Q); EFX_FF #(.CLK_POLARITY(1'b1), .CE_POLARITY(1'b1), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b1), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(E), .CLK(C), .SR(1'b0), .Q(Q)); endmodule + +module \$_DFF_NN0_ (input D, C, R, output Q); EFX_FF #(.CLK_POLARITY(1'b0), .CE_POLARITY(1'b1), .SR_POLARITY(1'b0), .D_POLARITY(1'b1), .SR_SYNC(1'b0), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(R), .Q(Q)); endmodule +module \$_DFF_NN1_ (input D, C, R, output Q); EFX_FF #(.CLK_POLARITY(1'b0), .CE_POLARITY(1'b1), .SR_POLARITY(1'b0), .D_POLARITY(1'b1), .SR_SYNC(1'b0), .SR_VALUE(1'b1), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(R), .Q(Q)); endmodule +module \$_DFF_PN0_ (input D, C, R, output Q); EFX_FF #(.CLK_POLARITY(1'b1), .CE_POLARITY(1'b1), .SR_POLARITY(1'b0), .D_POLARITY(1'b1), .SR_SYNC(1'b0), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(R), .Q(Q)); endmodule +module \$_DFF_PN1_ (input D, C, R, output Q); EFX_FF #(.CLK_POLARITY(1'b1), .CE_POLARITY(1'b1), .SR_POLARITY(1'b0), .D_POLARITY(1'b1), .SR_SYNC(1'b0), .SR_VALUE(1'b1), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(R), .Q(Q)); endmodule + +module \$_DFF_NP0_ (input D, C, R, output Q); EFX_FF #(.CLK_POLARITY(1'b0), .CE_POLARITY(1'b1), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b0), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(R), .Q(Q)); endmodule +module \$_DFF_NP1_ (input D, C, R, output Q); EFX_FF #(.CLK_POLARITY(1'b0), .CE_POLARITY(1'b1), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b0), .SR_VALUE(1'b1), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(R), .Q(Q)); endmodule +module \$_DFF_PP0_ (input D, C, R, output Q); EFX_FF #(.CLK_POLARITY(1'b1), .CE_POLARITY(1'b1), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b0), .SR_VALUE(1'b0), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(R), .Q(Q)); endmodule +module \$_DFF_PP1_ (input D, C, R, output Q); EFX_FF #(.CLK_POLARITY(1'b1), .CE_POLARITY(1'b1), .SR_POLARITY(1'b1), .D_POLARITY(1'b1), .SR_SYNC(1'b0), .SR_VALUE(1'b1), .SR_SYNC_PRIORITY(1'b1)) _TECHMAP_REPLACE_ (.D(D), .CE(1'b1), .CLK(C), .SR(R), .Q(Q)); endmodule + +`ifndef NO_LUT +module \$lut (A, Y); + parameter WIDTH = 0; + parameter LUT = 0; + + input [WIDTH-1:0] A; + output Y; + + generate + if (WIDTH == 1) begin + EFX_LUT4 #(.LUTMASK(LUT)) _TECHMAP_REPLACE_ (.O(Y), .I0(A[0]), .I1(1'b0), .I2(1'b0), .I3(1'b0)); + end else + if (WIDTH == 2) begin + EFX_LUT4 #(.LUTMASK(LUT)) _TECHMAP_REPLACE_ (.O(Y), .I0(A[0]), .I1(A[1]), .I2(1'b0), .I3(1'b0)); + end else + if (WIDTH == 3) begin + EFX_LUT4 #(.LUTMASK(LUT)) _TECHMAP_REPLACE_ (.O(Y), .I0(A[0]), .I1(A[1]), .I2(A[2]), .I3(1'b0)); + end else + if (WIDTH == 4) begin + EFX_LUT4 #(.LUTMASK(LUT)) _TECHMAP_REPLACE_ (.O(Y), .I0(A[0]), .I1(A[1]), .I2(A[2]), .I3(A[3])); + end else begin + wire _TECHMAP_FAIL_ = 1; + end + endgenerate +endmodule +`endif diff --git a/techlibs/efinix/cells_sim.v b/techlibs/efinix/cells_sim.v new file mode 100644 index 000000000..2fc2034a6 --- /dev/null +++ b/techlibs/efinix/cells_sim.v @@ -0,0 +1,173 @@ +module EFX_LUT4( + output O, + input I0, + input I1, + input I2, + input I3 +); + parameter LUTMASK = 16'h0000; + + wire [7:0] s3 = I3 ? LUTMASK[15:8] : LUTMASK[7:0]; + wire [3:0] s2 = I2 ? s3[ 7:4] : s3[3:0]; + wire [1:0] s1 = I1 ? s2[ 3:2] : s2[1:0]; + assign O = I0 ? s1[1] : s1[0]; +endmodule + +module EFX_ADD( + output O, + output CO, + input I0, + input I1, + input CI +); + parameter I0_POLARITY = 1; + parameter I1_POLARITY = 1; + + wire i0; + wire i1; + + assign i0 = I0_POLARITY ? I0 : ~I0; + assign i1 = I1_POLARITY ? I1 : ~I1; + + assign {CO, O} = i0 + i1 + CI; +endmodule + +module EFX_FF( + output reg Q, + input D, + input CE, + input CLK, + input SR +); + parameter CLK_POLARITY = 1; + parameter CE_POLARITY = 1; + parameter SR_POLARITY = 1; + parameter SR_SYNC = 0; + parameter SR_VALUE = 0; + parameter SR_SYNC_PRIORITY = 0; + parameter D_POLARITY = 1; + + wire clk; + wire ce; + wire sr; + wire d; + wire prio; + wire sync; + wire async; + + assign clk = CLK_POLARITY ? CLK : ~CLK; + assign ce = CE_POLARITY ? CE : ~CE; + assign sr = SR_POLARITY ? SR : ~SR; + assign d = D_POLARITY ? D : ~D; + + generate + if (SR_SYNC == 1) + begin + if (SR_SYNC_PRIORITY == 1) + begin + always @(posedge clk) + if (sr) + Q <= SR_VALUE; + else if (ce) + Q <= d; + end + else + begin + always @(posedge clk) + if (ce) + begin + if (sr) + Q <= SR_VALUE; + else + Q <= d; + end + end + end + else + begin + always @(posedge clk or posedge sr) + if (sr) + Q <= SR_VALUE; + else if (ce) + Q <= d; + + end + endgenerate +endmodule + +module EFX_GBUFCE( + input CE, + input I, + output O +); + parameter CE_POLARITY = 1'b1; + + wire ce; + assign ce = CE_POLARITY ? CE : ~CE; + + assign O = I & ce; + +endmodule + +module EFX_RAM_5K( + input [WRITE_WIDTH-1:0] WDATA, + input [WRITE_ADDR_WIDTH-1:0] WADDR, + input WE, + input WCLK, + input WCLKE, + output [READ_WIDTH-1:0] RDATA, + input [READ_ADDR_WIDTH-1:0] RADDR, + input RE, + input RCLK +); + parameter READ_WIDTH = 20; + parameter WRITE_WIDTH = 20; + parameter OUTPUT_REG = 1'b0; + parameter RCLK_POLARITY = 1'b1; + parameter RE_POLARITY = 1'b1; + parameter WCLK_POLARITY = 1'b1; + parameter WE_POLARITY = 1'b1; + parameter WCLKE_POLARITY = 1'b1; + parameter WRITE_MODE = "READ_FIRST"; + parameter INIT_0 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_1 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_2 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_3 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_4 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_5 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_6 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_7 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_8 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_9 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_A = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_B = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_C = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_D = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_10 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_11 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_12 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_13 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + + localparam READ_ADDR_WIDTH = + (READ_WIDTH == 16) ? 8 : // 256x16 + (READ_WIDTH == 8) ? 9 : // 512x8 + (READ_WIDTH == 4) ? 10 : // 1024x4 + (READ_WIDTH == 2) ? 11 : // 2048x2 + (READ_WIDTH == 1) ? 12 : // 4096x1 + (READ_WIDTH == 20) ? 8 : // 256x20 + (READ_WIDTH == 10) ? 9 : // 512x10 + (READ_WIDTH == 5) ? 10 : -1; // 1024x5 + + localparam WRITE_ADDR_WIDTH = + (WRITE_WIDTH == 16) ? 8 : // 256x16 + (WRITE_WIDTH == 8) ? 9 : // 512x8 + (WRITE_WIDTH == 4) ? 10 : // 1024x4 + (WRITE_WIDTH == 2) ? 11 : // 2048x2 + (WRITE_WIDTH == 1) ? 12 : // 4096x1 + (WRITE_WIDTH == 20) ? 8 : // 256x20 + (WRITE_WIDTH == 10) ? 9 : // 512x10 + (WRITE_WIDTH == 5) ? 10 : -1; // 1024x5 + +endmodule
\ No newline at end of file diff --git a/techlibs/efinix/efinix_fixcarry.cc b/techlibs/efinix/efinix_fixcarry.cc new file mode 100644 index 000000000..b7cd995b8 --- /dev/null +++ b/techlibs/efinix/efinix_fixcarry.cc @@ -0,0 +1,122 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2019 Miodrag Milanovic <miodrag@symbioticeda.com> + * + * 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 + +static SigBit get_bit_or_zero(const SigSpec &sig) +{ + if (GetSize(sig) == 0) + return State::S0; + return sig[0]; +} + +static void fix_carry_chain(Module *module) +{ + SigMap sigmap(module); + + pool<SigBit> ci_bits; + dict<SigBit, SigBit> mapping_bits; + + for (auto cell : module->cells()) + { + if (cell->type == "\\EFX_ADD") { + SigBit bit_i0 = get_bit_or_zero(cell->getPort("\\I0")); + SigBit bit_i1 = get_bit_or_zero(cell->getPort("\\I1")); + if (bit_i0 == State::S0 && bit_i1== State::S0) { + SigBit bit_ci = get_bit_or_zero(cell->getPort("\\CI")); + SigBit bit_o = sigmap(cell->getPort("\\O")); + ci_bits.insert(bit_ci); + mapping_bits[bit_ci] = bit_o; + } + } + } + + vector<Cell*> adders_to_fix_cells; + for (auto cell : module->cells()) + { + if (cell->type == "\\EFX_ADD") { + SigBit bit_ci = get_bit_or_zero(cell->getPort("\\CI")); + SigBit bit_i0 = get_bit_or_zero(cell->getPort("\\I0")); + SigBit bit_i1 = get_bit_or_zero(cell->getPort("\\I1")); + SigBit canonical_bit = sigmap(bit_ci); + if (!ci_bits.count(canonical_bit)) + continue; + if (bit_i0 == State::S0 && bit_i1== State::S0) + continue; + + adders_to_fix_cells.push_back(cell); + log("Found %s cell named %s with invalid CI signal.\n", log_id(cell->type), log_id(cell)); + } + } + + for (auto cell : adders_to_fix_cells) + { + SigBit bit_ci = get_bit_or_zero(cell->getPort("\\CI")); + SigBit canonical_bit = sigmap(bit_ci); + auto bit = mapping_bits.at(canonical_bit); + log("Fixing %s cell named %s breaking carry chain.\n", log_id(cell->type), log_id(cell)); + Cell *c = module->addCell(NEW_ID, "\\EFX_ADD"); + SigBit new_bit = module->addWire(NEW_ID); + c->setParam("\\I0_POLARITY", State::S1); + c->setParam("\\I1_POLARITY", State::S1); + c->setPort("\\I0", bit); + c->setPort("\\I1", State::S1); + c->setPort("\\CI", State::S0); + c->setPort("\\CO", new_bit); + + cell->setPort("\\CI", new_bit); + } +} + +struct EfinixCarryFixPass : public Pass { + EfinixCarryFixPass() : Pass("efinix_fixcarry", "Efinix: fix carry chain") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" efinix_fixcarry [options] [selection]\n"); + log("\n"); + log("Add Efinix adders to fix carry chain if needed.\n"); + log("\n"); + } + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + log_header(design, "Executing efinix_fixcarry pass (fix invalid carry chain).\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + break; + } + extra_args(args, argidx, design); + + Module *module = design->top_module(); + + if (module == nullptr) + log_cmd_error("No top module found.\n"); + + fix_carry_chain(module); + } +} EfinixCarryFixPass; + +PRIVATE_NAMESPACE_END diff --git a/techlibs/efinix/efinix_gbuf.cc b/techlibs/efinix/efinix_gbuf.cc new file mode 100644 index 000000000..e75fb3f4d --- /dev/null +++ b/techlibs/efinix/efinix_gbuf.cc @@ -0,0 +1,119 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2019 Miodrag Milanovic <miodrag@symbioticeda.com> + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * + * 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 + +static void handle_gbufs(Module *module) +{ + SigMap sigmap(module); + + pool<SigBit> clk_bits; + dict<SigBit, SigBit> rewrite_bits; + vector<pair<Cell*, SigBit>> pad_bits; + + for (auto cell : module->cells()) + { + if (cell->type == "\\EFX_FF") { + for (auto bit : sigmap(cell->getPort("\\CLK"))) + clk_bits.insert(bit); + } + if (cell->type == "\\EFX_RAM_5K") { + for (auto bit : sigmap(cell->getPort("\\RCLK"))) + clk_bits.insert(bit); + for (auto bit : sigmap(cell->getPort("\\WCLK"))) + clk_bits.insert(bit); + } + } + + for (auto wire : vector<Wire*>(module->wires())) + { + if (!wire->port_input) + continue; + + for (int index = 0; index < GetSize(wire); index++) + { + SigBit bit(wire, index); + SigBit canonical_bit = sigmap(bit); + + if (!clk_bits.count(canonical_bit)) + continue; + + Cell *c = module->addCell(NEW_ID, "\\EFX_GBUFCE"); + SigBit new_bit = module->addWire(NEW_ID); + c->setParam("\\CE_POLARITY", State::S1); + c->setPort("\\O", new_bit); + c->setPort("\\CE", State::S1); + pad_bits.push_back(make_pair(c, bit)); + rewrite_bits[canonical_bit] = new_bit; + + log("Added %s cell %s for port bit %s.\n", log_id(c->type), log_id(c), log_signal(bit)); + } + } + + auto rewrite_function = [&](SigSpec &s) { + for (auto &bit : s) { + SigBit canonical_bit = sigmap(bit); + if (rewrite_bits.count(canonical_bit)) + bit = rewrite_bits.at(canonical_bit); + } + }; + + module->rewrite_sigspecs(rewrite_function); + + for (auto &it : pad_bits) + it.first->setPort("\\I", it.second); +} + +struct EfinixGbufPass : public Pass { + EfinixGbufPass() : Pass("efinix_gbuf", "Efinix: insert global clock buffers") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" efinix_gbuf [options] [selection]\n"); + log("\n"); + log("Add Efinix global clock buffers to top module as needed.\n"); + log("\n"); + } + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + log_header(design, "Executing efinix_gbuf pass (insert global clock buffers).\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + break; + } + extra_args(args, argidx, design); + + Module *module = design->top_module(); + + if (module == nullptr) + log_cmd_error("No top module found.\n"); + + handle_gbufs(module); + } +} EfinixGbufPass; + +PRIVATE_NAMESPACE_END diff --git a/techlibs/efinix/synth_efinix.cc b/techlibs/efinix/synth_efinix.cc new file mode 100644 index 000000000..26a8d4eda --- /dev/null +++ b/techlibs/efinix/synth_efinix.cc @@ -0,0 +1,219 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2019 Miodrag Milanovic <miodrag@symbioticeda.com> + * Copyright (C) 2019 Clifford Wolf <clifford@clifford.at> + * + * 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/register.h" +#include "kernel/celltypes.h" +#include "kernel/rtlil.h" +#include "kernel/log.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct SynthEfinixPass : public ScriptPass +{ + SynthEfinixPass() : ScriptPass("synth_efinix", "synthesis for Efinix FPGAs") { } + + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" synth_efinix [options]\n"); + log("\n"); + log("This command runs synthesis for Efinix FPGAs.\n"); + log("\n"); + log(" -top <module>\n"); + log(" use the specified module as top module\n"); + log("\n"); + log(" -edif <file>\n"); + log(" write the design to the specified EDIF file. writing of an output file\n"); + log(" is omitted if this parameter is not specified.\n"); + log("\n"); + log(" -json <file>\n"); + log(" write the design to the specified JSON file. writing of an output file\n"); + log(" is omitted if this parameter is not specified.\n"); + log("\n"); + log(" -run <from_label>:<to_label>\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"); + log(" synonymous to the end of the command list.\n"); + log("\n"); + log(" -noflatten\n"); + log(" do not flatten design before synthesis\n"); + log("\n"); + log(" -retime\n"); + log(" run 'abc' with -dff option\n"); + log("\n"); + log("\n"); + log("The following commands are executed by this synthesis command:\n"); + help_script(); + log("\n"); + } + + string top_opt, edif_file, json_file; + bool flatten, retime; + + void clear_flags() YS_OVERRIDE + { + top_opt = "-auto-top"; + edif_file = ""; + json_file = ""; + flatten = true; + retime = false; + } + + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + string run_from, run_to; + clear_flags(); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + if (args[argidx] == "-top" && argidx+1 < args.size()) { + top_opt = "-top " + args[++argidx]; + continue; + } + if (args[argidx] == "-edif" && argidx+1 < args.size()) { + edif_file = args[++argidx]; + continue; + } + if (args[argidx] == "-json" && argidx+1 < args.size()) { + json_file = args[++argidx]; + continue; + } + if (args[argidx] == "-run" && argidx+1 < args.size()) { + size_t pos = args[argidx+1].find(':'); + if (pos == std::string::npos) + break; + run_from = args[++argidx].substr(0, pos); + run_to = args[argidx].substr(pos+1); + continue; + } + if (args[argidx] == "-noflatten") { + flatten = false; + continue; + } + if (args[argidx] == "-retime") { + retime = true; + continue; + } + break; + } + extra_args(args, argidx, design); + + if (!design->full_selection()) + log_cmd_error("This command only operates on fully selected designs!\n"); + + log_header(design, "Executing SYNTH_EFINIX pass.\n"); + log_push(); + + run_script(design, run_from, run_to); + + log_pop(); + } + + void script() YS_OVERRIDE + { + if (check_label("begin")) + { + run("read_verilog -lib +/efinix/cells_sim.v"); + run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str())); + } + + if (flatten && check_label("flatten", "(unless -noflatten)")) + { + run("proc"); + run("flatten"); + run("tribuf -logic"); + run("deminout"); + } + + if (check_label("coarse")) + { + run("synth -run coarse"); + } + + if (check_label("map_bram", "(skip if -nobram)")) + { + run("memory_bram -rules +/efinix/bram.txt"); + run("techmap -map +/efinix/brams_map.v"); + run("setundef -zero -params t:EFX_RAM_5K"); + } + + if (check_label("fine")) + { + run("opt -fast -mux_undef -undriven -fine"); + run("memory_map"); + run("opt -undriven -fine"); + run("techmap -map +/techmap.v -map +/efinix/arith_map.v"); + if (retime || help_mode) + run("abc -dff", "(only if -retime)"); + } + + if (check_label("map_ffs")) + { + run("dffsr2dff"); + run("techmap -D NO_LUT -map +/efinix/cells_map.v"); + run("dffinit -strinit SET RESET -ff AL_MAP_SEQ q REGSET -noreinit"); + run("opt_expr -mux_undef"); + run("simplemap"); + } + + if (check_label("map_luts")) + { + run("abc -lut 4"); + run("clean"); + } + + if (check_label("map_cells")) + { + run("techmap -map +/efinix/cells_map.v"); + run("clean"); + } + + if (check_label("map_gbuf")) + { + run("efinix_gbuf"); + run("efinix_fixcarry"); + run("clean"); + } + + if (check_label("check")) + { + run("hierarchy -check"); + run("stat"); + run("check -noinit"); + } + + if (check_label("edif")) + { + if (!edif_file.empty() || help_mode) + run(stringf("write_edif %s", help_mode ? "<file-name>" : edif_file.c_str())); + } + + if (check_label("json")) + { + if (!json_file.empty() || help_mode) + run(stringf("write_json %s", help_mode ? "<file-name>" : json_file.c_str())); + } + } +} SynthEfinixPass; + +PRIVATE_NAMESPACE_END diff --git a/techlibs/gowin/Makefile.inc b/techlibs/gowin/Makefile.inc index 679d7eff5..6f2159349 100644 --- a/techlibs/gowin/Makefile.inc +++ b/techlibs/gowin/Makefile.inc @@ -1,6 +1,17 @@ OBJS += techlibs/gowin/synth_gowin.o +OBJS += techlibs/gowin/determine_init.o + $(eval $(call add_share_file,share/gowin,techlibs/gowin/cells_map.v)) $(eval $(call add_share_file,share/gowin,techlibs/gowin/cells_sim.v)) +$(eval $(call add_share_file,share/gowin,techlibs/gowin/arith_map.v)) +$(eval $(call add_share_file,share/gowin,techlibs/gowin/brams_map.v)) +$(eval $(call add_share_file,share/gowin,techlibs/gowin/bram.txt)) +$(eval $(call add_share_file,share/gowin,techlibs/gowin/drams_map.v)) +$(eval $(call add_share_file,share/gowin,techlibs/gowin/dram.txt)) + + + +$(eval $(call add_share_file,share/gowin,techlibs/gowin/brams_init3.vh)) diff --git a/techlibs/gowin/arith_map.v b/techlibs/gowin/arith_map.v new file mode 100644 index 000000000..e15de6423 --- /dev/null +++ b/techlibs/gowin/arith_map.v @@ -0,0 +1,59 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * Copyright (C) 2018 David Shah <dave@ds0.me> + * + * 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. + * + */ + +(* techmap_celltype = "$alu" *) +module _80_gw1n_alu(A, B, CI, BI, X, Y, CO); + parameter A_SIGNED = 0; + parameter B_SIGNED = 0; + parameter A_WIDTH = 1; + parameter B_WIDTH = 1; + parameter Y_WIDTH = 1; + + input [A_WIDTH-1:0] A; + input [B_WIDTH-1:0] B; + output [Y_WIDTH-1:0] X, Y; + + input CI, BI; + output [Y_WIDTH-1:0] CO; + + wire _TECHMAP_FAIL_ = Y_WIDTH <= 2; + + wire [Y_WIDTH-1:0] A_buf, B_buf; + \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf)); + \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf)); + + wire [Y_WIDTH-1:0] AA = A_buf; + wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; + wire [Y_WIDTH-1:0] C = {CO, CI}; + + genvar i; + generate for (i = 0; i < Y_WIDTH; i = i + 1) begin:slice + ALU #(.ALU_MODE(32'b0)) + alu(.I0(AA[i]), + .I1(BB[i]), + .I3(1'b0), + .CIN(C[i]), + .COUT(CO[i]), + .SUM(Y[i]) + ); + end endgenerate + assign X = AA ^ BB; +endmodule + diff --git a/techlibs/gowin/bram.txt b/techlibs/gowin/bram.txt new file mode 100644 index 000000000..b5f9a981c --- /dev/null +++ b/techlibs/gowin/bram.txt @@ -0,0 +1,29 @@ +bram $__GW1NR_SDP +# uncomment when done +# init 1 + abits 10 @a10d18 + dbits 16 @a10d18 + abits 11 @a11d9 + dbits 8 @a11d9 + abits 12 @a12d4 + dbits 4 @a12d4 + abits 13 @a13d2 + dbits 2 @a13d2 + abits 14 @a14d1 + dbits 1 @a14d1 + groups 2 + ports 1 1 + wrmode 1 0 + enable 1 1 @a10d18 + enable 1 1 @a11d9 @a12d4 @a13d2 @a14d1 + transp 0 0 + clocks 2 3 + clkpol 2 3 +endbram + +match $__GW1NR_SDP + min bits 2048 + min efficiency 5 + shuffle_enable B + make_transp +endmatch diff --git a/techlibs/gowin/brams_init3.vh b/techlibs/gowin/brams_init3.vh new file mode 100644 index 000000000..84397fa24 --- /dev/null +++ b/techlibs/gowin/brams_init3.vh @@ -0,0 +1,12 @@ +localparam [15:0] INIT_0 = { + INIT[ 60], INIT[ 56], INIT[ 52], INIT[ 48], INIT[ 44], INIT[ 40], INIT[ 36], INIT[ 32], INIT[ 28], INIT[ 24], INIT[ 20], INIT[ 16], INIT[ 12], INIT[ 8], INIT[ 4], INIT[ 0] +}; +localparam [15:0] INIT_1 = { + INIT[ 61], INIT[ 57], INIT[ 53], INIT[ 49], INIT[ 45], INIT[ 41], INIT[ 37], INIT[ 33], INIT[ 29], INIT[ 25], INIT[ 21], INIT[ 17], INIT[ 13], INIT[ 9], INIT[ 5], INIT[ 1] +}; +localparam [15:0] INIT_2 = { + INIT[ 62], INIT[ 58], INIT[ 54], INIT[ 50], INIT[ 46], INIT[ 42], INIT[ 38], INIT[ 34], INIT[ 30], INIT[ 26], INIT[ 22], INIT[ 18], INIT[ 14], INIT[ 10], INIT[ 6], INIT[ 2] +}; +localparam [15:0] INIT_3 = { + INIT[ 63], INIT[ 59], INIT[ 55], INIT[ 51], INIT[ 47], INIT[ 43], INIT[ 39], INIT[ 35], INIT[ 31], INIT[ 27], INIT[ 23], INIT[ 19], INIT[ 15], INIT[ 11], INIT[ 7], INIT[ 3] +}; diff --git a/techlibs/gowin/brams_map.v b/techlibs/gowin/brams_map.v new file mode 100644 index 000000000..e963cfa88 --- /dev/null +++ b/techlibs/gowin/brams_map.v @@ -0,0 +1,103 @@ +/* Semi Dual Port (SDP) memory have the following configurations: + * Memory Config RAM(BIT) Port Mode Memory Depth Data Depth + * ----------------|---------| ----------|--------------|------------| + * B-SRAM_16K_SD1 16K 16Kx1 16,384 1 + * B-SRAM_8K_SD2 16K 8Kx2 8,192 2 + * B-SRAM_4K_SD4 16K 4Kx2 4,096 4 + */ +module \$__GW1NR_SDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN); + parameter CFG_ABITS = 10; + parameter CFG_DBITS = 16; + parameter CFG_ENABLE_A = 3; + + parameter [16383:0] INIT = 16384'hx; + parameter CLKPOL2 = 1; + parameter CLKPOL3 = 1; + + input CLK2; + input CLK3; + + input [CFG_ABITS-1:0] A1ADDR; + input [CFG_DBITS-1:0] A1DATA; + input [CFG_ENABLE_A-1:0] A1EN; + + input [CFG_ABITS-1:0] B1ADDR; + output [CFG_DBITS-1:0] B1DATA; + input B1EN; + + + generate if (CFG_DBITS == 1) begin + SDP #( + .READ_MODE(0), + .BIT_WIDTH_0(1), + .BIT_WIDTH_1(1), + .BLK_SEL(3'b000), + .RESET_MODE("SYNC") + ) _TECHMAP_REPLACE_ ( + .CLKA(CLK2), .CLKB(CLK3), + .WREA(A1EN), .OCE(1'b0), .CEA(1'b1), + .WREB(1'b0), .CEB(B1EN), + .RESETA(1'b0), .RESETB(1'b0), .BLKSEL(3'b000), + .DI(A1DATA), .DO(B1DATA), .ADA(A1ADDR), .ADB(B1ADDR) + ); + end else if (CFG_DBITS == 2) begin + SDP #( + .READ_MODE(0), + .BIT_WIDTH_0(2), + .BIT_WIDTH_1(2), + .BLK_SEL(3'b000), + .RESET_MODE("SYNC") + ) _TECHMAP_REPLACE_ ( + .CLKA(CLK2), .CLKB(CLK3), + .WREA(A1EN), .OCE(1'b0), .CEA(1'b1), + .WREB(1'b0), .CEB(B1EN), + .RESETA(1'b0), .RESETB(1'b0), .BLKSEL(3'b000), + .DI(A1DATA), .DO(B1DATA), .ADA(A1ADDR), .ADB(B1ADDR) + ); + end else if (CFG_DBITS <= 4) begin + SDP #( + .READ_MODE(0), + .BIT_WIDTH_0(4), + .BIT_WIDTH_1(4), + .BLK_SEL(3'b000), + .RESET_MODE("SYNC") + ) _TECHMAP_REPLACE_ ( + .CLKA(CLK2), .CLKB(CLK3), + .WREA(A1EN), .OCE(1'b0), + .WREB(1'b0), .CEB(B1EN), .CEA(1'b1), + .RESETA(1'b0), .RESETB(1'b0), .BLKSEL(3'b000), + .DI(A1DATA), .DO(B1DATA), .ADA(A1ADDR), .ADB(B1ADDR) + ); + end else if (CFG_DBITS <= 8) begin + SDP #( + .READ_MODE(0), + .BIT_WIDTH_0(8), + .BIT_WIDTH_1(8), + .BLK_SEL(3'b000), + .RESET_MODE("SYNC") + ) _TECHMAP_REPLACE_ ( + .CLKA(CLK2), .CLKB(CLK3), + .WREA(A1EN), .OCE(1'b0), .CEA(1'b1), + .WREB(1'b0), .CEB(B1EN), + .RESETA(1'b0), .RESETB(1'b0), .BLKSEL(3'b000), + .DI(A1DATA), .DO(B1DATA), .ADA(A1ADDR), .ADB(B1ADDR) + ); + end else if (CFG_DBITS <= 16) begin + SDP #( + .READ_MODE(0), + .BIT_WIDTH_0(16), + .BIT_WIDTH_1(16), + .BLK_SEL(3'b000), + .RESET_MODE("SYNC") + ) _TECHMAP_REPLACE_ ( + .CLKA(CLK2), .CLKB(CLK3), + .WREA(A1EN), .OCE(1'b0), + .WREB(1'b0), .CEB(B1EN), .CEA(1'b1), + .RESETA(1'b0), .RESETB(1'b0), .BLKSEL(3'b000), + .DI(A1DATA), .DO(B1DATA), .ADA(A1ADDR), .ADB(B1ADDR) + ); + end else begin + wire TECHMAP_FAIL = 1'b1; + end endgenerate + +endmodule diff --git a/techlibs/gowin/cells_map.v b/techlibs/gowin/cells_map.v index e1f85effa..ebdc88a0a 100644 --- a/techlibs/gowin/cells_map.v +++ b/techlibs/gowin/cells_map.v @@ -1,5 +1,9 @@ module \$_DFF_N_ (input D, C, output Q); DFFN _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C)); endmodule -module \$_DFF_P_ (input D, C, output Q); DFF _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C)); endmodule +module \$_DFF_P_ #(parameter INIT = 1'b0) (input D, C, output Q); DFF #(.INIT(INIT)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C)); endmodule + +module \$__DFFS_PN0_ (input D, C, R, output Q); DFFR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .RESET(!R)); endmodule +module \$__DFFS_PP0_ (input D, C, R, output Q); DFFR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .RESET(R)); endmodule +module \$__DFFS_PP1_ (input D, C, R, output Q); DFFR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .RESET(R)); endmodule module \$lut (A, Y); parameter WIDTH = 0; diff --git a/techlibs/gowin/cells_sim.v b/techlibs/gowin/cells_sim.v index 947942626..ebb238bad 100644 --- a/techlibs/gowin/cells_sim.v +++ b/techlibs/gowin/cells_sim.v @@ -38,6 +38,17 @@ module DFFN (output reg Q, input CLK, D); Q <= D; endmodule +module DFFR (output reg Q, input D, CLK, RESET); + parameter [0:0] INIT = 1'b0; + initial Q = INIT; + always @(posedge CLK) begin + if (RESET) + Q <= 1'b0; + else + Q <= D; + end +endmodule // DFFR (positive clock edge; synchronous reset) + module VCC(output V); assign V = 1; endmodule @@ -57,3 +68,132 @@ endmodule module GSR (input GSRI); wire GSRO = GSRI; endmodule + +module ALU (input I0, input I1, input I3, input CIN, output COUT, output SUM); + parameter [3:0] ALU_MODE = 0; // default 0 = ADD + assign {COUT, SUM} = CIN + I1 + I0; +endmodule // alu + +module RAM16S4 (DO, DI, AD, WRE, CLK); + parameter WIDTH = 4; + parameter INIT_0 = 16'h0000; + parameter INIT_1 = 16'h0000; + parameter INIT_2 = 16'h0000; + parameter INIT_3 = 16'h0000; + + input [WIDTH-1:0] AD; + input [WIDTH-1:0] DI; + output [WIDTH-1:0] DO; + input CLK; + input WRE; + + reg [15:0] mem0, mem1, mem2, mem3; + + initial begin + mem0 = INIT_0; + mem1 = INIT_1; + mem2 = INIT_2; + mem3 = INIT_3; + end + + assign DO[0] = mem0[AD]; + assign DO[1] = mem1[AD]; + assign DO[2] = mem2[AD]; + assign DO[3] = mem3[AD]; + + always @(posedge CLK) begin + if (WRE) begin + mem0[AD] <= DI[0]; + mem1[AD] <= DI[1]; + mem2[AD] <= DI[2]; + mem3[AD] <= DI[3]; + end + end + +endmodule // RAM16S4 + + +(* blackbox *) +module SDP (DO, DI, BLKSEL, ADA, ADB, WREA, WREB, CLKA, CLKB, CEA, CEB, OCE, RESETA, RESETB); +//1'b0: Bypass mode; 1'b1 Pipeline mode +parameter READ_MODE = 1'b0; +parameter BIT_WIDTH_0 = 32; // 1, 2, 4, 8, 16, 32 +parameter BIT_WIDTH_1 = 32; // 1, 2, 4, 8, 16, 32 +parameter BLK_SEL = 3'b000; +parameter RESET_MODE = "SYNC"; +parameter INIT_RAM_00 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_01 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_02 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_03 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_04 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_05 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_06 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_07 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_08 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_09 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_0A = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_0B = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_0C = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_0D = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_0E = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_0F = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_10 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_11 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_12 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_13 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_14 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_15 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_16 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_17 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_18 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_19 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_1A = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_1B = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_1C = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_1D = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_1E = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_1F = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_20 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_21 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_22 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_23 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_24 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_25 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_26 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_27 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_28 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_29 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_2A = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_2B = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_2C = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_2D = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_2E = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_2F = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_30 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_31 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_32 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_33 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_34 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_35 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_36 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_37 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_38 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_39 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_3A = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_3B = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_3C = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_3D = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_3E = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_3F = 256'h0000000000000000000000000000000000000000000000000000000000000000; + +input CLKA, CEA, CLKB, CEB; +input OCE; // clock enable of memory output register +input RESETA, RESETB; // resets output registers, not memory contents +input WREA, WREB; // 1'b0: read enabled; 1'b1: write enabled +input [13:0] ADA, ADB; +input [31:0] DI; +input [2:0] BLKSEL; +output [31:0] DO; + +endmodule + diff --git a/techlibs/gowin/determine_init.cc b/techlibs/gowin/determine_init.cc new file mode 100644 index 000000000..d9a0880f6 --- /dev/null +++ b/techlibs/gowin/determine_init.cc @@ -0,0 +1,72 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2018 Icenowy Zheng <icenowy@aosc.io> + * + * 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 DetermineInitPass : public Pass { + DetermineInitPass() : Pass("determine_init", "Determine the init value of cells") { } + void help() YS_OVERRIDE + { + log("\n"); + log(" determine_init [selection]\n"); + log("\n"); + log("Determine the init value of cells that doesn't allow unknown init value.\n"); + log("\n"); + } + + Const determine_init(Const init) + { + for (int i = 0; i < GetSize(init); i++) { + if (init[i] != State::S0 && init[i] != State::S1) + init[i] = State::S0; + } + + return init; + } + + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + log_header(design, "Executing DETERMINE_INIT pass (determine init value for cells).\n"); + + extra_args(args, args.size(), design); + + int cnt = 0; + for (auto module : design->selected_modules()) + { + for (auto cell : module->selected_cells()) + { + if (cell->type == "\\RAM16S4") + { + cell->setParam("\\INIT_0", determine_init(cell->getParam("\\INIT_0"))); + cell->setParam("\\INIT_1", determine_init(cell->getParam("\\INIT_1"))); + cell->setParam("\\INIT_2", determine_init(cell->getParam("\\INIT_2"))); + cell->setParam("\\INIT_3", determine_init(cell->getParam("\\INIT_3"))); + cnt++; + } + } + } + log_header(design, "Updated %d cells with determined init value.\n", cnt); + } +} DetermineInitPass; + +PRIVATE_NAMESPACE_END diff --git a/techlibs/gowin/dram.txt b/techlibs/gowin/dram.txt new file mode 100644 index 000000000..9db530251 --- /dev/null +++ b/techlibs/gowin/dram.txt @@ -0,0 +1,17 @@ +bram $__GW1NR_RAM16S4 + init 1 + abits 4 + dbits 4 + groups 2 + ports 1 1 + wrmode 0 1 + enable 0 1 + transp 0 1 + clocks 0 1 + clkpol 0 1 +endbram + +match $__GW1NR_RAM16S4 + make_outreg + min wports 1 +endmatch diff --git a/techlibs/gowin/drams_map.v b/techlibs/gowin/drams_map.v new file mode 100644 index 000000000..a50ab365a --- /dev/null +++ b/techlibs/gowin/drams_map.v @@ -0,0 +1,31 @@ +module \$__GW1NR_RAM16S4 (CLK1, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN); + parameter CFG_ABITS = 4; + parameter CFG_DBITS = 4; + + parameter [63:0] INIT = 64'bx; + input CLK1; + + input [CFG_ABITS-1:0] A1ADDR; + output [CFG_DBITS-1:0] A1DATA; + input A1EN; + + input [CFG_ABITS-1:0] B1ADDR; + input [CFG_DBITS-1:0] B1DATA; + input B1EN; + + `include "brams_init3.vh" + + RAM16S4 + #(.INIT_0(INIT_0), + .INIT_1(INIT_1), + .INIT_2(INIT_2), + .INIT_3(INIT_3)) + _TECHMAP_REPLACE_ + (.AD(B1ADDR), + .DI(B1DATA), + .DO(A1DATA), + .CLK(CLK1), + .WRE(B1EN)); + + +endmodule diff --git a/techlibs/gowin/synth_gowin.cc b/techlibs/gowin/synth_gowin.cc index 44dec265d..ac3dbfb29 100644 --- a/techlibs/gowin/synth_gowin.cc +++ b/techlibs/gowin/synth_gowin.cc @@ -29,7 +29,7 @@ struct SynthGowinPass : public ScriptPass { SynthGowinPass() : ScriptPass("synth_gowin", "synthesis for Gowin FPGAs") { } - virtual void help() YS_OVERRIDE + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -49,6 +49,18 @@ struct SynthGowinPass : public ScriptPass log(" from label is synonymous to 'begin', and empty to label is\n"); log(" synonymous to the end of the command list.\n"); log("\n"); + log(" -nodffe\n"); + log(" do not use flipflops with CE in output netlist\n"); + log("\n"); + log(" -nobram\n"); + log(" do not use BRAM cells in output netlist\n"); + log("\n"); + log(" -nodram\n"); + log(" do not use distributed RAM cells in output netlist\n"); + log("\n"); + log(" -noflatten\n"); + log(" do not flatten design before synthesis\n"); + log("\n"); log(" -retime\n"); log(" run 'abc' with -dff option\n"); log("\n"); @@ -59,16 +71,20 @@ struct SynthGowinPass : public ScriptPass } string top_opt, vout_file; - bool retime; + bool retime, nobram, nodram, flatten, nodffe; - virtual void clear_flags() YS_OVERRIDE + void clear_flags() YS_OVERRIDE { top_opt = "-auto-top"; vout_file = ""; retime = false; + flatten = true; + nobram = false; + nodffe = false; + nodram = false; } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { string run_from, run_to; clear_flags(); @@ -96,12 +112,28 @@ struct SynthGowinPass : public ScriptPass retime = true; continue; } + if (args[argidx] == "-nobram") { + nobram = true; + continue; + } + if (args[argidx] == "-nodram") { + nodram = true; + continue; + } + if (args[argidx] == "-nodffe") { + nodffe = true; + continue; + } + if (args[argidx] == "-noflatten") { + flatten = false; + continue; + } break; } extra_args(args, argidx, design); if (!design->full_selection()) - log_cmd_error("This comannd only operates on fully selected designs!\n"); + log_cmd_error("This command only operates on fully selected designs!\n"); log_header(design, "Executing SYNTH_GOWIN pass.\n"); log_push(); @@ -111,7 +143,7 @@ struct SynthGowinPass : public ScriptPass log_pop(); } - virtual void script() YS_OVERRIDE + void script() YS_OVERRIDE { if (check_label("begin")) { @@ -119,7 +151,7 @@ struct SynthGowinPass : public ScriptPass run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str())); } - if (check_label("flatten")) + if (flatten && check_label("flatten", "(unless -noflatten)")) { run("proc"); run("flatten"); @@ -131,20 +163,43 @@ struct SynthGowinPass : public ScriptPass { run("synth -run coarse"); } + + if (!nobram && check_label("bram", "(skip if -nobram)")) + { + run("memory_bram -rules +/gowin/bram.txt"); + run("techmap -map +/gowin/brams_map.v -map +/gowin/cells_sim.v"); + } + + if (!nodram && check_label("dram", "(skip if -nodram)")) + { + run("memory_bram -rules +/gowin/dram.txt"); + run("techmap -map +/gowin/drams_map.v"); + run("determine_init"); + } if (check_label("fine")) { run("opt -fast -mux_undef -undriven -fine"); run("memory_map"); run("opt -undriven -fine"); - run("techmap"); - run("clean -purge"); - run("splitnets -ports"); - run("setundef -undriven -zero"); + run("techmap -map +/techmap.v -map +/gowin/arith_map.v"); + run("techmap -map +/techmap.v"); if (retime || help_mode) run("abc -dff", "(only if -retime)"); } + if (check_label("map_ffs")) + { + run("dffsr2dff"); + run("dff2dffs"); + run("opt_clean"); + if (!nodffe) + run("dff2dffe -direct-match $_DFF_* -direct-match $__DFFS_*"); + run("techmap -map +/gowin/cells_map.v"); + run("opt_expr -mux_undef"); + run("simplemap"); + } + if (check_label("map_luts")) { run("abc -lut 4"); @@ -155,8 +210,10 @@ struct SynthGowinPass : public ScriptPass { run("techmap -map +/gowin/cells_map.v"); run("hilomap -hicell VCC V -locell GND G"); - run("iopadmap -inpad IBUF O:I -outpad OBUF I:O"); - run("clean -purge"); + run("iopadmap -bits -inpad IBUF O:I -outpad OBUF I:O", "(unless -noiopads)"); + run("dffinit -ff DFF Q INIT"); + run("clean"); + } if (check_label("check")) diff --git a/techlibs/greenpak4/cells_map.v b/techlibs/greenpak4/cells_map.v index b971a51fa..51c85183d 100644 --- a/techlibs/greenpak4/cells_map.v +++ b/techlibs/greenpak4/cells_map.v @@ -112,14 +112,14 @@ module GP_OBUFT(input IN, input OE, output OUT); endmodule module \$lut (A, Y); - parameter WIDTH = 0; - parameter LUT = 0; + parameter WIDTH = 0; + parameter LUT = 0; - input [WIDTH-1:0] A; - output Y; + input [WIDTH-1:0] A; + output Y; - generate - if (WIDTH == 1) begin + generate + if (WIDTH == 1) begin if(LUT == 2'b01) begin GP_INV _TECHMAP_REPLACE_ (.OUT(Y), .IN(A[0]) ); end @@ -127,22 +127,22 @@ module \$lut (A, Y); GP_2LUT #(.INIT({2'b00, LUT})) _TECHMAP_REPLACE_ (.OUT(Y), .IN0(A[0]), .IN1(1'b0)); end - end else - if (WIDTH == 2) begin - GP_2LUT #(.INIT(LUT)) _TECHMAP_REPLACE_ (.OUT(Y), - .IN0(A[0]), .IN1(A[1])); - end else - if (WIDTH == 3) begin - GP_3LUT #(.INIT(LUT)) _TECHMAP_REPLACE_ (.OUT(Y), - .IN0(A[0]), .IN1(A[1]), .IN2(A[2])); - end else - if (WIDTH == 4) begin - GP_4LUT #(.INIT(LUT)) _TECHMAP_REPLACE_ (.OUT(Y), - .IN0(A[0]), .IN1(A[1]), .IN2(A[2]), .IN3(A[3])); - end else begin - wire _TECHMAP_FAIL_ = 1; - end - endgenerate + end else + if (WIDTH == 2) begin + GP_2LUT #(.INIT(LUT)) _TECHMAP_REPLACE_ (.OUT(Y), + .IN0(A[0]), .IN1(A[1])); + end else + if (WIDTH == 3) begin + GP_3LUT #(.INIT(LUT)) _TECHMAP_REPLACE_ (.OUT(Y), + .IN0(A[0]), .IN1(A[1]), .IN2(A[2])); + end else + if (WIDTH == 4) begin + GP_4LUT #(.INIT(LUT)) _TECHMAP_REPLACE_ (.OUT(Y), + .IN0(A[0]), .IN1(A[1]), .IN2(A[2]), .IN3(A[3])); + end else begin + wire _TECHMAP_FAIL_ = 1; + end + endgenerate endmodule module \$__COUNT_ (CE, CLK, OUT, POUT, RST, UP); diff --git a/techlibs/greenpak4/greenpak4_dffinv.cc b/techlibs/greenpak4/greenpak4_dffinv.cc index 7d9d7d5b0..d57e978a0 100644 --- a/techlibs/greenpak4/greenpak4_dffinv.cc +++ b/techlibs/greenpak4/greenpak4_dffinv.cc @@ -91,7 +91,7 @@ void invert_gp_dff(Cell *cell, bool invert_input) struct Greenpak4DffInvPass : public Pass { Greenpak4DffInvPass() : Pass("greenpak4_dffinv", "merge greenpak4 inverters and DFF/latches") { } - virtual void help() + void help() YS_OVERRIDE { log("\n"); log(" greenpak4_dffinv [options] [selection]\n"); @@ -99,7 +99,7 @@ struct Greenpak4DffInvPass : public Pass { log("Merge GP_INV cells with GP_DFF* and GP_DLATCH* cells.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing GREENPAK4_DFFINV pass (merge input/output inverters into FF/latch cells).\n"); diff --git a/techlibs/greenpak4/synth_greenpak4.cc b/techlibs/greenpak4/synth_greenpak4.cc index 5e0e9e5d5..eeb001b46 100644 --- a/techlibs/greenpak4/synth_greenpak4.cc +++ b/techlibs/greenpak4/synth_greenpak4.cc @@ -29,7 +29,7 @@ struct SynthGreenPAK4Pass : public ScriptPass { SynthGreenPAK4Pass() : ScriptPass("synth_greenpak4", "synthesis for GreenPAK4 FPGAs") { } - virtual void help() YS_OVERRIDE + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -70,7 +70,7 @@ struct SynthGreenPAK4Pass : public ScriptPass string top_opt, part, json_file; bool flatten, retime; - virtual void clear_flags() YS_OVERRIDE + void clear_flags() YS_OVERRIDE { top_opt = "-auto-top"; part = "SLG46621V"; @@ -79,7 +79,7 @@ struct SynthGreenPAK4Pass : public ScriptPass retime = false; } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { string run_from, run_to; clear_flags(); @@ -120,7 +120,7 @@ struct SynthGreenPAK4Pass : public ScriptPass extra_args(args, argidx, design); if (!design->full_selection()) - log_cmd_error("This comannd only operates on fully selected designs!\n"); + log_cmd_error("This command only operates on fully selected designs!\n"); if (part != "SLG46140V" && part != "SLG46620V" && part != "SLG46621V") log_cmd_error("Invalid part name: '%s'\n", part.c_str()); @@ -133,7 +133,7 @@ struct SynthGreenPAK4Pass : public ScriptPass log_pop(); } - virtual void script() YS_OVERRIDE + void script() YS_OVERRIDE { if (check_label("begin")) { diff --git a/techlibs/ice40/Makefile.inc b/techlibs/ice40/Makefile.inc index 14761c6c8..76a89b107 100644 --- a/techlibs/ice40/Makefile.inc +++ b/techlibs/ice40/Makefile.inc @@ -1,5 +1,6 @@ OBJS += techlibs/ice40/synth_ice40.o +OBJS += techlibs/ice40/ice40_braminit.o OBJS += techlibs/ice40/ice40_ffssr.o OBJS += techlibs/ice40/ice40_ffinit.o OBJS += techlibs/ice40/ice40_opt.o @@ -26,6 +27,12 @@ $(eval $(call add_share_file,share/ice40,techlibs/ice40/cells_sim.v)) $(eval $(call add_share_file,share/ice40,techlibs/ice40/latches_map.v)) $(eval $(call add_share_file,share/ice40,techlibs/ice40/brams.txt)) $(eval $(call add_share_file,share/ice40,techlibs/ice40/brams_map.v)) +$(eval $(call add_share_file,share/ice40,techlibs/ice40/abc_hx.box)) +$(eval $(call add_share_file,share/ice40,techlibs/ice40/abc_hx.lut)) +$(eval $(call add_share_file,share/ice40,techlibs/ice40/abc_lp.box)) +$(eval $(call add_share_file,share/ice40,techlibs/ice40/abc_lp.lut)) +$(eval $(call add_share_file,share/ice40,techlibs/ice40/abc_u.box)) +$(eval $(call add_share_file,share/ice40,techlibs/ice40/abc_u.lut)) $(eval $(call add_gen_share_file,share/ice40,techlibs/ice40/brams_init1.vh)) $(eval $(call add_gen_share_file,share/ice40,techlibs/ice40/brams_init2.vh)) diff --git a/techlibs/ice40/abc_hx.box b/techlibs/ice40/abc_hx.box new file mode 100644 index 000000000..3ea70bc91 --- /dev/null +++ b/techlibs/ice40/abc_hx.box @@ -0,0 +1,13 @@ +# From https://github.com/cliffordwolf/icestorm/blob/be0bca0/icefuzz/timings_hx8k.txt + +# NB: Inputs/Outputs must be ordered alphabetically +# (with exceptions for carry in/out) + +# Inputs: A B I0 I3 CI +# Outputs: O CO +# (NB: carry chain input/output must be last +# input/output and have been moved there +# overriding the alphabetical ordering) +$__ICE40_CARRY_WRAPPER 1 1 5 2 +400 379 449 316 316 +259 231 - - 126 diff --git a/techlibs/ice40/abc_hx.lut b/techlibs/ice40/abc_hx.lut new file mode 100644 index 000000000..3b3bb11e2 --- /dev/null +++ b/techlibs/ice40/abc_hx.lut @@ -0,0 +1,6 @@ +# From https://github.com/cliffordwolf/icestorm/blob/be0bca0/icefuzz/timings_hx8k.txt +# I3 I2 I1 I0 +1 1 316 +2 1 316 379 +3 1 316 379 400 +4 1 316 379 400 449 diff --git a/techlibs/ice40/abc_lp.box b/techlibs/ice40/abc_lp.box new file mode 100644 index 000000000..473e92fe9 --- /dev/null +++ b/techlibs/ice40/abc_lp.box @@ -0,0 +1,13 @@ +# From https://github.com/cliffordwolf/icestorm/blob/be0bca0/icefuzz/timings_lp8k.txt + +# NB: Inputs/Outputs must be ordered alphabetically +# (with exceptions for carry in/out) + +# Inputs: A B I0 I3 CI +# Outputs: O CO +# (NB: carry chain input/output must be last +# input/output and have been moved there +# overriding the alphabetical ordering) +$__ICE40_CARRY_WRAPPER 1 1 5 2 +589 558 661 465 465 +675 609 - - 186 diff --git a/techlibs/ice40/abc_lp.lut b/techlibs/ice40/abc_lp.lut new file mode 100644 index 000000000..e72f760a2 --- /dev/null +++ b/techlibs/ice40/abc_lp.lut @@ -0,0 +1,6 @@ +# From https://github.com/cliffordwolf/icestorm/blob/be0bca0/icefuzz/timings_lp8k.txt +# I3 I2 I1 I0 +1 1 465 +2 1 465 558 +3 1 465 558 589 +4 1 465 558 589 661 diff --git a/techlibs/ice40/abc_u.box b/techlibs/ice40/abc_u.box new file mode 100644 index 000000000..f00e247b8 --- /dev/null +++ b/techlibs/ice40/abc_u.box @@ -0,0 +1,13 @@ +# From https://github.com/cliffordwolf/icestorm/blob/be0bca0/icefuzz/timings_up5k.txt + +# NB: Inputs/Outputs must be ordered alphabetically +# (with exceptions for carry in/out) + +# Inputs: A B I0 I3 CI +# Outputs: O CO +# (NB: carry chain input/output must be last +# input/output and have been moved there +# overriding the alphabetical ordering) +$__ICE40_CARRY_WRAPPER 1 1 5 2 +1231 1205 1285 874 874 +675 609 - - 278 diff --git a/techlibs/ice40/abc_u.lut b/techlibs/ice40/abc_u.lut new file mode 100644 index 000000000..1e4fcadb6 --- /dev/null +++ b/techlibs/ice40/abc_u.lut @@ -0,0 +1,6 @@ +# From https://github.com/cliffordwolf/icestorm/blob/be0bca0/icefuzz/timings_up5k.txt +# I3 I2 I1 I0 +1 1 874 +2 1 874 1205 +3 1 874 1205 1231 +4 1 874 1205 1231 1285 diff --git a/techlibs/ice40/arith_map.v b/techlibs/ice40/arith_map.v index 4449fdc1b..26b24db9e 100644 --- a/techlibs/ice40/arith_map.v +++ b/techlibs/ice40/arith_map.v @@ -44,23 +44,19 @@ module _80_ice40_alu (A, B, CI, BI, X, Y, CO); genvar i; generate for (i = 0; i < Y_WIDTH; i = i + 1) begin:slice - SB_CARRY carry ( - .I0(AA[i]), - .I1(BB[i]), + \$__ICE40_CARRY_WRAPPER #( + // A[0]: 1010 1010 1010 1010 + // A[1]: 1100 1100 1100 1100 + // A[2]: 1111 0000 1111 0000 + // A[3]: 1111 1111 0000 0000 + .LUT(16'b 0110_1001_1001_0110) + ) fadd ( + .A(AA[i]), + .B(BB[i]), .CI(C[i]), - .CO(CO[i]) - ); - SB_LUT4 #( - // I0: 1010 1010 1010 1010 - // I1: 1100 1100 1100 1100 - // I2: 1111 0000 1111 0000 - // I3: 1111 1111 0000 0000 - .LUT_INIT(16'b 0110_1001_1001_0110) - ) adder ( .I0(1'b0), - .I1(AA[i]), - .I2(BB[i]), .I3(C[i]), + .CO(CO[i]), .O(Y[i]) ); end endgenerate diff --git a/techlibs/ice40/brams_map.v b/techlibs/ice40/brams_map.v index 19a61d73b..ad3bccd21 100644 --- a/techlibs/ice40/brams_map.v +++ b/techlibs/ice40/brams_map.v @@ -7,8 +7,8 @@ module \$__ICE40_RAM4K ( input [10:0] WADDR, input [15:0] MASK, WDATA ); - parameter integer READ_MODE = 0; - parameter integer WRITE_MODE = 0; + parameter [1:0] READ_MODE = 0; + parameter [1:0] WRITE_MODE = 0; parameter [0:0] NEGCLK_R = 0; parameter [0:0] NEGCLK_W = 0; diff --git a/techlibs/ice40/cells_map.v b/techlibs/ice40/cells_map.v index d0ddfd02e..662423f0a 100644 --- a/techlibs/ice40/cells_map.v +++ b/techlibs/ice40/cells_map.v @@ -37,23 +37,46 @@ module \$lut (A, Y); generate if (WIDTH == 1) begin - SB_LUT4 #(.LUT_INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), - .I0(A[0]), .I1(1'b0), .I2(1'b0), .I3(1'b0)); + localparam [15:0] INIT = {{8{LUT[1]}}, {8{LUT[0]}}}; + SB_LUT4 #(.LUT_INIT(INIT)) _TECHMAP_REPLACE_ (.O(Y), + .I0(1'b0), .I1(1'b0), .I2(1'b0), .I3(A[0])); end else if (WIDTH == 2) begin - SB_LUT4 #(.LUT_INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), - .I0(A[0]), .I1(A[1]), .I2(1'b0), .I3(1'b0)); + localparam [15:0] INIT = {{4{LUT[3]}}, {4{LUT[1]}}, {4{LUT[2]}}, {4{LUT[0]}}}; + SB_LUT4 #(.LUT_INIT(INIT)) _TECHMAP_REPLACE_ (.O(Y), + .I0(1'b0), .I1(1'b0), .I2(A[1]), .I3(A[0])); end else if (WIDTH == 3) begin - SB_LUT4 #(.LUT_INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), - .I0(A[0]), .I1(A[1]), .I2(A[2]), .I3(1'b0)); + localparam [15:0] INIT = {{2{LUT[7]}}, {2{LUT[3]}}, {2{LUT[5]}}, {2{LUT[1]}}, {2{LUT[6]}}, {2{LUT[2]}}, {2{LUT[4]}}, {2{LUT[0]}}}; + SB_LUT4 #(.LUT_INIT(INIT)) _TECHMAP_REPLACE_ (.O(Y), + .I0(1'b0), .I1(A[2]), .I2(A[1]), .I3(A[0])); end else if (WIDTH == 4) begin - SB_LUT4 #(.LUT_INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), - .I0(A[0]), .I1(A[1]), .I2(A[2]), .I3(A[3])); + localparam [15:0] INIT = {LUT[15], LUT[7], LUT[11], LUT[3], LUT[13], LUT[5], LUT[9], LUT[1], LUT[14], LUT[6], LUT[10], LUT[2], LUT[12], LUT[4], LUT[8], LUT[0]}; + SB_LUT4 #(.LUT_INIT(INIT)) _TECHMAP_REPLACE_ (.O(Y), + .I0(A[3]), .I1(A[2]), .I2(A[1]), .I3(A[0])); end else begin wire _TECHMAP_FAIL_ = 1; end endgenerate endmodule `endif + +`ifndef NO_ADDER +module \$__ICE40_CARRY_WRAPPER (output CO, O, input A, B, CI, I0, I3); + parameter LUT = 0; + SB_CARRY carry ( + .I0(A), + .I1(B), + .CI(CI), + .CO(CO) + ); + \$lut #( + .WIDTH(4), + .LUT(LUT) + ) lut ( + .A({I0,A,B,I3}), + .Y(O) + ); +endmodule +`endif diff --git a/techlibs/ice40/cells_sim.v b/techlibs/ice40/cells_sim.v index 45a02111f..8e5e0358e 100644 --- a/techlibs/ice40/cells_sim.v +++ b/techlibs/ice40/cells_sim.v @@ -2,6 +2,10 @@ `define SB_DFF_REG reg Q = 0 // `define SB_DFF_REG reg Q +`define ABC_ARRIVAL_HX(TIME) `ifdef ICE40_HX (* abc_arrival=TIME *) `endif +`define ABC_ARRIVAL_LP(TIME) `ifdef ICE40_LP (* abc_arrival=TIME *) `endif +`define ABC_ARRIVAL_U(TIME) `ifdef ICE40_U (* abc_arrival=TIME *) `endif + // SiliconBlue IO Cells module SB_IO ( @@ -27,18 +31,27 @@ module SB_IO ( reg dout_q_0, dout_q_1; reg outena_q; + // IO tile generates a constant 1'b1 internally if global_cen is not connected + wire clken_pulled = CLOCK_ENABLE || CLOCK_ENABLE === 1'bz; + reg clken_pulled_ri; + reg clken_pulled_ro; + generate if (!NEG_TRIGGER) begin - always @(posedge INPUT_CLK) if (CLOCK_ENABLE) din_q_0 <= PACKAGE_PIN; - always @(negedge INPUT_CLK) if (CLOCK_ENABLE) din_q_1 <= PACKAGE_PIN; - always @(posedge OUTPUT_CLK) if (CLOCK_ENABLE) dout_q_0 <= D_OUT_0; - always @(negedge OUTPUT_CLK) if (CLOCK_ENABLE) dout_q_1 <= D_OUT_1; - always @(posedge OUTPUT_CLK) if (CLOCK_ENABLE) outena_q <= OUTPUT_ENABLE; + always @(posedge INPUT_CLK) clken_pulled_ri <= clken_pulled; + always @(posedge INPUT_CLK) if (clken_pulled) din_q_0 <= PACKAGE_PIN; + always @(negedge INPUT_CLK) if (clken_pulled_ri) din_q_1 <= PACKAGE_PIN; + always @(posedge OUTPUT_CLK) clken_pulled_ro <= clken_pulled; + always @(posedge OUTPUT_CLK) if (clken_pulled) dout_q_0 <= D_OUT_0; + always @(negedge OUTPUT_CLK) if (clken_pulled_ro) dout_q_1 <= D_OUT_1; + always @(posedge OUTPUT_CLK) if (clken_pulled) outena_q <= OUTPUT_ENABLE; end else begin - always @(negedge INPUT_CLK) if (CLOCK_ENABLE) din_q_0 <= PACKAGE_PIN; - always @(posedge INPUT_CLK) if (CLOCK_ENABLE) din_q_1 <= PACKAGE_PIN; - always @(negedge OUTPUT_CLK) if (CLOCK_ENABLE) dout_q_0 <= D_OUT_0; - always @(posedge OUTPUT_CLK) if (CLOCK_ENABLE) dout_q_1 <= D_OUT_1; - always @(negedge OUTPUT_CLK) if (CLOCK_ENABLE) outena_q <= OUTPUT_ENABLE; + always @(negedge INPUT_CLK) clken_pulled_ri <= clken_pulled; + always @(negedge INPUT_CLK) if (clken_pulled) din_q_0 <= PACKAGE_PIN; + always @(posedge INPUT_CLK) if (clken_pulled_ri) din_q_1 <= PACKAGE_PIN; + always @(negedge OUTPUT_CLK) clken_pulled_ro <= clken_pulled; + always @(negedge OUTPUT_CLK) if (clken_pulled) dout_q_0 <= D_OUT_0; + always @(posedge OUTPUT_CLK) if (clken_pulled_ro) dout_q_1 <= D_OUT_1; + always @(negedge OUTPUT_CLK) if (clken_pulled) outena_q <= OUTPUT_ENABLE; end endgenerate always @* begin @@ -118,6 +131,7 @@ endmodule // SiliconBlue Logic Cells +(* lib_whitebox *) module SB_LUT4 (output O, input I0, I1, I2, I3); parameter [15:0] LUT_INIT = 0; wire [7:0] s3 = I3 ? LUT_INIT[15:8] : LUT_INIT[7:0]; @@ -126,24 +140,75 @@ module SB_LUT4 (output O, input I0, I1, I2, I3); assign O = I0 ? s1[1] : s1[0]; endmodule +(* lib_whitebox *) module SB_CARRY (output CO, input I0, I1, CI); assign CO = (I0 && I1) || ((I0 || I1) && CI); endmodule +(* abc_box_id = 1, lib_whitebox *) +module \$__ICE40_CARRY_WRAPPER ( + (* abc_carry *) + output CO, + output O, + input A, B, + (* abc_carry *) + input CI, + input I0, I3 +); + parameter LUT = 0; + SB_CARRY carry ( + .I0(A), + .I1(B), + .CI(CI), + .CO(CO) + ); + SB_LUT4 #( + .LUT_INIT(LUT) + ) adder ( + .I0(I0), + .I1(A), + .I2(B), + .I3(I3), + .O(O) + ); +endmodule + +// Max delay from: https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L90 +// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L90 +// https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L102 + // Positive Edge SiliconBlue FF Cells -module SB_DFF (output `SB_DFF_REG, input C, D); +module SB_DFF ( + `ABC_ARRIVAL_HX(540) + `ABC_ARRIVAL_LP(796) + `ABC_ARRIVAL_U(1391) + output `SB_DFF_REG, + input C, D +); always @(posedge C) Q <= D; endmodule -module SB_DFFE (output `SB_DFF_REG, input C, E, D); +module SB_DFFE ( + `ABC_ARRIVAL_HX(540) + `ABC_ARRIVAL_LP(796) + `ABC_ARRIVAL_U(1391) + output `SB_DFF_REG, + input C, E, D +); always @(posedge C) if (E) Q <= D; endmodule -module SB_DFFSR (output `SB_DFF_REG, input C, R, D); +module SB_DFFSR ( + `ABC_ARRIVAL_HX(540) + `ABC_ARRIVAL_LP(796) + `ABC_ARRIVAL_U(1391) + output `SB_DFF_REG, + input C, R, D +); always @(posedge C) if (R) Q <= 0; @@ -151,7 +216,13 @@ module SB_DFFSR (output `SB_DFF_REG, input C, R, D); Q <= D; endmodule -module SB_DFFR (output `SB_DFF_REG, input C, R, D); +module SB_DFFR ( + `ABC_ARRIVAL_HX(540) + `ABC_ARRIVAL_LP(796) + `ABC_ARRIVAL_U(1391) + output `SB_DFF_REG, + input C, R, D +); always @(posedge C, posedge R) if (R) Q <= 0; @@ -159,7 +230,13 @@ module SB_DFFR (output `SB_DFF_REG, input C, R, D); Q <= D; endmodule -module SB_DFFSS (output `SB_DFF_REG, input C, S, D); +module SB_DFFSS ( + `ABC_ARRIVAL_HX(540) + `ABC_ARRIVAL_LP(796) + `ABC_ARRIVAL_U(1391) + output `SB_DFF_REG, + input C, S, D +); always @(posedge C) if (S) Q <= 1; @@ -167,7 +244,13 @@ module SB_DFFSS (output `SB_DFF_REG, input C, S, D); Q <= D; endmodule -module SB_DFFS (output `SB_DFF_REG, input C, S, D); +module SB_DFFS ( + `ABC_ARRIVAL_HX(540) + `ABC_ARRIVAL_LP(796) + `ABC_ARRIVAL_U(1391) + output `SB_DFF_REG, + input C, S, D +); always @(posedge C, posedge S) if (S) Q <= 1; @@ -175,7 +258,13 @@ module SB_DFFS (output `SB_DFF_REG, input C, S, D); Q <= D; endmodule -module SB_DFFESR (output `SB_DFF_REG, input C, E, R, D); +module SB_DFFESR ( + `ABC_ARRIVAL_HX(540) + `ABC_ARRIVAL_LP(796) + `ABC_ARRIVAL_U(1391) + output `SB_DFF_REG, + input C, E, R, D +); always @(posedge C) if (E) begin if (R) @@ -185,7 +274,13 @@ module SB_DFFESR (output `SB_DFF_REG, input C, E, R, D); end endmodule -module SB_DFFER (output `SB_DFF_REG, input C, E, R, D); +module SB_DFFER ( + `ABC_ARRIVAL_HX(540) + `ABC_ARRIVAL_LP(796) + `ABC_ARRIVAL_U(1391) + output `SB_DFF_REG, + input C, E, R, D +); always @(posedge C, posedge R) if (R) Q <= 0; @@ -193,7 +288,13 @@ module SB_DFFER (output `SB_DFF_REG, input C, E, R, D); Q <= D; endmodule -module SB_DFFESS (output `SB_DFF_REG, input C, E, S, D); +module SB_DFFESS ( + `ABC_ARRIVAL_HX(540) + `ABC_ARRIVAL_LP(796) + `ABC_ARRIVAL_U(1391) + output `SB_DFF_REG, + input C, E, S, D +); always @(posedge C) if (E) begin if (S) @@ -203,7 +304,13 @@ module SB_DFFESS (output `SB_DFF_REG, input C, E, S, D); end endmodule -module SB_DFFES (output `SB_DFF_REG, input C, E, S, D); +module SB_DFFES ( + `ABC_ARRIVAL_HX(540) + `ABC_ARRIVAL_LP(796) + `ABC_ARRIVAL_U(1391) + output `SB_DFF_REG, + input C, E, S, D +); always @(posedge C, posedge S) if (S) Q <= 1; @@ -213,18 +320,36 @@ endmodule // Negative Edge SiliconBlue FF Cells -module SB_DFFN (output `SB_DFF_REG, input C, D); +module SB_DFFN ( + `ABC_ARRIVAL_HX(540) + `ABC_ARRIVAL_LP(796) + `ABC_ARRIVAL_U(1391) + output `SB_DFF_REG, + input C, D +); always @(negedge C) Q <= D; endmodule -module SB_DFFNE (output `SB_DFF_REG, input C, E, D); +module SB_DFFNE ( + `ABC_ARRIVAL_HX(540) + `ABC_ARRIVAL_LP(796) + `ABC_ARRIVAL_U(1391) + output `SB_DFF_REG, + input C, E, D +); always @(negedge C) if (E) Q <= D; endmodule -module SB_DFFNSR (output `SB_DFF_REG, input C, R, D); +module SB_DFFNSR ( + `ABC_ARRIVAL_HX(540) + `ABC_ARRIVAL_LP(796) + `ABC_ARRIVAL_U(1391) + output `SB_DFF_REG, + input C, R, D +); always @(negedge C) if (R) Q <= 0; @@ -232,7 +357,13 @@ module SB_DFFNSR (output `SB_DFF_REG, input C, R, D); Q <= D; endmodule -module SB_DFFNR (output `SB_DFF_REG, input C, R, D); +module SB_DFFNR ( + `ABC_ARRIVAL_HX(540) + `ABC_ARRIVAL_LP(796) + `ABC_ARRIVAL_U(1391) + output `SB_DFF_REG, + input C, R, D +); always @(negedge C, posedge R) if (R) Q <= 0; @@ -240,7 +371,13 @@ module SB_DFFNR (output `SB_DFF_REG, input C, R, D); Q <= D; endmodule -module SB_DFFNSS (output `SB_DFF_REG, input C, S, D); +module SB_DFFNSS ( + `ABC_ARRIVAL_HX(540) + `ABC_ARRIVAL_LP(796) + `ABC_ARRIVAL_U(1391) + output `SB_DFF_REG, + input C, S, D +); always @(negedge C) if (S) Q <= 1; @@ -248,7 +385,13 @@ module SB_DFFNSS (output `SB_DFF_REG, input C, S, D); Q <= D; endmodule -module SB_DFFNS (output `SB_DFF_REG, input C, S, D); +module SB_DFFNS ( + `ABC_ARRIVAL_HX(540) + `ABC_ARRIVAL_LP(796) + `ABC_ARRIVAL_U(1391) + output `SB_DFF_REG, + input C, S, D +); always @(negedge C, posedge S) if (S) Q <= 1; @@ -256,7 +399,13 @@ module SB_DFFNS (output `SB_DFF_REG, input C, S, D); Q <= D; endmodule -module SB_DFFNESR (output `SB_DFF_REG, input C, E, R, D); +module SB_DFFNESR ( + `ABC_ARRIVAL_HX(540) + `ABC_ARRIVAL_LP(796) + `ABC_ARRIVAL_U(1391) + output `SB_DFF_REG, + input C, E, R, D +); always @(negedge C) if (E) begin if (R) @@ -266,7 +415,13 @@ module SB_DFFNESR (output `SB_DFF_REG, input C, E, R, D); end endmodule -module SB_DFFNER (output `SB_DFF_REG, input C, E, R, D); +module SB_DFFNER ( + `ABC_ARRIVAL_HX(540) + `ABC_ARRIVAL_LP(796) + `ABC_ARRIVAL_U(1391) + output `SB_DFF_REG, + input C, E, R, D +); always @(negedge C, posedge R) if (R) Q <= 0; @@ -274,7 +429,13 @@ module SB_DFFNER (output `SB_DFF_REG, input C, E, R, D); Q <= D; endmodule -module SB_DFFNESS (output `SB_DFF_REG, input C, E, S, D); +module SB_DFFNESS ( + `ABC_ARRIVAL_HX(540) + `ABC_ARRIVAL_LP(796) + `ABC_ARRIVAL_U(1391) + output `SB_DFF_REG, + input C, E, S, D +); always @(negedge C) if (E) begin if (S) @@ -284,7 +445,13 @@ module SB_DFFNESS (output `SB_DFF_REG, input C, E, S, D); end endmodule -module SB_DFFNES (output `SB_DFF_REG, input C, E, S, D); +module SB_DFFNES ( + `ABC_ARRIVAL_HX(540) + `ABC_ARRIVAL_LP(796) + `ABC_ARRIVAL_U(1391) + output `SB_DFF_REG, + input C, E, S, D +); always @(negedge C, posedge S) if (S) Q <= 1; @@ -295,6 +462,9 @@ endmodule // SiliconBlue RAM Cells module SB_RAM40_4K ( + `ABC_ARRIVAL_HX(2146) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L401 + `ABC_ARRIVAL_LP(3163) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L401 + `ABC_ARRIVAL_U(1179) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L13026 output [15:0] RDATA, input RCLK, RCLKE, RE, input [10:0] RADDR, @@ -326,6 +496,8 @@ module SB_RAM40_4K ( parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000; parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_FILE = ""; + `ifndef BLACKBOX wire [15:0] WMASK_I; wire [15:0] RMASK_I; @@ -408,24 +580,27 @@ module SB_RAM40_4K ( reg [15:0] memory [0:255]; initial begin - for (i=0; i<16; i=i+1) begin - memory[ 0*16 + i] <= INIT_0[16*i +: 16]; - memory[ 1*16 + i] <= INIT_1[16*i +: 16]; - memory[ 2*16 + i] <= INIT_2[16*i +: 16]; - memory[ 3*16 + i] <= INIT_3[16*i +: 16]; - memory[ 4*16 + i] <= INIT_4[16*i +: 16]; - memory[ 5*16 + i] <= INIT_5[16*i +: 16]; - memory[ 6*16 + i] <= INIT_6[16*i +: 16]; - memory[ 7*16 + i] <= INIT_7[16*i +: 16]; - memory[ 8*16 + i] <= INIT_8[16*i +: 16]; - memory[ 9*16 + i] <= INIT_9[16*i +: 16]; - memory[10*16 + i] <= INIT_A[16*i +: 16]; - memory[11*16 + i] <= INIT_B[16*i +: 16]; - memory[12*16 + i] <= INIT_C[16*i +: 16]; - memory[13*16 + i] <= INIT_D[16*i +: 16]; - memory[14*16 + i] <= INIT_E[16*i +: 16]; - memory[15*16 + i] <= INIT_F[16*i +: 16]; - end + if (INIT_FILE != "") + $readmemh(INIT_FILE, memory); + else + for (i=0; i<16; i=i+1) begin + memory[ 0*16 + i] = INIT_0[16*i +: 16]; + memory[ 1*16 + i] = INIT_1[16*i +: 16]; + memory[ 2*16 + i] = INIT_2[16*i +: 16]; + memory[ 3*16 + i] = INIT_3[16*i +: 16]; + memory[ 4*16 + i] = INIT_4[16*i +: 16]; + memory[ 5*16 + i] = INIT_5[16*i +: 16]; + memory[ 6*16 + i] = INIT_6[16*i +: 16]; + memory[ 7*16 + i] = INIT_7[16*i +: 16]; + memory[ 8*16 + i] = INIT_8[16*i +: 16]; + memory[ 9*16 + i] = INIT_9[16*i +: 16]; + memory[10*16 + i] = INIT_A[16*i +: 16]; + memory[11*16 + i] = INIT_B[16*i +: 16]; + memory[12*16 + i] = INIT_C[16*i +: 16]; + memory[13*16 + i] = INIT_D[16*i +: 16]; + memory[14*16 + i] = INIT_E[16*i +: 16]; + memory[15*16 + i] = INIT_F[16*i +: 16]; + end end always @(posedge WCLK) begin @@ -458,6 +633,9 @@ module SB_RAM40_4K ( endmodule module SB_RAM40_4KNR ( + `ABC_ARRIVAL_HX(2146) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L401 + `ABC_ARRIVAL_LP(3163) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L401 + `ABC_ARRIVAL_U(1179) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L13026 output [15:0] RDATA, input RCLKN, RCLKE, RE, input [10:0] RADDR, @@ -485,6 +663,8 @@ module SB_RAM40_4KNR ( parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000; parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_FILE = ""; + SB_RAM40_4K #( .WRITE_MODE(WRITE_MODE), .READ_MODE (READ_MODE ), @@ -503,7 +683,8 @@ module SB_RAM40_4KNR ( .INIT_C (INIT_C ), .INIT_D (INIT_D ), .INIT_E (INIT_E ), - .INIT_F (INIT_F ) + .INIT_F (INIT_F ), + .INIT_FILE (INIT_FILE ) ) RAM ( .RDATA(RDATA), .RCLK (~RCLKN), @@ -520,6 +701,9 @@ module SB_RAM40_4KNR ( endmodule module SB_RAM40_4KNW ( + `ABC_ARRIVAL_HX(2146) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L401 + `ABC_ARRIVAL_LP(3163) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L401 + `ABC_ARRIVAL_U(1179) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L13026 output [15:0] RDATA, input RCLK, RCLKE, RE, input [10:0] RADDR, @@ -547,6 +731,8 @@ module SB_RAM40_4KNW ( parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000; parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_FILE = ""; + SB_RAM40_4K #( .WRITE_MODE(WRITE_MODE), .READ_MODE (READ_MODE ), @@ -565,7 +751,8 @@ module SB_RAM40_4KNW ( .INIT_C (INIT_C ), .INIT_D (INIT_D ), .INIT_E (INIT_E ), - .INIT_F (INIT_F ) + .INIT_F (INIT_F ), + .INIT_FILE (INIT_FILE ) ) RAM ( .RDATA(RDATA), .RCLK (RCLK ), @@ -582,6 +769,9 @@ module SB_RAM40_4KNW ( endmodule module SB_RAM40_4KNRNW ( + `ABC_ARRIVAL_HX(2146) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_hx1k.txt#L401 + `ABC_ARRIVAL_LP(3163) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_lp1k.txt#L401 + `ABC_ARRIVAL_U(1179) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L13026 output [15:0] RDATA, input RCLKN, RCLKE, RE, input [10:0] RADDR, @@ -609,6 +799,8 @@ module SB_RAM40_4KNRNW ( parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000; parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_FILE = ""; + SB_RAM40_4K #( .WRITE_MODE(WRITE_MODE), .READ_MODE (READ_MODE ), @@ -627,7 +819,8 @@ module SB_RAM40_4KNRNW ( .INIT_C (INIT_C ), .INIT_D (INIT_D ), .INIT_E (INIT_E ), - .INIT_F (INIT_F ) + .INIT_F (INIT_F ), + .INIT_FILE (INIT_FILE ) ) RAM ( .RDATA(RDATA), .RCLK (~RCLKN), @@ -647,7 +840,12 @@ endmodule module ICESTORM_LC ( input I0, I1, I2, I3, CIN, CLK, CEN, SR, - output LO, O, COUT + output LO, + `ABC_ARRIVAL_HX(540) + `ABC_ARRIVAL_LP(796) + `ABC_ARRIVAL_U(1391) + output O, + output COUT ); parameter [15:0] LUT_INIT = 0; @@ -657,7 +855,12 @@ module ICESTORM_LC ( parameter [0:0] SET_NORESET = 0; parameter [0:0] ASYNC_SR = 0; - assign COUT = CARRY_ENABLE ? (I1 && I2) || ((I1 || I2) && CIN) : 1'bx; + parameter [0:0] CIN_CONST = 0; + parameter [0:0] CIN_SET = 0; + + wire mux_cin = CIN_CONST ? CIN_SET : CIN; + + assign COUT = CARRY_ENABLE ? (I1 && I2) || ((I1 || I2) && mux_cin) : 1'bx; wire [7:0] lut_s3 = I3 ? LUT_INIT[15:8] : LUT_INIT[7:0]; wire [3:0] lut_s2 = I2 ? lut_s3[ 7:4] : lut_s3[3:0]; @@ -862,80 +1065,61 @@ module SB_WARMBOOT ( ); endmodule -// UltraPlus feature cells -(* blackbox *) -module SB_MAC16 ( - input CLK, - input CE, - input [15:0] C, - input [15:0] A, - input [15:0] B, - input [15:0] D, - input AHOLD, - input BHOLD, - input CHOLD, - input DHOLD, - input IRSTTOP, - input IRSTBOT, - input ORSTTOP, - input ORSTBOT, - input OLOADTOP, - input OLOADBOT, - input ADDSUBTOP, - input ADDSUBBOT, - input OHOLDTOP, - input OHOLDBOT, - input CI, - input ACCUMCI, - input SIGNEXTIN, - output [31:0] O, - output CO, - output ACCUMCO, - output SIGNEXTOUT -); -parameter NEG_TRIGGER = 1'b0; -parameter C_REG = 1'b0; -parameter A_REG = 1'b0; -parameter B_REG = 1'b0; -parameter D_REG = 1'b0; -parameter TOP_8x8_MULT_REG = 1'b0; -parameter BOT_8x8_MULT_REG = 1'b0; -parameter PIPELINE_16x16_MULT_REG1 = 1'b0; -parameter PIPELINE_16x16_MULT_REG2 = 1'b0; -parameter TOPOUTPUT_SELECT = 2'b00; -parameter TOPADDSUB_LOWERINPUT = 2'b00; -parameter TOPADDSUB_UPPERINPUT = 1'b0; -parameter TOPADDSUB_CARRYSELECT = 2'b00; -parameter BOTOUTPUT_SELECT = 2'b00; -parameter BOTADDSUB_LOWERINPUT = 2'b00; -parameter BOTADDSUB_UPPERINPUT = 1'b0; -parameter BOTADDSUB_CARRYSELECT = 2'b00; -parameter MODE_8x8 = 1'b0; -parameter A_SIGNED = 1'b0; -parameter B_SIGNED = 1'b0; -endmodule - -(* blackbox *) -module SB_SPRAM256KA( +module SB_SPRAM256KA ( input [13:0] ADDRESS, input [15:0] DATAIN, input [3:0] MASKWREN, - input WREN, - input CHIPSELECT, - input CLOCK, - input STANDBY, - input SLEEP, - input POWEROFF, - output [15:0] DATAOUT + input WREN, CHIPSELECT, CLOCK, STANDBY, SLEEP, POWEROFF, + output reg [15:0] DATAOUT ); +`ifndef BLACKBOX +`ifndef EQUIV + reg [15:0] mem [0:16383]; + wire off = SLEEP || !POWEROFF; + integer i; + + always @(negedge POWEROFF) begin + for (i = 0; i <= 16383; i = i+1) + mem[i] = 'bx; + end + + always @(posedge CLOCK, posedge off) begin + if (off) begin + DATAOUT <= 0; + end else + if (CHIPSELECT && !STANDBY && !WREN) begin + DATAOUT <= mem[ADDRESS]; + end else begin + if (CHIPSELECT && !STANDBY && WREN) begin + if (MASKWREN[0]) mem[ADDRESS][ 3: 0] = DATAIN[ 3: 0]; + if (MASKWREN[1]) mem[ADDRESS][ 7: 4] = DATAIN[ 7: 4]; + if (MASKWREN[2]) mem[ADDRESS][11: 8] = DATAIN[11: 8]; + if (MASKWREN[3]) mem[ADDRESS][15:12] = DATAIN[15:12]; + end + DATAOUT <= 'bx; + end + end +`endif +`endif endmodule (* blackbox *) module SB_HFOSC( + input TRIM0, + input TRIM1, + input TRIM2, + input TRIM3, + input TRIM4, + input TRIM5, + input TRIM6, + input TRIM7, + input TRIM8, + input TRIM9, input CLKHFPU, input CLKHFEN, output CLKHF ); +parameter TRIM_EN = "0b0"; parameter CLKHF_DIV = "0b00"; endmodule @@ -965,6 +1149,30 @@ 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, input SBRWI, @@ -1227,3 +1435,173 @@ module SB_IO_OD ( `endif endmodule +module SB_MAC16 ( + input CLK, CE, + input [15:0] C, A, B, D, + input AHOLD, BHOLD, CHOLD, DHOLD, + input IRSTTOP, IRSTBOT, + input ORSTTOP, ORSTBOT, + input OLOADTOP, OLOADBOT, + input ADDSUBTOP, ADDSUBBOT, + input OHOLDTOP, OHOLDBOT, + input CI, ACCUMCI, SIGNEXTIN, + //`ABC_ARRIVAL_U(1984) // https://github.com/cliffordwolf/icestorm/blob/95949315364f8d9b0c693386aefadf44b28e2cf6/icefuzz/timings_up5k.txt#L13026 + output [31:0] O, + output CO, ACCUMCO, SIGNEXTOUT +); + parameter [0:0] NEG_TRIGGER = 0; + parameter [0:0] C_REG = 0; + parameter [0:0] A_REG = 0; + parameter [0:0] B_REG = 0; + parameter [0:0] D_REG = 0; + parameter [0:0] TOP_8x8_MULT_REG = 0; + parameter [0:0] BOT_8x8_MULT_REG = 0; + parameter [0:0] PIPELINE_16x16_MULT_REG1 = 0; + parameter [0:0] PIPELINE_16x16_MULT_REG2 = 0; + parameter [1:0] TOPOUTPUT_SELECT = 0; + parameter [1:0] TOPADDSUB_LOWERINPUT = 0; + parameter [0:0] TOPADDSUB_UPPERINPUT = 0; + parameter [1:0] TOPADDSUB_CARRYSELECT = 0; + parameter [1:0] BOTOUTPUT_SELECT = 0; + parameter [1:0] BOTADDSUB_LOWERINPUT = 0; + parameter [0:0] BOTADDSUB_UPPERINPUT = 0; + parameter [1:0] BOTADDSUB_CARRYSELECT = 0; + parameter [0:0] MODE_8x8 = 0; + parameter [0:0] A_SIGNED = 0; + parameter [0:0] B_SIGNED = 0; + + wire clock = CLK ^ NEG_TRIGGER; + + // internal wires, compare Figure on page 133 of ICE Technology Library 3.0 and Fig 2 on page 2 of Lattice TN1295-DSP + // http://www.latticesemi.com/~/media/LatticeSemi/Documents/TechnicalBriefs/SBTICETechnologyLibrary201608.pdf + // https://www.latticesemi.com/-/media/LatticeSemi/Documents/ApplicationNotes/AD/DSPFunctionUsageGuideforICE40Devices.ashx + wire [15:0] iA, iB, iC, iD; + wire [15:0] iF, iJ, iK, iG; + wire [31:0] iL, iH; + wire [15:0] iW, iX, iP, iQ; + wire [15:0] iY, iZ, iR, iS; + wire HCI, LCI, LCO; + + // Regs C and A + reg [15:0] rC, rA; + always @(posedge clock, posedge IRSTTOP) begin + if (IRSTTOP) begin + rC <= 0; + rA <= 0; + end else if (CE) begin + if (!CHOLD) rC <= C; + if (!AHOLD) rA <= A; + end + end + assign iC = C_REG ? rC : C; + assign iA = A_REG ? rA : A; + + // Regs B and D + reg [15:0] rB, rD; + always @(posedge clock, posedge IRSTBOT) begin + if (IRSTBOT) begin + rB <= 0; + rD <= 0; + end else if (CE) begin + if (!BHOLD) rB <= B; + if (!DHOLD) rD <= D; + end + end + assign iB = B_REG ? rB : B; + assign iD = D_REG ? rD : D; + + // Multiplier Stage + wire [15:0] p_Ah_Bh, p_Al_Bh, p_Ah_Bl, p_Al_Bl; + wire [15:0] Ah, Al, Bh, Bl; + assign Ah = {A_SIGNED ? {8{iA[15]}} : 8'b0, iA[15: 8]}; + assign Al = {A_SIGNED && MODE_8x8 ? {8{iA[ 7]}} : 8'b0, iA[ 7: 0]}; + assign Bh = {B_SIGNED ? {8{iB[15]}} : 8'b0, iB[15: 8]}; + assign Bl = {B_SIGNED && MODE_8x8 ? {8{iB[ 7]}} : 8'b0, iB[ 7: 0]}; + assign p_Ah_Bh = Ah * Bh; // F + assign p_Al_Bh = {8'b0, Al[7:0]} * Bh; // J + assign p_Ah_Bl = Ah * {8'b0, Bl[7:0]}; // K + assign p_Al_Bl = Al * Bl; // G + + // Regs F and J + reg [15:0] rF, rJ; + always @(posedge clock, posedge IRSTTOP) begin + if (IRSTTOP) begin + rF <= 0; + rJ <= 0; + end else if (CE) begin + rF <= p_Ah_Bh; + if (!MODE_8x8) rJ <= p_Al_Bh; + end + end + assign iF = TOP_8x8_MULT_REG ? rF : p_Ah_Bh; + assign iJ = PIPELINE_16x16_MULT_REG1 ? rJ : p_Al_Bh; + + // Regs K and G + reg [15:0] rK, rG; + always @(posedge clock, posedge IRSTBOT) begin + if (IRSTBOT) begin + rK <= 0; + rG <= 0; + end else if (CE) begin + if (!MODE_8x8) rK <= p_Ah_Bl; + rG <= p_Al_Bl; + end + end + assign iK = PIPELINE_16x16_MULT_REG1 ? rK : p_Ah_Bl; + assign iG = BOT_8x8_MULT_REG ? rG : p_Al_Bl; + + // Adder Stage + wire [23:0] iK_e = {A_SIGNED ? {8{iK[15]}} : 8'b0, iK}; + wire [23:0] iJ_e = {B_SIGNED ? {8{iJ[15]}} : 8'b0, iJ}; + assign iL = iG + (iK_e << 8) + (iJ_e << 8) + (iF << 16); + + // Reg H + reg [31:0] rH; + always @(posedge clock, posedge IRSTBOT) begin + if (IRSTBOT) begin + rH <= 0; + end else if (CE) begin + if (!MODE_8x8) rH <= iL; + end + end + assign iH = PIPELINE_16x16_MULT_REG2 ? rH : iL; + + // Hi Output Stage + wire [15:0] XW, Oh; + reg [15:0] rQ; + assign iW = TOPADDSUB_UPPERINPUT ? iC : iQ; + assign iX = (TOPADDSUB_LOWERINPUT == 0) ? iA : (TOPADDSUB_LOWERINPUT == 1) ? iF : (TOPADDSUB_LOWERINPUT == 2) ? iH[31:16] : {16{iZ[15]}}; + assign {ACCUMCO, XW} = iX + (iW ^ {16{ADDSUBTOP}}) + HCI; + assign CO = ACCUMCO ^ ADDSUBTOP; + assign iP = OLOADTOP ? iC : XW ^ {16{ADDSUBTOP}}; + always @(posedge clock, posedge ORSTTOP) begin + if (ORSTTOP) begin + rQ <= 0; + end else if (CE) begin + if (!OHOLDTOP) rQ <= iP; + end + end + assign iQ = rQ; + assign Oh = (TOPOUTPUT_SELECT == 0) ? iP : (TOPOUTPUT_SELECT == 1) ? iQ : (TOPOUTPUT_SELECT == 2) ? iF : iH[31:16]; + assign HCI = (TOPADDSUB_CARRYSELECT == 0) ? 1'b0 : (TOPADDSUB_CARRYSELECT == 1) ? 1'b1 : (TOPADDSUB_CARRYSELECT == 2) ? LCO : LCO ^ ADDSUBBOT; + assign SIGNEXTOUT = iX[15]; + + // Lo Output Stage + wire [15:0] YZ, Ol; + reg [15:0] rS; + assign iY = BOTADDSUB_UPPERINPUT ? iD : iS; + assign iZ = (BOTADDSUB_LOWERINPUT == 0) ? iB : (BOTADDSUB_LOWERINPUT == 1) ? iG : (BOTADDSUB_LOWERINPUT == 2) ? iH[15:0] : {16{SIGNEXTIN}}; + assign {LCO, YZ} = iZ + (iY ^ {16{ADDSUBBOT}}) + LCI; + assign iR = OLOADBOT ? iD : YZ ^ {16{ADDSUBBOT}}; + always @(posedge clock, posedge ORSTBOT) begin + if (ORSTBOT) begin + rS <= 0; + end else if (CE) begin + if (!OHOLDBOT) rS <= iR; + end + end + assign iS = rS; + assign Ol = (BOTOUTPUT_SELECT == 0) ? iR : (BOTOUTPUT_SELECT == 1) ? iS : (BOTOUTPUT_SELECT == 2) ? iG : iH[15:0]; + assign LCI = (BOTADDSUB_CARRYSELECT == 0) ? 1'b0 : (BOTADDSUB_CARRYSELECT == 1) ? 1'b1 : (BOTADDSUB_CARRYSELECT == 2) ? ACCUMCI : CI; + assign O = {Oh, Ol}; +endmodule diff --git a/techlibs/ice40/ice40_braminit.cc b/techlibs/ice40/ice40_braminit.cc new file mode 100644 index 000000000..1a139ffea --- /dev/null +++ b/techlibs/ice40/ice40_braminit.cc @@ -0,0 +1,159 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * + * 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" +#include <stdlib.h> +#include <stdio.h> +#include <bitset> + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +static void run_ice40_braminit(Module *module) +{ + for (auto cell : module->selected_cells()) + { + uint16_t mem[256]; + + /* Only consider cells we're interested in */ + if (cell->type != "\\SB_RAM40_4K" && + cell->type != "\\SB_RAM40_4KNR" && + cell->type != "\\SB_RAM40_4KNW" && + cell->type != "\\SB_RAM40_4KNRNW") + continue; + if (!cell->hasParam("\\INIT_FILE")) + continue; + std::string init_file = cell->getParam("\\INIT_FILE").decode_string(); + cell->unsetParam("\\INIT_FILE"); + if (init_file == "") + continue; + + /* Open file */ + log("Processing %s : %s\n", RTLIL::id2cstr(cell->name), init_file.c_str()); + + std::ifstream f; + f.open(init_file.c_str()); + if (f.fail()) { + log("Can not open file `%s`.\n", init_file.c_str()); + continue; + } + + /* Defaults to 0 */ + memset(mem, 0x00, sizeof(mem)); + + /* Process each line */ + bool in_comment = false; + int cursor = 0; + + while (!f.eof()) + { + std::string line, token; + std::getline(f, line); + + for (int i = 0; i < GetSize(line); i++) + { + if (in_comment && line.compare(i, 2, "*/") == 0) { + line[i] = ' '; + line[i+1] = ' '; + in_comment = false; + continue; + } + if (!in_comment && line.compare(i, 2, "/*") == 0) + in_comment = true; + if (in_comment) + line[i] = ' '; + } + + while (1) + { + bool set_cursor = false; + long value; + + token = next_token(line, " \t\r\n"); + if (token.empty() || token.compare(0, 2, "//") == 0) + break; + + if (token[0] == '@') { + token = token.substr(1); + set_cursor = true; + } + + const char *nptr = token.c_str(); + char *endptr; + value = strtol(nptr, &endptr, 16); + if (!*nptr || *endptr) { + log("Can not parse %s `%s` for %s.\n", + set_cursor ? "address" : "value", + nptr, token.c_str() + ); + continue; + } + + if (set_cursor) + cursor = value; + else if (cursor >= 0 && cursor < 256) + mem[cursor++] = value; + else + log("Attempt to initialize non existent address %d\n", cursor); + } + } + + /* Set attributes */ + const char *hex = "0123456789ABCDEF"; + for (int i=0; i<16; i++) { + std::string val = ""; + for (int j=15; j>=0; j--) + val += std::bitset<16>(mem[i*16+j]).to_string(); + cell->setParam("\\INIT_" + std::string(1, hex[i]), RTLIL::Const::from_string(val)); + } + } +} + +struct Ice40BRAMInitPass : public Pass { + Ice40BRAMInitPass() : Pass("ice40_braminit", "iCE40: perform SB_RAM40_4K initialization from file") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" ice40_braminit\n"); + log("\n"); + log("This command processes all SB_RAM40_4K blocks with a non-empty INIT_FILE\n"); + log("parameter and converts it into the required INIT_x attributes\n"); + log("\n"); + } + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + log_header(design, "Executing ICE40_BRAMINIT pass.\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + // if (args[argidx] == "-???") { + // continue; + // } + break; + } + extra_args(args, argidx, design); + + for (auto module : design->selected_modules()) + run_ice40_braminit(module); + } +} Ice40BRAMInitPass; + +PRIVATE_NAMESPACE_END diff --git a/techlibs/ice40/ice40_ffinit.cc b/techlibs/ice40/ice40_ffinit.cc index c914b20e8..3089d8932 100644 --- a/techlibs/ice40/ice40_ffinit.cc +++ b/techlibs/ice40/ice40_ffinit.cc @@ -25,7 +25,7 @@ PRIVATE_NAMESPACE_BEGIN struct Ice40FfinitPass : public Pass { Ice40FfinitPass() : Pass("ice40_ffinit", "iCE40: handle FF init values") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -35,7 +35,7 @@ struct Ice40FfinitPass : public Pass { log("nonzero init values.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing ICE40_FFINIT pass (implement FF init values).\n"); diff --git a/techlibs/ice40/ice40_ffssr.cc b/techlibs/ice40/ice40_ffssr.cc index 9afbc0fce..a7649d7a0 100644 --- a/techlibs/ice40/ice40_ffssr.cc +++ b/techlibs/ice40/ice40_ffssr.cc @@ -25,7 +25,7 @@ PRIVATE_NAMESPACE_BEGIN struct Ice40FfssrPass : public Pass { Ice40FfssrPass() : Pass("ice40_ffssr", "iCE40: merge synchronous set/reset into FF cells") { } - virtual void help() + void help() YS_OVERRIDE { log("\n"); log(" ice40_ffssr [options] [selection]\n"); @@ -33,7 +33,7 @@ struct Ice40FfssrPass : public Pass { log("Merge synchronous set/reset $_MUX_ cells into iCE40 FFs.\n"); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing ICE40_FFSSR pass (merge synchronous set/reset into FF cells).\n"); @@ -81,6 +81,9 @@ struct Ice40FfssrPass : public Pass { for (auto cell : ff_cells) { + if (cell->get_bool_attribute("\\dont_touch")) + continue; + SigSpec sig_d = cell->getPort("\\D"); if (GetSize(sig_d) < 1) diff --git a/techlibs/ice40/ice40_opt.cc b/techlibs/ice40/ice40_opt.cc index 7af60f297..ea56d3f4d 100644 --- a/techlibs/ice40/ice40_opt.cc +++ b/techlibs/ice40/ice40_opt.cc @@ -33,7 +33,7 @@ static SigBit get_bit_or_zero(const SigSpec &sig) return sig[0]; } -static void run_ice40_opts(Module *module, bool unlut_mode) +static void run_ice40_opts(Module *module) { pool<SigBit> optimized_co; vector<Cell*> sb_lut_cells; @@ -83,6 +83,52 @@ static void run_ice40_opts(Module *module, bool unlut_mode) } continue; } + + if (cell->type == "$__ICE40_CARRY_WRAPPER") + { + SigSpec non_const_inputs, replacement_output; + int count_zeros = 0, count_ones = 0; + + SigBit inbit[3] = { + cell->getPort("\\A"), + cell->getPort("\\B"), + cell->getPort("\\CI") + }; + for (int i = 0; i < 3; i++) + if (inbit[i].wire == nullptr) { + if (inbit[i] == State::S1) + count_ones++; + else + count_zeros++; + } else + non_const_inputs.append(inbit[i]); + + if (count_zeros >= 2) + replacement_output = State::S0; + else if (count_ones >= 2) + replacement_output = State::S1; + else if (GetSize(non_const_inputs) == 1) + replacement_output = non_const_inputs; + + if (GetSize(replacement_output)) { + optimized_co.insert(sigmap(cell->getPort("\\CO")[0])); + module->connect(cell->getPort("\\CO")[0], replacement_output); + module->design->scratchpad_set_bool("opt.did_something", true); + log("Optimized $__ICE40_CARRY_WRAPPER cell back to logic (without SB_CARRY) %s.%s: CO=%s\n", + log_id(module), log_id(cell), log_signal(replacement_output)); + cell->type = "$lut"; + cell->setPort("\\A", { cell->getPort("\\I0"), inbit[0], inbit[1], cell->getPort("\\I3") }); + cell->setPort("\\Y", cell->getPort("\\O")); + cell->unsetPort("\\B"); + cell->unsetPort("\\CI"); + cell->unsetPort("\\I0"); + cell->unsetPort("\\I3"); + cell->unsetPort("\\CO"); + cell->unsetPort("\\O"); + cell->setParam("\\WIDTH", 4); + } + continue; + } } for (auto cell : sb_lut_cells) @@ -95,9 +141,6 @@ static void run_ice40_opts(Module *module, bool unlut_mode) inbits.append(get_bit_or_zero(cell->getPort("\\I3"))); sigmap.apply(inbits); - if (unlut_mode) - goto remap_lut; - if (optimized_co.count(inbits[0])) goto remap_lut; if (optimized_co.count(inbits[1])) goto remap_lut; if (optimized_co.count(inbits[2])) goto remap_lut; @@ -136,7 +179,7 @@ static void run_ice40_opts(Module *module, bool unlut_mode) struct Ice40OptPass : public Pass { Ice40OptPass() : Pass("ice40_opt", "iCE40: perform simple optimizations") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -152,14 +195,10 @@ struct Ice40OptPass : public Pass { log(" opt_clean\n"); log(" while <changed design>\n"); log("\n"); - log("When called with the option -unlut, this command will transform all already\n"); - log("mapped SB_LUT4 cells back to logic.\n"); - log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { string opt_expr_args = "-mux_undef -undriven"; - bool unlut_mode = false; log_header(design, "Executing ICE40_OPT pass (performing simple optimizations).\n"); log_push(); @@ -170,10 +209,6 @@ struct Ice40OptPass : public Pass { opt_expr_args += " -full"; continue; } - if (args[argidx] == "-unlut") { - unlut_mode = true; - continue; - } break; } extra_args(args, argidx, design); @@ -184,7 +219,7 @@ struct Ice40OptPass : public Pass { log_header(design, "Running ICE40 specific optimizations.\n"); for (auto module : design->selected_modules()) - run_ice40_opts(module, unlut_mode); + run_ice40_opts(module); Pass::call(design, "opt_expr " + opt_expr_args); Pass::call(design, "opt_merge"); diff --git a/techlibs/ice40/synth_ice40.cc b/techlibs/ice40/synth_ice40.cc index abd890a56..a3890268a 100644 --- a/techlibs/ice40/synth_ice40.cc +++ b/techlibs/ice40/synth_ice40.cc @@ -29,7 +29,7 @@ struct SynthIce40Pass : public ScriptPass { SynthIce40Pass() : ScriptPass("synth_ice40", "synthesis for iCE40 FPGAs") { } - virtual void help() YS_OVERRIDE + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -37,6 +37,10 @@ struct SynthIce40Pass : public ScriptPass log("\n"); log("This command runs synthesis for iCE40 FPGAs.\n"); log("\n"); + log(" -device < hx | lp | u >\n"); + log(" relevant only for '-abc9' flow, optimise timing for the specified device.\n"); + log(" default: hx\n"); + log("\n"); log(" -top <module>\n"); log(" use the specified module as top module\n"); log("\n"); @@ -69,9 +73,19 @@ struct SynthIce40Pass : public ScriptPass log(" -nodffe\n"); log(" do not use SB_DFFE* cells in output netlist\n"); log("\n"); + log(" -dffe_min_ce_use <min_ce_use>\n"); + log(" do not use SB_DFFE* cells if the resulting CE line would go to less\n"); + log(" than min_ce_use SB_DFFE* in output netlist\n"); + log("\n"); log(" -nobram\n"); log(" do not use SB_RAM40_4K* cells in output netlist\n"); log("\n"); + log(" -dsp\n"); + log(" use iCE40 UltraPlus DSP cells for large arithmetic\n"); + log("\n"); + log(" -noabc\n"); + log(" use built-in Yosys LUT techmapping instead of abc\n"); + log("\n"); log(" -abc2\n"); log(" run two passes of 'abc' for slightly improved logic density\n"); log("\n"); @@ -79,16 +93,20 @@ struct SynthIce40Pass : public ScriptPass log(" generate an output netlist (and BLIF file) suitable for VPR\n"); log(" (this feature is experimental and incomplete)\n"); log("\n"); + log(" -abc9\n"); + log(" use new ABC9 flow (EXPERIMENTAL)\n"); + log("\n"); log("\n"); log("The following commands are executed by this synthesis command:\n"); help_script(); log("\n"); } - string top_opt, blif_file, edif_file, json_file; - bool nocarry, nodffe, nobram, flatten, retime, abc2, vpr; + string top_opt, blif_file, edif_file, json_file, abc, device_opt; + bool nocarry, nodffe, nobram, dsp, flatten, retime, noabc, abc2, vpr; + int min_ce_use; - virtual void clear_flags() YS_OVERRIDE + void clear_flags() YS_OVERRIDE { top_opt = "-auto-top"; blif_file = ""; @@ -96,14 +114,19 @@ struct SynthIce40Pass : public ScriptPass json_file = ""; nocarry = false; nodffe = false; + min_ce_use = -1; nobram = false; + dsp = false; flatten = true; retime = false; + noabc = false; abc2 = false; vpr = false; + abc = "abc"; + device_opt = "hx"; } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { string run_from, run_to; clear_flags(); @@ -147,6 +170,10 @@ struct SynthIce40Pass : public ScriptPass retime = true; continue; } + if (args[argidx] == "-relut") { + // removed, opt_lut is always run + continue; + } if (args[argidx] == "-nocarry") { nocarry = true; continue; @@ -155,10 +182,22 @@ struct SynthIce40Pass : public ScriptPass nodffe = true; continue; } + if (args[argidx] == "-dffe_min_ce_use" && argidx+1 < args.size()) { + min_ce_use = atoi(args[++argidx].c_str()); + continue; + } if (args[argidx] == "-nobram") { nobram = true; continue; } + if (args[argidx] == "-dsp") { + dsp = true; + continue; + } + if (args[argidx] == "-noabc") { + noabc = true; + continue; + } if (args[argidx] == "-abc2") { abc2 = true; continue; @@ -167,12 +206,25 @@ struct SynthIce40Pass : public ScriptPass vpr = true; continue; } + if (args[argidx] == "-abc9") { + abc = "abc9"; + continue; + } + if (args[argidx] == "-device" && argidx+1 < args.size()) { + device_opt = args[++argidx]; + continue; + } break; } extra_args(args, argidx, design); if (!design->full_selection()) - log_cmd_error("This comannd only operates on fully selected designs!\n"); + log_cmd_error("This command only operates on fully selected designs!\n"); + if (device_opt != "hx" && device_opt != "lp" && device_opt !="u") + log_cmd_error("Invalid or no device specified: '%s'\n", device_opt.c_str()); + + if (abc == "abc9" && retime) + log_cmd_error("-retime option not currently compatible with -abc9!\n"); log_header(design, "Executing SYNTH_ICE40 pass.\n"); log_push(); @@ -182,44 +234,78 @@ struct SynthIce40Pass : public ScriptPass log_pop(); } - virtual void script() YS_OVERRIDE + void script() YS_OVERRIDE { if (check_label("begin")) { - run("read_verilog -lib +/ice40/cells_sim.v"); + std::string define; + if (device_opt == "lp") + define = "-D ICE40_LP"; + else if (device_opt == "u") + define = "-D ICE40_U"; + else + define = "-D ICE40_HX"; + run("read_verilog -icells " + define + " -lib +/ice40/cells_sim.v"); run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str())); + run("proc"); } - if (flatten && check_label("flatten", "(unless -noflatten)")) + if (check_label("flatten", "(unless -noflatten)")) { - run("proc"); - run("flatten"); - run("tribuf -logic"); - run("deminout"); + if (flatten) { + run("flatten"); + run("tribuf -logic"); + run("deminout"); + } } if (check_label("coarse")) { - run("synth -run coarse"); + run("opt_expr"); + run("opt_clean"); + run("check"); + run("opt"); + run("wreduce"); + run("peepopt"); + run("opt_clean"); + run("share"); + run("techmap -map +/cmp2lut.v -D LUT_WIDTH=4"); + run("opt_expr"); + run("opt_clean"); + if (help_mode || dsp) + run("ice40_dsp", "(if -dsp)"); + run("alumacc"); + run("opt"); + run("fsm"); + run("opt -fast"); + run("memory -nomap"); + run("opt_clean"); } - if (!nobram && check_label("bram", "(skip if -nobram)")) + if (!nobram && check_label("map_bram", "(skip if -nobram)")) { run("memory_bram -rules +/ice40/brams.txt"); run("techmap -map +/ice40/brams_map.v"); + run("ice40_braminit"); } - if (check_label("fine")) + if (check_label("map_ffram")) { run("opt -fast -mux_undef -undriven -fine"); run("memory_map"); run("opt -undriven -fine"); + } + + if (check_label("map_gates")) + { if (nocarry) run("techmap"); - else + else { + run("ice40_wrapcarry"); run("techmap -map +/techmap.v -map +/ice40/arith_map.v"); + } if (retime || help_mode) - run("abc -dff", "(only if -retime)"); + run(abc + " -dff", "(only if -retime)"); run("ice40_opt"); } @@ -228,7 +314,11 @@ struct SynthIce40Pass : public ScriptPass run("dffsr2dff"); if (!nodffe) run("dff2dffe -direct-match $_DFF_*"); - run("techmap -D NO_LUT -map +/ice40/cells_map.v"); + if (min_ce_use >= 0) { + run("opt_merge"); + run(stringf("dff2dffe -unmap-mince %d", min_ce_use)); + } + run("techmap -D NO_LUT -D NO_ADDER -map +/ice40/cells_map.v"); run("opt_expr -mux_undef"); run("simplemap"); run("ice40_ffinit"); @@ -239,12 +329,31 @@ struct SynthIce40Pass : public ScriptPass if (check_label("map_luts")) { if (abc2 || help_mode) { - run("abc", " (only if -abc2)"); + run(abc, " (only if -abc2)"); run("ice40_opt", "(only if -abc2)"); } run("techmap -map +/ice40/latches_map.v"); - run("abc -lut 4"); + if (noabc || help_mode) { + run("simplemap", " (only if -noabc)"); + run("techmap -map +/gate2lut.v -D LUT_WIDTH=4", "(only if -noabc)"); + } + if (!noabc) { + if (abc == "abc9") { + int wire_delay; + if (device_opt == "lp") + wire_delay = 400; + else if (device_opt == "u") + wire_delay = 750; + else + wire_delay = 250; + run(abc + stringf(" -W %d -lut +/ice40/abc_%s.lut -box +/ice40/abc_%s.box", wire_delay, device_opt.c_str(), device_opt.c_str()), "(skip if -noabc)"); + } + else + run(abc + " -dress -lut 4", "(skip if -noabc)"); + } + run("techmap -D NO_LUT -map +/ice40/cells_map.v"); run("clean"); + run("opt_lut -dlogic SB_CARRY:I0=2:I1=1:CI=0"); } if (check_label("map_cells")) diff --git a/techlibs/ice40/tests/.gitignore b/techlibs/ice40/tests/.gitignore index b58f9ad4a..120286550 100644 --- a/techlibs/ice40/tests/.gitignore +++ b/techlibs/ice40/tests/.gitignore @@ -1,2 +1,11 @@ -test_ffs_[01][01][01][01][01]_* -test_bram_[0-9]* +/test_ffs_[01][01][01][01][01]_* +/test_bram_[0-9]* +/test_dsp_model +/test_dsp_model.vcd +/test_dsp_model_ref.v +/test_dsp_model_uut.v +/test_dsp_map +/test_dsp_map.vcd +/test_dsp_map_tb.v +/test_dsp_map_top.v +/test_dsp_map_syn.v diff --git a/techlibs/ice40/tests/test_arith.ys b/techlibs/ice40/tests/test_arith.ys index 160c767fb..ddb80b700 100644 --- a/techlibs/ice40/tests/test_arith.ys +++ b/techlibs/ice40/tests/test_arith.ys @@ -1,6 +1,5 @@ read_verilog test_arith.v synth_ice40 -techmap -map ../cells_sim.v rename test gate read_verilog test_arith.v @@ -8,3 +7,11 @@ rename test gold miter -equiv -flatten -make_outputs gold gate miter sat -verify -prove trigger 0 -show-ports miter + +synth_ice40 -top gate + +read_verilog test_arith.v +rename test gold + +miter -equiv -flatten -make_outputs gold gate miter +sat -verify -prove trigger 0 -show-ports miter diff --git a/techlibs/ice40/tests/test_dsp_map.sh b/techlibs/ice40/tests/test_dsp_map.sh new file mode 100644 index 000000000..3f7f134e4 --- /dev/null +++ b/techlibs/ice40/tests/test_dsp_map.sh @@ -0,0 +1,107 @@ +#!/bin/bash +set -ex + +for iter in {1..100} +do + SZA=$(( 3 + $RANDOM % 13 )) + SZB=$(( 3 + $RANDOM % 13 )) + SZO=$(( 3 + $RANDOM % 29 )) + + C0=clk$(( $RANDOM & 1)) + C1=clk$(( $RANDOM & 1)) + C2=clk$(( $RANDOM & 1)) + C3=clk$(( $RANDOM & 1)) + + E0=$( test $(( $RANDOM & 1 )) -eq 0 && echo posedge || echo negedge ) + E1=$( test $(( $RANDOM & 1 )) -eq 0 && echo posedge || echo negedge ) + E2=$( test $(( $RANDOM & 1 )) -eq 0 && echo posedge || echo negedge ) + E3=$( test $(( $RANDOM & 1 )) -eq 0 && echo posedge || echo negedge ) + + SP=$( test $(( $RANDOM & 1 )) -eq 0 && echo S || echo P ) + + RC=$( test $(( $RANDOM & 1 )) -eq 0 && echo "reset" || echo "!reset" ) + RV="32'h$( echo $RANDOM | md5sum | cut -c1-8 )" + + cat > test_dsp_map_top.v << EOT +module top ( + input clk0, clk1, reset, + input [$SZA:0] A, + input [$SZB:0] B, + output [$SZO:0] O +); + reg [15:0] AA, BB; + reg [31:0] P, S; + + always @($E0 $C0) AA <= A; + always @($E1 $C1) BB <= B; + always @($E2 $C2) P <= AA * BB; + always @($E3 $C3) S <= $RC ? $RV : S + P; + assign O = $SP; +endmodule +EOT + + cat > test_dsp_map_tb.v << EOT +\`timescale 1ns / 1ps +module testbench; + reg clk1, clk0, reset; + reg [$SZA:0] A; + reg [$SZB:0] B; + + wire [$SZO:0] O_top, O_syn; + + top top_inst (.clk0(clk0), .clk1(clk1), .reset(reset), .A(A), .B(B), .O(O_top)); + syn syn_inst (.clk0(clk0), .clk1(clk1), .reset(reset), .A(A), .B(B), .O(O_syn)); + + initial begin + // \$dumpfile("test_dsp_map.vcd"); + // \$dumpvars(0, testbench); + + #2; + clk0 = 0; + clk1 = 0; + reset = 1; + reset = $RC; + A = 0; + B = 0; + + repeat (3) begin + #2; clk0 = ~clk0; + #2; clk0 = ~clk0; + #2; clk1 = ~clk1; + #2; clk1 = ~clk1; + end + + repeat (100) begin + #2; + A = \$urandom; + B = \$urandom; + reset = \$urandom & \$urandom & \$urandom & \$urandom; + if (\$urandom & 1) begin + #2; clk0 = ~clk0; + #2; clk0 = ~clk0; + end else begin + #2; clk1 = ~clk1; + #2; clk1 = ~clk1; + end + #2; + if (O_top !== O_syn) begin + \$display("ERROR: O_top=%b O_syn=%b", O_top, O_syn); + \$stop; + end + // \$display("OK O_top=O_syn=%b", O_top); + end + + \$display("Test passed."); + \$finish; + end +endmodule +EOT + + ../../../yosys -p 'read_verilog test_dsp_map_top.v; synth_ice40 -dsp; rename top syn; write_verilog test_dsp_map_syn.v' + iverilog -o test_dsp_map -s testbench test_dsp_map_tb.v test_dsp_map_top.v test_dsp_map_syn.v ../cells_sim.v + vvp -N test_dsp_map +done + +: "" +: "#### All tests passed. ####" +: "" diff --git a/techlibs/ice40/tests/test_dsp_model.sh b/techlibs/ice40/tests/test_dsp_model.sh new file mode 100644 index 000000000..1e564d1b2 --- /dev/null +++ b/techlibs/ice40/tests/test_dsp_model.sh @@ -0,0 +1,16 @@ +#!/bin/bash +set -ex +sed 's/SB_MAC16/SB_MAC16_UUT/; /SB_MAC16_UUT/,/endmodule/ p; d;' < ../cells_sim.v > test_dsp_model_uut.v +if [ ! -f "test_dsp_model_ref.v" ]; then + cat /opt/lscc/iCEcube2.2017.01/verilog/sb_ice_syn.v > test_dsp_model_ref.v +fi +for tb in testbench \ + testbench_comb_8x8_A testbench_comb_8x8_B testbench_comb_16x16 \ + testbench_seq_16x16_A testbench_seq_16x16_B \ + testbench_comb_8x8_A_signedA testbench_comb_8x8_A_signedB testbench_comb_8x8_A_signedAB \ + testbench_comb_8x8_B_signedA testbench_comb_8x8_B_signedB testbench_comb_8x8_B_signedAB \ + testbench_comb_16x16_signedA testbench_comb_16x16_signedB testbench_comb_16x16_signedAB +do + iverilog -s $tb -o test_dsp_model test_dsp_model.v test_dsp_model_uut.v test_dsp_model_ref.v + vvp -N ./test_dsp_model +done diff --git a/techlibs/ice40/tests/test_dsp_model.v b/techlibs/ice40/tests/test_dsp_model.v new file mode 100644 index 000000000..f4f6858f0 --- /dev/null +++ b/techlibs/ice40/tests/test_dsp_model.v @@ -0,0 +1,567 @@ +`timescale 1ns / 1ps + +module testbench; + parameter [0:0] NEG_TRIGGER = 0; + parameter [0:0] C_REG = 0; + parameter [0:0] A_REG = 0; + parameter [0:0] B_REG = 0; + parameter [0:0] D_REG = 0; + parameter [0:0] TOP_8x8_MULT_REG = 0; + parameter [0:0] BOT_8x8_MULT_REG = 0; + parameter [0:0] PIPELINE_16x16_MULT_REG1 = 0; + parameter [0:0] PIPELINE_16x16_MULT_REG2 = 0; + parameter [1:0] TOPOUTPUT_SELECT = 0; + parameter [1:0] TOPADDSUB_LOWERINPUT = 0; + parameter [0:0] TOPADDSUB_UPPERINPUT = 1; + parameter [1:0] TOPADDSUB_CARRYSELECT = 0; + parameter [1:0] BOTOUTPUT_SELECT = 0; + parameter [1:0] BOTADDSUB_LOWERINPUT = 0; + parameter [0:0] BOTADDSUB_UPPERINPUT = 1; + parameter [1:0] BOTADDSUB_CARRYSELECT = 0; + parameter [0:0] MODE_8x8 = 0; + parameter [0:0] A_SIGNED = 0; + parameter [0:0] B_SIGNED = 0; + + reg CLK, CE; + reg [15:0] C, A, B, D; + reg AHOLD, BHOLD, CHOLD, DHOLD; + reg IRSTTOP, IRSTBOT; + reg ORSTTOP, ORSTBOT; + reg OLOADTOP, OLOADBOT; + reg ADDSUBTOP, ADDSUBBOT; + reg OHOLDTOP, OHOLDBOT; + reg CI, ACCUMCI, SIGNEXTIN; + + output [31:0] REF_O, UUT_O; + output REF_CO, REF_ACCUMCO, REF_SIGNEXTOUT; + output UUT_CO, UUT_ACCUMCO, UUT_SIGNEXTOUT; + + integer errcount = 0; + + task clkcycle; + begin + #5; + CLK = ~CLK; + #10; + CLK = ~CLK; + #2; + if (REF_O !== UUT_O) begin + $display("ERROR at %1t: REF_O=%b UUT_O=%b DIFF=%b", $time, REF_O, UUT_O, REF_O ^ UUT_O); + errcount = errcount + 1; + end + if (REF_CO !== UUT_CO) begin + $display("ERROR at %1t: REF_CO=%b UUT_CO=%b", $time, REF_CO, UUT_CO); + errcount = errcount + 1; + end + if (REF_ACCUMCO !== UUT_ACCUMCO) begin + $display("ERROR at %1t: REF_ACCUMCO=%b UUT_ACCUMCO=%b", $time, REF_ACCUMCO, UUT_ACCUMCO); + errcount = errcount + 1; + end + if (REF_SIGNEXTOUT !== UUT_SIGNEXTOUT) begin + $display("ERROR at %1t: REF_SIGNEXTOUT=%b UUT_SIGNEXTOUT=%b", $time, REF_SIGNEXTOUT, UUT_SIGNEXTOUT); + errcount = errcount + 1; + end + #3; + end + endtask + + initial begin + $dumpfile("test_dsp_model.vcd"); + $dumpvars(0, testbench); + + #2; + CLK = NEG_TRIGGER; + CE = 1; + {C, A, B, D} = 0; + {AHOLD, BHOLD, CHOLD, DHOLD} = 0; + {OLOADTOP, OLOADBOT} = 0; + {ADDSUBTOP, ADDSUBBOT} = 0; + {OHOLDTOP, OHOLDBOT} = 0; + {CI, ACCUMCI, SIGNEXTIN} = 0; + + {IRSTTOP, IRSTBOT} = ~0; + {ORSTTOP, ORSTBOT} = ~0; + + #3; + {IRSTTOP, IRSTBOT} = 0; + {ORSTTOP, ORSTBOT} = 0; + + repeat (300) begin + clkcycle; + + A = $urandom; + B = $urandom; + C = $urandom; + D = $urandom; + + {AHOLD, BHOLD, CHOLD, DHOLD} = $urandom & $urandom & $urandom; + {OLOADTOP, OLOADBOT} = $urandom & $urandom & $urandom; + {ADDSUBTOP, ADDSUBBOT} = $urandom & $urandom & $urandom; + {OHOLDTOP, OHOLDBOT} = $urandom & $urandom & $urandom; + {CI, ACCUMCI, SIGNEXTIN} = $urandom & $urandom & $urandom; + + {IRSTTOP, IRSTBOT} = $urandom & $urandom & $urandom; + {ORSTTOP, ORSTBOT} = $urandom & $urandom & $urandom; + end + + if (errcount == 0) begin + $display("All tests passed."); + $finish; + end else begin + $display("Caught %1d errors.", errcount); + $stop; + end + end + + SB_MAC16 #( + .NEG_TRIGGER (NEG_TRIGGER ), + .C_REG (C_REG ), + .A_REG (A_REG ), + .B_REG (B_REG ), + .D_REG (D_REG ), + .TOP_8x8_MULT_REG (TOP_8x8_MULT_REG ), + .BOT_8x8_MULT_REG (BOT_8x8_MULT_REG ), + .PIPELINE_16x16_MULT_REG1 (PIPELINE_16x16_MULT_REG1), + .PIPELINE_16x16_MULT_REG2 (PIPELINE_16x16_MULT_REG2), + .TOPOUTPUT_SELECT (TOPOUTPUT_SELECT ), + .TOPADDSUB_LOWERINPUT (TOPADDSUB_LOWERINPUT ), + .TOPADDSUB_UPPERINPUT (TOPADDSUB_UPPERINPUT ), + .TOPADDSUB_CARRYSELECT (TOPADDSUB_CARRYSELECT ), + .BOTOUTPUT_SELECT (BOTOUTPUT_SELECT ), + .BOTADDSUB_LOWERINPUT (BOTADDSUB_LOWERINPUT ), + .BOTADDSUB_UPPERINPUT (BOTADDSUB_UPPERINPUT ), + .BOTADDSUB_CARRYSELECT (BOTADDSUB_CARRYSELECT ), + .MODE_8x8 (MODE_8x8 ), + .A_SIGNED (A_SIGNED ), + .B_SIGNED (B_SIGNED ) + ) ref ( + .CLK (CLK ), + .CE (CE ), + .C (C ), + .A (A ), + .B (B ), + .D (D ), + .AHOLD (AHOLD ), + .BHOLD (BHOLD ), + .CHOLD (CHOLD ), + .DHOLD (DHOLD ), + .IRSTTOP (IRSTTOP ), + .IRSTBOT (IRSTBOT ), + .ORSTTOP (ORSTTOP ), + .ORSTBOT (ORSTBOT ), + .OLOADTOP (OLOADTOP ), + .OLOADBOT (OLOADBOT ), + .ADDSUBTOP (ADDSUBTOP ), + .ADDSUBBOT (ADDSUBBOT ), + .OHOLDTOP (OHOLDTOP ), + .OHOLDBOT (OHOLDBOT ), + .CI (CI ), + .ACCUMCI (ACCUMCI ), + .SIGNEXTIN (SIGNEXTIN ), + .O (REF_O ), + .CO (REF_CO ), + .ACCUMCO (REF_ACCUMCO ), + .SIGNEXTOUT (REF_SIGNEXTOUT) + ); + + SB_MAC16_UUT #( + .NEG_TRIGGER (NEG_TRIGGER ), + .C_REG (C_REG ), + .A_REG (A_REG ), + .B_REG (B_REG ), + .D_REG (D_REG ), + .TOP_8x8_MULT_REG (TOP_8x8_MULT_REG ), + .BOT_8x8_MULT_REG (BOT_8x8_MULT_REG ), + .PIPELINE_16x16_MULT_REG1 (PIPELINE_16x16_MULT_REG1), + .PIPELINE_16x16_MULT_REG2 (PIPELINE_16x16_MULT_REG2), + .TOPOUTPUT_SELECT (TOPOUTPUT_SELECT ), + .TOPADDSUB_LOWERINPUT (TOPADDSUB_LOWERINPUT ), + .TOPADDSUB_UPPERINPUT (TOPADDSUB_UPPERINPUT ), + .TOPADDSUB_CARRYSELECT (TOPADDSUB_CARRYSELECT ), + .BOTOUTPUT_SELECT (BOTOUTPUT_SELECT ), + .BOTADDSUB_LOWERINPUT (BOTADDSUB_LOWERINPUT ), + .BOTADDSUB_UPPERINPUT (BOTADDSUB_UPPERINPUT ), + .BOTADDSUB_CARRYSELECT (BOTADDSUB_CARRYSELECT ), + .MODE_8x8 (MODE_8x8 ), + .A_SIGNED (A_SIGNED ), + .B_SIGNED (B_SIGNED ) + ) uut ( + .CLK (CLK ), + .CE (CE ), + .C (C ), + .A (A ), + .B (B ), + .D (D ), + .AHOLD (AHOLD ), + .BHOLD (BHOLD ), + .CHOLD (CHOLD ), + .DHOLD (DHOLD ), + .IRSTTOP (IRSTTOP ), + .IRSTBOT (IRSTBOT ), + .ORSTTOP (ORSTTOP ), + .ORSTBOT (ORSTBOT ), + .OLOADTOP (OLOADTOP ), + .OLOADBOT (OLOADBOT ), + .ADDSUBTOP (ADDSUBTOP ), + .ADDSUBBOT (ADDSUBBOT ), + .OHOLDTOP (OHOLDTOP ), + .OHOLDBOT (OHOLDBOT ), + .CI (CI ), + .ACCUMCI (ACCUMCI ), + .SIGNEXTIN (SIGNEXTIN ), + .O (UUT_O ), + .CO (UUT_CO ), + .ACCUMCO (UUT_ACCUMCO ), + .SIGNEXTOUT (UUT_SIGNEXTOUT) + ); +endmodule + +module testbench_comb_8x8_A; + testbench #( + .NEG_TRIGGER (0), + .C_REG (0), + .A_REG (0), + .B_REG (0), + .D_REG (0), + .TOP_8x8_MULT_REG (0), + .BOT_8x8_MULT_REG (0), + .PIPELINE_16x16_MULT_REG1 (0), + .PIPELINE_16x16_MULT_REG2 (0), + .TOPOUTPUT_SELECT (2), // 0=P, 1=Q, 2=8x8, 3=16x16 + .TOPADDSUB_LOWERINPUT (0), // 0=A, 1=8x8, 2=16x16, 3=S-EXT + .TOPADDSUB_UPPERINPUT (0), // 0=Q, 1=C + .TOPADDSUB_CARRYSELECT (0), // 0=0, 1=1, 2=ACI, 3=CI + .BOTOUTPUT_SELECT (2), // 0=R, 1=S, 2=8x8, 3=16x16 + .BOTADDSUB_LOWERINPUT (0), // 0=B, 1=8x8, 2=16x16, 3=S-EXT + .BOTADDSUB_UPPERINPUT (0), // 0=S, 1=D + .BOTADDSUB_CARRYSELECT (0), // 0=0, 1=1, 2=ACI, 3=CI + .MODE_8x8 (0), + .A_SIGNED (0), + .B_SIGNED (0) + ) testbench (); +endmodule + +module testbench_comb_8x8_A_signedA; + testbench #( + .NEG_TRIGGER (0), + .C_REG (0), + .A_REG (0), + .B_REG (0), + .D_REG (0), + .TOP_8x8_MULT_REG (0), + .BOT_8x8_MULT_REG (0), + .PIPELINE_16x16_MULT_REG1 (0), + .PIPELINE_16x16_MULT_REG2 (0), + .TOPOUTPUT_SELECT (2), // 0=P, 1=Q, 2=8x8, 3=16x16 + .TOPADDSUB_LOWERINPUT (0), // 0=A, 1=8x8, 2=16x16, 3=S-EXT + .TOPADDSUB_UPPERINPUT (0), // 0=Q, 1=C + .TOPADDSUB_CARRYSELECT (0), // 0=0, 1=1, 2=ACI, 3=CI + .BOTOUTPUT_SELECT (2), // 0=R, 1=S, 2=8x8, 3=16x16 + .BOTADDSUB_LOWERINPUT (0), // 0=B, 1=8x8, 2=16x16, 3=S-EXT + .BOTADDSUB_UPPERINPUT (0), // 0=S, 1=D + .BOTADDSUB_CARRYSELECT (0), // 0=0, 1=1, 2=ACI, 3=CI + .MODE_8x8 (0), + .A_SIGNED (1), + .B_SIGNED (0) + ) testbench (); +endmodule + +module testbench_comb_8x8_A_signedB; + testbench #( + .NEG_TRIGGER (0), + .C_REG (0), + .A_REG (0), + .B_REG (0), + .D_REG (0), + .TOP_8x8_MULT_REG (0), + .BOT_8x8_MULT_REG (0), + .PIPELINE_16x16_MULT_REG1 (0), + .PIPELINE_16x16_MULT_REG2 (0), + .TOPOUTPUT_SELECT (2), // 0=P, 1=Q, 2=8x8, 3=16x16 + .TOPADDSUB_LOWERINPUT (0), // 0=A, 1=8x8, 2=16x16, 3=S-EXT + .TOPADDSUB_UPPERINPUT (0), // 0=Q, 1=C + .TOPADDSUB_CARRYSELECT (0), // 0=0, 1=1, 2=ACI, 3=CI + .BOTOUTPUT_SELECT (2), // 0=R, 1=S, 2=8x8, 3=16x16 + .BOTADDSUB_LOWERINPUT (0), // 0=B, 1=8x8, 2=16x16, 3=S-EXT + .BOTADDSUB_UPPERINPUT (0), // 0=S, 1=D + .BOTADDSUB_CARRYSELECT (0), // 0=0, 1=1, 2=ACI, 3=CI + .MODE_8x8 (0), + .A_SIGNED (0), + .B_SIGNED (1) + ) testbench (); +endmodule + +module testbench_comb_8x8_A_signedAB; + testbench #( + .NEG_TRIGGER (0), + .C_REG (0), + .A_REG (0), + .B_REG (0), + .D_REG (0), + .TOP_8x8_MULT_REG (0), + .BOT_8x8_MULT_REG (0), + .PIPELINE_16x16_MULT_REG1 (0), + .PIPELINE_16x16_MULT_REG2 (0), + .TOPOUTPUT_SELECT (2), // 0=P, 1=Q, 2=8x8, 3=16x16 + .TOPADDSUB_LOWERINPUT (0), // 0=A, 1=8x8, 2=16x16, 3=S-EXT + .TOPADDSUB_UPPERINPUT (0), // 0=Q, 1=C + .TOPADDSUB_CARRYSELECT (0), // 0=0, 1=1, 2=ACI, 3=CI + .BOTOUTPUT_SELECT (2), // 0=R, 1=S, 2=8x8, 3=16x16 + .BOTADDSUB_LOWERINPUT (0), // 0=B, 1=8x8, 2=16x16, 3=S-EXT + .BOTADDSUB_UPPERINPUT (0), // 0=S, 1=D + .BOTADDSUB_CARRYSELECT (0), // 0=0, 1=1, 2=ACI, 3=CI + .MODE_8x8 (0), + .A_SIGNED (1), + .B_SIGNED (1) + ) testbench (); +endmodule + +module testbench_comb_8x8_B; + testbench #( + .NEG_TRIGGER (0), + .C_REG (0), + .A_REG (0), + .B_REG (0), + .D_REG (0), + .TOP_8x8_MULT_REG (0), + .BOT_8x8_MULT_REG (0), + .PIPELINE_16x16_MULT_REG1 (0), + .PIPELINE_16x16_MULT_REG2 (0), + .TOPOUTPUT_SELECT (0), // 0=P, 1=Q, 2=8x8, 3=16x16 + .TOPADDSUB_LOWERINPUT (1), // 0=A, 1=8x8, 2=16x16, 3=S-EXT + .TOPADDSUB_UPPERINPUT (1), // 0=Q, 1=C + .TOPADDSUB_CARRYSELECT (0), // 0=0, 1=1, 2=ACI, 3=CI + .BOTOUTPUT_SELECT (0), // 0=R, 1=S, 2=8x8, 3=16x16 + .BOTADDSUB_LOWERINPUT (1), // 0=B, 1=8x8, 2=16x16, 3=S-EXT + .BOTADDSUB_UPPERINPUT (1), // 0=S, 1=D + .BOTADDSUB_CARRYSELECT (0), // 0=0, 1=1, 2=ACI, 3=CI + .MODE_8x8 (0), + .A_SIGNED (0), + .B_SIGNED (0) + ) testbench (); +endmodule + +module testbench_comb_8x8_B_signedA; + testbench #( + .NEG_TRIGGER (0), + .C_REG (0), + .A_REG (0), + .B_REG (0), + .D_REG (0), + .TOP_8x8_MULT_REG (0), + .BOT_8x8_MULT_REG (0), + .PIPELINE_16x16_MULT_REG1 (0), + .PIPELINE_16x16_MULT_REG2 (0), + .TOPOUTPUT_SELECT (0), // 0=P, 1=Q, 2=8x8, 3=16x16 + .TOPADDSUB_LOWERINPUT (1), // 0=A, 1=8x8, 2=16x16, 3=S-EXT + .TOPADDSUB_UPPERINPUT (1), // 0=Q, 1=C + .TOPADDSUB_CARRYSELECT (0), // 0=0, 1=1, 2=ACI, 3=CI + .BOTOUTPUT_SELECT (0), // 0=R, 1=S, 2=8x8, 3=16x16 + .BOTADDSUB_LOWERINPUT (1), // 0=B, 1=8x8, 2=16x16, 3=S-EXT + .BOTADDSUB_UPPERINPUT (1), // 0=S, 1=D + .BOTADDSUB_CARRYSELECT (0), // 0=0, 1=1, 2=ACI, 3=CI + .MODE_8x8 (0), + .A_SIGNED (1), + .B_SIGNED (0) + ) testbench (); +endmodule + +module testbench_comb_8x8_B_signedB; + testbench #( + .NEG_TRIGGER (0), + .C_REG (0), + .A_REG (0), + .B_REG (0), + .D_REG (0), + .TOP_8x8_MULT_REG (0), + .BOT_8x8_MULT_REG (0), + .PIPELINE_16x16_MULT_REG1 (0), + .PIPELINE_16x16_MULT_REG2 (0), + .TOPOUTPUT_SELECT (0), // 0=P, 1=Q, 2=8x8, 3=16x16 + .TOPADDSUB_LOWERINPUT (1), // 0=A, 1=8x8, 2=16x16, 3=S-EXT + .TOPADDSUB_UPPERINPUT (1), // 0=Q, 1=C + .TOPADDSUB_CARRYSELECT (0), // 0=0, 1=1, 2=ACI, 3=CI + .BOTOUTPUT_SELECT (0), // 0=R, 1=S, 2=8x8, 3=16x16 + .BOTADDSUB_LOWERINPUT (1), // 0=B, 1=8x8, 2=16x16, 3=S-EXT + .BOTADDSUB_UPPERINPUT (1), // 0=S, 1=D + .BOTADDSUB_CARRYSELECT (0), // 0=0, 1=1, 2=ACI, 3=CI + .MODE_8x8 (0), + .A_SIGNED (0), + .B_SIGNED (1) + ) testbench (); +endmodule + +module testbench_comb_8x8_B_signedAB; + testbench #( + .NEG_TRIGGER (0), + .C_REG (0), + .A_REG (0), + .B_REG (0), + .D_REG (0), + .TOP_8x8_MULT_REG (0), + .BOT_8x8_MULT_REG (0), + .PIPELINE_16x16_MULT_REG1 (0), + .PIPELINE_16x16_MULT_REG2 (0), + .TOPOUTPUT_SELECT (0), // 0=P, 1=Q, 2=8x8, 3=16x16 + .TOPADDSUB_LOWERINPUT (1), // 0=A, 1=8x8, 2=16x16, 3=S-EXT + .TOPADDSUB_UPPERINPUT (1), // 0=Q, 1=C + .TOPADDSUB_CARRYSELECT (0), // 0=0, 1=1, 2=ACI, 3=CI + .BOTOUTPUT_SELECT (0), // 0=R, 1=S, 2=8x8, 3=16x16 + .BOTADDSUB_LOWERINPUT (1), // 0=B, 1=8x8, 2=16x16, 3=S-EXT + .BOTADDSUB_UPPERINPUT (1), // 0=S, 1=D + .BOTADDSUB_CARRYSELECT (0), // 0=0, 1=1, 2=ACI, 3=CI + .MODE_8x8 (0), + .A_SIGNED (1), + .B_SIGNED (1) + ) testbench (); +endmodule + +module testbench_comb_16x16; + testbench #( + .NEG_TRIGGER (0), + .C_REG (0), + .A_REG (0), + .B_REG (0), + .D_REG (0), + .TOP_8x8_MULT_REG (0), + .BOT_8x8_MULT_REG (0), + .PIPELINE_16x16_MULT_REG1 (0), + .PIPELINE_16x16_MULT_REG2 (0), + .TOPOUTPUT_SELECT (0), // 0=P, 1=Q, 2=8x8, 3=16x16 + .TOPADDSUB_LOWERINPUT (2), // 0=A, 1=8x8, 2=16x16, 3=S-EXT + .TOPADDSUB_UPPERINPUT (1), // 0=Q, 1=C + .TOPADDSUB_CARRYSELECT (2), // 0=0, 1=1, 2=ACI, 3=CI + .BOTOUTPUT_SELECT (0), // 0=R, 1=S, 2=8x8, 3=16x16 + .BOTADDSUB_LOWERINPUT (2), // 0=B, 1=8x8, 2=16x16, 3=S-EXT + .BOTADDSUB_UPPERINPUT (1), // 0=S, 1=D + .BOTADDSUB_CARRYSELECT (2), // 0=0, 1=1, 2=ACI, 3=CI + .MODE_8x8 (0), + .A_SIGNED (0), + .B_SIGNED (0) + ) testbench (); +endmodule + +module testbench_comb_16x16_signedA; + testbench #( + .NEG_TRIGGER (0), + .C_REG (0), + .A_REG (0), + .B_REG (0), + .D_REG (0), + .TOP_8x8_MULT_REG (0), + .BOT_8x8_MULT_REG (0), + .PIPELINE_16x16_MULT_REG1 (0), + .PIPELINE_16x16_MULT_REG2 (0), + .TOPOUTPUT_SELECT (0), // 0=P, 1=Q, 2=8x8, 3=16x16 + .TOPADDSUB_LOWERINPUT (2), // 0=A, 1=8x8, 2=16x16, 3=S-EXT + .TOPADDSUB_UPPERINPUT (1), // 0=Q, 1=C + .TOPADDSUB_CARRYSELECT (2), // 0=0, 1=1, 2=ACI, 3=CI + .BOTOUTPUT_SELECT (0), // 0=R, 1=S, 2=8x8, 3=16x16 + .BOTADDSUB_LOWERINPUT (2), // 0=B, 1=8x8, 2=16x16, 3=S-EXT + .BOTADDSUB_UPPERINPUT (1), // 0=S, 1=D + .BOTADDSUB_CARRYSELECT (2), // 0=0, 1=1, 2=ACI, 3=CI + .MODE_8x8 (0), + .A_SIGNED (1), + .B_SIGNED (0) + ) testbench (); +endmodule + +module testbench_comb_16x16_signedB; + testbench #( + .NEG_TRIGGER (0), + .C_REG (0), + .A_REG (0), + .B_REG (0), + .D_REG (0), + .TOP_8x8_MULT_REG (0), + .BOT_8x8_MULT_REG (0), + .PIPELINE_16x16_MULT_REG1 (0), + .PIPELINE_16x16_MULT_REG2 (0), + .TOPOUTPUT_SELECT (0), // 0=P, 1=Q, 2=8x8, 3=16x16 + .TOPADDSUB_LOWERINPUT (2), // 0=A, 1=8x8, 2=16x16, 3=S-EXT + .TOPADDSUB_UPPERINPUT (1), // 0=Q, 1=C + .TOPADDSUB_CARRYSELECT (2), // 0=0, 1=1, 2=ACI, 3=CI + .BOTOUTPUT_SELECT (0), // 0=R, 1=S, 2=8x8, 3=16x16 + .BOTADDSUB_LOWERINPUT (2), // 0=B, 1=8x8, 2=16x16, 3=S-EXT + .BOTADDSUB_UPPERINPUT (1), // 0=S, 1=D + .BOTADDSUB_CARRYSELECT (2), // 0=0, 1=1, 2=ACI, 3=CI + .MODE_8x8 (0), + .A_SIGNED (0), + .B_SIGNED (1) + ) testbench (); +endmodule + +module testbench_comb_16x16_signedAB; + testbench #( + .NEG_TRIGGER (0), + .C_REG (0), + .A_REG (0), + .B_REG (0), + .D_REG (0), + .TOP_8x8_MULT_REG (0), + .BOT_8x8_MULT_REG (0), + .PIPELINE_16x16_MULT_REG1 (0), + .PIPELINE_16x16_MULT_REG2 (0), + .TOPOUTPUT_SELECT (0), // 0=P, 1=Q, 2=8x8, 3=16x16 + .TOPADDSUB_LOWERINPUT (2), // 0=A, 1=8x8, 2=16x16, 3=S-EXT + .TOPADDSUB_UPPERINPUT (1), // 0=Q, 1=C + .TOPADDSUB_CARRYSELECT (2), // 0=0, 1=1, 2=ACI, 3=CI + .BOTOUTPUT_SELECT (0), // 0=R, 1=S, 2=8x8, 3=16x16 + .BOTADDSUB_LOWERINPUT (2), // 0=B, 1=8x8, 2=16x16, 3=S-EXT + .BOTADDSUB_UPPERINPUT (1), // 0=S, 1=D + .BOTADDSUB_CARRYSELECT (2), // 0=0, 1=1, 2=ACI, 3=CI + .MODE_8x8 (0), + .A_SIGNED (1), + .B_SIGNED (1) + ) testbench (); +endmodule + +module testbench_seq_16x16_A; + testbench #( + .NEG_TRIGGER (0), + .C_REG (1), + .A_REG (1), + .B_REG (1), + .D_REG (1), + .TOP_8x8_MULT_REG (1), + .BOT_8x8_MULT_REG (1), + .PIPELINE_16x16_MULT_REG1 (1), + .PIPELINE_16x16_MULT_REG2 (1), + .TOPOUTPUT_SELECT (0), // 0=P, 1=Q, 2=8x8, 3=16x16 + .TOPADDSUB_LOWERINPUT (2), // 0=A, 1=8x8, 2=16x16, 3=S-EXT + .TOPADDSUB_UPPERINPUT (1), // 0=Q, 1=C + .TOPADDSUB_CARRYSELECT (2), // 0=0, 1=1, 2=ACI, 3=CI + .BOTOUTPUT_SELECT (0), // 0=R, 1=S, 2=8x8, 3=16x16 + .BOTADDSUB_LOWERINPUT (2), // 0=B, 1=8x8, 2=16x16, 3=S-EXT + .BOTADDSUB_UPPERINPUT (1), // 0=S, 1=D + .BOTADDSUB_CARRYSELECT (2), // 0=0, 1=1, 2=ACI, 3=CI + .MODE_8x8 (0), + .A_SIGNED (0), + .B_SIGNED (0) + ) testbench (); +endmodule + +module testbench_seq_16x16_B; + testbench #( + .NEG_TRIGGER (0), + .C_REG (1), + .A_REG (1), + .B_REG (1), + .D_REG (1), + .TOP_8x8_MULT_REG (1), + .BOT_8x8_MULT_REG (1), + .PIPELINE_16x16_MULT_REG1 (1), + .PIPELINE_16x16_MULT_REG2 (0), + .TOPOUTPUT_SELECT (1), // 0=P, 1=Q, 2=8x8, 3=16x16 + .TOPADDSUB_LOWERINPUT (2), // 0=A, 1=8x8, 2=16x16, 3=S-EXT + .TOPADDSUB_UPPERINPUT (0), // 0=Q, 1=C + .TOPADDSUB_CARRYSELECT (2), // 0=0, 1=1, 2=ACI, 3=CI + .BOTOUTPUT_SELECT (1), // 0=R, 1=S, 2=8x8, 3=16x16 + .BOTADDSUB_LOWERINPUT (2), // 0=B, 1=8x8, 2=16x16, 3=S-EXT + .BOTADDSUB_UPPERINPUT (0), // 0=S, 1=D + .BOTADDSUB_CARRYSELECT (2), // 0=0, 1=1, 2=ACI, 3=CI + .MODE_8x8 (0), + .A_SIGNED (0), + .B_SIGNED (0) + ) testbench (); +endmodule diff --git a/techlibs/intel/Makefile.inc b/techlibs/intel/Makefile.inc index ec7cea379..4e8f423c8 100644 --- a/techlibs/intel/Makefile.inc +++ b/techlibs/intel/Makefile.inc @@ -3,22 +3,12 @@ OBJS += techlibs/intel/synth_intel.o $(eval $(call add_share_file,share/intel/common,techlibs/intel/common/m9k_bb.v)) $(eval $(call add_share_file,share/intel/common,techlibs/intel/common/altpll_bb.v)) -$(eval $(call add_share_file,share/intel/common,techlibs/intel/common/brams.txt)) -$(eval $(call add_share_file,share/intel/common,techlibs/intel/common/brams_map.v)) -$(eval $(call add_share_file,share/intel/max10,techlibs/intel/max10/cells_sim.v)) -$(eval $(call add_share_file,share/intel/a10gx,techlibs/intel/a10gx/cells_sim.v)) -$(eval $(call add_share_file,share/intel/cyclonev,techlibs/intel/cyclonev/cells_sim.v)) -$(eval $(call add_share_file,share/intel/cyclone10,techlibs/intel/cyclone10/cells_sim.v)) -$(eval $(call add_share_file,share/intel/cycloneiv,techlibs/intel/cycloneiv/cells_sim.v)) -$(eval $(call add_share_file,share/intel/cycloneive,techlibs/intel/cycloneive/cells_sim.v)) -$(eval $(call add_share_file,share/intel/max10,techlibs/intel/max10/cells_map.v)) -$(eval $(call add_share_file,share/intel/a10gx,techlibs/intel/a10gx/cells_map.v)) -$(eval $(call add_share_file,share/intel/cyclonev,techlibs/intel/cyclonev/cells_map.v)) -$(eval $(call add_share_file,share/intel/cyclone10,techlibs/intel/cyclone10/cells_map.v)) -$(eval $(call add_share_file,share/intel/cycloneiv,techlibs/intel/cycloneiv/cells_map.v)) -$(eval $(call add_share_file,share/intel/cycloneive,techlibs/intel/cycloneive/cells_map.v)) -#$(eval $(call add_share_file,share/intel/max10,techlibs/intel/max10/arith_map.v)) -#$(eval $(call add_share_file,share/intel/a10gx,techlibs/intel/a10gx/arith_map.v)) -#$(eval $(call add_share_file,share/intel/cycloneiv,techlibs/intel/cycloneiv/arith_map.v)) +$(eval $(call add_share_file,share/intel/common,techlibs/intel/common/brams_m9k.txt)) +$(eval $(call add_share_file,share/intel/common,techlibs/intel/common/brams_map_m9k.v)) + +# Add the cell models and mappings for the VQM backend +families := max10 a10gx cyclonev cyclone10 cycloneiv cycloneive +$(foreach family,$(families), $(eval $(call add_share_file,share/intel/$(family),techlibs/intel/$(family)/cells_sim.v))) +$(foreach family,$(families), $(eval $(call add_share_file,share/intel/$(family),techlibs/intel/$(family)/cells_map.v))) #$(eval $(call add_share_file,share/intel/cycloneive,techlibs/intel/cycloneive/arith_map.v)) diff --git a/techlibs/intel/common/brams.txt b/techlibs/intel/common/brams_m9k.txt index 3bf21afc9..3bf21afc9 100644 --- a/techlibs/intel/common/brams.txt +++ b/techlibs/intel/common/brams_m9k.txt diff --git a/techlibs/intel/common/brams_map.v b/techlibs/intel/common/brams_map_m9k.v index fae4af2ab..d0f07c1de 100644 --- a/techlibs/intel/common/brams_map.v +++ b/techlibs/intel/common/brams_map_m9k.v @@ -2,8 +2,8 @@ module \$__M9K_ALTSYNCRAM_SINGLEPORT_FULL (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1A parameter CFG_ABITS = 8; parameter CFG_DBITS = 36; - parameter ABITS = "1"; - parameter DBITS = "1"; + parameter ABITS = 1; + parameter DBITS = 1; parameter CLKPOL2 = 1; parameter CLKPOL3 = 1; @@ -63,21 +63,21 @@ module \$__M9K_ALTSYNCRAM_SINGLEPORT_FULL (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1A .width_byteena_a (1), // Forced value .numwords_b ( NUMWORDS ), .numwords_a ( NUMWORDS ), - .widthad_b ( CFG_ABITS ), - .width_b ( CFG_DBITS ), - .widthad_a ( CFG_ABITS ), - .width_a ( CFG_DBITS ) + .widthad_b ( CFG_DBITS ), + .width_b ( CFG_ABITS ), + .widthad_a ( CFG_DBITS ), + .width_a ( CFG_ABITS ) ) _TECHMAP_REPLACE_ ( .data_a(B1DATA), .address_a(B1ADDR), .wren_a(B1EN), .rden_a(A1EN), .q_a(A1DATA), - .data_b(1'b0), + .data_b(B1DATA), .address_b(0), .wren_b(1'b0), .rden_b(1'b0), - .q_b(1'b0), + .q_b(), .clock0(CLK2), .clock1(1'b1), // Unused in single port mode .clocken0(1'b1), diff --git a/techlibs/intel/cycloneive/arith_map.v b/techlibs/intel/cycloneive/arith_map.v index b3a11272b..49e36aa25 100644 --- a/techlibs/intel/cycloneive/arith_map.v +++ b/techlibs/intel/cycloneive/arith_map.v @@ -32,7 +32,7 @@ module fa wire VCC; assign VCC = 1'b1; - + cycloneiv_lcell_comb gen_sum_0 (.combout(sum_x), .dataa(a_c), .datab(b_c), @@ -40,7 +40,7 @@ module fa .datad(VCC)); defparam syn__05_.lut_mask = 16'b1001011010010110; defparam syn__05_.sum_lutc_input = "datac"; - + cycloneiv_lcell_comb gen_cout_0 (.combout(cout_t), .dataa(cin_c), .datab(b_c), @@ -48,11 +48,11 @@ module fa .datad(VCC)); defparam syn__06_.lut_mask = 16'b1110000011100000; defparam syn__06_.sum_lutc_input = "datac"; - + endmodule // fa module f_stage(); - + endmodule // f_stage module f_end(); @@ -88,7 +88,7 @@ module _80_cycloneive_alu (A, B, CI, BI, X, Y, CO); .cin_c(C[0]), .cout_t(C0[1]), .sum_x(Y[0])); - + genvar i; generate for (i = 1; i < Y_WIDTH; i = i + 1) begin:slice cycloneive_lcell_comb #(.lut_mask(16'b0101_1010_0101_0000), .sum_lutc_input("cin")) arith_cell (.combout(Y[i]), .cout(CO[i]), .dataa(BB[i]), .datab(1'b1), .datac(1'b1), .datad(1'b1), .cin(C[i])); diff --git a/techlibs/intel/cyclonev/cells_map.v b/techlibs/intel/cyclonev/cells_map.v index bd60d4e17..f8d142bc9 100644 --- a/techlibs/intel/cyclonev/cells_map.v +++ b/techlibs/intel/cyclonev/cells_map.v @@ -76,7 +76,7 @@ module \$lut (A, Y); wire VCC; wire GND; assign {VCC,GND} = {1'b1,1'b0}; - + generate if (WIDTH == 1) begin assign Y = ~A[0]; // Not need to spend 1 logic cell for such an easy function @@ -151,7 +151,7 @@ module \$lut (A, Y); TODO: There's not a just 7-input function on Cyclone V, see the following note: **Extended LUT Mode** Use extended LUT mode to implement a specific set of 7-input functions. The set must - be a 2-to-1 multiplexer fed by two arbitrary 5-input functions sharing four inputs. + be a 2-to-1 multiplexer fed by two arbitrary 5-input functions sharing four inputs. [source](Device Interfaces and Integration Basics for Cyclone V Devices). end*/ else diff --git a/techlibs/intel/cyclonev/cells_sim.v b/techlibs/intel/cyclonev/cells_sim.v index 5ecdabcfc..9b2a10e72 100644 --- a/techlibs/intel/cyclonev/cells_sim.v +++ b/techlibs/intel/cyclonev/cells_sim.v @@ -54,7 +54,7 @@ module cyclonev_lcell_comb // Internal variables // Sub mask for fragmented LUTs wire [15:0] mask_a, mask_b, mask_c, mask_d; - // Independant output for fragmented LUTs + // Independent output for fragmented LUTs wire output_0, output_1, output_2, output_3; // Extended mode uses mux to define the output wire mux_0, mux_1; @@ -85,7 +85,7 @@ module cyclonev_lcell_comb begin upper_lut_value = lut4(mask[31:16], dataa, datab, datac, datad); lower_lut_value = lut4(mask[15:0], dataa, datab, datac, datad); - lut5 = (datae) ? upper_mask_value : lower_mask_value; + lut5 = (datae) ? upper_lut_value : lower_lut_value; end endfunction // lut5 @@ -95,15 +95,16 @@ module cyclonev_lcell_comb input dataa, datab, datac, datad, datae, dataf; reg upper_lut_value; reg lower_lut_value; + reg out_0, out_1, out_2, out_3; begin upper_lut_value = lut5(mask[63:32], dataa, datab, datac, datad, datae); lower_lut_value = lut5(mask[31:0], dataa, datab, datac, datad, datae); - lut6 = (dataf) ? upper_mask_value : lower_mask_value; + lut6 = (dataf) ? upper_lut_value : lower_lut_value; end endfunction // lut6 assign {mask_a, mask_b, mask_c, mask_d} = {lut_mask[15:0], lut_mask[31:16], lut_mask[47:32], lut_mask[63:48]}; - +`ifdef ADVANCED_ALM always @(*) begin if(extended_lut == "on") shared_lut_alm = datag; @@ -115,6 +116,11 @@ module cyclonev_lcell_comb out_2 = lut4(mask_c, dataa, datab, datac, datad); out_3 = lut4(mask_d, dataa, datab, shared_lut_alm, datad); end +`else + `ifdef DEBUG + initial $display("Advanced ALM lut combine is not implemented yet"); + `endif +`endif endmodule // cyclonev_lcell_comb diff --git a/techlibs/intel/synth_intel.cc b/techlibs/intel/synth_intel.cc index c51949bd4..e5dc1adc7 100644 --- a/techlibs/intel/synth_intel.cc +++ b/techlibs/intel/synth_intel.cc @@ -17,254 +17,237 @@ * */ -#include "kernel/register.h" #include "kernel/celltypes.h" -#include "kernel/rtlil.h" #include "kernel/log.h" +#include "kernel/register.h" +#include "kernel/rtlil.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN struct SynthIntelPass : public ScriptPass { - SynthIntelPass() : ScriptPass("synth_intel", "synthesis for Intel (Altera) FPGAs.") { } - - virtual void help() YS_OVERRIDE - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" synth_intel [options]\n"); - log("\n"); - log("This command runs synthesis for Intel FPGAs.\n"); - log("\n"); - log(" -family < max10 | a10gx | cyclone10 | cyclonev | cycloneiv | cycloneive>\n"); - log(" generate the synthesis netlist for the specified family.\n"); - log(" MAX10 is the default target if not family argument specified.\n"); - log(" For Cyclone GX devices, use cycloneiv argument; For Cyclone E, use cycloneive.\n"); - log(" Cyclone V and Arria 10 GX devices are experimental, use it with a10gx argument.\n"); - log("\n"); - log(" -top <module>\n"); - log(" use the specified module as top module (default='top')\n"); - log("\n"); - log(" -vqm <file>\n"); - log(" write the design to the specified Verilog Quartus Mapping File. Writing of an\n"); - log(" output file is omitted if this parameter is not specified.\n"); - log("\n"); - log(" -vpr <file>\n"); - log(" write BLIF files for VPR flow experiments. The synthesized BLIF output file is not\n"); - log(" compatible with the Quartus flow. Writing of an\n"); - log(" output file is omitted if this parameter is not specified.\n"); - log("\n"); - log(" -run <from_label>:<to_label>\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"); - log(" synonymous to the end of the command list.\n"); - log("\n"); - log(" -noiopads\n"); - log(" do not use altsyncram cells in output netlist\n"); - log("\n"); - log(" -nobram\n"); - log(" do not use altsyncram cells in output netlist\n"); - log("\n"); - log(" -noflatten\n"); - log(" do not flatten design before synthesis\n"); - log("\n"); - log(" -retime\n"); - log(" run 'abc' with -dff option\n"); - log("\n"); - log("The following commands are executed by this synthesis command:\n"); - help_script(); - log("\n"); - } - - string top_opt, family_opt, vout_file, blif_file; - bool retime, flatten, nobram, noiopads; - - virtual void clear_flags() YS_OVERRIDE - { - top_opt = "-auto-top"; - family_opt = "max10"; - vout_file = ""; - blif_file = ""; - retime = false; - flatten = true; - nobram = false; - noiopads = false; - } - - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE - { - string run_from, run_to; - clear_flags(); - - size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) - { - if (args[argidx] == "-family" && argidx+1 < args.size()) { - family_opt = args[++argidx]; - continue; - } - if (args[argidx] == "-top" && argidx+1 < args.size()) { - top_opt = "-top " + args[++argidx]; - continue; - } - if (args[argidx] == "-vqm" && argidx+1 < args.size()) { - vout_file = args[++argidx]; - continue; - } - if (args[argidx] == "-vpr" && argidx+1 < args.size()) { - blif_file = args[++argidx]; - continue; - } - if (args[argidx] == "-run" && argidx+1 < args.size()) { - size_t pos = args[argidx+1].find(':'); - if (pos == std::string::npos) - break; - run_from = args[++argidx].substr(0, pos); - run_to = args[argidx].substr(pos+1); - continue; - } - if (args[argidx] == "-noiopads") { - noiopads = true; - continue; - } - if (args[argidx] == "-nobram") { - nobram = true; - continue; - } - if (args[argidx] == "-flatten") { - flatten = true; - continue; - } - if (args[argidx] == "-retime") { - retime = true; - continue; - } - break; - } - extra_args(args, argidx, design); - - if (!design->full_selection()) - log_cmd_error("This command only operates on fully selected designs!\n"); - if (family_opt != "max10" && family_opt !="a10gx" && family_opt != "cyclonev" && family_opt !="cycloneiv" && family_opt !="cycloneive" && family_opt != "cyclone10") - log_cmd_error("Invalid or not family specified: '%s'\n", family_opt.c_str()); - - log_header(design, "Executing SYNTH_INTEL pass.\n"); - log_push(); - - run_script(design, run_from, run_to); - - log_pop(); - } - - virtual void script() YS_OVERRIDE - { - if (check_label("begin")) - { - if(check_label("family") && family_opt=="max10") - run("read_verilog -sv -lib +/intel/max10/cells_sim.v"); - else if(check_label("family") && family_opt=="a10gx") - run("read_verilog -sv -lib +/intel/a10gx/cells_sim.v"); - else if(check_label("family") && family_opt=="cyclonev") - run("read_verilog -sv -lib +/intel/cyclonev/cells_sim.v"); - else if(check_label("family") && family_opt=="cyclone10") - run("read_verilog -sv -lib +/intel/cyclone10/cells_sim.v"); - else if(check_label("family") && family_opt=="cycloneiv") - run("read_verilog -sv -lib +/intel/cycloneiv/cells_sim.v"); - else - run("read_verilog -sv -lib +/intel/cycloneive/cells_sim.v"); - // Misc and common cells - run("read_verilog -sv -lib +/intel/common/m9k_bb.v"); - run("read_verilog -sv -lib +/intel/common/altpll_bb.v"); - run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str())); - } - - if (flatten && check_label("flatten", "(unless -noflatten)")) - { - run("proc"); - run("flatten"); - run("tribuf -logic"); - run("deminout"); - } - - if (check_label("coarse")) - { - run("synth -run coarse"); - } - - if (!nobram && check_label("bram", "(skip if -nobram)")) - { - run("memory_bram -rules +/intel/common/brams.txt"); - run("techmap -map +/intel/common/brams_map.v"); - } - - if (check_label("fine")) - { - run("opt -fast -mux_undef -undriven -fine -full"); - run("memory_map"); - run("opt -undriven -fine"); - run("dffsr2dff"); - run("dff2dffe -direct-match $_DFF_*"); - run("opt -fine"); - run("techmap -map +/techmap.v"); - run("opt -full"); - run("clean -purge"); - run("setundef -undriven -zero"); - if (retime || help_mode) - run("abc -markgroups -dff", "(only if -retime)"); - } - - if (check_label("map_luts")) - { - if(family_opt=="a10gx" || family_opt=="cyclonev") - run("abc -luts 2:2,3,6:5" + string(retime ? " -dff" : "")); - else - run("abc -lut 4" + string(retime ? " -dff" : "")); - run("clean"); - } - - if (check_label("map_cells")) - { - if (!noiopads) - run("iopadmap -bits -outpad $__outpad I:O -inpad $__inpad O:I", "(unless -noiopads)"); - if(family_opt=="max10") - run("techmap -map +/intel/max10/cells_map.v"); - else if(family_opt=="a10gx") - run("techmap -map +/intel/a10gx/cells_map.v"); - else if(family_opt=="cyclonev") - run("techmap -map +/intel/cyclonev/cells_map.v"); - else if(family_opt=="cyclone10") - run("techmap -map +/intel/cyclone10/cells_map.v"); - else if(family_opt=="cycloneiv") - run("techmap -map +/intel/cycloneiv/cells_map.v"); - else - run("techmap -map +/intel/cycloneive/cells_map.v"); - run("dffinit -highlow -ff dffeas q power_up"); - run("clean -purge"); - } - - if (check_label("check")) - { - run("hierarchy -check"); - run("stat"); - run("check -noinit"); - } - - if (check_label("vqm")) - { - if (!vout_file.empty() || help_mode) - run(stringf("write_verilog -attr2comment -defparam -nohex -decimal -renameprefix syn_ %s", - help_mode ? "<file-name>" : vout_file.c_str())); - } - - if (check_label("vpr")) - { - if (!blif_file.empty() || help_mode) - { - run(stringf("opt_clean -purge")); - run(stringf("write_blif %s", help_mode ? "<file-name>" : blif_file.c_str())); - } - } - } + SynthIntelPass() : ScriptPass("synth_intel", "synthesis for Intel (Altera) FPGAs.") {} + + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" synth_intel [options]\n"); + log("\n"); + log("This command runs synthesis for Intel FPGAs.\n"); + log("\n"); + log(" -family < max10 | a10gx | cyclone10 | cyclonev | cycloneiv | cycloneive>\n"); + log(" generate the synthesis netlist for the specified family.\n"); + log(" MAX10 is the default target if no family argument specified.\n"); + log(" For Cyclone GX devices, use cycloneiv argument; For Cyclone E, use cycloneive.\n"); + log(" Cyclone V and Arria 10 GX devices are experimental.\n"); + log("\n"); + log(" -top <module>\n"); + log(" use the specified module as top module (default='top')\n"); + log("\n"); + log(" -vqm <file>\n"); + log(" write the design to the specified Verilog Quartus Mapping File. Writing of an\n"); + log(" output file is omitted if this parameter is not specified.\n"); + log(" Note that this backend has not been tested and is likely incompatible\n"); + log(" with recent versions of Quartus.\n"); + log("\n"); + log(" -vpr <file>\n"); + log(" write BLIF files for VPR flow experiments. The synthesized BLIF output file is not\n"); + log(" compatible with the Quartus flow. Writing of an\n"); + log(" output file is omitted if this parameter is not specified.\n"); + log("\n"); + log(" -run <from_label>:<to_label>\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"); + log(" synonymous to the end of the command list.\n"); + log("\n"); + log(" -iopads\n"); + log(" use IO pad cells in output netlist\n"); + log("\n"); + log(" -nobram\n"); + log(" do not use block RAM cells in output netlist\n"); + log("\n"); + log(" -noflatten\n"); + log(" do not flatten design before synthesis\n"); + log("\n"); + log(" -retime\n"); + log(" run 'abc' with -dff option\n"); + log("\n"); + log("The following commands are executed by this synthesis command:\n"); + help_script(); + log("\n"); + } + + string top_opt, family_opt, vout_file, blif_file; + bool retime, flatten, nobram, iopads; + + void clear_flags() YS_OVERRIDE + { + top_opt = "-auto-top"; + family_opt = "max10"; + vout_file = ""; + blif_file = ""; + retime = false; + flatten = true; + nobram = false; + iopads = false; + } + + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + string run_from, run_to; + clear_flags(); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + if (args[argidx] == "-family" && argidx + 1 < args.size()) { + family_opt = args[++argidx]; + continue; + } + if (args[argidx] == "-top" && argidx + 1 < args.size()) { + top_opt = "-top " + args[++argidx]; + continue; + } + if (args[argidx] == "-vqm" && argidx + 1 < args.size()) { + vout_file = args[++argidx]; + log_warning("The Quartus backend has not been tested recently and is likely incompatible with modern versions of Quartus.\n"); + continue; + } + if (args[argidx] == "-vpr" && argidx + 1 < args.size()) { + blif_file = args[++argidx]; + continue; + } + if (args[argidx] == "-run" && argidx + 1 < args.size()) { + size_t pos = args[argidx + 1].find(':'); + if (pos == std::string::npos) + break; + run_from = args[++argidx].substr(0, pos); + run_to = args[argidx].substr(pos + 1); + continue; + } + if (args[argidx] == "-iopads") { + iopads = true; + continue; + } + if (args[argidx] == "-nobram") { + nobram = true; + continue; + } + if (args[argidx] == "-noflatten") { + flatten = false; + continue; + } + if (args[argidx] == "-retime") { + retime = true; + continue; + } + break; + } + extra_args(args, argidx, design); + + if (!design->full_selection()) + log_cmd_error("This command only operates on fully selected designs!\n"); + if (family_opt != "max10" && + family_opt != "a10gx" && + family_opt != "cyclonev" && + family_opt != "cycloneiv" && + family_opt != "cycloneive" && + family_opt != "cyclone10") + log_cmd_error("Invalid or no family specified: '%s'\n", family_opt.c_str()); + + log_header(design, "Executing SYNTH_INTEL pass.\n"); + log_push(); + + run_script(design, run_from, run_to); + + log_pop(); + } + + void script() YS_OVERRIDE + { + if (check_label("begin")) { + if (check_label("family")) + run(stringf("read_verilog -sv -lib +/intel/%s/cells_sim.v", family_opt.c_str())); + + // Misc and common cells + run("read_verilog -sv -lib +/intel/common/m9k_bb.v"); + run("read_verilog -sv -lib +/intel/common/altpll_bb.v"); + run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str())); + } + + if (flatten && check_label("flatten", "(unless -noflatten)")) { + run("proc"); + run("flatten"); + run("tribuf -logic"); + run("deminout"); + } + + if (check_label("coarse")) { + run("synth -run coarse"); + } + + if (!nobram && check_label("map_bram", "(skip if -nobram)")) { + if (family_opt == "cycloneiv" || + family_opt == "cycloneive" || + family_opt == "max10" || + help_mode) { + run("memory_bram -rules +/intel/common/brams_m9k.txt", "(if applicable for family)"); + run("techmap -map +/intel/common/brams_map_m9k.v", "(if applicable for family)"); + } else { + log_warning("BRAM mapping is not currently supported for %s.\n", family_opt.c_str()); + } + } + + if (check_label("map_ffram")) { + run("opt -fast -mux_undef -undriven -fine -full"); + run("memory_map"); + run("opt -undriven -fine"); + run("dffsr2dff"); + run("dff2dffe -direct-match $_DFF_*"); + run("opt -fine"); + run("techmap -map +/techmap.v"); + run("opt -full"); + run("clean -purge"); + run("setundef -undriven -zero"); + if (retime || help_mode) + run("abc -markgroups -dff", "(only if -retime)"); + } + + if (check_label("map_luts")) { + if (family_opt == "a10gx" || family_opt == "cyclonev") + run("abc -luts 2:2,3,6:5" + string(retime ? " -dff" : "")); + else + run("abc -lut 4" + string(retime ? " -dff" : "")); + run("clean"); + } + + if (check_label("map_cells")) { + if (iopads || help_mode) + run("iopadmap -bits -outpad $__outpad I:O -inpad $__inpad O:I", "(if -iopads)"); + run(stringf("techmap -map +/intel/%s/cells_map.v", family_opt.c_str())); + run("dffinit -highlow -ff dffeas q power_up"); + run("clean -purge"); + } + + if (check_label("check")) { + run("hierarchy -check"); + run("stat"); + run("check -noinit"); + } + + if (check_label("vqm")) { + if (!vout_file.empty() || help_mode) + run(stringf("write_verilog -attr2comment -defparam -nohex -decimal -renameprefix syn_ %s", + help_mode ? "<file-name>" : vout_file.c_str())); + } + + if (check_label("vpr")) { + if (!blif_file.empty() || help_mode) { + run(stringf("opt_clean -purge")); + run(stringf("write_blif %s", help_mode ? "<file-name>" : blif_file.c_str())); + } + } + } } SynthIntelPass; PRIVATE_NAMESPACE_END diff --git a/techlibs/sf2/Makefile.inc b/techlibs/sf2/Makefile.inc new file mode 100644 index 000000000..cc3054ace --- /dev/null +++ b/techlibs/sf2/Makefile.inc @@ -0,0 +1,8 @@ + +OBJS += techlibs/sf2/synth_sf2.o +OBJS += techlibs/sf2/sf2_iobs.o + +$(eval $(call add_share_file,share/sf2,techlibs/sf2/arith_map.v)) +$(eval $(call add_share_file,share/sf2,techlibs/sf2/cells_map.v)) +$(eval $(call add_share_file,share/sf2,techlibs/sf2/cells_sim.v)) + diff --git a/techlibs/sf2/arith_map.v b/techlibs/sf2/arith_map.v new file mode 100644 index 000000000..462d3ce50 --- /dev/null +++ b/techlibs/sf2/arith_map.v @@ -0,0 +1,21 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * + * 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. + * + */ + + +// nothing here yet diff --git a/techlibs/sf2/cells_map.v b/techlibs/sf2/cells_map.v new file mode 100644 index 000000000..6ad7807d2 --- /dev/null +++ b/techlibs/sf2/cells_map.v @@ -0,0 +1,82 @@ +module \$_DFF_N_ (input D, C, output Q); + SLE _TECHMAP_REPLACE_ (.D(D), .CLK(!C), .EN(1'b1), .ALn(1'b1), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q)); +endmodule + +module \$_DFF_P_ (input D, C, output Q); + SLE _TECHMAP_REPLACE_ (.D(D), .CLK(C), .EN(1'b1), .ALn(1'b1), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q)); +endmodule + +module \$_DFF_NN0_ (input D, C, R, output Q); + SLE _TECHMAP_REPLACE_ (.D(D), .CLK(!C), .EN(1'b1), .ALn(R), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q)); +endmodule + +module \$_DFF_NN1_ (input D, C, R, output Q); + SLE _TECHMAP_REPLACE_ (.D(D), .CLK(!C), .EN(1'b1), .ALn(R), .ADn(1'b0), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q)); +endmodule + +module \$_DFF_NP0_ (input D, C, R, output Q); + SLE _TECHMAP_REPLACE_ (.D(D), .CLK(!C), .EN(1'b1), .ALn(!R), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q)); +endmodule + +module \$_DFF_NP1_ (input D, C, R, output Q); + SLE _TECHMAP_REPLACE_ (.D(D), .CLK(!C), .EN(1'b1), .ALn(!R), .ADn(1'b0), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q)); +endmodule + +module \$_DFF_PN0_ (input D, C, R, output Q); + SLE _TECHMAP_REPLACE_ (.D(D), .CLK(C), .EN(1'b1), .ALn(R), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q)); +endmodule + +module \$_DFF_PN1_ (input D, C, R, output Q); + SLE _TECHMAP_REPLACE_ (.D(D), .CLK(C), .EN(1'b1), .ALn(R), .ADn(1'b0), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q)); +endmodule + +module \$_DFF_PP0_ (input D, C, R, output Q); + SLE _TECHMAP_REPLACE_ (.D(D), .CLK(C), .EN(1'b1), .ALn(!R), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q)); +endmodule + +module \$_DFF_PP1_ (input D, C, R, output Q); + SLE _TECHMAP_REPLACE_ (.D(D), .CLK(C), .EN(1'b1), .ALn(!R), .ADn(1'b0), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q)); +endmodule + +// module \$_DFFE_NN_ (input D, C, E, output Q); SB_DFFNE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(!E)); endmodule +// module \$_DFFE_PN_ (input D, C, E, output Q); SB_DFFE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(!E)); endmodule +// +// module \$_DFFE_NP_ (input D, C, E, output Q); SB_DFFNE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E)); endmodule +// module \$_DFFE_PP_ (input D, C, E, output Q); SB_DFFE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E)); endmodule +// +// module \$__DFFE_NN0 (input D, C, E, R, output Q); SB_DFFNER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(!R)); endmodule +// module \$__DFFE_NN1 (input D, C, E, R, output Q); SB_DFFNES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(!R)); endmodule +// module \$__DFFE_PN0 (input D, C, E, R, output Q); SB_DFFER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(!R)); endmodule +// module \$__DFFE_PN1 (input D, C, E, R, output Q); SB_DFFES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(!R)); endmodule +// +// module \$__DFFE_NP0 (input D, C, E, R, output Q); SB_DFFNER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(R)); endmodule +// module \$__DFFE_NP1 (input D, C, E, R, output Q); SB_DFFNES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(R)); endmodule +// module \$__DFFE_PP0 (input D, C, E, R, output Q); SB_DFFER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(R)); endmodule +// module \$__DFFE_PP1 (input D, C, E, R, output Q); SB_DFFES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(R)); endmodule + +`ifndef NO_LUT +module \$lut (A, Y); + parameter WIDTH = 0; + parameter LUT = 0; + + input [WIDTH-1:0] A; + output Y; + + generate + if (WIDTH == 1) begin + CFG1 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.Y(Y), .A(A[0])); + end else + if (WIDTH == 2) begin + CFG2 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.Y(Y), .A(A[0]), .B(A[1])); + end else + if (WIDTH == 3) begin + CFG3 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.Y(Y), .A(A[0]), .B(A[1]), .C(A[2])); + end else + if (WIDTH == 4) begin + CFG4 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.Y(Y), .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); + end else begin + wire _TECHMAP_FAIL_ = 1; + end + endgenerate +endmodule +`endif diff --git a/techlibs/sf2/cells_sim.v b/techlibs/sf2/cells_sim.v new file mode 100644 index 000000000..c62748b11 --- /dev/null +++ b/techlibs/sf2/cells_sim.v @@ -0,0 +1,327 @@ +// https://coredocs.s3.amazonaws.com/Libero/12_0_0/Tool/sf2_mlg.pdf + +module ADD2 ( + + input A, B, + output Y +); + assign Y = A & B; +endmodule + +module ADD3 ( + input A, B, C, + output Y +); + assign Y = A & B & C; +endmodule + +module ADD4 ( + input A, B, C, D, + output Y +); + assign Y = A & B & C & D; +endmodule + +module CFG1 ( + output Y, + input A +); + parameter [1:0] INIT = 2'h0; + assign Y = INIT >> A; +endmodule + +module CFG2 ( + output Y, + input A, + input B +); + parameter [3:0] INIT = 4'h0; + assign Y = INIT >> {B, A}; +endmodule + +module CFG3 ( + output Y, + input A, + input B, + input C +); + parameter [7:0] INIT = 8'h0; + assign Y = INIT >> {C, B, A}; +endmodule + +module CFG4 ( + output Y, + input A, + input B, + input C, + input D +); + parameter [15:0] INIT = 16'h0; + assign Y = INIT >> {D, C, B, A}; +endmodule + +module BUFF ( + input A, + output Y +); + assign Y = A; +endmodule + +module BUFD ( + input A, + output Y +); + assign Y = A; +endmodule + +module CLKINT ( + input A, + output Y +); + assign Y = A; +endmodule + +module CLKINT_PRESERVE ( + input A, + output Y +); + assign Y = A; +endmodule + +module GCLKINT ( + input A, EN, + output Y +); + assign Y = A & EN; +endmodule + +module RCLKINT ( + input A, + output Y +); + assign Y = A; +endmodule + +module RGCLKINT ( + input A, EN, + output Y +); + assign Y = A & EN; +endmodule + +module SLE ( + output Q, + input ADn, + input ALn, + input CLK, + input D, + input LAT, + input SD, + input EN, + input SLn +); + reg q_latch, q_ff; + + always @(posedge CLK, negedge ALn) begin + if (!ALn) begin + q_ff <= !ADn; + end else if (EN) begin + if (!SLn) + q_ff <= SD; + else + q_ff <= D; + end + end + + always @* begin + if (!ALn) begin + q_latch <= !ADn; + end else if (CLK && EN) begin + if (!SLn) + q_ff <= SD; + else + q_ff <= D; + end + end + + assign Q = LAT ? q_latch : q_ff; +endmodule + +// module AR1 +// module FCEND_BUFF +// module FCINIT_BUFF +// module FLASH_FREEZE +// module OSCILLATOR +// module SYSRESET +// module SYSCTRL_RESET_STATUS +// module LIVE_PROBE_FB +// module GCLKBUF +// module GCLKBUF_DIFF +// module GCLKBIBUF +// module DFN1 +// module DFN1C0 +// module DFN1E1 +// module DFN1E1C0 +// module DFN1E1P0 +// module DFN1P0 +// module DLN1 +// module DLN1C0 +// module DLN1P0 + +module INV ( + input A, + output Y +); + assign Y = !A; +endmodule + +module INVD ( + input A, + output Y +); + assign Y = !A; +endmodule + +module MX2 ( + input A, B, S, + output Y +); + assign Y = S ? B : A; +endmodule + +module MX4 ( + input D0, D1, D2, D3, S0, S1, + output Y +); + assign Y = S1 ? (S0 ? D3 : D2) : (S0 ? D1 : D0); +endmodule + +module NAND2 ( + input A, B, + output Y +); + assign Y = !(A & B); +endmodule + +module NAND3 ( + input A, B, C, + output Y +); + assign Y = !(A & B & C); +endmodule + +module NAND4 ( + input A, B, C, D, + output Y +); + assign Y = !(A & B & C & D); +endmodule + +module NOR2 ( + input A, B, + output Y +); + assign Y = !(A | B); +endmodule + +module NOR3 ( + input A, B, C, + output Y +); + assign Y = !(A | B | C); +endmodule + +module NOR4 ( + input A, B, C, D, + output Y +); + assign Y = !(A | B | C | D); +endmodule + +module OR2 ( + input A, B, + output Y +); + assign Y = A | B; +endmodule + +module OR3 ( + input A, B, C, + output Y +); + assign Y = A | B | C; +endmodule + +module OR4 ( + input A, B, C, D, + output Y +); + assign Y = A | B | C | D; +endmodule + +module XOR2 ( + input A, B, + output Y +); + assign Y = A ^ B; +endmodule + +module XOR3 ( + input A, B, C, + output Y +); + assign Y = A ^ B ^ C; +endmodule + +module XOR4 ( + input A, B, C, D, + output Y +); + assign Y = A ^ B ^ C ^ D; +endmodule + +module XOR8 ( + input A, B, C, D, E, F, G, H, + output Y +); + assign Y = A ^ B ^ C ^ D ^ E ^ F ^ G ^ H; +endmodule + +// module UJTAG +// module BIBUF +// module BIBUF_DIFF +// module CLKBIBUF + +module CLKBUF ( + input PAD, + output Y +); + assign Y = PAD; +endmodule + +// module CLKBUF_DIFF + +module INBUF ( + input PAD, + output Y +); + assign Y = PAD; +endmodule + +// module INBUF_DIFF + +module OUTBUF ( + input D, + output PAD +); + assign PAD = D; +endmodule + +// module OUTBUF_DIFF +// module TRIBUFF +// module TRIBUFF_DIFF +// module DDR_IN +// module DDR_OUT +// module RAM1K18 +// module RAM64x18 +// module MACC diff --git a/techlibs/sf2/sf2_iobs.cc b/techlibs/sf2/sf2_iobs.cc new file mode 100644 index 000000000..3d43332e2 --- /dev/null +++ b/techlibs/sf2/sf2_iobs.cc @@ -0,0 +1,197 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * + * 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 + +static void handle_iobufs(Module *module, bool clkbuf_mode) +{ + SigMap sigmap(module); + + pool<SigBit> clk_bits; + pool<SigBit> handled_io_bits; + dict<SigBit, SigBit> rewrite_bits; + vector<pair<Cell*, SigBit>> pad_bits; + + for (auto cell : module->cells()) + { + if (clkbuf_mode && cell->type == "\\SLE") { + for (auto bit : sigmap(cell->getPort("\\CLK"))) + clk_bits.insert(bit); + } + if (cell->type.in("\\INBUF", "\\OUTBUF", "\\TRIBUFF", "\\BIBUF", "\\CLKBUF", "\\CLKBIBUF", + "\\INBUF_DIFF", "\\OUTBUF_DIFF", "\\BIBUFF_DIFF", "\\TRIBUFF_DIFF", "\\CLKBUF_DIFF", + "\\GCLKBUF", "\\GCLKBUF_DIFF", "\\GCLKBIBUF")) { + for (auto bit : sigmap(cell->getPort("\\PAD"))) + handled_io_bits.insert(bit); + } + } + + for (auto wire : vector<Wire*>(module->wires())) + { + if (!wire->port_input && !wire->port_output) + continue; + + for (int index = 0; index < GetSize(wire); index++) + { + SigBit bit(wire, index); + SigBit canonical_bit = sigmap(bit); + + if (handled_io_bits.count(canonical_bit)) + continue; + + if (wire->port_input && wire->port_output) + log_error("Failed to add buffer for inout port bit %s.\n", log_signal(bit)); + + IdString buf_type, buf_port; + + if (wire->port_output) { + buf_type = "\\OUTBUF"; + buf_port = "\\D"; + } else if (clkbuf_mode && clk_bits.count(canonical_bit)) { + buf_type = "\\CLKBUF"; + buf_port = "\\Y"; + } else { + buf_type = "\\INBUF"; + buf_port = "\\Y"; + } + + Cell *c = module->addCell(NEW_ID, buf_type); + SigBit new_bit = module->addWire(NEW_ID); + c->setPort(buf_port, new_bit); + pad_bits.push_back(make_pair(c, bit)); + rewrite_bits[canonical_bit] = new_bit; + + log("Added %s cell %s for port bit %s.\n", log_id(c->type), log_id(c), log_signal(bit)); + } + } + + auto rewrite_function = [&](SigSpec &s) { + for (auto &bit : s) { + SigBit canonical_bit = sigmap(bit); + if (rewrite_bits.count(canonical_bit)) + bit = rewrite_bits.at(canonical_bit); + } + }; + + module->rewrite_sigspecs(rewrite_function); + + for (auto &it : pad_bits) + it.first->setPort("\\PAD", it.second); +} + +static void handle_clkint(Module *module) +{ + SigMap sigmap(module); + + pool<SigBit> clk_bits; + vector<SigBit> handled_clk_bits; + + for (auto cell : module->cells()) + { + if (cell->type == "\\SLE") { + for (auto bit : sigmap(cell->getPort("\\CLK"))) + clk_bits.insert(bit); + } + if (cell->type.in("\\CLKBUF", "\\CLKBIBUF", "\\CLKBUF_DIFF", "\\GCLKBUF", "\\GCLKBUF_DIFF", "\\GCLKBIBUF", + "\\CLKINT", "\\CLKINT_PRESERVE", "\\GCLKINT", "\\RCLKINT", "\\RGCLKINT")) { + for (auto bit : sigmap(cell->getPort("\\Y"))) + handled_clk_bits.push_back(bit); + } + } + + for (auto bit : handled_clk_bits) + clk_bits.erase(bit); + + for (auto cell : vector<Cell*>(module->cells())) + for (auto &conn : cell->connections()) + { + if (!cell->output(conn.first)) + continue; + + SigSpec sig = conn.second; + bool did_something = false; + + for (auto &bit : sig) { + SigBit canonical_bit = sigmap(bit); + if (clk_bits.count(canonical_bit)) { + Cell *c = module->addCell(NEW_ID, "\\CLKINT"); + SigBit new_bit = module->addWire(NEW_ID); + c->setPort("\\A", new_bit); + c->setPort("\\Y", bit); + log("Added %s cell %s for clock signal %s.\n", log_id(c->type), log_id(c), log_signal(bit)); + clk_bits.erase(canonical_bit); + did_something = true; + bit = new_bit; + } + } + + if (did_something) + cell->setPort(conn.first, sig); + } + + for (auto bit : clk_bits) + log_error("Failed to insert CLKINT for clock signal %s.\n", log_signal(bit)); +} + +struct Sf2IobsPass : public Pass { + Sf2IobsPass() : Pass("sf2_iobs", "SF2: insert IO buffers") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" sf2_iobs [options] [selection]\n"); + log("\n"); + log("Add SF2 I/O buffers and global buffers to top module as needed.\n"); + log("\n"); + log(" -clkbuf\n"); + log(" Insert PAD->global_net clock buffers\n"); + log("\n"); + } + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + bool clkbuf_mode = false; + + log_header(design, "Executing sf2_iobs pass (insert IO buffers).\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + if (args[argidx] == "-clkbuf") { + clkbuf_mode = true; + continue; + } + break; + } + extra_args(args, argidx, design); + + Module *module = design->top_module(); + + if (module == nullptr) + log_cmd_error("No top module found.\n"); + + handle_iobufs(module, clkbuf_mode); + handle_clkint(module); + } +} Sf2IobsPass; + +PRIVATE_NAMESPACE_END diff --git a/techlibs/sf2/synth_sf2.cc b/techlibs/sf2/synth_sf2.cc new file mode 100644 index 000000000..0924df7a6 --- /dev/null +++ b/techlibs/sf2/synth_sf2.cc @@ -0,0 +1,246 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * + * 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/register.h" +#include "kernel/celltypes.h" +#include "kernel/rtlil.h" +#include "kernel/log.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct SynthSf2Pass : public ScriptPass +{ + SynthSf2Pass() : ScriptPass("synth_sf2", "synthesis for SmartFusion2 and IGLOO2 FPGAs") { } + + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" synth_sf2 [options]\n"); + log("\n"); + log("This command runs synthesis for SmartFusion2 and IGLOO2 FPGAs.\n"); + log("\n"); + log(" -top <module>\n"); + log(" use the specified module as top module\n"); + log("\n"); + log(" -edif <file>\n"); + log(" write the design to the specified EDIF file. writing of an output file\n"); + log(" is omitted if this parameter is not specified.\n"); + log("\n"); + log(" -vlog <file>\n"); + log(" write the design to the specified Verilog file. writing of an output file\n"); + log(" is omitted if this parameter is not specified.\n"); + log("\n"); + log(" -json <file>\n"); + log(" write the design to the specified JSON file. writing of an output file\n"); + log(" is omitted if this parameter is not specified.\n"); + log("\n"); + log(" -run <from_label>:<to_label>\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"); + log(" synonymous to the end of the command list.\n"); + log("\n"); + log(" -noflatten\n"); + log(" do not flatten design before synthesis\n"); + log("\n"); + log(" -noiobs\n"); + log(" run synthesis in \"block mode\", i.e. do not insert IO buffers\n"); + log("\n"); + log(" -clkbuf\n"); + log(" insert direct PAD->global_net buffers\n"); + log("\n"); + log(" -retime\n"); + log(" run 'abc' with -dff option\n"); + log("\n"); + log("\n"); + log("The following commands are executed by this synthesis command:\n"); + help_script(); + log("\n"); + } + + string top_opt, edif_file, vlog_file, json_file; + bool flatten, retime, iobs, clkbuf; + + void clear_flags() YS_OVERRIDE + { + top_opt = "-auto-top"; + edif_file = ""; + vlog_file = ""; + json_file = ""; + flatten = true; + retime = false; + iobs = true; + clkbuf = false; + } + + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + string run_from, run_to; + clear_flags(); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + if (args[argidx] == "-top" && argidx+1 < args.size()) { + top_opt = "-top " + args[++argidx]; + continue; + } + if (args[argidx] == "-edif" && argidx+1 < args.size()) { + edif_file = args[++argidx]; + continue; + } + if (args[argidx] == "-vlog" && argidx+1 < args.size()) { + vlog_file = args[++argidx]; + continue; + } + if (args[argidx] == "-json" && argidx+1 < args.size()) { + json_file = args[++argidx]; + continue; + } + if (args[argidx] == "-run" && argidx+1 < args.size()) { + size_t pos = args[argidx+1].find(':'); + if (pos == std::string::npos) + break; + run_from = args[++argidx].substr(0, pos); + run_to = args[argidx].substr(pos+1); + continue; + } + if (args[argidx] == "-noflatten") { + flatten = false; + continue; + } + if (args[argidx] == "-retime") { + retime = true; + continue; + } + if (args[argidx] == "-noiobs") { + iobs = false; + continue; + } + if (args[argidx] == "-clkbuf") { + clkbuf = true; + continue; + } + break; + } + extra_args(args, argidx, design); + + if (!design->full_selection()) + log_cmd_error("This command only operates on fully selected designs!\n"); + + log_header(design, "Executing SYNTH_SF2 pass.\n"); + log_push(); + + run_script(design, run_from, run_to); + + log_pop(); + } + + void script() YS_OVERRIDE + { + if (check_label("begin")) + { + run("read_verilog -lib +/sf2/cells_sim.v"); + run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str())); + } + + if (flatten && check_label("flatten", "(unless -noflatten)")) + { + run("proc"); + run("flatten"); + run("tribuf -logic"); + run("deminout"); + } + + if (check_label("coarse")) + { + run("synth -run coarse"); + } + + if (check_label("fine")) + { + run("opt -fast -mux_undef -undriven -fine"); + run("memory_map"); + run("opt -undriven -fine"); + run("techmap -map +/techmap.v -map +/sf2/arith_map.v"); + if (retime || help_mode) + run("abc -dff", "(only if -retime)"); + } + + if (check_label("map_ffs")) + { + run("dffsr2dff"); + run("techmap -D NO_LUT -map +/sf2/cells_map.v"); + run("opt_expr -mux_undef"); + run("simplemap"); + // run("sf2_ffinit"); + // run("sf2_ffssr"); + // run("sf2_opt -full"); + } + + if (check_label("map_luts")) + { + run("abc -lut 4"); + run("clean"); + } + + if (check_label("map_cells")) + { + run("techmap -map +/sf2/cells_map.v"); + run("clean"); + } + + if (check_label("map_iobs")) + { + if (help_mode) + run("sf2_iobs [-clkbuf]", "(unless -noiobs)"); + else if (iobs) + run(clkbuf ? "sf2_iobs -clkbuf" : "sf2_iobs"); + run("clean"); + } + + if (check_label("check")) + { + run("hierarchy -check"); + run("stat"); + run("check -noinit"); + } + + if (check_label("edif")) + { + if (!edif_file.empty() || help_mode) + run(stringf("write_edif -gndvccy %s", help_mode ? "<file-name>" : edif_file.c_str())); + } + + if (check_label("vlog")) + { + if (!vlog_file.empty() || help_mode) + run(stringf("write_verilog %s", help_mode ? "<file-name>" : vlog_file.c_str())); + } + + if (check_label("json")) + { + if (!json_file.empty() || help_mode) + run(stringf("write_json %s", help_mode ? "<file-name>" : json_file.c_str())); + } + } +} SynthSf2Pass; + +PRIVATE_NAMESPACE_END diff --git a/techlibs/xilinx/Makefile.inc b/techlibs/xilinx/Makefile.inc index 887ea27d9..c26e1f4db 100644 --- a/techlibs/xilinx/Makefile.inc +++ b/techlibs/xilinx/Makefile.inc @@ -5,6 +5,8 @@ GENFILES += techlibs/xilinx/brams_init_36.vh GENFILES += techlibs/xilinx/brams_init_32.vh GENFILES += techlibs/xilinx/brams_init_18.vh GENFILES += techlibs/xilinx/brams_init_16.vh +GENFILES += techlibs/xilinx/brams_init_9.vh +GENFILES += techlibs/xilinx/brams_init_8.vh EXTRA_OBJS += techlibs/xilinx/brams_init.mk .SECONDARY: techlibs/xilinx/brams_init.mk @@ -18,20 +20,40 @@ techlibs/xilinx/brams_init_36.vh: techlibs/xilinx/brams_init.mk techlibs/xilinx/brams_init_32.vh: techlibs/xilinx/brams_init.mk techlibs/xilinx/brams_init_18.vh: techlibs/xilinx/brams_init.mk techlibs/xilinx/brams_init_16.vh: techlibs/xilinx/brams_init.mk +techlibs/xilinx/brams_init_9.vh: techlibs/xilinx/brams_init.mk +techlibs/xilinx/brams_init_8.vh: techlibs/xilinx/brams_init.mk $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/cells_map.v)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/cells_sim.v)) -$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/cells_xtra.v)) -$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/brams.txt)) -$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/brams_map.v)) -$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/brams_bb.v)) -$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/drams.txt)) -$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/drams_map.v)) +$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc6s_cells_xtra.v)) +$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc6v_cells_xtra.v)) +$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc7_cells_xtra.v)) +$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xcu_cells_xtra.v)) +$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc6s_brams.txt)) +$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc6s_brams_map.v)) +$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc6s_brams_bb.v)) +$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc7_brams.txt)) +$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc7_brams_map.v)) +$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc7_brams_bb.v)) +$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lutrams.txt)) +$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lutrams_map.v)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/arith_map.v)) -$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lut2lut.v)) +$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc6s_ff_map.v)) +$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc7_ff_map.v)) +$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lut_map.v)) +$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/mux_map.v)) + +$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc_map.v)) +$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc_unmap.v)) +$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc_model.v)) +$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc_xc7.box)) +$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc_xc7.lut)) +$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc_xc7_nowide.lut)) $(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_36.vh)) $(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_32.vh)) $(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_18.vh)) $(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_16.vh)) +$(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_9.vh)) +$(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_8.vh)) diff --git a/techlibs/xilinx/abc_map.v b/techlibs/xilinx/abc_map.v new file mode 100644 index 000000000..0c85d6656 --- /dev/null +++ b/techlibs/xilinx/abc_map.v @@ -0,0 +1,123 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * 2019 Eddie Hung <eddie@fpgeh.com> + * + * 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. + * + */ + +// ============================================================================ + +module RAM32X1D ( + output DPO, SPO, + input D, + input WCLK, + input WE, + input A0, A1, A2, A3, A4, + input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4 +); + parameter INIT = 32'h0; + parameter IS_WCLK_INVERTED = 1'b0; + wire \$DPO , \$SPO ; + RAM32X1D #( + .INIT(INIT), .IS_WCLK_INVERTED(IS_WCLK_INVERTED) + ) _TECHMAP_REPLACE_ ( + .DPO(\$DPO ), .SPO(\$SPO ), + .D(D), .WCLK(WCLK), .WE(WE), + .A0(A0), .A1(A1), .A2(A2), .A3(A3), .A4(A4), + .DPRA0(DPRA0), .DPRA1(DPRA1), .DPRA2(DPRA2), .DPRA3(DPRA3), .DPRA4(DPRA4) + ); + \$__ABC_LUT6 dpo (.A(\$DPO ), .S({1'b0, A0, A1, A2, A3, A4}), .Y(DPO)); + \$__ABC_LUT6 spo (.A(\$SPO ), .S({1'b0, A0, A1, A2, A3, A4}), .Y(SPO)); +endmodule + +module RAM64X1D ( + output DPO, SPO, + input D, + input WCLK, + input WE, + input A0, A1, A2, A3, A4, A5, + input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, DPRA5 +); + parameter INIT = 64'h0; + parameter IS_WCLK_INVERTED = 1'b0; + wire \$DPO , \$SPO ; + RAM64X1D #( + .INIT(INIT), .IS_WCLK_INVERTED(IS_WCLK_INVERTED) + ) _TECHMAP_REPLACE_ ( + .DPO(\$DPO ), .SPO(\$SPO ), + .D(D), .WCLK(WCLK), .WE(WE), + .A0(A0), .A1(A1), .A2(A2), .A3(A3), .A4(A4), .A5(A5), + .DPRA0(DPRA0), .DPRA1(DPRA1), .DPRA2(DPRA2), .DPRA3(DPRA3), .DPRA4(DPRA4), .DPRA5(DPRA5) + ); + \$__ABC_LUT6 dpo (.A(\$DPO ), .S({A0, A1, A2, A3, A4, A5}), .Y(DPO)); + \$__ABC_LUT6 spo (.A(\$SPO ), .S({A0, A1, A2, A3, A4, A5}), .Y(SPO)); +endmodule + +module RAM128X1D ( + output DPO, SPO, + input D, + input WCLK, + input WE, + input [6:0] A, DPRA +); + parameter INIT = 128'h0; + parameter IS_WCLK_INVERTED = 1'b0; + wire \$DPO , \$SPO ; + RAM128X1D #( + .INIT(INIT), .IS_WCLK_INVERTED(IS_WCLK_INVERTED) + ) _TECHMAP_REPLACE_ ( + .DPO(\$DPO ), .SPO(\$SPO ), + .D(D), .WCLK(WCLK), .WE(WE), + .A(A), + .DPRA(DPRA) + ); + \$__ABC_LUT7 dpo (.A(\$DPO ), .S(A), .Y(DPO)); + \$__ABC_LUT7 spo (.A(\$SPO ), .S(A), .Y(SPO)); +endmodule + +module SRL16E ( + output Q, + input A0, A1, A2, A3, CE, CLK, D +); + parameter [15:0] INIT = 16'h0000; + parameter [0:0] IS_CLK_INVERTED = 1'b0; + wire \$Q ; + SRL16E #( + .INIT(INIT), .IS_CLK_INVERTED(IS_CLK_INVERTED) + ) _TECHMAP_REPLACE_ ( + .Q(\$Q ), + .A0(A0), .A1(A1), .A2(A2), .A3(A3), .CE(CE), .CLK(CLK), .D(D) + ); + \$__ABC_LUT6 q (.A(\$Q ), .S({1'b1, A0, A1, A2, A3, 1'b1}), .Y(Q)); +endmodule + +module SRLC32E ( + output Q, + output Q31, + input [4:0] A, + input CE, CLK, D +); + parameter [31:0] INIT = 32'h00000000; + parameter [0:0] IS_CLK_INVERTED = 1'b0; + wire \$Q ; + SRLC32E #( + .INIT(INIT), .IS_CLK_INVERTED(IS_CLK_INVERTED) + ) _TECHMAP_REPLACE_ ( + .Q(\$Q ), .Q31(Q31), + .A(A), .CE(CE), .CLK(CLK), .D(D) + ); + \$__ABC_LUT6 q (.A(\$Q ), .S({1'b1, A}), .Y(Q)); +endmodule diff --git a/techlibs/xilinx/abc_model.v b/techlibs/xilinx/abc_model.v new file mode 100644 index 000000000..655b993f6 --- /dev/null +++ b/techlibs/xilinx/abc_model.v @@ -0,0 +1,34 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * 2019 Eddie Hung <eddie@fpgeh.com> + * + * 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. + * + */ + +// ============================================================================ + +(* abc_box_id = 3, lib_whitebox *) +module \$__XILINX_MUXF78 (output O, input I0, I1, I2, I3, S0, S1); + assign O = S1 ? (S0 ? I3 : I2) + : (S0 ? I1 : I0); +endmodule + +(* abc_box_id=2000 *) +module \$__ABC_LUT6 (input A, input [5:0] S, output Y); +endmodule +(* abc_box_id=2001 *) +module \$__ABC_LUT7 (input A, input [6:0] S, output Y); +endmodule diff --git a/techlibs/xilinx/abc_unmap.v b/techlibs/xilinx/abc_unmap.v new file mode 100644 index 000000000..f101a22d0 --- /dev/null +++ b/techlibs/xilinx/abc_unmap.v @@ -0,0 +1,28 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * 2019 Eddie Hung <eddie@fpgeh.com> + * + * 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. + * + */ + +// ============================================================================ + +module \$__ABC_LUT6 (input A, input [5:0] S, output Y); + assign Y = A; +endmodule +module \$__ABC_LUT7 (input A, input [6:0] S, output Y); + assign Y = A; +endmodule diff --git a/techlibs/xilinx/abc_xc7.box b/techlibs/xilinx/abc_xc7.box new file mode 100644 index 000000000..20da3b8a0 --- /dev/null +++ b/techlibs/xilinx/abc_xc7.box @@ -0,0 +1,61 @@ +# Max delays from https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLL_L.sdf +# https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf + +# NB: Inputs/Outputs must be ordered alphabetically +# (with exceptions for carry in/out) + +# Average across F7[AB]MUX +# Inputs: I0 I1 S0 +# Outputs: O +F7MUX 1 1 3 1 +204 208 286 + +# Inputs: I0 I1 S0 +# Outputs: O +MUXF8 2 1 3 1 +104 94 273 + +# Box containing MUXF7.[AB] + MUXF8, +# Necessary to make these an atomic unit so that +# ABC cannot optimise just one of the MUXF7 away +# and expect to save on its delay +# Inputs: I0 I1 I2 I3 S0 S1 +# Outputs: O +$__MUXF78 3 1 6 1 +294 297 311 317 390 273 + +# CARRY4 + CARRY4_[ABCD]X +# Inputs: CYINIT DI0 DI1 DI2 DI3 S0 S1 S2 S3 CI +# Outputs: O0 O1 O2 O3 CO0 CO1 CO2 CO3 +# (NB: carry chain input/output must be last +# input/output and the entire bus has been +# moved there overriding the otherwise +# alphabetical ordering) +CARRY4 4 1 10 8 +482 - - - - 223 - - - 222 +598 407 - - - 400 205 - - 334 +584 556 537 - - 523 558 226 - 239 +642 615 596 438 - 582 618 330 227 313 +536 379 - - - 340 - - - 271 +494 465 445 - - 433 469 - - 157 +592 540 520 356 - 512 548 292 - 228 +580 526 507 398 385 508 528 378 380 114 + +# SLICEM/A6LUT +# Box to emulate comb/seq behaviour of RAMD{32,64} and SRL{16,32} +# Necessary since RAMD* and SRL* have both combinatorial (i.e. +# same-cycle read operation) and sequential (write operation +# is only committed on the next clock edge). +# To model the combinatorial path, such cells have to be split +# into comb and seq parts, with this box modelling only the former. +# Inputs: A S0 S1 S2 S3 S4 S5 +# Outputs: Y +$__ABC_LUT6 2000 0 7 1 +0 642 631 472 407 238 127 + +# SLICEM/A6LUT + F7BMUX +# Box to emulate comb/seq behaviour of RAMD128 +# Inputs: A S0 S1 S2 S3 S4 S5 S6 +# Outputs: DPO SPO +$__ABC_LUT7 2001 0 8 1 +0 1047 1036 877 812 643 532 478 diff --git a/techlibs/xilinx/abc_xc7.lut b/techlibs/xilinx/abc_xc7.lut new file mode 100644 index 000000000..bcbdec127 --- /dev/null +++ b/techlibs/xilinx/abc_xc7.lut @@ -0,0 +1,15 @@ +# Max delays from https://github.com/SymbiFlow/prjxray-db/blob/82bf5f158cd8e9a11ac4d04f1aeef48ed1a528a5/artix7/timings/CLBLL_L.sdf +# and https://github.com/SymbiFlow/prjxray-db/blob/82bf5f158cd8e9a11ac4d04f1aeef48ed1a528a5/artix7/tile_type_CLBLL_L.json + +# K area delay +1 1 127 +2 2 127 238 +3 3 127 238 407 +4 3 127 238 407 472 +5 3 127 238 407 472 631 +6 5 127 238 407 472 631 642 + # (F7[AB]MUX.S + [AC]OUTMUX) / 2 +7 10 464 513 624 793 858 1017 1028 + # F8MUX.S+BOUTMUX + # F8MUX.I0+F7MUX.S+BOUTMUX +8 20 468 585 634 745 914 979 1138 1149 diff --git a/techlibs/xilinx/abc_xc7_nowide.lut b/techlibs/xilinx/abc_xc7_nowide.lut new file mode 100644 index 000000000..fab48c879 --- /dev/null +++ b/techlibs/xilinx/abc_xc7_nowide.lut @@ -0,0 +1,10 @@ +# Max delays from https://github.com/SymbiFlow/prjxray-db/blob/82bf5f158cd8e9a11ac4d04f1aeef48ed1a528a5/artix7/timings/CLBLL_L.sdf +# and https://github.com/SymbiFlow/prjxray-db/blob/82bf5f158cd8e9a11ac4d04f1aeef48ed1a528a5/artix7/tile_type_CLBLL_L.json + +# K area delay +1 1 127 +2 2 127 238 +3 3 127 238 407 +4 3 127 238 407 472 +5 3 127 238 407 472 631 +6 5 127 238 407 472 631 642 diff --git a/techlibs/xilinx/arith_map.v b/techlibs/xilinx/arith_map.v index 03719659b..5c848d4e6 100644 --- a/techlibs/xilinx/arith_map.v +++ b/techlibs/xilinx/arith_map.v @@ -17,6 +17,9 @@ * */ +// ============================================================================ +// LCU + (* techmap_celltype = "$lcu" *) module _80_xilinx_lcu (P, G, CI, CO); parameter WIDTH = 2; @@ -28,10 +31,78 @@ module _80_xilinx_lcu (P, G, CI, CO); wire _TECHMAP_FAIL_ = WIDTH <= 2; + genvar i; + +`ifdef _CLB_CARRY + + localparam CARRY4_COUNT = (WIDTH + 3) / 4; + localparam MAX_WIDTH = CARRY4_COUNT * 4; + localparam PAD_WIDTH = MAX_WIDTH - WIDTH; + + wire [MAX_WIDTH-1:0] S = {{PAD_WIDTH{1'b0}}, P & ~G}; + wire [MAX_WIDTH-1:0] C = CO; + + generate for (i = 0; i < CARRY4_COUNT; i = i + 1) begin:slice + + // Partially occupied CARRY4 + if ((i+1)*4 > WIDTH) begin + + // First one + if (i == 0) begin + CARRY4 carry4_1st_part + ( + .CYINIT(CI), + .CI (1'd0), + .DI (G [(Y_WIDTH - 1):i*4]), + .S (S [(Y_WIDTH - 1):i*4]), + .CO (CO[(Y_WIDTH - 1):i*4]), + ); + // Another one + end else begin + CARRY4 carry4_part + ( + .CYINIT(1'd0), + .CI (C [i*4 - 1]), + .DI (G [(Y_WIDTH - 1):i*4]), + .S (S [(Y_WIDTH - 1):i*4]), + .CO (CO[(Y_WIDTH - 1):i*4]), + ); + end + + // Fully occupied CARRY4 + end else begin + + // First one + if (i == 0) begin + CARRY4 carry4_1st_full + ( + .CYINIT(CI), + .CI (1'd0), + .DI (G [((i+1)*4 - 1):i*4]), + .S (S [((i+1)*4 - 1):i*4]), + .CO (CO[((i+1)*4 - 1):i*4]), + ); + // Another one + end else begin + CARRY4 carry4_full + ( + .CYINIT(1'd0), + .CI (C [i*4 - 1]), + .DI (G [((i+1)*4 - 1):i*4]), + .S (S [((i+1)*4 - 1):i*4]), + .CO (CO[((i+1)*4 - 1):i*4]), + ); + end + + end + + end endgenerate + +`elsif _EXPLICIT_CARRY + wire [WIDTH-1:0] C = {CO, CI}; wire [WIDTH-1:0] S = P & ~G; - genvar i; generate for (i = 0; i < WIDTH; i = i + 1) begin:slice MUXCY muxcy ( .CI(C[i]), @@ -40,8 +111,28 @@ module _80_xilinx_lcu (P, G, CI, CO); .O(CO[i]) ); end endgenerate + +`else + + wire [WIDTH-1:0] C = {CO, CI}; + wire [WIDTH-1:0] S = P & ~G; + + generate for (i = 0; i < WIDTH; i = i + 1) begin:slice + MUXCY muxcy ( + .CI(C[i]), + .DI(G[i]), + .S(S[i]), + .O(CO[i]) + ); + end endgenerate +`endif + endmodule + +// ============================================================================ +// ALU + (* techmap_celltype = "$alu" *) module _80_xilinx_alu (A, B, CI, BI, X, Y, CO); parameter A_SIGNED = 0; @@ -49,6 +140,8 @@ module _80_xilinx_alu (A, B, CI, BI, X, Y, CO); parameter A_WIDTH = 1; parameter B_WIDTH = 1; parameter Y_WIDTH = 1; + parameter _TECHMAP_CONSTVAL_CI_ = 0; + parameter _TECHMAP_CONSTMSK_CI_ = 0; input [A_WIDTH-1:0] A; input [B_WIDTH-1:0] B; @@ -66,16 +159,189 @@ module _80_xilinx_alu (A, B, CI, BI, X, Y, CO); wire [Y_WIDTH-1:0] AA = A_buf; wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; - wire [Y_WIDTH-1:0] P = AA ^ BB; - wire [Y_WIDTH-1:0] G = AA & BB; - wire [Y_WIDTH-1:0] C = {CO, CI}; - wire [Y_WIDTH-1:0] S = P & ~G; + genvar i; + +`ifdef _CLB_CARRY + + localparam CARRY4_COUNT = (Y_WIDTH + 3) / 4; + localparam MAX_WIDTH = CARRY4_COUNT * 4; + localparam PAD_WIDTH = MAX_WIDTH - Y_WIDTH; + + wire [MAX_WIDTH-1:0] S = {{PAD_WIDTH{1'b0}}, AA ^ BB}; + wire [MAX_WIDTH-1:0] DI = {{PAD_WIDTH{1'b0}}, AA & BB}; + + wire [MAX_WIDTH-1:0] C = CO; genvar i; + generate for (i = 0; i < CARRY4_COUNT; i = i + 1) begin:slice + + // Partially occupied CARRY4 + if ((i+1)*4 > Y_WIDTH) begin + + // First one + if (i == 0) begin + CARRY4 carry4_1st_part + ( + .CYINIT(CI), + .CI (1'd0), + .DI (DI[(Y_WIDTH - 1):i*4]), + .S (S [(Y_WIDTH - 1):i*4]), + .O (Y [(Y_WIDTH - 1):i*4]), + .CO (CO[(Y_WIDTH - 1):i*4]) + ); + // Another one + end else begin + CARRY4 carry4_part + ( + .CYINIT(1'd0), + .CI (C [i*4 - 1]), + .DI (DI[(Y_WIDTH - 1):i*4]), + .S (S [(Y_WIDTH - 1):i*4]), + .O (Y [(Y_WIDTH - 1):i*4]), + .CO (CO[(Y_WIDTH - 1):i*4]) + ); + end + + // Fully occupied CARRY4 + end else begin + + // First one + if (i == 0) begin + CARRY4 carry4_1st_full + ( + .CYINIT(CI), + .CI (1'd0), + .DI (DI[((i+1)*4 - 1):i*4]), + .S (S [((i+1)*4 - 1):i*4]), + .O (Y [((i+1)*4 - 1):i*4]), + .CO (CO[((i+1)*4 - 1):i*4]) + ); + // Another one + end else begin + CARRY4 carry4_full + ( + .CYINIT(1'd0), + .CI (C [i*4 - 1]), + .DI (DI[((i+1)*4 - 1):i*4]), + .S (S [((i+1)*4 - 1):i*4]), + .O (Y [((i+1)*4 - 1):i*4]), + .CO (CO[((i+1)*4 - 1):i*4]) + ); + end + + end + + end endgenerate + +`elsif _EXPLICIT_CARRY + + wire [Y_WIDTH-1:0] S = AA ^ BB; + wire [Y_WIDTH-1:0] DI = AA & BB; + + wire CINIT; + // Carry chain. + // + // VPR requires that the carry chain never hit the fabric. The CO input + // to this techmap is the carry outputs for synthesis, e.g. might hit the + // fabric. + // + // So we maintain two wire sets, CO_CHAIN is the carry that is for VPR, + // e.g. off fabric dedicated chain. CO is the carry outputs that are + // available to the fabric. + wire [Y_WIDTH-1:0] CO_CHAIN; + wire [Y_WIDTH-1:0] C = {CO_CHAIN, CINIT}; + + // If carry chain is being initialized to a constant, techmap the constant + // source. Otherwise techmap the fabric source. + generate for (i = 0; i < 1; i = i + 1) begin:slice + CARRY0 #(.CYINIT_FABRIC(1)) carry( + .CI_INIT(CI), + .DI(DI[0]), + .S(S[0]), + .CO_CHAIN(CO_CHAIN[0]), + .CO_FABRIC(CO[0]), + .O(Y[0]) + ); + end endgenerate + + generate for (i = 1; i < Y_WIDTH-1; i = i + 1) begin:slice + if(i % 4 == 0) begin + CARRY0 carry ( + .CI(C[i]), + .DI(DI[i]), + .S(S[i]), + .CO_CHAIN(CO_CHAIN[i]), + .CO_FABRIC(CO[i]), + .O(Y[i]) + ); + end + else + begin + CARRY carry ( + .CI(C[i]), + .DI(DI[i]), + .S(S[i]), + .CO_CHAIN(CO_CHAIN[i]), + .CO_FABRIC(CO[i]), + .O(Y[i]) + ); + end + end endgenerate + + generate for (i = Y_WIDTH-1; i < Y_WIDTH; i = i + 1) begin:slice + if(i % 4 == 0) begin + CARRY0 top_of_carry ( + .CI(C[i]), + .DI(DI[i]), + .S(S[i]), + .CO_CHAIN(CO_CHAIN[i]), + .O(Y[i]) + ); + end + else + begin + CARRY top_of_carry ( + .CI(C[i]), + .DI(DI[i]), + .S(S[i]), + .CO_CHAIN(CO_CHAIN[i]), + .O(Y[i]) + ); + end + // Turns out CO_FABRIC and O both use [ABCD]MUX, so provide + // a non-congested path to output the top of the carry chain. + // Registering the output of the CARRY block would solve this, but not + // all designs do that. + if((i+1) % 4 == 0) begin + CARRY0 carry_output ( + .CI(CO_CHAIN[i]), + .DI(0), + .S(0), + .O(CO[i]) + ); + end + else + begin + CARRY carry_output ( + .CI(CO_CHAIN[i]), + .DI(0), + .S(0), + .O(CO[i]) + ); + end + end endgenerate + +`else + + wire [Y_WIDTH-1:0] S = AA ^ BB; + wire [Y_WIDTH-1:0] DI = AA & BB; + + wire [Y_WIDTH-1:0] C = {CO, CI}; + generate for (i = 0; i < Y_WIDTH; i = i + 1) begin:slice MUXCY muxcy ( .CI(C[i]), - .DI(G[i]), + .DI(DI[i]), .S(S[i]), .O(CO[i]) ); @@ -86,6 +352,8 @@ module _80_xilinx_alu (A, B, CI, BI, X, Y, CO); ); end endgenerate - assign X = P; +`endif + + assign X = S; endmodule diff --git a/techlibs/xilinx/brams_init.py b/techlibs/xilinx/brams_init.py index d46a2b4f7..10057a0cb 100644 --- a/techlibs/xilinx/brams_init.py +++ b/techlibs/xilinx/brams_init.py @@ -1,5 +1,17 @@ #!/usr/bin/env python3 +with open("techlibs/xilinx/brams_init_9.vh", "w") as f: + for i in range(4): + init_snippets = [" INIT[%3d*9+8]" % (k+256*i,) for k in range(255, -1, -1)] + for k in range(4, 256, 4): + init_snippets[k] = "\n " + init_snippets[k] + print(".INITP_%02X({%s})," % (i, ",".join(init_snippets)), file=f) + for i in range(32): + init_snippets = [" INIT[%3d*9 +: 8]" % (k+32*i,) for k in range(31, -1, -1)] + for k in range(4, 32, 4): + init_snippets[k] = "\n " + init_snippets[k] + print(".INIT_%02X({%s})," % (i, ",".join(init_snippets)), file=f) + with open("techlibs/xilinx/brams_init_18.vh", "w") as f: for i in range(8): init_snippets = [" INIT[%3d*9+8]" % (k+256*i,) for k in range(255, -1, -1)] @@ -24,6 +36,10 @@ with open("techlibs/xilinx/brams_init_36.vh", "w") as f: init_snippets[k] = "\n " + init_snippets[k] print(".INIT_%02X({%s})," % (i, ",".join(init_snippets)), file=f) +with open("techlibs/xilinx/brams_init_8.vh", "w") as f: + for i in range(32): + print(".INIT_%02X(INIT[%3d*256 +: 256])," % (i, i), file=f) + with open("techlibs/xilinx/brams_init_16.vh", "w") as f: for i in range(64): print(".INIT_%02X(INIT[%3d*256 +: 256])," % (i, i), file=f) diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v index 0771be0b9..a15884ec4 100644 --- a/techlibs/xilinx/cells_map.v +++ b/techlibs/xilinx/cells_map.v @@ -1,86 +1,365 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * 2019 Eddie Hung <eddie@fpgeh.com> + * + * 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. + * + */ -module \$_DFF_N_ (input D, C, output Q); FDRE #(.INIT(|0), .IS_C_INVERTED(|1), .IS_D_INVERTED(|0), .IS_R_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); endmodule -module \$_DFF_P_ (input D, C, output Q); FDRE #(.INIT(|0), .IS_C_INVERTED(|0), .IS_D_INVERTED(|0), .IS_R_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); endmodule +// Convert negative-polarity reset to positive-polarity +(* techmap_celltype = "$_DFF_NN0_" *) +module _90_dff_nn0_to_np0 (input D, C, R, output Q); \$_DFF_NP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule +(* techmap_celltype = "$_DFF_PN0_" *) +module _90_dff_pn0_to_pp0 (input D, C, R, output Q); \$_DFF_PP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule +(* techmap_celltype = "$_DFF_NN1_" *) +module _90_dff_nn1_to_np1 (input D, C, R, output Q); \$_DFF_NP1_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule +(* techmap_celltype = "$_DFF_PN1_" *) +module _90_dff_pn1_to_pp1 (input D, C, R, output Q); \$_DFF_PP1_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule -module \$_DFFE_NP_ (input D, C, E, output Q); FDRE #(.INIT(|0), .IS_C_INVERTED(|1), .IS_D_INVERTED(|0), .IS_R_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); endmodule -module \$_DFFE_PP_ (input D, C, E, output Q); FDRE #(.INIT(|0), .IS_C_INVERTED(|0), .IS_D_INVERTED(|0), .IS_R_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); endmodule +module \$__SHREG_ (input C, input D, input E, output Q); + parameter DEPTH = 0; + parameter [DEPTH-1:0] INIT = 0; + parameter CLKPOL = 1; + parameter ENPOL = 2; -module \$_DFF_NN0_ (input D, C, R, output Q); FDCE #(.INIT(|0), .IS_C_INVERTED(|1), .IS_D_INVERTED(|0), .IS_CLR_INVERTED(|1)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(R)); endmodule -module \$_DFF_NP0_ (input D, C, R, output Q); FDCE #(.INIT(|0), .IS_C_INVERTED(|1), .IS_D_INVERTED(|0), .IS_CLR_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(R)); endmodule -module \$_DFF_PN0_ (input D, C, R, output Q); FDCE #(.INIT(|0), .IS_C_INVERTED(|0), .IS_D_INVERTED(|0), .IS_CLR_INVERTED(|1)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(R)); endmodule -module \$_DFF_PP0_ (input D, C, R, output Q); FDCE #(.INIT(|0), .IS_C_INVERTED(|0), .IS_D_INVERTED(|0), .IS_CLR_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(R)); endmodule + \$__XILINX_SHREG_ #(.DEPTH(DEPTH), .INIT(INIT), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) _TECHMAP_REPLACE_ (.C(C), .D(D), .L(DEPTH-1), .E(E), .Q(Q)); +endmodule -module \$_DFF_NN1_ (input D, C, R, output Q); FDPE #(.INIT(|0), .IS_C_INVERTED(|1), .IS_D_INVERTED(|0), .IS_PRE_INVERTED(|1)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(R)); endmodule -module \$_DFF_NP1_ (input D, C, R, output Q); FDPE #(.INIT(|0), .IS_C_INVERTED(|1), .IS_D_INVERTED(|0), .IS_PRE_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(R)); endmodule -module \$_DFF_PN1_ (input D, C, R, output Q); FDPE #(.INIT(|0), .IS_C_INVERTED(|0), .IS_D_INVERTED(|0), .IS_PRE_INVERTED(|1)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(R)); endmodule -module \$_DFF_PP1_ (input D, C, R, output Q); FDPE #(.INIT(|0), .IS_C_INVERTED(|0), .IS_D_INVERTED(|0), .IS_PRE_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(R)); endmodule +module \$__XILINX_SHREG_ (input C, input D, input [31:0] L, input E, output Q, output SO); + parameter DEPTH = 0; + parameter [DEPTH-1:0] INIT = 0; + parameter CLKPOL = 1; + parameter ENPOL = 2; -`ifndef NO_LUT -module \$lut (A, Y); - parameter WIDTH = 0; - parameter LUT = 0; + // shregmap's INIT parameter shifts out LSB first; + // however Xilinx expects MSB first + function [DEPTH-1:0] brev; + input [DEPTH-1:0] din; + integer i; + begin + for (i = 0; i < DEPTH; i=i+1) + brev[i] = din[DEPTH-1-i]; + end + endfunction + localparam [DEPTH-1:0] INIT_R = brev(INIT); - input [WIDTH-1:0] A; - output Y; + parameter _TECHMAP_CONSTMSK_L_ = 0; + wire CE; generate - if (WIDTH == 1) begin - LUT1 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), - .I0(A[0])); + if (ENPOL == 0) + assign CE = ~E; + else if (ENPOL == 1) + assign CE = E; + else + assign CE = 1'b1; + if (DEPTH == 1) begin + if (CLKPOL) + FDRE #(.INIT(INIT_R)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(CE), .R(1'b0)); + else + FDRE_1 #(.INIT(INIT_R)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(CE), .R(1'b0)); end else - if (WIDTH == 2) begin - LUT2 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), - .I0(A[0]), .I1(A[1])); + if (DEPTH <= 16) begin + SRL16E #(.INIT(INIT_R), .IS_CLK_INVERTED(~CLKPOL[0])) _TECHMAP_REPLACE_ (.A0(L[0]), .A1(L[1]), .A2(L[2]), .A3(L[3]), .CE(CE), .CLK(C), .D(D), .Q(Q)); end else - if (WIDTH == 3) begin - LUT3 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), - .I0(A[0]), .I1(A[1]), .I2(A[2])); + if (DEPTH > 17 && DEPTH <= 32) begin + SRLC32E #(.INIT(INIT_R), .IS_CLK_INVERTED(~CLKPOL[0])) _TECHMAP_REPLACE_ (.A(L[4:0]), .CE(CE), .CLK(C), .D(D), .Q(Q)); end else - if (WIDTH == 4) begin - LUT4 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), - .I0(A[0]), .I1(A[1]), .I2(A[2]), - .I3(A[3])); + if (DEPTH > 33 && DEPTH <= 64) begin + wire T0, T1, T2; + SRLC32E #(.INIT(INIT_R[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(L[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1)); + \$__XILINX_SHREG_ #(.DEPTH(DEPTH-32), .INIT(INIT[DEPTH-32-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T1), .L(L), .E(E), .Q(T2)); + if (&_TECHMAP_CONSTMSK_L_) + assign Q = T2; + else + MUXF7 fpga_mux_0 (.O(Q), .I0(T0), .I1(T2), .S(L[5])); end else - if (WIDTH == 5) begin - LUT5 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), - .I0(A[0]), .I1(A[1]), .I2(A[2]), - .I3(A[3]), .I4(A[4])); + if (DEPTH > 65 && DEPTH <= 96) begin + wire T0, T1, T2, T3, T4, T5, T6; + SRLC32E #(.INIT(INIT_R[32-1: 0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(L[4:0]), .CE(CE), .CLK(C), .D( D), .Q(T0), .Q31(T1)); + SRLC32E #(.INIT(INIT_R[64-1:32]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_1 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T1), .Q(T2), .Q31(T3)); + \$__XILINX_SHREG_ #(.DEPTH(DEPTH-64), .INIT(INIT[DEPTH-64-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_2 (.C(C), .D(T3), .L(L[4:0]), .E(E), .Q(T4)); + if (&_TECHMAP_CONSTMSK_L_) + assign Q = T4; + else + \$__XILINX_MUXF78 fpga_hard_mux (.I0(T0), .I1(T2), .I2(T4), .I3(1'bx), .S0(L[5]), .S1(L[6]), .O(Q)); end else - if (WIDTH == 6) begin - LUT6 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), - .I0(A[0]), .I1(A[1]), .I2(A[2]), - .I3(A[3]), .I4(A[4]), .I5(A[5])); - end else - if (WIDTH == 7) begin - wire T0, T1; - LUT6 #(.INIT(LUT[63:0])) fpga_lut_0 (.O(T0), - .I0(A[0]), .I1(A[1]), .I2(A[2]), - .I3(A[3]), .I4(A[4]), .I5(A[5])); - LUT6 #(.INIT(LUT[127:64])) fpga_lut_1 (.O(T1), - .I0(A[0]), .I1(A[1]), .I2(A[2]), - .I3(A[3]), .I4(A[4]), .I5(A[5])); - MUXF7 fpga_mux_0 (.O(Y), .I0(T0), .I1(T1), .S(A[6])); - end else - if (WIDTH == 8) begin - wire T0, T1, T2, T3, T4, T5; - LUT6 #(.INIT(LUT[63:0])) fpga_lut_0 (.O(T0), - .I0(A[0]), .I1(A[1]), .I2(A[2]), - .I3(A[3]), .I4(A[4]), .I5(A[5])); - LUT6 #(.INIT(LUT[127:64])) fpga_lut_1 (.O(T1), - .I0(A[0]), .I1(A[1]), .I2(A[2]), - .I3(A[3]), .I4(A[4]), .I5(A[5])); - LUT6 #(.INIT(LUT[191:128])) fpga_lut_2 (.O(T2), - .I0(A[0]), .I1(A[1]), .I2(A[2]), - .I3(A[3]), .I4(A[4]), .I5(A[5])); - LUT6 #(.INIT(LUT[255:192])) fpga_lut_3 (.O(T3), - .I0(A[0]), .I1(A[1]), .I2(A[2]), - .I3(A[3]), .I4(A[4]), .I5(A[5])); - MUXF7 fpga_mux_0 (.O(T4), .I0(T0), .I1(T1), .S(A[6])); - MUXF7 fpga_mux_1 (.O(T5), .I0(T2), .I1(T3), .S(A[6])); - MUXF8 fpga_mux_2 (.O(Y), .I0(T4), .I1(T5), .S(A[7])); - end else begin + if (DEPTH > 97 && DEPTH < 128) begin + wire T0, T1, T2, T3, T4, T5, T6, T7, T8; + SRLC32E #(.INIT(INIT_R[32-1: 0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(L[4:0]), .CE(CE), .CLK(C), .D( D), .Q(T0), .Q31(T1)); + SRLC32E #(.INIT(INIT_R[64-1:32]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_1 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T1), .Q(T2), .Q31(T3)); + SRLC32E #(.INIT(INIT_R[96-1:64]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_2 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T3), .Q(T4), .Q31(T5)); + \$__XILINX_SHREG_ #(.DEPTH(DEPTH-96), .INIT(INIT[DEPTH-96-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_3 (.C(C), .D(T5), .L(L[4:0]), .E(E), .Q(T6)); + if (&_TECHMAP_CONSTMSK_L_) + assign Q = T6; + else + \$__XILINX_MUXF78 fpga_hard_mux (.I0(T0), .I1(T2), .I2(T4), .I3(T6), .S0(L[5]), .S1(L[6]), .O(Q)); + end + else if (DEPTH == 128) begin + wire T0, T1, T2, T3, T4, T5, T6; + SRLC32E #(.INIT(INIT_R[ 32-1: 0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(L[4:0]), .CE(CE), .CLK(C), .D( D), .Q(T0), .Q31(T1)); + SRLC32E #(.INIT(INIT_R[ 64-1:32]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_1 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T1), .Q(T2), .Q31(T3)); + SRLC32E #(.INIT(INIT_R[ 96-1:64]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_2 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T3), .Q(T4), .Q31(T5)); + SRLC32E #(.INIT(INIT_R[128-1:96]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_3 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T5), .Q(T6), .Q31(SO)); + if (&_TECHMAP_CONSTMSK_L_) + assign Q = T6; + else + \$__XILINX_MUXF78 fpga_hard_mux (.I0(T0), .I1(T2), .I2(T4), .I3(T6), .S0(L[5]), .S1(L[6]), .O(Q)); + end + // For fixed length, if just 1 over a convenient value, decompose + else if (DEPTH <= 129 && &_TECHMAP_CONSTMSK_L_) begin + wire T; + \$__XILINX_SHREG_ #(.DEPTH(DEPTH-1), .INIT(INIT[DEPTH-1:1]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl (.C(C), .D(D), .L({32{1'b1}}), .E(E), .Q(T)); + \$__XILINX_SHREG_ #(.DEPTH(1), .INIT(INIT[0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_last (.C(C), .D(T), .L(L), .E(E), .Q(Q)); + end + // For variable length, if just 1 over a convenient value, then bump up one more + else if (DEPTH < 129 && ~&_TECHMAP_CONSTMSK_L_) + \$__XILINX_SHREG_ #(.DEPTH(DEPTH+1), .INIT({INIT,1'b0}), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) _TECHMAP_REPLACE_ (.C(C), .D(D), .L(L), .E(E), .Q(Q)); + else begin + localparam depth0 = 128; + localparam num_srl128 = DEPTH / depth0; + localparam depthN = DEPTH % depth0; + wire [num_srl128 + (depthN > 0 ? 1 : 0) - 1:0] T; + wire [num_srl128 + (depthN > 0 ? 1 : 0) :0] S; + assign S[0] = D; + genvar i; + for (i = 0; i < num_srl128; i++) + \$__XILINX_SHREG_ #(.DEPTH(depth0), .INIT(INIT[DEPTH-1-i*depth0-:depth0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl (.C(C), .D(S[i]), .L(L[$clog2(depth0)-1:0]), .E(E), .Q(T[i]), .SO(S[i+1])); + + if (depthN > 0) + \$__XILINX_SHREG_ #(.DEPTH(depthN), .INIT(INIT[depthN-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_last (.C(C), .D(S[num_srl128]), .L(L[$clog2(depth0)-1:0]), .E(E), .Q(T[num_srl128])); + + if (&_TECHMAP_CONSTMSK_L_) + assign Q = T[num_srl128 + (depthN > 0 ? 1 : 0) - 1]; + else + assign Q = T[L[DEPTH-1:$clog2(depth0)]]; + end + endgenerate +endmodule + +`ifdef MIN_MUX_INPUTS +module \$__XILINX_SHIFTX (A, B, Y); + parameter A_SIGNED = 0; + parameter B_SIGNED = 0; + parameter A_WIDTH = 1; + parameter B_WIDTH = 1; + parameter Y_WIDTH = 1; + + input [A_WIDTH-1:0] A; + input [B_WIDTH-1:0] B; + output [Y_WIDTH-1:0] Y; + + parameter [A_WIDTH-1:0] _TECHMAP_CONSTMSK_A_ = 0; + parameter [A_WIDTH-1:0] _TECHMAP_CONSTVAL_A_ = 0; + parameter [B_WIDTH-1:0] _TECHMAP_CONSTMSK_B_ = 0; + parameter [B_WIDTH-1:0] _TECHMAP_CONSTVAL_B_ = 0; + + function integer A_WIDTH_trimmed; + input integer start; + begin + A_WIDTH_trimmed = start; + while (A_WIDTH_trimmed > 0 && _TECHMAP_CONSTMSK_A_[A_WIDTH_trimmed-1] && _TECHMAP_CONSTVAL_A_[A_WIDTH_trimmed-1] === 1'bx) + A_WIDTH_trimmed = A_WIDTH_trimmed - 1; + end + endfunction + + generate + genvar i, j; + // Bit-blast + if (Y_WIDTH > 1) begin + for (i = 0; i < Y_WIDTH; i++) + \$__XILINX_SHIFTX #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(A_WIDTH-Y_WIDTH+1), .B_WIDTH(B_WIDTH), .Y_WIDTH(1'd1)) bitblast (.A(A[A_WIDTH-Y_WIDTH+i:i]), .B(B), .Y(Y[i])); + end + // If the LSB of B is constant zero (and Y_WIDTH is 1) then + // we can optimise by removing every other entry from A + // and popping the constant zero from B + else if (_TECHMAP_CONSTMSK_B_[0] && !_TECHMAP_CONSTVAL_B_[0]) begin + wire [(A_WIDTH+1)/2-1:0] A_i; + for (i = 0; i < (A_WIDTH+1)/2; i++) + assign A_i[i] = A[i*2]; + \$__XILINX_SHIFTX #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH((A_WIDTH+1'd1)/2'd2), .B_WIDTH(B_WIDTH-1'd1), .Y_WIDTH(Y_WIDTH)) _TECHMAP_REPLACE_ (.A(A_i), .B(B[B_WIDTH-1:1]), .Y(Y)); + end + // Trim off any leading 1'bx -es in A + else if (_TECHMAP_CONSTMSK_A_[A_WIDTH-1] && _TECHMAP_CONSTVAL_A_[A_WIDTH-1] === 1'bx) begin + localparam A_WIDTH_new = A_WIDTH_trimmed(A_WIDTH-1); + \$__XILINX_SHIFTX #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(A_WIDTH_new), .B_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) _TECHMAP_REPLACE_ (.A(A[A_WIDTH_new-1:0]), .B(B), .Y(Y)); + end + else if (A_WIDTH < `MIN_MUX_INPUTS) begin wire _TECHMAP_FAIL_ = 1; end + else if (A_WIDTH == 2) begin + MUXF7 fpga_hard_mux (.I0(A[0]), .I1(A[1]), .S(B[0]), .O(Y)); + end + else if (A_WIDTH <= 4) begin + wire [4-1:0] Ax; + if (A_WIDTH == 4) + assign Ax = A; + else + // Rather than extend with 1'bx which gets flattened to 1'b0 + // causing the "don't care" status to get lost, extend with + // the same driver of F7B.I0 so that we can optimise F7B away + // later + assign Ax = {A[1], A}; + \$__XILINX_MUXF78 fpga_hard_mux (.I0(Ax[0]), .I1(Ax[2]), .I2(Ax[1]), .I3(Ax[3]), .S0(B[1]), .S1(B[0]), .O(Y)); + end + // Note that the following decompositions are 'backwards' in that + // the LSBs are placed on the hard resources, and the soft resources + // are used for MSBs. + // This has the effect of more effectively utilising the hard mux; + // take for example a 5:1 multiplexer, currently this would map as: + // + // A[0] \___ __ A[0] \__ __ + // A[4] / \| \ whereas the more A[1] / \| \ + // A[1] _____| | obvious mapping A[2] \___| | + // A[2] _____| |-- of MSBs to hard A[3] / | |__ + // A[3]______| | resources would A[4] ____| | + // |__/ lead to: 1'bx ____| | + // || |__/ + // || || + // B[1:0] B[1:2] + // + // Expectation would be that the 'forward' mapping (right) is more + // area efficient (consider a 9:1 multiplexer using 2x4:1 multiplexers + // on its I0 and I1 inputs, and A[8] and 1'bx on its I2 and I3 inputs) + // but that the 'backwards' mapping (left) is more delay efficient + // since smaller LUTs are faster than wider ones. + else if (A_WIDTH <= 8) begin + wire [8-1:0] Ax = {{{8-A_WIDTH}{1'bx}}, A}; + wire T0 = B[2] ? Ax[4] : Ax[0]; + wire T1 = B[2] ? Ax[5] : Ax[1]; + wire T2 = B[2] ? Ax[6] : Ax[2]; + wire T3 = B[2] ? Ax[7] : Ax[3]; + \$__XILINX_MUXF78 fpga_hard_mux (.I0(T0), .I1(T2), .I2(T1), .I3(T3), .S0(B[1]), .S1(B[0]), .O(Y)); + end + else if (A_WIDTH <= 16) begin + wire [16-1:0] Ax = {{{16-A_WIDTH}{1'bx}}, A}; + wire T0 = B[2] ? B[3] ? Ax[12] : Ax[4] + : B[3] ? Ax[ 8] : Ax[0]; + wire T1 = B[2] ? B[3] ? Ax[13] : Ax[5] + : B[3] ? Ax[ 9] : Ax[1]; + wire T2 = B[2] ? B[3] ? Ax[14] : Ax[6] + : B[3] ? Ax[10] : Ax[2]; + wire T3 = B[2] ? B[3] ? Ax[15] : Ax[7] + : B[3] ? Ax[11] : Ax[3]; + \$__XILINX_MUXF78 fpga_hard_mux (.I0(T0), .I1(T2), .I2(T1), .I3(T3), .S0(B[1]), .S1(B[0]), .O(Y)); + end + else begin + localparam num_mux16 = (A_WIDTH+15) / 16; + localparam clog2_num_mux16 = $clog2(num_mux16); + wire [num_mux16-1:0] T; + wire [num_mux16*16-1:0] Ax = {{(num_mux16*16-A_WIDTH){1'bx}}, A}; + for (i = 0; i < num_mux16; i++) + \$__XILINX_SHIFTX #( + .A_SIGNED(A_SIGNED), + .B_SIGNED(B_SIGNED), + .A_WIDTH(16), + .B_WIDTH(4), + .Y_WIDTH(Y_WIDTH) + ) fpga_mux ( + .A(Ax[i*16+:16]), + .B(B[3:0]), + .Y(T[i]) + ); + \$__XILINX_SHIFTX #( + .A_SIGNED(A_SIGNED), + .B_SIGNED(B_SIGNED), + .A_WIDTH(num_mux16), + .B_WIDTH(clog2_num_mux16), + .Y_WIDTH(Y_WIDTH) + ) _TECHMAP_REPLACE_ ( + .A(T), + .B(B[B_WIDTH-1-:clog2_num_mux16]), + .Y(Y)); + end + endgenerate +endmodule + +(* techmap_celltype = "$__XILINX_SHIFTX" *) +module _90__XILINX_SHIFTX (A, B, Y); + parameter A_SIGNED = 0; + parameter B_SIGNED = 0; + parameter A_WIDTH = 1; + parameter B_WIDTH = 1; + parameter Y_WIDTH = 1; + + input [A_WIDTH-1:0] A; + input [B_WIDTH-1:0] B; + output [Y_WIDTH-1:0] Y; + + \$shiftx #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(A_WIDTH), .B_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) _TECHMAP_REPLACE_ (.A(A), .B(B), .Y(Y)); +endmodule + +module \$_MUX_ (A, B, S, Y); + input A, B, S; + output Y; + generate + if (`MIN_MUX_INPUTS == 2) + \$__XILINX_SHIFTX #(.A_SIGNED(0), .B_SIGNED(0), .A_WIDTH(2), .B_WIDTH(1), .Y_WIDTH(1)) _TECHMAP_REPLACE_ (.A({B,A}), .B(S), .Y(Y)); + else + wire _TECHMAP_FAIL_ = 1; endgenerate endmodule + +module \$_MUX4_ (A, B, C, D, S, T, Y); + input A, B, C, D, S, T; + output Y; + \$__XILINX_SHIFTX #(.A_SIGNED(0), .B_SIGNED(0), .A_WIDTH(4), .B_WIDTH(2), .Y_WIDTH(1)) _TECHMAP_REPLACE_ (.A({D,C,B,A}), .B({T,S}), .Y(Y)); +endmodule + +module \$_MUX8_ (A, B, C, D, E, F, G, H, S, T, U, Y); + input A, B, C, D, E, F, G, H, S, T, U; + output Y; + \$__XILINX_SHIFTX #(.A_SIGNED(0), .B_SIGNED(0), .A_WIDTH(8), .B_WIDTH(3), .Y_WIDTH(1)) _TECHMAP_REPLACE_ (.A({H,G,F,E,D,C,B,A}), .B({U,T,S}), .Y(Y)); +endmodule + +module \$_MUX16_ (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, S, T, U, V, Y); + input A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, S, T, U, V; + output Y; + \$__XILINX_SHIFTX #(.A_SIGNED(0), .B_SIGNED(0), .A_WIDTH(16), .B_WIDTH(4), .Y_WIDTH(1)) _TECHMAP_REPLACE_ (.A({P,O,N,M,L,K,J,I,H,G,F,E,D,C,B,A}), .B({V,U,T,S}), .Y(Y)); +endmodule `endif + +module \$__XILINX_MUXF78 (O, I0, I1, I2, I3, S0, S1); + output O; + input I0, I1, I2, I3, S0, S1; + wire T0, T1; + parameter _TECHMAP_BITS_CONNMAP_ = 0; + parameter [_TECHMAP_BITS_CONNMAP_-1:0] _TECHMAP_CONNMAP_I0_ = 0; + parameter [_TECHMAP_BITS_CONNMAP_-1:0] _TECHMAP_CONNMAP_I1_ = 0; + parameter [_TECHMAP_BITS_CONNMAP_-1:0] _TECHMAP_CONNMAP_I2_ = 0; + parameter [_TECHMAP_BITS_CONNMAP_-1:0] _TECHMAP_CONNMAP_I3_ = 0; + parameter _TECHMAP_CONSTMSK_S0_ = 0; + parameter _TECHMAP_CONSTVAL_S0_ = 0; + parameter _TECHMAP_CONSTMSK_S1_ = 0; + parameter _TECHMAP_CONSTVAL_S1_ = 0; + if (_TECHMAP_CONSTMSK_S0_ && _TECHMAP_CONSTVAL_S0_ === 1'b1) + assign T0 = I1; + else if (_TECHMAP_CONSTMSK_S0_ || _TECHMAP_CONNMAP_I0_ === _TECHMAP_CONNMAP_I1_) + assign T0 = I0; + else + MUXF7 mux7a (.I0(I0), .I1(I1), .S(S0), .O(T0)); + if (_TECHMAP_CONSTMSK_S0_ && _TECHMAP_CONSTVAL_S0_ === 1'b1) + assign T1 = I3; + else if (_TECHMAP_CONSTMSK_S0_ || _TECHMAP_CONNMAP_I2_ === _TECHMAP_CONNMAP_I3_) + assign T1 = I2; + else + MUXF7 mux7b (.I0(I2), .I1(I3), .S(S0), .O(T1)); + if (_TECHMAP_CONSTMSK_S1_ && _TECHMAP_CONSTVAL_S1_ === 1'b1) + assign O = T1; + else if (_TECHMAP_CONSTMSK_S1_ || (_TECHMAP_CONNMAP_I0_ === _TECHMAP_CONNMAP_I1_ && _TECHMAP_CONNMAP_I1_ === _TECHMAP_CONNMAP_I2_ && _TECHMAP_CONNMAP_I2_ === _TECHMAP_CONNMAP_I3_)) + assign O = T0; + else + MUXF8 mux8 (.I0(T0), .I1(T1), .S(S1), .O(O)); +endmodule diff --git a/techlibs/xilinx/cells_sim.v b/techlibs/xilinx/cells_sim.v index eba17ac9c..ef4340d10 100644 --- a/techlibs/xilinx/cells_sim.v +++ b/techlibs/xilinx/cells_sim.v @@ -1,3 +1,21 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * + * 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. + * + */ // See Xilinx UG953 and UG474 for a description of the cell types below. // http://www.xilinx.com/support/documentation/user_guides/ug474_7Series_CLB.pdf @@ -11,18 +29,84 @@ module GND(output G); assign G = 0; endmodule -module IBUF(output O, input I); +module IBUF( + output O, + (* iopad_external_pin *) + input I); + parameter IOSTANDARD = "default"; + parameter IBUF_LOW_PWR = 0; assign O = I; endmodule -module OBUF(output O, input I); +module OBUF( + (* iopad_external_pin *) + output O, + input I); + parameter IOSTANDARD = "default"; + parameter DRIVE = 12; + parameter SLEW = "SLOW"; assign O = I; endmodule -module BUFG(output O, input I); +module BUFG( + (* clkbuf_driver *) + output O, + input I); + assign O = I; endmodule +module BUFGCTRL( + (* clkbuf_driver *) + output O, + input I0, input I1, + (* invertible_pin = "IS_S0_INVERTED" *) + input S0, + (* invertible_pin = "IS_S1_INVERTED" *) + input S1, + (* invertible_pin = "IS_CE0_INVERTED" *) + input CE0, + (* invertible_pin = "IS_CE1_INVERTED" *) + input CE1, + (* invertible_pin = "IS_IGNORE0_INVERTED" *) + input IGNORE0, + (* invertible_pin = "IS_IGNORE1_INVERTED" *) + input IGNORE1); + +parameter [0:0] INIT_OUT = 1'b0; +parameter PRESELECT_I0 = "FALSE"; +parameter PRESELECT_I1 = "FALSE"; +parameter [0:0] IS_CE0_INVERTED = 1'b0; +parameter [0:0] IS_CE1_INVERTED = 1'b0; +parameter [0:0] IS_S0_INVERTED = 1'b0; +parameter [0:0] IS_S1_INVERTED = 1'b0; +parameter [0:0] IS_IGNORE0_INVERTED = 1'b0; +parameter [0:0] IS_IGNORE1_INVERTED = 1'b0; + +wire I0_internal = ((CE0 ^ IS_CE0_INVERTED) ? I0 : INIT_OUT); +wire I1_internal = ((CE1 ^ IS_CE1_INVERTED) ? I1 : INIT_OUT); +wire S0_true = (S0 ^ IS_S0_INVERTED); +wire S1_true = (S1 ^ IS_S1_INVERTED); + +assign O = S0_true ? I0_internal : (S1_true ? I1_internal : INIT_OUT); + +endmodule + +module BUFHCE( + (* clkbuf_driver *) + output O, + input I, + (* invertible_pin = "IS_CE_INVERTED" *) + input CE); + +parameter [0:0] INIT_OUT = 1'b0; +parameter CE_TYPE = "SYNC"; +parameter [0:0] IS_CE_INVERTED = 1'b0; + +assign O = ((CE ^ IS_CE_INVERTED) ? I : INIT_OUT); + +endmodule + // module OBUFT(output O, input I, T); // assign O = T ? 1'bz : I; // endmodule @@ -80,14 +164,32 @@ module LUT6(output O, input I0, I1, I2, I3, I4, I5); assign O = I0 ? s1[1] : s1[0]; endmodule +module LUT6_2(output O6, output O5, input I0, I1, I2, I3, I4, I5); + parameter [63:0] INIT = 0; + wire [31: 0] s5 = I5 ? INIT[63:32] : INIT[31: 0]; + wire [15: 0] s4 = I4 ? s5[31:16] : s5[15: 0]; + wire [ 7: 0] s3 = I3 ? s4[15: 8] : s4[ 7: 0]; + wire [ 3: 0] s2 = I2 ? s3[ 7: 4] : s3[ 3: 0]; + wire [ 1: 0] s1 = I1 ? s2[ 3: 2] : s2[ 1: 0]; + assign O6 = I0 ? s1[1] : s1[0]; + + wire [15: 0] s5_4 = I4 ? INIT[31:16] : INIT[15: 0]; + wire [ 7: 0] s5_3 = I3 ? s5_4[15: 8] : s5_4[ 7: 0]; + wire [ 3: 0] s5_2 = I2 ? s5_3[ 7: 4] : s5_3[ 3: 0]; + wire [ 1: 0] s5_1 = I1 ? s5_2[ 3: 2] : s5_2[ 1: 0]; + assign O5 = I0 ? s5_1[1] : s5_1[0]; +endmodule + module MUXCY(output O, input CI, DI, S); assign O = S ? CI : DI; endmodule +(* abc_box_id = 1, lib_whitebox *) module MUXF7(output O, input I0, I1, S); assign O = S ? I1 : I0; endmodule +(* abc_box_id = 2, lib_whitebox *) module MUXF8(output O, input I0, I1, S); assign O = S ? I1 : I0; endmodule @@ -96,7 +198,16 @@ module XORCY(output O, input CI, LI); assign O = CI ^ LI; endmodule -module CARRY4(output [3:0] CO, O, input CI, CYINIT, input [3:0] DI, S); +(* abc_box_id = 4, lib_whitebox *) +module CARRY4( + (* abc_carry *) + output [3:0] CO, + output [3:0] O, + (* abc_carry *) + input CI, + input CYINIT, + input [3:0] DI, S +); assign O = S ^ {CO[2:0], CI | CYINIT}; assign CO[0] = S[0] ? CI | CYINIT : DI[0]; assign CO[1] = S[1] ? CO[0] : DI[1]; @@ -104,7 +215,43 @@ module CARRY4(output [3:0] CO, O, input CI, CYINIT, input [3:0] DI, S); assign CO[3] = S[3] ? CO[2] : DI[3]; endmodule -module FDRE (output reg Q, input C, CE, D, R); +`ifdef _EXPLICIT_CARRY + +module CARRY0(output CO_CHAIN, CO_FABRIC, O, input CI, CI_INIT, DI, S); + parameter CYINIT_FABRIC = 0; + wire CI_COMBINE; + if(CYINIT_FABRIC) begin + assign CI_COMBINE = CI_INIT; + end else begin + assign CI_COMBINE = CI; + end + assign CO_CHAIN = S ? CI_COMBINE : DI; + assign CO_FABRIC = S ? CI_COMBINE : DI; + assign O = S ^ CI_COMBINE; +endmodule + +module CARRY(output CO_CHAIN, CO_FABRIC, O, input CI, DI, S); + assign CO_CHAIN = S ? CI : DI; + assign CO_FABRIC = S ? CI : DI; + assign O = S ^ CI; +endmodule + +`endif + +// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLL_L.sdf#L238-L250 + +module FDRE ( + (* abc_arrival=303 *) + output reg Q, + (* clkbuf_sink *) + (* invertible_pin = "IS_C_INVERTED" *) + input C, + input CE, + (* invertible_pin = "IS_D_INVERTED" *) + input D, + (* invertible_pin = "IS_R_INVERTED" *) + input R +); parameter [0:0] INIT = 1'b0; parameter [0:0] IS_C_INVERTED = 1'b0; parameter [0:0] IS_D_INVERTED = 1'b0; @@ -116,8 +263,19 @@ module FDRE (output reg Q, input C, CE, D, R); endcase endgenerate endmodule -module FDSE (output reg Q, input C, CE, D, S); - parameter [0:0] INIT = 1'b0; +module FDSE ( + (* abc_arrival=303 *) + output reg Q, + (* clkbuf_sink *) + (* invertible_pin = "IS_C_INVERTED" *) + input C, + input CE, + (* invertible_pin = "IS_D_INVERTED" *) + input D, + (* invertible_pin = "IS_S_INVERTED" *) + input S +); + parameter [0:0] INIT = 1'b1; parameter [0:0] IS_C_INVERTED = 1'b0; parameter [0:0] IS_D_INVERTED = 1'b0; parameter [0:0] IS_S_INVERTED = 1'b0; @@ -128,7 +286,18 @@ module FDSE (output reg Q, input C, CE, D, S); endcase endgenerate endmodule -module FDCE (output reg Q, input C, CE, D, CLR); +module FDCE ( + (* abc_arrival=303 *) + output reg Q, + (* clkbuf_sink *) + (* invertible_pin = "IS_C_INVERTED" *) + input C, + input CE, + (* invertible_pin = "IS_D_INVERTED" *) + input D, + (* invertible_pin = "IS_CLR_INVERTED" *) + input CLR +); parameter [0:0] INIT = 1'b0; parameter [0:0] IS_C_INVERTED = 1'b0; parameter [0:0] IS_D_INVERTED = 1'b0; @@ -142,8 +311,19 @@ module FDCE (output reg Q, input C, CE, D, CLR); endcase endgenerate endmodule -module FDPE (output reg Q, input C, CE, D, PRE); - parameter [0:0] INIT = 1'b0; +module FDPE ( + (* abc_arrival=303 *) + output reg Q, + (* clkbuf_sink *) + (* invertible_pin = "IS_C_INVERTED" *) + input C, + input CE, + (* invertible_pin = "IS_D_INVERTED" *) + input D, + (* invertible_pin = "IS_PRE_INVERTED" *) + input PRE +); + parameter [0:0] INIT = 1'b1; parameter [0:0] IS_C_INVERTED = 1'b0; parameter [0:0] IS_D_INVERTED = 1'b0; parameter [0:0] IS_PRE_INVERTED = 1'b0; @@ -156,9 +336,86 @@ module FDPE (output reg Q, input C, CE, D, PRE); endcase endgenerate endmodule +module FDRE_1 ( + (* abc_arrival=303 *) + output reg Q, + (* clkbuf_sink *) + input C, + input CE, D, R +); + parameter [0:0] INIT = 1'b0; + initial Q <= INIT; + always @(negedge C) if (R) Q <= 1'b0; else if(CE) Q <= D; +endmodule + +module FDSE_1 ( + (* abc_arrival=303 *) + output reg Q, + (* clkbuf_sink *) + input C, + input CE, D, S +); + parameter [0:0] INIT = 1'b1; + initial Q <= INIT; + always @(negedge C) if (S) Q <= 1'b1; else if(CE) Q <= D; +endmodule + +module FDCE_1 ( + (* abc_arrival=303 *) + output reg Q, + (* clkbuf_sink *) + input C, + input CE, D, CLR +); + parameter [0:0] INIT = 1'b0; + initial Q <= INIT; + always @(negedge C, posedge CLR) if (CLR) Q <= 1'b0; else if (CE) Q <= D; +endmodule + +module FDPE_1 ( + (* abc_arrival=303 *) + output reg Q, + (* clkbuf_sink *) + input C, + input CE, D, PRE +); + parameter [0:0] INIT = 1'b1; + initial Q <= INIT; + always @(negedge C, posedge PRE) if (PRE) Q <= 1'b1; else if (CE) Q <= D; +endmodule + +module RAM32X1D ( + // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L957 + (* abc_arrival=1153 *) + output DPO, SPO, + input D, + (* clkbuf_sink *) + (* invertible_pin = "IS_WCLK_INVERTED" *) + input WCLK, + input 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 ( + // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L957 + (* abc_arrival=1153 *) output DPO, SPO, - input D, WCLK, WE, + input D, + (* clkbuf_sink *) + (* invertible_pin = "IS_WCLK_INVERTED" *) + input WCLK, + input WE, input A0, A1, A2, A3, A4, A5, input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, DPRA5 ); @@ -174,8 +431,14 @@ module RAM64X1D ( endmodule module RAM128X1D ( - output DPO, SPO, - input D, WCLK, WE, + // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L957 + (* abc_arrival=1153 *) + output DPO, SPO, + input D, + (* clkbuf_sink *) + (* invertible_pin = "IS_WCLK_INVERTED" *) + input WCLK, + input WE, input [6:0] A, DPRA ); parameter INIT = 128'h0; @@ -186,3 +449,79 @@ module RAM128X1D ( wire clk = WCLK ^ IS_WCLK_INVERTED; always @(posedge clk) if (WE) mem[A] <= D; endmodule + +module SRL16E ( + // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L904-L905 + (* abc_arrival=1472 *) + output Q, + input A0, A1, A2, A3, CE, + (* clkbuf_sink *) + (* invertible_pin = "IS_CLK_INVERTED" *) + input CLK, + input D +); + parameter [15:0] INIT = 16'h0000; + parameter [0:0] IS_CLK_INVERTED = 1'b0; + + reg [15:0] r = INIT; + assign Q = r[{A3,A2,A1,A0}]; + generate + if (IS_CLK_INVERTED) begin + always @(negedge CLK) if (CE) r <= { r[14:0], D }; + end + else + always @(posedge CLK) if (CE) r <= { r[14:0], D }; + endgenerate +endmodule + +module SRLC16E ( + output Q, + output Q15, + input A0, A1, A2, A3, CE, + (* clkbuf_sink *) + (* invertible_pin = "IS_CLK_INVERTED" *) + input CLK, + input D +); + parameter [15:0] INIT = 16'h0000; + parameter [0:0] IS_CLK_INVERTED = 1'b0; + + reg [15:0] r = INIT; + assign Q15 = r[15]; + assign Q = r[{A3,A2,A1,A0}]; + generate + if (IS_CLK_INVERTED) begin + always @(negedge CLK) if (CE) r <= { r[14:0], D }; + end + else + always @(posedge CLK) if (CE) r <= { r[14:0], D }; + endgenerate +endmodule + +module SRLC32E ( + // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L904-L905 + (* abc_arrival=1472 *) + output Q, + (* abc_arrival=1114 *) + output Q31, + input [4:0] A, + input CE, + (* clkbuf_sink *) + (* invertible_pin = "IS_CLK_INVERTED" *) + input CLK, + input D +); + parameter [31:0] INIT = 32'h00000000; + parameter [0:0] IS_CLK_INVERTED = 1'b0; + + reg [31:0] r = INIT; + assign Q31 = r[31]; + assign Q = r[A]; + generate + if (IS_CLK_INVERTED) begin + always @(negedge CLK) if (CE) r <= { r[30:0], D }; + end + else + always @(posedge CLK) if (CE) r <= { r[30:0], D }; + endgenerate +endmodule diff --git a/techlibs/xilinx/cells_xtra.py b/techlibs/xilinx/cells_xtra.py new file mode 100644 index 000000000..561a61943 --- /dev/null +++ b/techlibs/xilinx/cells_xtra.py @@ -0,0 +1,708 @@ +#!/usr/bin/env python3 + +from argparse import ArgumentParser +from io import StringIO +from enum import Enum, auto +import os.path +import sys +import re + + +class Cell: + def __init__(self, name, keep=False, port_attrs={}): + self.name = name + self.keep = keep + self.port_attrs = port_attrs + + +XC6S_CELLS = [ + # Design elements types listed in Xilinx UG615. + + # Advanced. + Cell('MCB'), + Cell('PCIE_A1'), + + # Arithmetic functions. + Cell('DSP48A1', port_attrs={'CLK': ['clkbuf_sink']}), + + # Clock components. + # Cell('BUFG', port_attrs={'O': ['clkbuf_driver']}), + Cell('BUFGCE', port_attrs={'O': ['clkbuf_driver']}), + Cell('BUFGCE_1', port_attrs={'O': ['clkbuf_driver']}), + Cell('BUFGMUX', port_attrs={'O': ['clkbuf_driver']}), + Cell('BUFGMUX_1', port_attrs={'O': ['clkbuf_driver']}), + Cell('BUFH', port_attrs={'O': ['clkbuf_driver']}), + Cell('BUFIO2', port_attrs={'IOCLK': ['clkbuf_driver'], 'DIVCLK': ['clkbuf_driver']}), + Cell('BUFIO2_2CLK', port_attrs={'IOCLK': ['clkbuf_driver'], 'DIVCLK': ['clkbuf_driver']}), + Cell('BUFIO2FB', port_attrs={'O': ['clkbuf_driver']}), + Cell('BUFPLL_MCB', port_attrs={'IOCLK0': ['clkbuf_driver'], 'IOCLK1': ['clkbuf_driver']}), + Cell('DCM_CLKGEN'), + Cell('DCM_SP'), + Cell('PLL_BASE'), + + # Config/BSCAN components. + Cell('BSCAN_SPARTAN6', keep=True), + Cell('DNA_PORT'), + Cell('ICAP_SPARTAN6', keep=True), + Cell('POST_CRC_INTERNAL'), + Cell('STARTUP_SPARTAN6', keep=True), + Cell('SUSPEND_SYNC', keep=True), + + # I/O components. + Cell('GTPA1_DUAL'), + # Cell('IBUF', port_attrs={'I': ['iopad_external_pin']}), + Cell('IBUFDS', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), + Cell('IBUFDS_DIFF_OUT', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), + Cell('IBUFG', port_attrs={'I': ['iopad_external_pin']}), + Cell('IBUFGDS', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), + Cell('IBUFGDS_DIFF_OUT', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), + Cell('IOBUF', port_attrs={'IO': ['iopad_external_pin']}), + Cell('IOBUFDS', port_attrs={'IO': ['iopad_external_pin']}), + Cell('IODELAY2', port_attrs={'IOCLK0': ['clkbuf_sink'], 'IOCLK1': ['clkbuf_sink'], 'CLK': ['clkbuf_sink']}), + Cell('IODRP2', port_attrs={'IOCLK0': ['clkbuf_sink'], 'IOCLK1': ['clkbuf_sink'], 'CLK': ['clkbuf_sink']}), + Cell('IODRP2_MCB', port_attrs={'IOCLK0': ['clkbuf_sink'], 'IOCLK1': ['clkbuf_sink'], 'CLK': ['clkbuf_sink']}), + Cell('ISERDES2', port_attrs={ + 'CLK0': ['clkbuf_sink'], + 'CLK1': ['clkbuf_sink'], + 'CLKDIV': ['clkbuf_sink'], + }), + Cell('KEEPER'), + # Cell('OBUF', port_attrs={'O': ['iopad_external_pin']}), + Cell('OBUFDS', port_attrs={'O': ['iopad_external_pin'], 'OB': ['iopad_external_pin']}), + Cell('OBUFT', port_attrs={'O': ['iopad_external_pin']}), + Cell('OBUFTDS', port_attrs={'O': ['iopad_external_pin'], 'OB': ['iopad_external_pin']}), + Cell('OSERDES2', port_attrs={ + 'CLK0': ['clkbuf_sink'], + 'CLK1': ['clkbuf_sink'], + 'CLKDIV': ['clkbuf_sink'], + }), + Cell('PULLDOWN'), + Cell('PULLUP'), + + # RAM/ROM. + #Cell('RAM128X1D', port_attrs={'WCLK': ['clkbuf_sink']}), + # NOTE: not in the official library guide! + Cell('RAM128X1S', port_attrs={'WCLK': ['clkbuf_sink']}), + Cell('RAM256X1S', port_attrs={'WCLK': ['clkbuf_sink']}), + Cell('RAM32M', port_attrs={'WCLK': ['clkbuf_sink']}), + #Cell('RAM32X1D', port_attrs={'WCLK': ['clkbuf_sink']}), + Cell('RAM32X1S', port_attrs={'WCLK': ['clkbuf_sink']}), + Cell('RAM32X1S_1', port_attrs={'WCLK': ['clkbuf_sink']}), + Cell('RAM32X2S', port_attrs={'WCLK': ['clkbuf_sink']}), + Cell('RAM64M', port_attrs={'WCLK': ['clkbuf_sink']}), + #Cell('RAM64X1D', port_attrs={'WCLK': ['clkbuf_sink']}), + Cell('RAM64X1S', port_attrs={'WCLK': ['clkbuf_sink']}), + Cell('RAM64X1S_1', port_attrs={'WCLK': ['clkbuf_sink']}), + # NOTE: not in the official library guide! + Cell('RAM64X2S', port_attrs={'WCLK': ['clkbuf_sink']}), + # Cell('RAMB8BWER', port_attrs={'CLKAWRCLK': ['clkbuf_sink'], 'CLKBRDCLK': ['clkbuf_sink']}), + # Cell('RAMB16BWER', port_attrs={'CLKA': ['clkbuf_sink'], 'CLKB': ['clkbuf_sink']}), + Cell('ROM128X1'), + Cell('ROM256X1'), + Cell('ROM32X1'), + Cell('ROM64X1'), + + # Registers/latches. + # Cell('FDCE'), + # Cell('FDPE'), + # Cell('FDRE'), + # Cell('FDSE'), + Cell('IDDR2', port_attrs={'C0': ['clkbuf_sink'], 'C1': ['clkbuf_sink']}), + Cell('LDCE'), + Cell('LDPE'), + Cell('ODDR2', port_attrs={'C0': ['clkbuf_sink'], 'C1': ['clkbuf_sink']}), + + # Slice/CLB primitives. + # Cell('CARRY4'), + Cell('CFGLUT5', port_attrs={'CLK': ['clkbuf_sink']}), + # Cell('LUT1'), + # Cell('LUT2'), + # Cell('LUT3'), + # Cell('LUT4'), + # Cell('LUT5'), + # Cell('LUT6'), + # Cell('LUT6_2'), + # Cell('MUXF7'), + # Cell('MUXF8'), + # Cell('SRL16E', port_attrs={'CLK': ['clkbuf_sink']}), + # Cell('SRLC32E', port_attrs={'CLK': ['clkbuf_sink']}), +] + + +XC6V_CELLS = [ + # Design elements types listed in Xilinx UG623. + + # Advanced. + Cell('PCIE_2_0'), + Cell('SYSMON'), + + # Arithmetic functions. + Cell('DSP48E1', port_attrs={'CLK': ['clkbuf_sink']}), + + # Clock components. + # Cell('BUFG', port_attrs={'O': ['clkbuf_driver']}), + Cell('BUFGCE', port_attrs={'O': ['clkbuf_driver']}), + Cell('BUFGCE_1', port_attrs={'O': ['clkbuf_driver']}), + #Cell('BUFGCTRL', port_attrs={'O': ['clkbuf_driver']}), + Cell('BUFGMUX', port_attrs={'O': ['clkbuf_driver']}), + Cell('BUFGMUX_1', port_attrs={'O': ['clkbuf_driver']}), + Cell('BUFGMUX_CTRL', port_attrs={'O': ['clkbuf_driver']}), + Cell('BUFH', port_attrs={'O': ['clkbuf_driver']}), + #Cell('BUFHCE', port_attrs={'O': ['clkbuf_driver']}), + Cell('BUFIO', port_attrs={'O': ['clkbuf_driver']}), + Cell('BUFIODQS', port_attrs={'O': ['clkbuf_driver']}), + Cell('BUFR', port_attrs={'O': ['clkbuf_driver']}), + Cell('IBUFDS_GTXE1', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), + Cell('MMCM_ADV'), + Cell('MMCM_BASE'), + + # Config/BSCAN components. + Cell('BSCAN_VIRTEX6', keep=True), + Cell('CAPTURE_VIRTEX6', keep=True), + Cell('DNA_PORT'), + Cell('EFUSE_USR'), + Cell('FRAME_ECC_VIRTEX6'), + Cell('ICAP_VIRTEX6', keep=True), + Cell('STARTUP_VIRTEX6', keep=True), + Cell('USR_ACCESS_VIRTEX6'), + + # I/O components. + Cell('DCIRESET', keep=True), + Cell('GTHE1_QUAD'), + Cell('GTXE1'), + # Cell('IBUF', port_attrs={'I': ['iopad_external_pin']}), + Cell('IBUFDS', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), + Cell('IBUFDS_DIFF_OUT', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), + Cell('IBUFDS_GTHE1', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), + Cell('IBUFG', port_attrs={'I': ['iopad_external_pin']}), + Cell('IBUFGDS', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), + Cell('IBUFGDS_DIFF_OUT', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), + Cell('IDELAYCTRL', keep=True, port_attrs={'REFCLK': ['clkbuf_sink']}), + Cell('IOBUF', port_attrs={'IO': ['iopad_external_pin']}), + Cell('IOBUFDS', port_attrs={'IO': ['iopad_external_pin']}), + Cell('IODELAYE1', port_attrs={'C': ['clkbuf_sink']}), + Cell('ISERDESE1', port_attrs={ + 'CLK': ['clkbuf_sink'], + 'CLKB': ['clkbuf_sink'], + 'OCLK': ['clkbuf_sink'], + 'CLKDIV': ['clkbuf_sink'], + }), + Cell('KEEPER'), + # Cell('OBUF', port_attrs={'O': ['iopad_external_pin']}), + Cell('OBUFDS', port_attrs={'O': ['iopad_external_pin'], 'OB': ['iopad_external_pin']}), + Cell('OBUFT', port_attrs={'O': ['iopad_external_pin']}), + Cell('OBUFTDS', port_attrs={'O': ['iopad_external_pin'], 'OB': ['iopad_external_pin']}), + Cell('OSERDESE1', port_attrs={'CLK': ['clkbuf_sink'], 'CLKDIV': ['clkbuf_sink']}), + Cell('PULLDOWN'), + Cell('PULLUP'), + Cell('TEMAC_SINGLE'), + + # RAM/ROM. + Cell('FIFO18E1', port_attrs={'RDCLK': ['clkbuf_sink'], 'WRCLK': ['clkbuf_sink']}), + Cell('FIFO36E1', port_attrs={'RDCLK': ['clkbuf_sink'], 'WRCLK': ['clkbuf_sink']}), + #Cell('RAM128X1D', port_attrs={'WCLK': ['clkbuf_sink']}), + Cell('RAM128X1S', port_attrs={'WCLK': ['clkbuf_sink']}), + Cell('RAM256X1S', port_attrs={'WCLK': ['clkbuf_sink']}), + Cell('RAM32M', port_attrs={'WCLK': ['clkbuf_sink']}), + #Cell('RAM32X1D', port_attrs={'WCLK': ['clkbuf_sink']}), + Cell('RAM32X1S', port_attrs={'WCLK': ['clkbuf_sink']}), + Cell('RAM32X1S_1', port_attrs={'WCLK': ['clkbuf_sink']}), + Cell('RAM32X2S', port_attrs={'WCLK': ['clkbuf_sink']}), + Cell('RAM64M', port_attrs={'WCLK': ['clkbuf_sink']}), + #Cell('RAM64X1D', port_attrs={'WCLK': ['clkbuf_sink']}), + Cell('RAM64X1S', port_attrs={'WCLK': ['clkbuf_sink']}), + Cell('RAM64X1S_1', port_attrs={'WCLK': ['clkbuf_sink']}), + # NOTE: not in the official library guide! + Cell('RAM64X2S', port_attrs={'WCLK': ['clkbuf_sink']}), + # Cell('RAMB18E1', port_attrs={'CLKARDCLK': ['clkbuf_sink'], 'CLKBWRCLK': ['clkbuf_sink']}), + # Cell('RAMB36E1', port_attrs={'CLKARDCLK': ['clkbuf_sink'], 'CLKBWRCLK': ['clkbuf_sink']}), + Cell('ROM128X1'), + Cell('ROM256X1'), + Cell('ROM32X1'), + Cell('ROM64X1'), + + # Registers/latches. + # Cell('FDCE'), + # Cell('FDPE'), + # Cell('FDRE'), + # Cell('FDSE'), + Cell('IDDR', port_attrs={'C': ['clkbuf_sink']}), + Cell('IDDR_2CLK', port_attrs={'C': ['clkbuf_sink'], 'CB': ['clkbuf_sink']}), + Cell('LDCE'), + Cell('LDPE'), + Cell('ODDR', port_attrs={'C': ['clkbuf_sink']}), + + # Slice/CLB primitives. + # Cell('CARRY4'), + Cell('CFGLUT5', port_attrs={'CLK': ['clkbuf_sink']}), + # Cell('LUT1'), + # Cell('LUT2'), + # Cell('LUT3'), + # Cell('LUT4'), + # Cell('LUT5'), + # Cell('LUT6'), + # Cell('LUT6_2'), + # Cell('MUXF7'), + # Cell('MUXF8'), + # Cell('SRL16E', port_attrs={'CLK': ['clkbuf_sink']}), + # Cell('SRLC32E', port_attrs={'CLK': ['clkbuf_sink']}), +] + + +XC7_CELLS = [ + # Design elements types listed in Xilinx UG953. + + # Advanced. + Cell('GTHE2_CHANNEL'), + Cell('GTHE2_COMMON'), + Cell('GTPE2_CHANNEL'), + Cell('GTPE2_COMMON'), + Cell('GTXE2_CHANNEL'), + Cell('GTXE2_COMMON'), + Cell('PCIE_2_1'), + Cell('PCIE_3_0'), + Cell('XADC'), + + # Arithmetic functions. + Cell('DSP48E1', port_attrs={'CLK': ['clkbuf_sink']}), + + # Clock components. + # Cell('BUFG', port_attrs={'O': ['clkbuf_driver']}), + Cell('BUFGCE', port_attrs={'O': ['clkbuf_driver']}), + Cell('BUFGCE_1', port_attrs={'O': ['clkbuf_driver']}), + #Cell('BUFGCTRL', port_attrs={'O': ['clkbuf_driver']}), + Cell('BUFGMUX', port_attrs={'O': ['clkbuf_driver']}), + Cell('BUFGMUX_1', port_attrs={'O': ['clkbuf_driver']}), + Cell('BUFGMUX_CTRL', port_attrs={'O': ['clkbuf_driver']}), + Cell('BUFH', port_attrs={'O': ['clkbuf_driver']}), + #Cell('BUFHCE', port_attrs={'O': ['clkbuf_driver']}), + Cell('BUFIO', port_attrs={'O': ['clkbuf_driver']}), + Cell('BUFMR', port_attrs={'O': ['clkbuf_driver']}), + Cell('BUFMRCE', port_attrs={'O': ['clkbuf_driver']}), + Cell('BUFR', port_attrs={'O': ['clkbuf_driver']}), + Cell('MMCME2_ADV'), + Cell('MMCME2_BASE'), + Cell('PLLE2_ADV'), + Cell('PLLE2_BASE'), + + # Config/BSCAN components. + Cell('BSCANE2', keep=True), + Cell('CAPTUREE2', keep=True), + Cell('DNA_PORT'), + Cell('EFUSE_USR'), + Cell('FRAME_ECCE2'), + Cell('ICAPE2', keep=True), + Cell('STARTUPE2', keep=True), + Cell('USR_ACCESSE2'), + + # I/O components. + Cell('DCIRESET', keep=True), + # Cell('IBUF', port_attrs={'I': ['iopad_external_pin']}), + Cell('IBUF_IBUFDISABLE', port_attrs={'I': ['iopad_external_pin']}), + Cell('IBUF_INTERMDISABLE', port_attrs={'I': ['iopad_external_pin']}), + Cell('IBUFDS', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), + Cell('IBUFDS_DIFF_OUT', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), + Cell('IBUFDS_DIFF_OUT_IBUFDISABLE', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), + Cell('IBUFDS_DIFF_OUT_INTERMDISABLE', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), + Cell('IBUFDS_GTE2', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), + Cell('IBUFDS_IBUFDISABLE', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), + Cell('IBUFDS_INTERMDISABLE', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), + Cell('IBUFG', port_attrs={'I': ['iopad_external_pin']}), + Cell('IBUFGDS', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), + Cell('IBUFGDS_DIFF_OUT', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), + Cell('IDELAYCTRL', keep=True, port_attrs={'REFCLK': ['clkbuf_sink']}), + Cell('IDELAYE2', port_attrs={'C': ['clkbuf_sink']}), + Cell('IN_FIFO', port_attrs={'RDCLK': ['clkbuf_sink'], 'WRCLK': ['clkbuf_sink']}), + Cell('IOBUF', port_attrs={'IO': ['iopad_external_pin']}), + Cell('IOBUF_DCIEN', port_attrs={'IO': ['iopad_external_pin']}), + Cell('IOBUF_INTERMDISABLE', port_attrs={'IO': ['iopad_external_pin']}), + Cell('IOBUFDS', port_attrs={'IO': ['iopad_external_pin']}), + Cell('IOBUFDS_DCIEN', port_attrs={'IO': ['iopad_external_pin'], 'IOB': ['iopad_external_pin']}), + Cell('IOBUFDS_DIFF_OUT', port_attrs={'IO': ['iopad_external_pin'], 'IOB': ['iopad_external_pin']}), + Cell('IOBUFDS_DIFF_OUT_DCIEN', port_attrs={'IO': ['iopad_external_pin'], 'IOB': ['iopad_external_pin']}), + Cell('IOBUFDS_DIFF_OUT_INTERMDISABLE', port_attrs={'IO': ['iopad_external_pin'], 'IOB': ['iopad_external_pin']}), + Cell('IOBUFDS_INTERMDISABLE', port_attrs={'IO': ['iopad_external_pin'], 'IOB': ['iopad_external_pin']}), + Cell('ISERDESE2', port_attrs={ + 'CLK': ['clkbuf_sink'], + 'CLKB': ['clkbuf_sink'], + 'OCLK': ['clkbuf_sink'], + 'OCLKB': ['clkbuf_sink'], + 'CLKDIV': ['clkbuf_sink'], + 'CLKDIVP': ['clkbuf_sink'], + }), + Cell('KEEPER'), + # Cell('OBUF', port_attrs={'O': ['iopad_external_pin']}), + Cell('OBUFDS', port_attrs={'O': ['iopad_external_pin'], 'OB': ['iopad_external_pin']}), + Cell('OBUFT', port_attrs={'O': ['iopad_external_pin']}), + Cell('OBUFTDS', port_attrs={'O': ['iopad_external_pin'], 'OB': ['iopad_external_pin']}), + Cell('ODELAYE2', port_attrs={'C': ['clkbuf_sink']}), + Cell('OSERDESE2', port_attrs={'CLK': ['clkbuf_sink'], 'CLKDIV': ['clkbuf_sink']}), + Cell('OUT_FIFO', port_attrs={'RDCLK': ['clkbuf_sink'], 'WRCLK': ['clkbuf_sink']}), + Cell('PHASER_IN'), + Cell('PHASER_IN_PHY'), + Cell('PHASER_OUT'), + Cell('PHASER_OUT_PHY'), + Cell('PHASER_REF'), + Cell('PHY_CONTROL'), + Cell('PULLDOWN'), + Cell('PULLUP'), + + # RAM/ROM. + Cell('FIFO18E1', port_attrs={'RDCLK': ['clkbuf_sink'], 'WRCLK': ['clkbuf_sink']}), + Cell('FIFO36E1', port_attrs={'RDCLK': ['clkbuf_sink'], 'WRCLK': ['clkbuf_sink']}), + #Cell('RAM128X1D', port_attrs={'WCLK': ['clkbuf_sink']}), + Cell('RAM128X1S', port_attrs={'WCLK': ['clkbuf_sink']}), + Cell('RAM256X1S', port_attrs={'WCLK': ['clkbuf_sink']}), + Cell('RAM32M', port_attrs={'WCLK': ['clkbuf_sink']}), + #Cell('RAM32X1D', port_attrs={'WCLK': ['clkbuf_sink']}), + Cell('RAM32X1S', port_attrs={'WCLK': ['clkbuf_sink']}), + Cell('RAM32X1S_1', port_attrs={'WCLK': ['clkbuf_sink']}), + Cell('RAM32X2S', port_attrs={'WCLK': ['clkbuf_sink']}), + Cell('RAM64M', port_attrs={'WCLK': ['clkbuf_sink']}), + #Cell('RAM64X1D', port_attrs={'WCLK': ['clkbuf_sink']}), + Cell('RAM64X1S', port_attrs={'WCLK': ['clkbuf_sink']}), + Cell('RAM64X1S_1', port_attrs={'WCLK': ['clkbuf_sink']}), + # NOTE: not in the official library guide! + Cell('RAM64X2S', port_attrs={'WCLK': ['clkbuf_sink']}), + # Cell('RAMB18E1', port_attrs={'CLKARDCLK': ['clkbuf_sink'], 'CLKBWRCLK': ['clkbuf_sink']}), + # Cell('RAMB36E1', port_attrs={'CLKARDCLK': ['clkbuf_sink'], 'CLKBWRCLK': ['clkbuf_sink']}), + Cell('ROM128X1'), + Cell('ROM256X1'), + Cell('ROM32X1'), + Cell('ROM64X1'), + + # Registers/latches. + # Cell('FDCE'), + # Cell('FDPE'), + # Cell('FDRE'), + # Cell('FDSE'), + Cell('IDDR', port_attrs={'C': ['clkbuf_sink']}), + Cell('IDDR_2CLK', port_attrs={'C': ['clkbuf_sink'], 'CB': ['clkbuf_sink']}), + Cell('LDCE'), + Cell('LDPE'), + Cell('ODDR', port_attrs={'C': ['clkbuf_sink']}), + + # Slice/CLB primitives. + # Cell('CARRY4'), + Cell('CFGLUT5', port_attrs={'CLK': ['clkbuf_sink']}), + # Cell('LUT1'), + # Cell('LUT2'), + # Cell('LUT3'), + # Cell('LUT4'), + # Cell('LUT5'), + # Cell('LUT6'), + # Cell('LUT6_2'), + # Cell('MUXF7'), + # Cell('MUXF8'), + # Cell('SRL16E', port_attrs={'CLK': ['clkbuf_sink']}), + # Cell('SRLC32E', port_attrs={'CLK': ['clkbuf_sink']}), + + # NOTE: not in the official library guide! + Cell('PS7', keep=True), +] + + +XCU_CELLS = [ + # Design elements types listed in Xilinx UG974. + + # Advanced. + Cell('CMAC'), + Cell('CMACE4'), + Cell('GTHE3_CHANNEL'), + Cell('GTHE3_COMMON'), + Cell('GTHE4_CHANNEL'), + Cell('GTHE4_COMMON'), + Cell('GTYE3_CHANNEL'), + Cell('GTYE3_COMMON'), + Cell('GTYE4_CHANNEL'), + Cell('GTYE4_COMMON'), + Cell('IBUFDS_GTE3', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), + Cell('IBUFDS_GTE4', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), + Cell('ILKN'), + Cell('ILKNE4'), + Cell('OBUFDS_GTE3', port_attrs={'O': ['iopad_external_pin'], 'OB': ['iopad_external_pin']}), + Cell('OBUFDS_GTE3_ADV', port_attrs={'O': ['iopad_external_pin'], 'OB': ['iopad_external_pin']}), + Cell('OBUFDS_GTE4', port_attrs={'O': ['iopad_external_pin'], 'OB': ['iopad_external_pin']}), + Cell('OBUFDS_GTE4_ADV', port_attrs={'O': ['iopad_external_pin'], 'OB': ['iopad_external_pin']}), + Cell('PCIE40E4'), + Cell('PCIE_3_1'), + Cell('SYSMONE1'), + Cell('SYSMONE4'), + + # Arithmetic functions. + Cell('DSP48E2', port_attrs={'CLK': ['clkbuf_sink']}), + + # Blockram. + Cell('FIFO18E2', port_attrs={'RDCLK': ['clkbuf_sink'], 'WRCLK': ['clkbuf_sink']}), + Cell('FIFO36E2', port_attrs={'RDCLK': ['clkbuf_sink'], 'WRCLK': ['clkbuf_sink']}), + Cell('RAMB18E2', port_attrs={'CLKARDCLK': ['clkbuf_sink'], 'CLKBWRCLK': ['clkbuf_sink']}), + Cell('RAMB36E2', port_attrs={'CLKARDCLK': ['clkbuf_sink'], 'CLKBWRCLK': ['clkbuf_sink']}), + Cell('URAM288', port_attrs={'CLK': ['clkbuf_sink']}), + Cell('URAM288_BASE', port_attrs={'CLK': ['clkbuf_sink']}), + + # CLB. + # Cell('LUT6_2'), + #Cell('RAM128X1D', port_attrs={'WCLK': ['clkbuf_sink']}), + Cell('RAM128X1S', port_attrs={'WCLK': ['clkbuf_sink']}), + Cell('RAM256X1D', port_attrs={'WCLK': ['clkbuf_sink']}), + Cell('RAM256X1S', port_attrs={'WCLK': ['clkbuf_sink']}), + Cell('RAM32M', port_attrs={'WCLK': ['clkbuf_sink']}), + Cell('RAM32M16', port_attrs={'WCLK': ['clkbuf_sink']}), + #Cell('RAM32X1D', port_attrs={'WCLK': ['clkbuf_sink']}), + Cell('RAM32X1S', port_attrs={'WCLK': ['clkbuf_sink']}), + Cell('RAM512X1S', port_attrs={'WCLK': ['clkbuf_sink']}), + Cell('RAM64M', port_attrs={'WCLK': ['clkbuf_sink']}), + Cell('RAM64M8', port_attrs={'WCLK': ['clkbuf_sink']}), + #Cell('RAM64X1D', port_attrs={'WCLK': ['clkbuf_sink']}), + Cell('RAM64X1S', port_attrs={'WCLK': ['clkbuf_sink']}), + Cell('AND2B1L'), + Cell('CARRY8'), + Cell('CFGLUT5', port_attrs={'CLK': ['clkbuf_sink']}), + # Cell('LUT1'), + # Cell('LUT2'), + # Cell('LUT3'), + # Cell('LUT4'), + # Cell('LUT5'), + # Cell('LUT6'), + # Cell('MUXF7'), + # Cell('MUXF8'), + Cell('MUXF9'), + Cell('OR2L'), + # Cell('SRL16E', port_attrs={'CLK': ['clkbuf_sink']}), + # Cell('SRLC32E', port_attrs={'CLK': ['clkbuf_sink']}), + + # Clock. + # Cell('BUFG', port_attrs={'O': ['clkbuf_driver']}), + Cell('BUFG_GT', port_attrs={'O': ['clkbuf_driver']}), + Cell('BUFG_GT_SYNC'), + Cell('BUFG_PS', port_attrs={'O': ['clkbuf_driver']}), + Cell('BUFGCE', port_attrs={'O': ['clkbuf_driver']}), + Cell('BUFGCE_1', port_attrs={'O': ['clkbuf_driver']}), + Cell('BUFGCE_DIV', port_attrs={'O': ['clkbuf_driver']}), + #Cell('BUFGCTRL', port_attrs={'O': ['clkbuf_driver']}), + Cell('BUFGMUX', port_attrs={'O': ['clkbuf_driver']}), + Cell('BUFGMUX_1', port_attrs={'O': ['clkbuf_driver']}), + Cell('BUFGMUX_CTRL', port_attrs={'O': ['clkbuf_driver']}), + Cell('MMCME3_ADV'), + Cell('MMCME3_BASE'), + Cell('MMCME4_ADV'), + Cell('MMCME4_BASE'), + Cell('PLLE3_ADV'), + Cell('PLLE3_BASE'), + Cell('PLLE4_ADV'), + Cell('PLLE4_BASE'), + + # Configuration. + Cell('BSCANE2', keep=True), + Cell('DNA_PORTE2'), + Cell('EFUSE_USR'), + Cell('FRAME_ECCE3'), + Cell('ICAPE3', keep=True), + Cell('MASTER_JTAG', keep=True), + Cell('STARTUPE3', keep=True), + Cell('USR_ACCESSE2'), + + # I/O. + Cell('BITSLICE_CONTROL', keep=True), + Cell('DCIRESET', keep=True), + Cell('HPIO_VREF'), + # XXX + # Cell('IBUF', port_attrs={'I': ['iopad_external_pin']}), + Cell('IBUF_ANALOG', port_attrs={'I': ['iopad_external_pin']}), + Cell('IBUF_IBUFDISABLE', port_attrs={'I': ['iopad_external_pin']}), + Cell('IBUF_INTERMDISABLE', port_attrs={'I': ['iopad_external_pin']}), + Cell('IBUFDS', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), + Cell('IBUFDS_DIFF_OUT', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), + Cell('IBUFDS_DIFF_OUT_IBUFDISABLE', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), + Cell('IBUFDS_DIFF_OUT_INTERMDISABLE', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), + Cell('IBUFDS_DPHY', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), + Cell('IBUFDS_IBUFDISABLE', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), + Cell('IBUFDS_INTERMDISABLE', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), + Cell('IBUFDSE3', port_attrs={'I': ['iopad_external_pin'], 'IB': ['iopad_external_pin']}), + Cell('IBUFE3', port_attrs={'I': ['iopad_external_pin']}), + Cell('IDELAYCTRL', keep=True, port_attrs={'REFCLK': ['clkbuf_sink']}), + Cell('IDELAYE3', port_attrs={'CLK': ['clkbuf_sink']}), + Cell('IOBUF', port_attrs={'IO': ['iopad_external_pin']}), + Cell('IOBUF_DCIEN', port_attrs={'IO': ['iopad_external_pin']}), + Cell('IOBUF_INTERMDISABLE', port_attrs={'IO': ['iopad_external_pin']}), + Cell('IOBUFDS', port_attrs={'IO': ['iopad_external_pin']}), + Cell('IOBUFDS_DCIEN', port_attrs={'IO': ['iopad_external_pin'], 'IOB': ['iopad_external_pin']}), + Cell('IOBUFDS_DIFF_OUT', port_attrs={'IO': ['iopad_external_pin'], 'IOB': ['iopad_external_pin']}), + Cell('IOBUFDS_DIFF_OUT_DCIEN', port_attrs={'IO': ['iopad_external_pin'], 'IOB': ['iopad_external_pin']}), + Cell('IOBUFDS_DIFF_OUT_INTERMDISABLE', port_attrs={'IO': ['iopad_external_pin'], 'IOB': ['iopad_external_pin']}), + Cell('IOBUFDS_INTERMDISABLE', port_attrs={'IO': ['iopad_external_pin'], 'IOB': ['iopad_external_pin']}), + Cell('IOBUFDSE3', port_attrs={'IO': ['iopad_external_pin']}), + Cell('IOBUFE3', port_attrs={'IO': ['iopad_external_pin']}), + Cell('ISERDESE3', port_attrs={ + 'CLK': ['clkbuf_sink'], + 'CLK_B': ['clkbuf_sink'], + 'FIFO_RD_CLK': ['clkbuf_sink'], + 'CLKDIV': ['clkbuf_sink'], + }), + Cell('KEEPER'), + # Cell('OBUF', port_attrs={'O': ['iopad_external_pin']}), + Cell('OBUFDS', port_attrs={'O': ['iopad_external_pin'], 'OB': ['iopad_external_pin']}), + Cell('OBUFDS_DPHY', port_attrs={'O': ['iopad_external_pin'], 'OB': ['iopad_external_pin']}), + Cell('OBUFT', port_attrs={'O': ['iopad_external_pin']}), + Cell('OBUFTDS', port_attrs={'O': ['iopad_external_pin'], 'OB': ['iopad_external_pin']}), + Cell('ODELAYE3', port_attrs={'CLK': ['clkbuf_sink']}), + Cell('OSERDESE3', port_attrs={'CLK': ['clkbuf_sink'], 'CLKDIV': ['clkbuf_sink']}), + Cell('PULLDOWN'), + Cell('PULLUP'), + Cell('RIU_OR'), + Cell('RX_BITSLICE'), + Cell('RXTX_BITSLICE'), + Cell('TX_BITSLICE'), + Cell('TX_BITSLICE_TRI'), + + # Registers. + # Cell('FDCE'), + # Cell('FDPE'), + # Cell('FDRE'), + # Cell('FDSE'), + Cell('HARD_SYNC', port_attrs={'CLK': ['clkbuf_sink']}), + Cell('IDDRE1', port_attrs={'C': ['clkbuf_sink'], 'CB': ['clkbuf_sink']}), + Cell('LDCE'), + Cell('LDPE'), + Cell('ODDRE1', port_attrs={'C': ['clkbuf_sink']}), + + # NOTE: not in the official library guide! + Cell('PS8', keep=True), +] + + +class State(Enum): + OUTSIDE = auto() + IN_MODULE = auto() + IN_OTHER_MODULE = auto() + IN_FUNCTION = auto() + IN_TASK = auto() + +def xtract_cell_decl(cell, dirs, outf): + for dir in dirs: + fname = os.path.join(dir, cell.name + '.v') + try: + with open(fname) as f: + state = State.OUTSIDE + found = False + # Probably the most horrible Verilog "parser" ever written. + module_ports = [] + invertible_ports = set() + for l in f: + l = l.partition('//')[0] + l = l.strip() + if l == 'module {}'.format(cell.name) or l.startswith('module {} '.format(cell.name)): + if found: + print('Multiple modules in {}.'.format(fname)) + sys.exit(1) + elif state != State.OUTSIDE: + print('Nested modules in {}.'.format(fname)) + sys.exit(1) + found = True + state = State.IN_MODULE + if cell.keep: + outf.write('(* keep *)\n') + outf.write('module {} (...);\n'.format(cell.name)) + elif l.startswith('module '): + if state != State.OUTSIDE: + print('Nested modules in {}.'.format(fname)) + sys.exit(1) + state = State.IN_OTHER_MODULE + elif l.startswith('task '): + if state == State.IN_MODULE: + state = State.IN_TASK + elif l.startswith('function '): + if state == State.IN_MODULE: + state = State.IN_FUNCTION + elif l == 'endtask': + if state == State.IN_TASK: + state = State.IN_MODULE + elif l == 'endfunction': + if state == State.IN_FUNCTION: + state = State.IN_MODULE + elif l == 'endmodule': + if state == State.IN_MODULE: + for kind, rng, port in module_ports: + for attr in cell.port_attrs.get(port, []): + outf.write(' (* {} *)\n'.format(attr)) + if port in invertible_ports: + outf.write(' (* invertible_pin = "IS_{}_INVERTED" *)\n'.format(port)) + if rng is None: + outf.write(' {} {};\n'.format(kind, port)) + else: + outf.write(' {} {} {};\n'.format(kind, rng, port)) + outf.write(l + '\n') + outf.write('\n') + elif state != State.IN_OTHER_MODULE: + print('endmodule in weird place in {}.'.format(cell.name, fname)) + sys.exit(1) + state = State.OUTSIDE + elif l.startswith(('input ', 'output ', 'inout ')) and state == State.IN_MODULE: + if l.endswith((';', ',')): + l = l[:-1] + if ';' in l: + print('Weird port line in {} [{}].'.format(fname, l)) + sys.exit(1) + kind, _, ports = l.partition(' ') + for port in ports.split(','): + port = port.strip() + if port.startswith('['): + rng, port = port.split() + else: + rng = None + module_ports.append((kind, rng, port)) + elif l.startswith('parameter ') and state == State.IN_MODULE: + if 'UNPLACED' in l: + continue + if l.endswith((';', ',')): + l = l[:-1] + while ' ' in l: + l = l.replace(' ', ' ') + if ';' in l: + print('Weird parameter line in {} [{}].'.format(fname, l)) + sys.exit(1) + outf.write(' {};\n'.format(l)) + match = re.search('IS_([a-zA-Z0-9_]+)_INVERTED', l) + if match: + invertible_ports.add(match[1]) + if state != State.OUTSIDE: + print('endmodule not found in {}.'.format(fname)) + sys.exit(1) + if not found: + print('Cannot find module {} in {}.'.format(cell.name, fname)) + sys.exit(1) + return + except FileNotFoundError: + continue + print('Cannot find {}.'.format(cell.name)) + sys.exit(1) + +if __name__ == '__main__': + parser = ArgumentParser(description='Extract Xilinx blackbox cell definitions from ISE and Vivado.') + parser.add_argument('vivado_dir', nargs='?', default='/opt/Xilinx/Vivado/2018.1') + parser.add_argument('ise_dir', nargs='?', default='/opt/Xilinx/ISE/14.7') + args = parser.parse_args() + + dirs = [ + os.path.join(args.vivado_dir, 'data/verilog/src/xeclib'), + os.path.join(args.vivado_dir, 'data/verilog/src/retarget'), + os.path.join(args.ise_dir, 'ISE_DS/ISE/verilog/xeclib/unisims'), + ] + for dir in dirs: + if not os.path.isdir(dir): + print('{} is not a directory'.format(dir)) + + for ofile, cells in [ + ('xc6s_cells_xtra.v', XC6S_CELLS), + ('xc6v_cells_xtra.v', XC6V_CELLS), + ('xc7_cells_xtra.v', XC7_CELLS), + ('xcu_cells_xtra.v', XCU_CELLS), + ]: + out = StringIO() + for cell in cells: + xtract_cell_decl(cell, dirs, out) + + with open(ofile, 'w') as f: + f.write('// Created by cells_xtra.py from Xilinx models\n') + f.write('\n') + f.write(out.getvalue()) diff --git a/techlibs/xilinx/cells_xtra.sh b/techlibs/xilinx/cells_xtra.sh deleted file mode 100644 index c7ad16043..000000000 --- a/techlibs/xilinx/cells_xtra.sh +++ /dev/null @@ -1,145 +0,0 @@ -#!/bin/bash - -set -e -libdir="/opt/Xilinx/Vivado/2015.4/data/verilog/src" - -function xtract_cell_decl() -{ - for dir in $libdir/xeclib $libdir/retarget; do - [ -f $dir/$1.v ] || continue - egrep '^\s*((end)?module|parameter|input|output|(end)?function|(end)?task)' $dir/$1.v | - sed -re '/UNPLACED/ d; /^\s*function/,/endfunction/ d; /^\s*task/,/endtask/ d; - s,//.*,,; s/#?\(.*/(...);/; s/^(input|output|parameter)/ \1/; - s/\s+$//; s/,$/;/; /input|output|parameter/ s/[^;]$/&;/; s/\s+/ /g; - s/^ ((end)?module)/\1/; s/^ / /; /module.*_bb/,/endmodule/ d;' - echo; return - done - echo "Can't find $1." - exit 1 -} - -{ - echo "// Created by cells_xtra.sh from Xilinx models" - echo - - # Design elements types listed in Xilinx UG953 - xtract_cell_decl BSCANE2 - # xtract_cell_decl BUFG - xtract_cell_decl BUFGCE - xtract_cell_decl BUFGCE_1 - xtract_cell_decl BUFGCTRL - xtract_cell_decl BUFGMUX - xtract_cell_decl BUFGMUX_1 - xtract_cell_decl BUFGMUX_CTRL - xtract_cell_decl BUFH - xtract_cell_decl BUFHCE - xtract_cell_decl BUFIO - xtract_cell_decl BUFMR - xtract_cell_decl BUFMRCE - xtract_cell_decl BUFR - xtract_cell_decl CAPTUREE2 - # xtract_cell_decl CARRY4 - xtract_cell_decl CFGLUT5 - xtract_cell_decl DCIRESET - xtract_cell_decl DNA_PORT - xtract_cell_decl DSP48E1 - xtract_cell_decl EFUSE_USR - # xtract_cell_decl FDCE - # xtract_cell_decl FDPE - # xtract_cell_decl FDRE - # xtract_cell_decl FDSE - xtract_cell_decl FIFO18E1 - xtract_cell_decl FIFO36E1 - xtract_cell_decl FRAME_ECCE2 - xtract_cell_decl GTHE2_CHANNEL - xtract_cell_decl GTHE2_COMMON - xtract_cell_decl GTPE2_CHANNEL - xtract_cell_decl GTPE2_COMMON - xtract_cell_decl GTXE2_CHANNEL - xtract_cell_decl GTXE2_COMMON - # xtract_cell_decl IBUF - xtract_cell_decl IBUF_IBUFDISABLE - xtract_cell_decl IBUF_INTERMDISABLE - xtract_cell_decl IBUFDS - xtract_cell_decl IBUFDS_DIFF_OUT - xtract_cell_decl IBUFDS_DIFF_OUT_IBUFDISABLE - xtract_cell_decl IBUFDS_DIFF_OUT_INTERMDISABLE - xtract_cell_decl IBUFDS_GTE2 - xtract_cell_decl IBUFDS_IBUFDISABLE - xtract_cell_decl IBUFDS_INTERMDISABLE - xtract_cell_decl ICAPE2 - xtract_cell_decl IDDR - xtract_cell_decl IDDR_2CLK - xtract_cell_decl IDELAYCTRL - xtract_cell_decl IDELAYE2 - xtract_cell_decl IN_FIFO - xtract_cell_decl IOBUF - xtract_cell_decl IOBUF_DCIEN - xtract_cell_decl IOBUF_INTERMDISABLE - xtract_cell_decl IOBUFDS - xtract_cell_decl IOBUFDS_DCIEN - xtract_cell_decl IOBUFDS_DIFF_OUT - xtract_cell_decl IOBUFDS_DIFF_OUT_DCIEN - xtract_cell_decl IOBUFDS_DIFF_OUT_INTERMDISABLE - xtract_cell_decl ISERDESE2 - xtract_cell_decl KEEPER - xtract_cell_decl LDCE - xtract_cell_decl LDPE - # xtract_cell_decl LUT1 - # xtract_cell_decl LUT2 - # xtract_cell_decl LUT3 - # xtract_cell_decl LUT4 - # xtract_cell_decl LUT5 - # xtract_cell_decl LUT6 - xtract_cell_decl LUT6_2 - xtract_cell_decl MMCME2_ADV - xtract_cell_decl MMCME2_BASE - # xtract_cell_decl MUXF7 - # xtract_cell_decl MUXF8 - # xtract_cell_decl OBUF - xtract_cell_decl OBUFDS - xtract_cell_decl OBUFT - xtract_cell_decl OBUFTDS - xtract_cell_decl ODDR - xtract_cell_decl ODELAYE2 - xtract_cell_decl OSERDESE2 - xtract_cell_decl OUT_FIFO - xtract_cell_decl PHASER_IN - xtract_cell_decl PHASER_IN_PHY - xtract_cell_decl PHASER_OUT - xtract_cell_decl PHASER_OUT_PHY - xtract_cell_decl PHASER_REF - xtract_cell_decl PHY_CONTROL - xtract_cell_decl PLLE2_ADV - xtract_cell_decl PLLE2_BASE - xtract_cell_decl PULLDOWN - xtract_cell_decl PULLUP - # xtract_cell_decl RAM128X1D - xtract_cell_decl RAM128X1S - xtract_cell_decl RAM256X1S - xtract_cell_decl RAM32M - xtract_cell_decl RAM32X1D - xtract_cell_decl RAM32X1S - xtract_cell_decl RAM32X1S_1 - xtract_cell_decl RAM32X2S - xtract_cell_decl RAM64M - # xtract_cell_decl RAM64X1D - xtract_cell_decl RAM64X1S - xtract_cell_decl RAM64X1S_1 - xtract_cell_decl RAM64X2S - # xtract_cell_decl RAMB18E1 - # xtract_cell_decl RAMB36E1 - xtract_cell_decl ROM128X1 - xtract_cell_decl ROM256X1 - xtract_cell_decl ROM32X1 - xtract_cell_decl ROM64X1 - xtract_cell_decl SRL16E - xtract_cell_decl SRLC32E - xtract_cell_decl STARTUPE2 - xtract_cell_decl USR_ACCESSE2 - xtract_cell_decl XADC -} > cells_xtra.new - -mv cells_xtra.new cells_xtra.v -exit 0 - diff --git a/techlibs/xilinx/lut2lut.v b/techlibs/xilinx/lut2lut.v deleted file mode 100644 index 061ad2041..000000000 --- a/techlibs/xilinx/lut2lut.v +++ /dev/null @@ -1,65 +0,0 @@ -module LUT1(output O, input I0); - parameter [1:0] INIT = 0; - \$lut #( - .WIDTH(1), - .LUT(INIT) - ) _TECHMAP_REPLACE_ ( - .A(I0), - .Y(O) - ); -endmodule - -module LUT2(output O, input I0, I1); - parameter [3:0] INIT = 0; - \$lut #( - .WIDTH(2), - .LUT(INIT) - ) _TECHMAP_REPLACE_ ( - .A({I1, I0}), - .Y(O) - ); -endmodule - -module LUT3(output O, input I0, I1, I2); - parameter [7:0] INIT = 0; - \$lut #( - .WIDTH(3), - .LUT(INIT) - ) _TECHMAP_REPLACE_ ( - .A({I2, I1, I0}), - .Y(O) - ); -endmodule - -module LUT4(output O, input I0, I1, I2, I3); - parameter [15:0] INIT = 0; - \$lut #( - .WIDTH(4), - .LUT(INIT) - ) _TECHMAP_REPLACE_ ( - .A({I3, I2, I1, I0}), - .Y(O) - ); -endmodule - -module LUT5(output O, input I0, I1, I2, I3, I4); - parameter [31:0] INIT = 0; - \$lut #( - .WIDTH(5), - .LUT(INIT) - ) _TECHMAP_REPLACE_ ( - .A({I4, I3, I2, I1, I0}), - .Y(O) - ); -endmodule - -module LUT6(output O, input I0, I1, I2, I3, I4, I5); - parameter [63:0] INIT = 0; - \$lut #( - .WIDTH(6), - .LUT(INIT) - ) _TECHMAP_REPLACE_ ( - .A({I5, I4, I3, I2, I1, I0}), - .Y(O) - ); -endmodule diff --git a/techlibs/xilinx/lut_map.v b/techlibs/xilinx/lut_map.v new file mode 100644 index 000000000..13d3c3268 --- /dev/null +++ b/techlibs/xilinx/lut_map.v @@ -0,0 +1,119 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * + * 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. + * + */ + +// ============================================================================ +// LUT mapping + +`ifndef _NO_LUTS + +module \$lut (A, Y); + parameter WIDTH = 0; + parameter LUT = 0; + + input [WIDTH-1:0] A; + output Y; + + // Need to swap input ordering, and fix init accordingly, + // to match ABC's expectation of LUT inputs in non-decreasing + // delay order + function [WIDTH-1:0] permute_index; + input [WIDTH-1:0] i; + integer j; + begin + permute_index = 0; + for (j = 0; j < WIDTH; j = j + 1) + permute_index[WIDTH-1 - j] = i[j]; + end + endfunction + + function [2**WIDTH-1:0] permute_init; + input [2**WIDTH-1:0] orig; + integer i; + begin + permute_init = 0; + for (i = 0; i < 2**WIDTH; i = i + 1) + permute_init[i] = orig[permute_index(i)]; + end + endfunction + + parameter [2**WIDTH-1:0] P_LUT = permute_init(LUT); + + generate + if (WIDTH == 1) begin + LUT1 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y), + .I0(A[0])); + end else + if (WIDTH == 2) begin + LUT2 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y), + .I0(A[1]), .I1(A[0])); + end else + if (WIDTH == 3) begin + LUT3 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y), + .I0(A[2]), .I1(A[1]), .I2(A[0])); + end else + if (WIDTH == 4) begin + LUT4 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y), + .I0(A[3]), .I1(A[2]), .I2(A[1]), + .I3(A[0])); + end else + if (WIDTH == 5) begin + LUT5 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y), + .I0(A[4]), .I1(A[3]), .I2(A[2]), + .I3(A[1]), .I4(A[0])); + end else + if (WIDTH == 6) begin + LUT6 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y), + .I0(A[5]), .I1(A[4]), .I2(A[3]), + .I3(A[2]), .I4(A[1]), .I5(A[0])); + end else + if (WIDTH == 7) begin + wire T0, T1; + LUT6 #(.INIT(P_LUT[63:0])) fpga_lut_0 (.O(T0), + .I0(A[6]), .I1(A[5]), .I2(A[4]), + .I3(A[3]), .I4(A[2]), .I5(A[1])); + LUT6 #(.INIT(P_LUT[127:64])) fpga_lut_1 (.O(T1), + .I0(A[6]), .I1(A[5]), .I2(A[4]), + .I3(A[3]), .I4(A[2]), .I5(A[1])); + MUXF7 fpga_mux_0 (.O(Y), .I0(T0), .I1(T1), .S(A[0])); + end else + if (WIDTH == 8) begin + wire T0, T1, T2, T3, T4, T5; + LUT6 #(.INIT(P_LUT[63:0])) fpga_lut_0 (.O(T0), + .I0(A[7]), .I1(A[6]), .I2(A[5]), + .I3(A[4]), .I4(A[3]), .I5(A[2])); + LUT6 #(.INIT(P_LUT[127:64])) fpga_lut_1 (.O(T1), + .I0(A[7]), .I1(A[6]), .I2(A[5]), + .I3(A[4]), .I4(A[3]), .I5(A[2])); + LUT6 #(.INIT(P_LUT[191:128])) fpga_lut_2 (.O(T2), + .I0(A[7]), .I1(A[6]), .I2(A[5]), + .I3(A[4]), .I4(A[3]), .I5(A[2])); + LUT6 #(.INIT(P_LUT[255:192])) fpga_lut_3 (.O(T3), + .I0(A[7]), .I1(A[6]), .I2(A[5]), + .I3(A[4]), .I4(A[3]), .I5(A[2])); + MUXF7 fpga_mux_0 (.O(T4), .I0(T0), .I1(T1), .S(A[1])); + MUXF7 fpga_mux_1 (.O(T5), .I0(T2), .I1(T3), .S(A[1])); + MUXF8 fpga_mux_2 (.O(Y), .I0(T4), .I1(T5), .S(A[0])); + end else begin + wire _TECHMAP_FAIL_ = 1; + end + endgenerate +endmodule + +`endif + diff --git a/techlibs/xilinx/drams.txt b/techlibs/xilinx/lutrams.txt index e6635d0e2..2613c206c 100644 --- a/techlibs/xilinx/drams.txt +++ b/techlibs/xilinx/lutrams.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,12 +38,23 @@ 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 make_outreg or_next_if_better endmatch match $__XILINX_RAM128X1D + min bits 9 + min wports 1 make_outreg endmatch diff --git a/techlibs/xilinx/drams_map.v b/techlibs/xilinx/lutrams_map.v index 47476b592..77041ca86 100644 --- a/techlibs/xilinx/drams_map.v +++ b/techlibs/xilinx/lutrams_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/techlibs/xilinx/mux_map.v b/techlibs/xilinx/mux_map.v new file mode 100644 index 000000000..91aaf2118 --- /dev/null +++ b/techlibs/xilinx/mux_map.v @@ -0,0 +1,71 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * 2019 Eddie Hung <eddie@fpgeh.com> + * + * 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. + * + */ + +// The purpose of these mapping rules is to allow preserve all (sufficiently +// wide) $shiftx cells during 'techmap' so that they can be mapped to hard +// resources, rather than being bit-blasted to gates during 'techmap' +// execution + +module \$shiftx (A, B, Y); + parameter A_SIGNED = 0; + parameter B_SIGNED = 0; + parameter A_WIDTH = 1; + parameter B_WIDTH = 1; + parameter Y_WIDTH = 1; + + input [A_WIDTH-1:0] A; + input [B_WIDTH-1:0] B; + output [Y_WIDTH-1:0] Y; + + parameter [B_WIDTH-1:0] _TECHMAP_CONSTMSK_B_ = 0; + parameter [B_WIDTH-1:0] _TECHMAP_CONSTVAL_B_ = 0; + + generate + if (B_SIGNED) begin + if (_TECHMAP_CONSTMSK_B_[B_WIDTH-1] && (_TECHMAP_CONSTVAL_B_[B_WIDTH-1] == 1'b0 || _TECHMAP_CONSTVAL_B_[B_WIDTH-1] === 1'bx)) + // Optimisation to remove B_SIGNED if sign bit of B is constant-0 + \$shiftx #( + .A_SIGNED(A_SIGNED), + .B_SIGNED(0), + .A_WIDTH(A_WIDTH), + .B_WIDTH(B_WIDTH-1'd1), + .Y_WIDTH(Y_WIDTH) + ) _TECHMAP_REPLACE_ ( + .A(A), .B(B[B_WIDTH-2:0]), .Y(Y) + ); + else + wire _TECHMAP_FAIL_ = 1; + end + else begin + if (((A_WIDTH + Y_WIDTH - 1) / Y_WIDTH) < `MIN_MUX_INPUTS) + wire _TECHMAP_FAIL_ = 1; + else + \$__XILINX_SHIFTX #( + .A_SIGNED(A_SIGNED), + .B_SIGNED(B_SIGNED), + .A_WIDTH(A_WIDTH), + .B_WIDTH(B_WIDTH), + .Y_WIDTH(Y_WIDTH) + ) _TECHMAP_REPLACE_ ( + .A(A), .B(B), .Y(Y) + ); + end + endgenerate +endmodule diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 1bc61daef..888b5ed7b 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -2,6 +2,7 @@ * yosys -- Yosys Open SYnthesis Suite * * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * (C) 2019 Eddie Hung <eddie@fpgeh.com> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -25,20 +26,14 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN -bool check_label(bool &active, std::string run_from, std::string run_to, std::string label) -{ - if (label == run_from) - active = true; - if (label == run_to) - active = false; - return active; -} - -struct SynthXilinxPass : public Pass +#define XC7_WIRE_DELAY 300 // Number with which ABC will map a 6-input gate + // to one LUT6 (instead of a LUT5 + LUT2) + +struct SynthXilinxPass : public ScriptPass { - SynthXilinxPass() : Pass("synth_xilinx", "synthesis for Xilinx FPGAs") { } + SynthXilinxPass() : ScriptPass("synth_xilinx", "synthesis for Xilinx FPGAs") { } - virtual void help() + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); @@ -51,6 +46,11 @@ struct SynthXilinxPass : public Pass log(" -top <module>\n"); log(" use the specified module as top module\n"); log("\n"); + log(" -family {xcup|xcu|xc7|xc6v|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 <file>\n"); log(" write the design to the specified edif file. writing of an output file\n"); log(" is omitted if this parameter is not specified.\n"); @@ -63,80 +63,91 @@ struct SynthXilinxPass : public Pass log(" generate an output netlist (and BLIF file) suitable for VPR\n"); log(" (this feature is experimental and incomplete)\n"); log("\n"); - log(" -run <from_label>:<to_label>\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"); - log(" synonymous to the end of the command list.\n"); + log(" -ise\n"); + log(" generate an output netlist suitable for ISE (enables -iopad)\n"); log("\n"); - log(" -flatten\n"); - log(" flatten design before synthesis\n"); + log(" -nobram\n"); + log(" do not use block RAM cells in output netlist\n"); log("\n"); - log(" -retime\n"); - log(" run 'abc' with -dff option\n"); + log(" -nolutram\n"); + log(" do not use distributed RAM cells in output netlist\n"); log("\n"); + log(" -nosrl\n"); + log(" do not use distributed SRL cells in output netlist\n"); log("\n"); - log("The following commands are executed by this synthesis command:\n"); + log(" -nocarry\n"); + log(" do not use XORCY/MUXCY/CARRY4 cells in output netlist\n"); log("\n"); - log(" begin:\n"); - log(" read_verilog -lib +/xilinx/cells_sim.v\n"); - log(" read_verilog -lib +/xilinx/cells_xtra.v\n"); - log(" read_verilog -lib +/xilinx/brams_bb.v\n"); - log(" hierarchy -check -top <top>\n"); + log(" -nowidelut\n"); + log(" do not use MUXF[78] resources to implement LUTs larger than LUT6s\n"); log("\n"); - log(" flatten: (only if -flatten)\n"); - log(" proc\n"); - log(" flatten\n"); + log(" -iopad\n"); + log(" enable I/O buffer insertion (selected automatically by -ise)\n"); log("\n"); - log(" coarse:\n"); - log(" synth -run coarse\n"); + log(" -noiopad\n"); + log(" disable I/O buffer insertion (only useful with -ise)\n"); log("\n"); - log(" bram:\n"); - log(" memory_bram -rules +/xilinx/brams.txt\n"); - log(" techmap -map +/xilinx/brams_map.v\n"); + log(" -noclkbuf\n"); + log(" disable automatic clock buffer insertion\n"); log("\n"); - log(" dram:\n"); - log(" memory_bram -rules +/xilinx/drams.txt\n"); - log(" techmap -map +/xilinx/drams_map.v\n"); + log(" -widemux <int>\n"); + log(" enable inference of hard multiplexer resources (MUXF[78]) for muxes at or\n"); + log(" above this number of inputs (minimum value 2, recommended value >= 5).\n"); + log(" default: 0 (no inference)\n"); log("\n"); - log(" fine:\n"); - log(" opt -fast -full\n"); - log(" memory_map\n"); - log(" dffsr2dff\n"); - log(" dff2dffe\n"); - log(" opt -full\n"); - log(" techmap -map +/techmap.v -map +/xilinx/arith_map.v\n"); - log(" opt -fast\n"); + log(" -run <from_label>:<to_label>\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"); + log(" synonymous to the end of the command list.\n"); log("\n"); - log(" map_luts:\n"); - log(" abc -luts 2:2,3,6:5,10,20 [-dff]\n"); - log(" clean\n"); + log(" -flatten\n"); + log(" flatten design before synthesis\n"); log("\n"); - log(" map_cells:\n"); - log(" techmap -map +/xilinx/cells_map.v (with -D NO_LUT in vpr mode)\n"); - log(" dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT\n"); - log(" clean\n"); + log(" -retime\n"); + log(" run 'abc' with -dff option\n"); log("\n"); - log(" check:\n"); - log(" hierarchy -check\n"); - log(" stat\n"); - log(" check -noinit\n"); + log(" -abc9\n"); + log(" use new ABC9 flow (EXPERIMENTAL)\n"); log("\n"); - log(" edif: (only if -edif)\n"); - log(" write_edif <file-name>\n"); log("\n"); - log(" blif: (only if -blif)\n"); - log(" write_blif <file-name>\n"); + log("The following commands are executed by this synthesis command:\n"); + help_script(); log("\n"); } - virtual void execute(std::vector<std::string> args, RTLIL::Design *design) + + std::string top_opt, edif_file, blif_file, family; + bool flatten, retime, vpr, ise, iopad, noiopad, noclkbuf, nobram, nolutram, nosrl, nocarry, nowidelut, abc9; + bool flatten_before_abc; + int widemux; + + void clear_flags() YS_OVERRIDE + { + top_opt = "-auto-top"; + edif_file.clear(); + blif_file.clear(); + family = "xc7"; + flatten = false; + retime = false; + vpr = false; + ise = false; + iopad = false; + noiopad = false; + noclkbuf = false; + nocarry = false; + nobram = false; + nolutram = false; + nosrl = false; + nocarry = false; + nowidelut = false; + abc9 = false; + flatten_before_abc = false; + widemux = 0; + } + + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { - std::string top_opt = "-auto-top"; - std::string edif_file; - std::string blif_file; std::string run_from, run_to; - bool flatten = false; - bool retime = false; - bool vpr = false; + clear_flags(); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) @@ -145,6 +156,10 @@ struct SynthXilinxPass : public Pass top_opt = "-top " + args[++argidx]; continue; } + if ((args[argidx] == "-family" || args[argidx] == "-arch") && argidx+1 < args.size()) { + family = args[++argidx]; + continue; + } if (args[argidx] == "-edif" && argidx+1 < args.size()) { edif_file = args[++argidx]; continue; @@ -165,103 +180,332 @@ struct SynthXilinxPass : public Pass flatten = true; continue; } + if (args[argidx] == "-flatten_before_abc") { + flatten_before_abc = true; + continue; + } if (args[argidx] == "-retime") { retime = true; continue; } + if (args[argidx] == "-nocarry") { + nocarry = true; + continue; + } + if (args[argidx] == "-nowidelut") { + nowidelut = true; + continue; + } if (args[argidx] == "-vpr") { vpr = true; continue; } + if (args[argidx] == "-ise") { + ise = true; + continue; + } + if (args[argidx] == "-iopad") { + iopad = true; + continue; + } + if (args[argidx] == "-noiopad") { + noiopad = true; + continue; + } + if (args[argidx] == "-noclkbuf") { + noclkbuf = true; + continue; + } + if (args[argidx] == "-nocarry") { + nocarry = true; + continue; + } + if (args[argidx] == "-nobram") { + nobram = true; + continue; + } + if (args[argidx] == "-nolutram" || /*deprecated alias*/ args[argidx] == "-nodram") { + nolutram = true; + continue; + } + if (args[argidx] == "-nosrl") { + nosrl = true; + continue; + } + if (args[argidx] == "-widemux" && argidx+1 < args.size()) { + widemux = atoi(args[++argidx].c_str()); + continue; + } + if (args[argidx] == "-abc9") { + abc9 = true; + continue; + } break; } extra_args(args, argidx, design); + if (family != "xcup" && family != "xcu" && family != "xc7" && family != "xc6v" && family != "xc6s") + log_cmd_error("Invalid Xilinx -family setting: '%s'.\n", family.c_str()); + + if (widemux != 0 && widemux < 2) + log_cmd_error("-widemux value must be 0 or >= 2.\n"); + if (!design->full_selection()) - log_cmd_error("This comannd only operates on fully selected designs!\n"); + log_cmd_error("This command only operates on fully selected designs!\n"); - bool active = run_from.empty(); + if (abc9 && retime) + log_cmd_error("-retime option not currently compatible with -abc9!\n"); log_header(design, "Executing SYNTH_XILINX pass.\n"); log_push(); - if (check_label(active, run_from, run_to, "begin")) - { - Pass::call(design, "read_verilog -lib +/xilinx/cells_sim.v"); - Pass::call(design, "read_verilog -lib +/xilinx/cells_xtra.v"); - Pass::call(design, "read_verilog -lib +/xilinx/brams_bb.v"); - Pass::call(design, stringf("hierarchy -check %s", top_opt.c_str())); + run_script(design, run_from, run_to); + + log_pop(); + } + + void script() YS_OVERRIDE + { + std::string ff_map_file; + if (help_mode) + ff_map_file = "+/xilinx/{family}_ff_map.v"; + else if (family == "xc6s") + ff_map_file = "+/xilinx/xc6s_ff_map.v"; + else + ff_map_file = "+/xilinx/xc7_ff_map.v"; + + if (check_label("begin")) { + if (vpr) + run("read_verilog -lib -D_EXPLICIT_CARRY +/xilinx/cells_sim.v"); + else + run("read_verilog -lib +/xilinx/cells_sim.v"); + + if (help_mode) + run("read_verilog -lib +/xilinx/{family}_cells_xtra.v"); + else if (family == "xc6s") + run("read_verilog -lib +/xilinx/xc6s_cells_xtra.v"); + else if (family == "xc6v") + run("read_verilog -lib +/xilinx/xc6v_cells_xtra.v"); + else if (family == "xc7") + run("read_verilog -lib +/xilinx/xc7_cells_xtra.v"); + else if (family == "xcu" || family == "xcup") + run("read_verilog -lib +/xilinx/xcu_cells_xtra.v"); + + if (help_mode) { + run("read_verilog -lib +/xilinx/{family}_brams_bb.v"); + } else if (family == "xc6s") { + run("read_verilog -lib +/xilinx/xc6s_brams_bb.v"); + } else if (family == "xc6v" || family == "xc7") { + run("read_verilog -lib +/xilinx/xc7_brams_bb.v"); + } + + run(stringf("hierarchy -check %s", top_opt.c_str())); } - if (flatten && check_label(active, run_from, run_to, "flatten")) - { - Pass::call(design, "proc"); - Pass::call(design, "flatten"); + if (check_label("coarse")) { + run("proc"); + if (help_mode || flatten) + run("flatten", "(if -flatten)"); + run("opt_expr"); + run("opt_clean"); + run("check"); + run("opt"); + if (help_mode) + run("wreduce [-keepdc]", "(option for '-widemux')"); + else + run("wreduce" + std::string(widemux > 0 ? " -keepdc" : "")); + run("peepopt"); + run("opt_clean"); + + if (widemux > 0 || help_mode) + run("muxpack", " ('-widemux' only)"); + + // xilinx_srl looks for $shiftx cells for identifying variable-length + // shift registers, so attempt to convert $pmux-es to this + // Also: wide multiplexer inference benefits from this too + if (!(nosrl && widemux == 0) || help_mode) { + run("pmux2shiftx", "(skip if '-nosrl' and '-widemux=0')"); + run("clean", " (skip if '-nosrl' and '-widemux=0')"); + } + + run("techmap -map +/cmp2lut.v -D LUT_WIDTH=6"); + run("alumacc"); + run("share"); + run("opt"); + run("fsm"); + run("opt -fast"); + run("memory -nomap"); + run("opt_clean"); } - if (check_label(active, run_from, run_to, "coarse")) - { - Pass::call(design, "synth -run coarse"); + if (check_label("map_bram", "(skip if '-nobram')")) { + if (help_mode) { + run("memory_bram -rules +/xilinx/{family}_brams.txt"); + run("techmap -map +/xilinx/{family}_brams_map.v"); + } else if (!nobram) { + if (family == "xc6s") { + run("memory_bram -rules +/xilinx/xc6s_brams.txt"); + run("techmap -map +/xilinx/xc6s_brams_map.v"); + } else if (family == "xc6v" || family == "xc7") { + run("memory_bram -rules +/xilinx/xc7_brams.txt"); + run("techmap -map +/xilinx/xc7_brams_map.v"); + } else { + log_warning("Block RAM inference not yet supported for family %s.\n", family.c_str()); + } + } } - if (check_label(active, run_from, run_to, "bram")) - { - Pass::call(design, "memory_bram -rules +/xilinx/brams.txt"); - Pass::call(design, "techmap -map +/xilinx/brams_map.v"); + if (check_label("map_lutram", "(skip if '-nolutram')")) { + if (!nolutram || help_mode) { + run("memory_bram -rules +/xilinx/lutrams.txt"); + run("techmap -map +/xilinx/lutrams_map.v"); + } } - if (check_label(active, run_from, run_to, "dram")) - { - Pass::call(design, "memory_bram -rules +/xilinx/drams.txt"); - Pass::call(design, "techmap -map +/xilinx/drams_map.v"); + if (check_label("map_ffram")) { + if (widemux > 0) + run("opt -fast -mux_bool -undriven -fine"); // Necessary to omit -mux_undef otherwise muxcover + // performs less efficiently + else + run("opt -fast -full"); + run("memory_map"); } - if (check_label(active, run_from, run_to, "fine")) - { - Pass::call(design, "opt -fast -full"); - Pass::call(design, "memory_map"); - Pass::call(design, "dffsr2dff"); - Pass::call(design, "dff2dffe"); - Pass::call(design, "opt -full"); - Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/arith_map.v"); - Pass::call(design, "opt -fast"); + if (check_label("fine")) { + run("dffsr2dff"); + run("dff2dffe"); + if (help_mode) { + run("simplemap t:$mux", " ('-widemux' only)"); + run("muxcover <internal options>, ('-widemux' only)"); + } + else if (widemux > 0) { + run("simplemap t:$mux"); + constexpr int cost_mux2 = 100; + std::string muxcover_args = stringf(" -nodecode -mux2=%d", cost_mux2); + switch (widemux) { + case 2: muxcover_args += stringf(" -mux4=%d -mux8=%d -mux16=%d", cost_mux2+1, cost_mux2+2, cost_mux2+3); break; + case 3: + case 4: muxcover_args += stringf(" -mux4=%d -mux8=%d -mux16=%d", cost_mux2*(widemux-1)-2, cost_mux2*(widemux-1)-1, cost_mux2*(widemux-1)); break; + case 5: + case 6: + case 7: + case 8: muxcover_args += stringf(" -mux8=%d -mux16=%d", cost_mux2*(widemux-1)-1, cost_mux2*(widemux-1)); break; + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + default: muxcover_args += stringf(" -mux16=%d", cost_mux2*(widemux-1)-1); break; + } + run("muxcover " + muxcover_args); + } + run("opt -full"); + + if (!nosrl || help_mode) + run("xilinx_srl -variable -minlen 3", "(skip if '-nosrl')"); + + std::string techmap_args = " -map +/techmap.v"; + if (help_mode) + techmap_args += " [-map +/xilinx/mux_map.v]"; + else if (widemux > 0) + techmap_args += stringf(" -D MIN_MUX_INPUTS=%d -map +/xilinx/mux_map.v", widemux); + if (help_mode) + techmap_args += " [-map +/xilinx/arith_map.v]"; + else if (!nocarry) { + techmap_args += " -map +/xilinx/arith_map.v"; + if (vpr) + techmap_args += " -D _EXPLICIT_CARRY"; + else if (abc9) + techmap_args += " -D _CLB_CARRY"; + } + run("techmap " + techmap_args); + run("opt -fast"); } - if (check_label(active, run_from, run_to, "map_luts")) - { - Pass::call(design, "abc -luts 2:2,3,6:5,10,20" + string(retime ? " -dff" : "")); - Pass::call(design, "clean"); + if (check_label("map_cells")) { + std::string techmap_args = "-map +/techmap.v -map +/xilinx/cells_map.v"; + if (widemux > 0) + techmap_args += stringf(" -D MIN_MUX_INPUTS=%d", widemux); + run("techmap " + techmap_args); + run("clean"); } - if (check_label(active, run_from, run_to, "map_cells")) - { - if (vpr) - Pass::call(design, "techmap -D NO_LUT -map +/xilinx/cells_map.v"); + if (check_label("map_ffs")) { + if (abc9 || help_mode) { + run("techmap -map " + ff_map_file, "('-abc9' only)"); + } + } + + if (check_label("map_luts")) { + run("opt_expr -mux_undef"); + if (flatten_before_abc) + run("flatten"); + if (help_mode) + run("abc -luts 2:2,3,6:5[,10,20] [-dff]", "(option for 'nowidelut'; option for '-retime')"); + else if (abc9) { + if (family != "xc7") + log_warning("'synth_xilinx -abc9' currently supports '-family xc7' only.\n"); + run("techmap -map +/xilinx/abc_map.v -max_iter 1"); + run("read_verilog -icells -lib +/xilinx/abc_model.v"); + if (nowidelut) + run("abc9 -lut +/xilinx/abc_xc7_nowide.lut -box +/xilinx/abc_xc7.box -W " + std::to_string(XC7_WIRE_DELAY)); + else + run("abc9 -lut +/xilinx/abc_xc7.lut -box +/xilinx/abc_xc7.box -W " + std::to_string(XC7_WIRE_DELAY)); + } + 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"); + + // This shregmap call infers fixed length shift registers after abc + // has performed any necessary retiming + if (!nosrl || help_mode) + run("xilinx_srl -fixed -minlen 3", "(skip if '-nosrl')"); + std::string techmap_args = "-map +/xilinx/lut_map.v -map +/xilinx/cells_map.v"; + if (help_mode) + techmap_args += " [-map " + ff_map_file + "]"; + else if (abc9) + techmap_args += " -map +/xilinx/abc_unmap.v"; else - Pass::call(design, "techmap -map +/xilinx/cells_map.v"); - Pass::call(design, "dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT"); - Pass::call(design, "clean"); + techmap_args += " -map " + ff_map_file; + run("techmap " + techmap_args); + run("clean"); } - if (check_label(active, run_from, run_to, "check")) - { - Pass::call(design, "hierarchy -check"); - Pass::call(design, "stat"); - Pass::call(design, "check -noinit"); + if (check_label("finalize")) { + bool do_iopad = iopad || (ise && !noiopad); + if (help_mode || !noclkbuf) { + if (help_mode || do_iopad) + run("clkbufmap -buf BUFG O:I -inpad IBUFG O:I", "(skip if '-noclkbuf', '-inpad' passed if '-iopad' or '-ise' and not '-noiopad')"); + else + run("clkbufmap -buf BUFG O:I"); + } + if (help_mode || do_iopad) + run("iopadmap -bits -outpad OBUF I:O -inpad IBUF O:I A:top", "(only if '-iopad' or '-ise' and not '-noiopad')"); + if (help_mode || ise) + run("extractinv -inv INV O:I", "(only if '-ise')"); } - if (check_label(active, run_from, run_to, "edif")) - { - if (!edif_file.empty()) - Pass::call(design, stringf("write_edif %s", edif_file.c_str())); + if (check_label("check")) { + run("hierarchy -check"); + run("stat -tech xilinx"); + run("check -noinit"); } - if (check_label(active, run_from, run_to, "blif")) - { - if (!blif_file.empty()) - Pass::call(design, stringf("write_blif %s", edif_file.c_str())); + + if (check_label("edif")) { + if (!edif_file.empty() || help_mode) + run(stringf("write_edif -pvector bra %s", edif_file.c_str())); } - log_pop(); + if (check_label("blif")) { + if (!blif_file.empty() || help_mode) + run(stringf("write_blif %s", edif_file.c_str())); + } } } SynthXilinxPass; diff --git a/techlibs/xilinx/xc6s_brams.txt b/techlibs/xilinx/xc6s_brams.txt new file mode 100644 index 000000000..17cd8e355 --- /dev/null +++ b/techlibs/xilinx/xc6s_brams.txt @@ -0,0 +1,84 @@ + +bram $__XILINX_RAMB8BWER_SDP + init 1 + abits 8 + dbits 36 + groups 2 + ports 1 1 + wrmode 0 1 + enable 1 4 + transp 0 0 + clocks 2 3 + clkpol 2 3 +endbram + +bram $__XILINX_RAMB16BWER_TDP + init 1 + abits 9 @a9d36 + dbits 36 @a9d36 + abits 10 @a10d18 + dbits 18 @a10d18 + abits 11 @a11d9 + dbits 9 @a11d9 + abits 12 @a12d4 + dbits 4 @a12d4 + abits 13 @a13d2 + dbits 2 @a13d2 + abits 14 @a14d1 + dbits 1 @a14d1 + groups 2 + ports 1 1 + wrmode 0 1 + enable 1 4 @a9d36 + enable 1 2 @a10d18 + enable 1 1 @a11d9 @a12d4 @a13d2 @a14d1 + transp 0 0 + clocks 2 3 + clkpol 2 3 +endbram + +bram $__XILINX_RAMB8BWER_TDP + init 1 + abits 9 @a9d18 + dbits 18 @a9d18 + abits 10 @a10d9 + dbits 9 @a10d9 + abits 11 @a11d4 + dbits 4 @a11d4 + abits 12 @a12d2 + dbits 2 @a12d2 + abits 13 @a13d1 + dbits 1 @a13d1 + groups 2 + ports 1 1 + wrmode 0 1 + enable 1 2 @a9d18 + enable 1 1 @a10d9 @a11d4 @a12d2 @a13d1 + transp 0 0 + clocks 2 3 + clkpol 2 3 +endbram + +match $__XILINX_RAMB8BWER_SDP + min bits 4096 + min efficiency 5 + shuffle_enable B + make_transp + or_next_if_better +endmatch + +match $__XILINX_RAMB16BWER_TDP + min bits 4096 + min efficiency 5 + shuffle_enable B + make_transp + or_next_if_better +endmatch + +match $__XILINX_RAMB8BWER_TDP + min bits 4096 + min efficiency 5 + shuffle_enable B + make_transp +endmatch + diff --git a/techlibs/xilinx/xc6s_brams_bb.v b/techlibs/xilinx/xc6s_brams_bb.v new file mode 100644 index 000000000..041d6b54f --- /dev/null +++ b/techlibs/xilinx/xc6s_brams_bb.v @@ -0,0 +1,215 @@ +module RAMB8BWER ( + (* clkbuf_sink *) + input CLKAWRCLK, + (* clkbuf_sink *) + input CLKBRDCLK, + input ENAWREN, + input ENBRDEN, + input REGCEA, + input REGCEBREGCE, + input RSTA, + input RSTBRST, + + input [12:0] ADDRAWRADDR, + input [12:0] ADDRBRDADDR, + input [15:0] DIADI, + input [15:0] DIBDI, + input [1:0] DIPADIP, + input [1:0] DIPBDIP, + input [1:0] WEAWEL, + input [1:0] WEBWEU, + + output [15:0] DOADO, + output [15:0] DOBDO, + output [1:0] DOPADOP, + output [1:0] DOPBDOP +); + parameter INITP_00 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INITP_01 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INITP_02 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INITP_03 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + + parameter INIT_00 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_01 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_02 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_03 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_04 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_05 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_06 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_07 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_08 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_09 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_0A = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_0B = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_0C = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_0D = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_0E = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_0F = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_10 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_11 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_12 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_13 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_14 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_15 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_16 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_17 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_18 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_19 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_1A = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_1B = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_1C = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_1D = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_1E = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_1F = 256'h0000000000000000000000000000000000000000000000000000000000000000; + + parameter RAM_MODE = "TDP"; + parameter integer DOA_REG = 0; + parameter integer DOB_REG = 0; + + parameter integer DATA_WIDTH_A = 0; + parameter integer DATA_WIDTH_B = 0; + + parameter WRITE_MODE_A = "WRITE_FIRST"; + parameter WRITE_MODE_B = "WRITE_FIRST"; + + parameter EN_RSTRAM_A = "TRUE"; + parameter EN_RSTRAM_B = "TRUE"; + + parameter INIT_A = 18'h000000000; + parameter INIT_B = 18'h000000000; + parameter SRVAL_A = 18'h000000000; + parameter SRVAL_B = 18'h000000000; + + parameter RST_PRIORITY_A = "CE"; + parameter RST_PRIORITY_B = "CE"; + + parameter RSTTYPE = "SYNC"; + + parameter SIM_COLLISION_CHECK = "ALL"; +endmodule + +module RAMB16BWER ( + (* clkbuf_sink *) + input CLKA, + (* clkbuf_sink *) + input CLKB, + input ENA, + input ENB, + input REGCEA, + input REGCEB, + input RSTA, + input RSTB, + + input [13:0] ADDRA, + input [13:0] ADDRB, + input [31:0] DIA, + input [31:0] DIB, + input [3:0] DIPA, + input [3:0] DIPB, + input [3:0] WEA, + input [3:0] WEB, + + output [31:0] DOA, + output [31:0] DOB, + output [3:0] DOPA, + output [3:0] DOPB +); + parameter INITP_00 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INITP_01 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INITP_02 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INITP_03 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INITP_04 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INITP_05 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INITP_06 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INITP_07 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + + parameter INIT_00 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_01 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_02 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_03 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_04 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_05 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_06 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_07 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_08 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_09 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_0A = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_0B = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_0C = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_0D = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_0E = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_0F = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_10 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_11 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_12 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_13 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_14 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_15 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_16 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_17 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_18 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_19 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_1A = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_1B = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_1C = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_1D = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_1E = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_1F = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_20 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_21 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_22 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_23 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_24 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_25 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_26 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_27 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_28 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_29 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_2A = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_2B = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_2C = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_2D = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_2E = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_2F = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_30 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_31 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_32 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_33 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_34 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_35 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_36 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_37 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_38 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_39 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_3A = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_3B = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_3C = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_3D = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_3E = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_3F = 256'h0000000000000000000000000000000000000000000000000000000000000000; + + parameter integer DOA_REG = 0; + parameter integer DOB_REG = 0; + + parameter integer DATA_WIDTH_A = 0; + parameter integer DATA_WIDTH_B = 0; + + parameter WRITE_MODE_A = "WRITE_FIRST"; + parameter WRITE_MODE_B = "WRITE_FIRST"; + + parameter EN_RSTRAM_A = "TRUE"; + parameter EN_RSTRAM_B = "TRUE"; + + parameter INIT_A = 36'h000000000; + parameter INIT_B = 36'h000000000; + parameter SRVAL_A = 36'h000000000; + parameter SRVAL_B = 36'h000000000; + + parameter RST_PRIORITY_A = "CE"; + parameter RST_PRIORITY_B = "CE"; + + parameter RSTTYPE = "SYNC"; + + parameter SIM_COLLISION_CHECK = "ALL"; +endmodule + diff --git a/techlibs/xilinx/xc6s_brams_map.v b/techlibs/xilinx/xc6s_brams_map.v new file mode 100644 index 000000000..16fd15e74 --- /dev/null +++ b/techlibs/xilinx/xc6s_brams_map.v @@ -0,0 +1,255 @@ +module \$__XILINX_RAMB8BWER_SDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN); + parameter CLKPOL2 = 1; + parameter CLKPOL3 = 1; + parameter [9215:0] INIT = 9216'bx; + + input CLK2; + input CLK3; + + input [7:0] A1ADDR; + output [35:0] A1DATA; + input A1EN; + + input [7:0] B1ADDR; + input [35:0] B1DATA; + input [3:0] B1EN; + + wire [12:0] A1ADDR_13 = {A1ADDR, 5'b0}; + wire [12:0] B1ADDR_13 = {B1ADDR, 5'b0}; + + wire [3:0] DIP, DOP; + wire [31:0] DI, DO; + + assign A1DATA = { DOP[3], DO[31:24], DOP[2], DO[23:16], DOP[1], DO[15: 8], DOP[0], DO[ 7: 0] }; + assign { DIP[3], DI[31:24], DIP[2], DI[23:16], DIP[1], DI[15: 8], DIP[0], DI[ 7: 0] } = B1DATA; + + RAMB8BWER #( + .RAM_MODE("SDP"), + .DATA_WIDTH_A(36), + .DATA_WIDTH_B(36), + .WRITE_MODE_A("READ_FIRST"), + .WRITE_MODE_B("READ_FIRST"), + `include "brams_init_9.vh" + ) _TECHMAP_REPLACE_ ( + .DOBDO(DO[31:16]), + .DOADO(DO[15:0]), + .DOPBDOP(DOP[3:2]), + .DOPADOP(DOP[1:0]), + .DIBDI(DI[31:16]), + .DIADI(DI[15:0]), + .DIPBDIP(DIP[3:2]), + .DIPADIP(DIP[1:0]), + .WEBWEU(B1EN[3:2]), + .WEAWEL(B1EN[1:0]), + + .ADDRAWRADDR(B1ADDR_13), + .CLKAWRCLK(CLK3 ^ !CLKPOL3), + .ENAWREN(|1), + .REGCEA(|0), + .RSTA(|0), + + .ADDRBRDADDR(A1ADDR_13), + .CLKBRDCLK(CLK2 ^ !CLKPOL2), + .ENBRDEN(A1EN), + .REGCEBREGCE(|1), + .RSTBRST(|0) + ); +endmodule + +// ------------------------------------------------------------------------ + +module \$__XILINX_RAMB16BWER_TDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN); + parameter CFG_ABITS = 9; + parameter CFG_DBITS = 36; + parameter CFG_ENABLE_B = 4; + + parameter CLKPOL2 = 1; + parameter CLKPOL3 = 1; + parameter [18431:0] INIT = 18432'bx; + + input CLK2; + input CLK3; + + input [CFG_ABITS-1:0] A1ADDR; + output [CFG_DBITS-1:0] A1DATA; + input A1EN; + + input [CFG_ABITS-1:0] B1ADDR; + input [CFG_DBITS-1:0] B1DATA; + input [CFG_ENABLE_B-1:0] B1EN; + + wire [13:0] A1ADDR_14 = A1ADDR << (14 - CFG_ABITS); + wire [13:0] B1ADDR_14 = B1ADDR << (14 - CFG_ABITS); + wire [3:0] B1EN_4 = {4{B1EN}}; + + wire [3:0] DIP, DOP; + wire [31:0] DI, DO; + + wire [31:0] DOB; + wire [3:0] DOPB; + + assign A1DATA = { DOP[3], DO[31:24], DOP[2], DO[23:16], DOP[1], DO[15: 8], DOP[0], DO[ 7: 0] }; + assign { DIP[3], DI[31:24], DIP[2], DI[23:16], DIP[1], DI[15: 8], DIP[0], DI[ 7: 0] } = B1DATA; + + generate if (CFG_DBITS > 8) begin + RAMB16BWER #( + .DATA_WIDTH_A(CFG_DBITS), + .DATA_WIDTH_B(CFG_DBITS), + .WRITE_MODE_A("READ_FIRST"), + .WRITE_MODE_B("READ_FIRST"), + `include "brams_init_18.vh" + ) _TECHMAP_REPLACE_ ( + .DIA(32'd0), + .DIPA(4'd0), + .DOA(DO[31:0]), + .DOPA(DOP[3:0]), + .ADDRA(A1ADDR_14), + .CLKA(CLK2 ^ !CLKPOL2), + .ENA(A1EN), + .REGCEA(|1), + .RSTA(|0), + .WEA(4'b0), + + .DIB(DI), + .DIPB(DIP), + .DOB(DOB), + .DOPB(DOPB), + .ADDRB(B1ADDR_14), + .CLKB(CLK3 ^ !CLKPOL3), + .ENB(|1), + .REGCEB(|0), + .RSTB(|0), + .WEB(B1EN_4) + ); + end else begin + RAMB16BWER #( + .DATA_WIDTH_A(CFG_DBITS), + .DATA_WIDTH_B(CFG_DBITS), + .WRITE_MODE_A("READ_FIRST"), + .WRITE_MODE_B("READ_FIRST"), + `include "brams_init_16.vh" + ) _TECHMAP_REPLACE_ ( + .DIA(32'd0), + .DIPA(4'd0), + .DOA(DO[31:0]), + .DOPA(DOP[3:0]), + .ADDRA(A1ADDR_14), + .CLKA(CLK2 ^ !CLKPOL2), + .ENA(A1EN), + .REGCEA(|1), + .RSTA(|0), + .WEA(4'b0), + + .DIB(DI), + .DIPB(DIP), + .DOB(DOB), + .DOPB(DOPB), + .ADDRB(B1ADDR_14), + .CLKB(CLK3 ^ !CLKPOL3), + .ENB(|1), + .REGCEB(|0), + .RSTB(|0), + .WEB(B1EN_4) + ); + end endgenerate +endmodule + +// ------------------------------------------------------------------------ + +module \$__XILINX_RAMB8BWER_TDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN); + parameter CFG_ABITS = 9; + parameter CFG_DBITS = 18; + parameter CFG_ENABLE_B = 2; + + parameter CLKPOL2 = 1; + parameter CLKPOL3 = 1; + parameter [9215:0] INIT = 9216'bx; + + input CLK2; + input CLK3; + + input [CFG_ABITS-1:0] A1ADDR; + output [CFG_DBITS-1:0] A1DATA; + input A1EN; + + input [CFG_ABITS-1:0] B1ADDR; + input [CFG_DBITS-1:0] B1DATA; + input [CFG_ENABLE_B-1:0] B1EN; + + wire [12:0] A1ADDR_13 = A1ADDR << (13 - CFG_ABITS); + wire [12:0] B1ADDR_13 = B1ADDR << (13 - CFG_ABITS); + wire [1:0] B1EN_2 = {2{B1EN}}; + + wire [1:0] DIP, DOP; + wire [15:0] DI, DO; + + wire [15:0] DOBDO; + wire [1:0] DOPBDOP; + + assign A1DATA = { DOP[1], DO[15: 8], DOP[0], DO[ 7: 0] }; + assign { DIP[1], DI[15: 8], DIP[0], DI[ 7: 0] } = B1DATA; + + generate if (CFG_DBITS > 8) begin + RAMB8BWER #( + .RAM_MODE("TDP"), + .DATA_WIDTH_A(CFG_DBITS), + .DATA_WIDTH_B(CFG_DBITS), + .WRITE_MODE_A("READ_FIRST"), + .WRITE_MODE_B("READ_FIRST"), + `include "brams_init_9.vh" + ) _TECHMAP_REPLACE_ ( + .DIADI(16'b0), + .DIPADIP(2'b0), + .DOADO(DO), + .DOPADOP(DOP), + .ADDRAWRADDR(A1ADDR_13), + .CLKAWRCLK(CLK2 ^ !CLKPOL2), + .ENAWREN(A1EN), + .REGCEA(|1), + .RSTA(|0), + .WEAWEL(2'b0), + + .DIBDI(DI), + .DIPBDIP(DIP), + .DOBDO(DOBDO), + .DOPBDOP(DOPBDOP), + .ADDRBRDADDR(B1ADDR_13), + .CLKBRDCLK(CLK3 ^ !CLKPOL3), + .ENBRDEN(|1), + .REGCEBREGCE(|0), + .RSTBRST(|0), + .WEBWEU(B1EN_2) + ); + end else begin + RAMB8BWER #( + .RAM_MODE("TDP"), + .DATA_WIDTH_A(CFG_DBITS), + .DATA_WIDTH_B(CFG_DBITS), + .WRITE_MODE_A("READ_FIRST"), + .WRITE_MODE_B("READ_FIRST"), + `include "brams_init_8.vh" + ) _TECHMAP_REPLACE_ ( + .DIADI(16'b0), + .DIPADIP(2'b0), + .DOADO(DO), + .DOPADOP(DOP), + .ADDRAWRADDR(A1ADDR_13), + .CLKAWRCLK(CLK2 ^ !CLKPOL2), + .ENAWREN(A1EN), + .REGCEA(|1), + .RSTA(|0), + .WEAWEL(2'b0), + + .DIBDI(DI), + .DIPBDIP(DIP), + .DOBDO(DOBDO), + .DOPBDOP(DOPBDOP), + .ADDRBRDADDR(B1ADDR_13), + .CLKBRDCLK(CLK3 ^ !CLKPOL3), + .ENBRDEN(|1), + .REGCEBREGCE(|0), + .RSTBRST(|0), + .WEBWEU(B1EN_2) + ); + end endgenerate +endmodule diff --git a/techlibs/xilinx/xc6s_cells_xtra.v b/techlibs/xilinx/xc6s_cells_xtra.v new file mode 100644 index 000000000..014e73df0 --- /dev/null +++ b/techlibs/xilinx/xc6s_cells_xtra.v @@ -0,0 +1,1859 @@ +// Created by cells_xtra.py from Xilinx models + +module MCB (...); + parameter integer ARB_NUM_TIME_SLOTS = 12; + parameter [17:0] ARB_TIME_SLOT_0 = 18'b111111111111111111; + parameter [17:0] ARB_TIME_SLOT_1 = 18'b111111111111111111; + parameter [17:0] ARB_TIME_SLOT_10 = 18'b111111111111111111; + parameter [17:0] ARB_TIME_SLOT_11 = 18'b111111111111111111; + parameter [17:0] ARB_TIME_SLOT_2 = 18'b111111111111111111; + parameter [17:0] ARB_TIME_SLOT_3 = 18'b111111111111111111; + parameter [17:0] ARB_TIME_SLOT_4 = 18'b111111111111111111; + parameter [17:0] ARB_TIME_SLOT_5 = 18'b111111111111111111; + parameter [17:0] ARB_TIME_SLOT_6 = 18'b111111111111111111; + parameter [17:0] ARB_TIME_SLOT_7 = 18'b111111111111111111; + parameter [17:0] ARB_TIME_SLOT_8 = 18'b111111111111111111; + parameter [17:0] ARB_TIME_SLOT_9 = 18'b111111111111111111; + parameter [2:0] CAL_BA = 3'h0; + parameter CAL_BYPASS = "YES"; + parameter [11:0] CAL_CA = 12'h000; + parameter CAL_CALIBRATION_MODE = "NOCALIBRATION"; + parameter integer CAL_CLK_DIV = 1; + parameter CAL_DELAY = "QUARTER"; + parameter [14:0] CAL_RA = 15'h0000; + parameter MEM_ADDR_ORDER = "BANK_ROW_COLUMN"; + parameter integer MEM_BA_SIZE = 3; + parameter integer MEM_BURST_LEN = 8; + parameter integer MEM_CAS_LATENCY = 4; + parameter integer MEM_CA_SIZE = 11; + parameter MEM_DDR1_2_ODS = "FULL"; + parameter MEM_DDR2_3_HIGH_TEMP_SR = "NORMAL"; + parameter MEM_DDR2_3_PA_SR = "FULL"; + parameter integer MEM_DDR2_ADD_LATENCY = 0; + parameter MEM_DDR2_DIFF_DQS_EN = "YES"; + parameter MEM_DDR2_RTT = "50OHMS"; + parameter integer MEM_DDR2_WRT_RECOVERY = 4; + parameter MEM_DDR3_ADD_LATENCY = "OFF"; + parameter MEM_DDR3_AUTO_SR = "ENABLED"; + parameter integer MEM_DDR3_CAS_LATENCY = 7; + parameter integer MEM_DDR3_CAS_WR_LATENCY = 5; + parameter MEM_DDR3_DYN_WRT_ODT = "OFF"; + parameter MEM_DDR3_ODS = "DIV7"; + parameter MEM_DDR3_RTT = "DIV2"; + parameter integer MEM_DDR3_WRT_RECOVERY = 7; + parameter MEM_MDDR_ODS = "FULL"; + parameter MEM_MOBILE_PA_SR = "FULL"; + parameter integer MEM_MOBILE_TC_SR = 0; + parameter integer MEM_RAS_VAL = 0; + parameter integer MEM_RA_SIZE = 13; + parameter integer MEM_RCD_VAL = 1; + parameter integer MEM_REFI_VAL = 0; + parameter integer MEM_RFC_VAL = 0; + parameter integer MEM_RP_VAL = 0; + parameter integer MEM_RTP_VAL = 0; + parameter MEM_TYPE = "DDR3"; + parameter integer MEM_WIDTH = 4; + parameter integer MEM_WR_VAL = 0; + parameter integer MEM_WTR_VAL = 3; + parameter PORT_CONFIG = "B32_B32_B32_B32"; + output CAS; + output CKE; + output DQIOWEN0; + output DQSIOWEN90N; + output DQSIOWEN90P; + output IOIDRPADD; + output IOIDRPBROADCAST; + output IOIDRPCLK; + output IOIDRPCS; + output IOIDRPSDO; + output IOIDRPTRAIN; + output IOIDRPUPDATE; + output LDMN; + output LDMP; + output ODT; + output P0CMDEMPTY; + output P0CMDFULL; + output P0RDEMPTY; + output P0RDERROR; + output P0RDFULL; + output P0RDOVERFLOW; + output P0WREMPTY; + output P0WRERROR; + output P0WRFULL; + output P0WRUNDERRUN; + output P1CMDEMPTY; + output P1CMDFULL; + output P1RDEMPTY; + output P1RDERROR; + output P1RDFULL; + output P1RDOVERFLOW; + output P1WREMPTY; + output P1WRERROR; + output P1WRFULL; + output P1WRUNDERRUN; + output P2CMDEMPTY; + output P2CMDFULL; + output P2EMPTY; + output P2ERROR; + output P2FULL; + output P2RDOVERFLOW; + output P2WRUNDERRUN; + output P3CMDEMPTY; + output P3CMDFULL; + output P3EMPTY; + output P3ERROR; + output P3FULL; + output P3RDOVERFLOW; + output P3WRUNDERRUN; + output P4CMDEMPTY; + output P4CMDFULL; + output P4EMPTY; + output P4ERROR; + output P4FULL; + output P4RDOVERFLOW; + output P4WRUNDERRUN; + output P5CMDEMPTY; + output P5CMDFULL; + output P5EMPTY; + output P5ERROR; + output P5FULL; + output P5RDOVERFLOW; + output P5WRUNDERRUN; + output RAS; + output RST; + output SELFREFRESHMODE; + output UDMN; + output UDMP; + output UOCALSTART; + output UOCMDREADYIN; + output UODATAVALID; + output UODONECAL; + output UOREFRSHFLAG; + output UOSDO; + output WE; + output [14:0] ADDR; + output [15:0] DQON; + output [15:0] DQOP; + output [2:0] BA; + output [31:0] P0RDDATA; + output [31:0] P1RDDATA; + output [31:0] P2RDDATA; + output [31:0] P3RDDATA; + output [31:0] P4RDDATA; + output [31:0] P5RDDATA; + output [31:0] STATUS; + output [4:0] IOIDRPADDR; + output [6:0] P0RDCOUNT; + output [6:0] P0WRCOUNT; + output [6:0] P1RDCOUNT; + output [6:0] P1WRCOUNT; + output [6:0] P2COUNT; + output [6:0] P3COUNT; + output [6:0] P4COUNT; + output [6:0] P5COUNT; + output [7:0] UODATA; + input DQSIOIN; + input DQSIOIP; + input IOIDRPSDI; + input P0ARBEN; + input P0CMDCLK; + input P0CMDEN; + input P0RDCLK; + input P0RDEN; + input P0WRCLK; + input P0WREN; + input P1ARBEN; + input P1CMDCLK; + input P1CMDEN; + input P1RDCLK; + input P1RDEN; + input P1WRCLK; + input P1WREN; + input P2ARBEN; + input P2CLK; + input P2CMDCLK; + input P2CMDEN; + input P2EN; + input P3ARBEN; + input P3CLK; + input P3CMDCLK; + input P3CMDEN; + input P3EN; + input P4ARBEN; + input P4CLK; + input P4CMDCLK; + input P4CMDEN; + input P4EN; + input P5ARBEN; + input P5CLK; + input P5CMDCLK; + input P5CMDEN; + input P5EN; + input PLLLOCK; + input RECAL; + input SELFREFRESHENTER; + input SYSRST; + input UDQSIOIN; + input UDQSIOIP; + input UIADD; + input UIBROADCAST; + input UICLK; + input UICMD; + input UICMDEN; + input UICMDIN; + input UICS; + input UIDONECAL; + input UIDQLOWERDEC; + input UIDQLOWERINC; + input UIDQUPPERDEC; + input UIDQUPPERINC; + input UIDRPUPDATE; + input UILDQSDEC; + input UILDQSINC; + input UIREAD; + input UISDI; + input UIUDQSDEC; + input UIUDQSINC; + input [11:0] P0CMDCA; + input [11:0] P1CMDCA; + input [11:0] P2CMDCA; + input [11:0] P3CMDCA; + input [11:0] P4CMDCA; + input [11:0] P5CMDCA; + input [14:0] P0CMDRA; + input [14:0] P1CMDRA; + input [14:0] P2CMDRA; + input [14:0] P3CMDRA; + input [14:0] P4CMDRA; + input [14:0] P5CMDRA; + input [15:0] DQI; + input [1:0] PLLCE; + input [1:0] PLLCLK; + input [2:0] P0CMDBA; + input [2:0] P0CMDINSTR; + input [2:0] P1CMDBA; + input [2:0] P1CMDINSTR; + input [2:0] P2CMDBA; + input [2:0] P2CMDINSTR; + input [2:0] P3CMDBA; + input [2:0] P3CMDINSTR; + input [2:0] P4CMDBA; + input [2:0] P4CMDINSTR; + input [2:0] P5CMDBA; + input [2:0] P5CMDINSTR; + input [31:0] P0WRDATA; + input [31:0] P1WRDATA; + input [31:0] P2WRDATA; + input [31:0] P3WRDATA; + input [31:0] P4WRDATA; + input [31:0] P5WRDATA; + input [3:0] P0RWRMASK; + input [3:0] P1RWRMASK; + input [3:0] P2WRMASK; + input [3:0] P3WRMASK; + input [3:0] P4WRMASK; + input [3:0] P5WRMASK; + input [3:0] UIDQCOUNT; + input [4:0] UIADDR; + input [5:0] P0CMDBL; + input [5:0] P1CMDBL; + input [5:0] P2CMDBL; + input [5:0] P3CMDBL; + input [5:0] P4CMDBL; + input [5:0] P5CMDBL; +endmodule + +module PCIE_A1 (...); + parameter [31:0] BAR0 = 32'h00000000; + parameter [31:0] BAR1 = 32'h00000000; + parameter [31:0] BAR2 = 32'h00000000; + parameter [31:0] BAR3 = 32'h00000000; + parameter [31:0] BAR4 = 32'h00000000; + parameter [31:0] BAR5 = 32'h00000000; + parameter [31:0] CARDBUS_CIS_POINTER = 32'h00000000; + parameter [23:0] CLASS_CODE = 24'h000000; + parameter integer DEV_CAP_ENDPOINT_L0S_LATENCY = 7; + parameter integer DEV_CAP_ENDPOINT_L1_LATENCY = 7; + parameter DEV_CAP_EXT_TAG_SUPPORTED = "FALSE"; + parameter integer DEV_CAP_MAX_PAYLOAD_SUPPORTED = 2; + parameter integer DEV_CAP_PHANTOM_FUNCTIONS_SUPPORT = 0; + parameter DEV_CAP_ROLE_BASED_ERROR = "TRUE"; + parameter DISABLE_BAR_FILTERING = "FALSE"; + parameter DISABLE_ID_CHECK = "FALSE"; + parameter DISABLE_SCRAMBLING = "FALSE"; + parameter ENABLE_RX_TD_ECRC_TRIM = "FALSE"; + parameter [21:0] EXPANSION_ROM = 22'h000000; + parameter FAST_TRAIN = "FALSE"; + parameter integer GTP_SEL = 0; + parameter integer LINK_CAP_ASPM_SUPPORT = 1; + parameter integer LINK_CAP_L0S_EXIT_LATENCY = 7; + parameter integer LINK_CAP_L1_EXIT_LATENCY = 7; + parameter LINK_STATUS_SLOT_CLOCK_CONFIG = "FALSE"; + parameter [14:0] LL_ACK_TIMEOUT = 15'h0204; + parameter LL_ACK_TIMEOUT_EN = "FALSE"; + parameter [14:0] LL_REPLAY_TIMEOUT = 15'h060D; + parameter LL_REPLAY_TIMEOUT_EN = "FALSE"; + parameter integer MSI_CAP_MULTIMSGCAP = 0; + parameter integer MSI_CAP_MULTIMSG_EXTENSION = 0; + parameter [3:0] PCIE_CAP_CAPABILITY_VERSION = 4'h1; + parameter [3:0] PCIE_CAP_DEVICE_PORT_TYPE = 4'h0; + parameter [4:0] PCIE_CAP_INT_MSG_NUM = 5'b00000; + parameter PCIE_CAP_SLOT_IMPLEMENTED = "FALSE"; + parameter [11:0] PCIE_GENERIC = 12'h000; + parameter PLM_AUTO_CONFIG = "FALSE"; + parameter integer PM_CAP_AUXCURRENT = 0; + parameter PM_CAP_D1SUPPORT = "TRUE"; + parameter PM_CAP_D2SUPPORT = "TRUE"; + parameter PM_CAP_DSI = "FALSE"; + parameter [4:0] PM_CAP_PMESUPPORT = 5'b01111; + parameter PM_CAP_PME_CLOCK = "FALSE"; + parameter integer PM_CAP_VERSION = 3; + parameter [7:0] PM_DATA0 = 8'h1E; + parameter [7:0] PM_DATA1 = 8'h1E; + parameter [7:0] PM_DATA2 = 8'h1E; + parameter [7:0] PM_DATA3 = 8'h1E; + parameter [7:0] PM_DATA4 = 8'h1E; + parameter [7:0] PM_DATA5 = 8'h1E; + parameter [7:0] PM_DATA6 = 8'h1E; + parameter [7:0] PM_DATA7 = 8'h1E; + parameter [1:0] PM_DATA_SCALE0 = 2'b01; + parameter [1:0] PM_DATA_SCALE1 = 2'b01; + parameter [1:0] PM_DATA_SCALE2 = 2'b01; + parameter [1:0] PM_DATA_SCALE3 = 2'b01; + parameter [1:0] PM_DATA_SCALE4 = 2'b01; + parameter [1:0] PM_DATA_SCALE5 = 2'b01; + parameter [1:0] PM_DATA_SCALE6 = 2'b01; + parameter [1:0] PM_DATA_SCALE7 = 2'b01; + parameter SIM_VERSION = "1.0"; + parameter SLOT_CAP_ATT_BUTTON_PRESENT = "FALSE"; + parameter SLOT_CAP_ATT_INDICATOR_PRESENT = "FALSE"; + parameter SLOT_CAP_POWER_INDICATOR_PRESENT = "FALSE"; + parameter integer TL_RX_RAM_RADDR_LATENCY = 1; + parameter integer TL_RX_RAM_RDATA_LATENCY = 2; + parameter integer TL_RX_RAM_WRITE_LATENCY = 0; + parameter TL_TFC_DISABLE = "FALSE"; + parameter TL_TX_CHECKS_DISABLE = "FALSE"; + parameter integer TL_TX_RAM_RADDR_LATENCY = 0; + parameter integer TL_TX_RAM_RDATA_LATENCY = 2; + parameter USR_CFG = "FALSE"; + parameter USR_EXT_CFG = "FALSE"; + parameter VC0_CPL_INFINITE = "TRUE"; + parameter [11:0] VC0_RX_RAM_LIMIT = 12'h01E; + parameter integer VC0_TOTAL_CREDITS_CD = 104; + parameter integer VC0_TOTAL_CREDITS_CH = 36; + parameter integer VC0_TOTAL_CREDITS_NPH = 8; + parameter integer VC0_TOTAL_CREDITS_PD = 288; + parameter integer VC0_TOTAL_CREDITS_PH = 32; + parameter integer VC0_TX_LASTPACKET = 31; + output CFGCOMMANDBUSMASTERENABLE; + output CFGCOMMANDINTERRUPTDISABLE; + output CFGCOMMANDIOENABLE; + output CFGCOMMANDMEMENABLE; + output CFGCOMMANDSERREN; + output CFGDEVCONTROLAUXPOWEREN; + output CFGDEVCONTROLCORRERRREPORTINGEN; + output CFGDEVCONTROLENABLERO; + output CFGDEVCONTROLEXTTAGEN; + output CFGDEVCONTROLFATALERRREPORTINGEN; + output CFGDEVCONTROLNONFATALREPORTINGEN; + output CFGDEVCONTROLNOSNOOPEN; + output CFGDEVCONTROLPHANTOMEN; + output CFGDEVCONTROLURERRREPORTINGEN; + output CFGDEVSTATUSCORRERRDETECTED; + output CFGDEVSTATUSFATALERRDETECTED; + output CFGDEVSTATUSNONFATALERRDETECTED; + output CFGDEVSTATUSURDETECTED; + output CFGERRCPLRDYN; + output CFGINTERRUPTMSIENABLE; + output CFGINTERRUPTRDYN; + output CFGLINKCONTOLRCB; + output CFGLINKCONTROLCOMMONCLOCK; + output CFGLINKCONTROLEXTENDEDSYNC; + output CFGRDWRDONEN; + output CFGTOTURNOFFN; + output DBGBADDLLPSTATUS; + output DBGBADTLPLCRC; + output DBGBADTLPSEQNUM; + output DBGBADTLPSTATUS; + output DBGDLPROTOCOLSTATUS; + output DBGFCPROTOCOLERRSTATUS; + output DBGMLFRMDLENGTH; + output DBGMLFRMDMPS; + output DBGMLFRMDTCVC; + output DBGMLFRMDTLPSTATUS; + output DBGMLFRMDUNRECTYPE; + output DBGPOISTLPSTATUS; + output DBGRCVROVERFLOWSTATUS; + output DBGREGDETECTEDCORRECTABLE; + output DBGREGDETECTEDFATAL; + output DBGREGDETECTEDNONFATAL; + output DBGREGDETECTEDUNSUPPORTED; + output DBGRPLYROLLOVERSTATUS; + output DBGRPLYTIMEOUTSTATUS; + output DBGURNOBARHIT; + output DBGURPOISCFGWR; + output DBGURSTATUS; + output DBGURUNSUPMSG; + output MIMRXREN; + output MIMRXWEN; + output MIMTXREN; + output MIMTXWEN; + output PIPEGTTXELECIDLEA; + output PIPEGTTXELECIDLEB; + output PIPERXPOLARITYA; + output PIPERXPOLARITYB; + output PIPERXRESETA; + output PIPERXRESETB; + output PIPETXRCVRDETA; + output PIPETXRCVRDETB; + output RECEIVEDHOTRESET; + output TRNLNKUPN; + output TRNREOFN; + output TRNRERRFWDN; + output TRNRSOFN; + output TRNRSRCDSCN; + output TRNRSRCRDYN; + output TRNTCFGREQN; + output TRNTDSTRDYN; + output TRNTERRDROPN; + output USERRSTN; + output [11:0] MIMRXRADDR; + output [11:0] MIMRXWADDR; + output [11:0] MIMTXRADDR; + output [11:0] MIMTXWADDR; + output [11:0] TRNFCCPLD; + output [11:0] TRNFCNPD; + output [11:0] TRNFCPD; + output [15:0] PIPETXDATAA; + output [15:0] PIPETXDATAB; + output [1:0] CFGLINKCONTROLASPMCONTROL; + output [1:0] PIPEGTPOWERDOWNA; + output [1:0] PIPEGTPOWERDOWNB; + output [1:0] PIPETXCHARDISPMODEA; + output [1:0] PIPETXCHARDISPMODEB; + output [1:0] PIPETXCHARDISPVALA; + output [1:0] PIPETXCHARDISPVALB; + output [1:0] PIPETXCHARISKA; + output [1:0] PIPETXCHARISKB; + output [2:0] CFGDEVCONTROLMAXPAYLOAD; + output [2:0] CFGDEVCONTROLMAXREADREQ; + output [2:0] CFGFUNCTIONNUMBER; + output [2:0] CFGINTERRUPTMMENABLE; + output [2:0] CFGPCIELINKSTATEN; + output [31:0] CFGDO; + output [31:0] TRNRD; + output [34:0] MIMRXWDATA; + output [35:0] MIMTXWDATA; + output [4:0] CFGDEVICENUMBER; + output [4:0] CFGLTSSMSTATE; + output [5:0] TRNTBUFAV; + output [6:0] TRNRBARHITN; + output [7:0] CFGBUSNUMBER; + output [7:0] CFGINTERRUPTDO; + output [7:0] TRNFCCPLH; + output [7:0] TRNFCNPH; + output [7:0] TRNFCPH; + input CFGERRCORN; + input CFGERRCPLABORTN; + input CFGERRCPLTIMEOUTN; + input CFGERRECRCN; + input CFGERRLOCKEDN; + input CFGERRPOSTEDN; + input CFGERRURN; + input CFGINTERRUPTASSERTN; + input CFGINTERRUPTN; + input CFGPMWAKEN; + input CFGRDENN; + input CFGTRNPENDINGN; + input CFGTURNOFFOKN; + input CLOCKLOCKED; + input MGTCLK; + input PIPEGTRESETDONEA; + input PIPEGTRESETDONEB; + input PIPEPHYSTATUSA; + input PIPEPHYSTATUSB; + input PIPERXENTERELECIDLEA; + input PIPERXENTERELECIDLEB; + input SYSRESETN; + input TRNRDSTRDYN; + input TRNRNPOKN; + input TRNTCFGGNTN; + input TRNTEOFN; + input TRNTERRFWDN; + input TRNTSOFN; + input TRNTSRCDSCN; + input TRNTSRCRDYN; + input TRNTSTRN; + input USERCLK; + input [15:0] CFGDEVID; + input [15:0] CFGSUBSYSID; + input [15:0] CFGSUBSYSVENID; + input [15:0] CFGVENID; + input [15:0] PIPERXDATAA; + input [15:0] PIPERXDATAB; + input [1:0] PIPERXCHARISKA; + input [1:0] PIPERXCHARISKB; + input [2:0] PIPERXSTATUSA; + input [2:0] PIPERXSTATUSB; + input [2:0] TRNFCSEL; + input [31:0] TRNTD; + input [34:0] MIMRXRDATA; + input [35:0] MIMTXRDATA; + input [47:0] CFGERRTLPCPLHEADER; + input [63:0] CFGDSN; + input [7:0] CFGINTERRUPTDI; + input [7:0] CFGREVID; + input [9:0] CFGDWADDR; +endmodule + +module DSP48A1 (...); + parameter integer A0REG = 0; + parameter integer A1REG = 1; + parameter integer B0REG = 0; + parameter integer B1REG = 1; + parameter integer CARRYINREG = 1; + parameter integer CARRYOUTREG = 1; + parameter CARRYINSEL = "OPMODE5"; + parameter integer CREG = 1; + parameter integer DREG = 1; + parameter integer MREG = 1; + parameter integer OPMODEREG = 1; + parameter integer PREG = 1; + parameter RSTTYPE = "SYNC"; + output [17:0] BCOUT; + output CARRYOUT; + output CARRYOUTF; + output [35:0] M; + output [47:0] P; + output [47:0] PCOUT; + input [17:0] A; + input [17:0] B; + input [47:0] C; + input CARRYIN; + input CEA; + input CEB; + input CEC; + input CECARRYIN; + input CED; + input CEM; + input CEOPMODE; + input CEP; + (* clkbuf_sink *) + input CLK; + input [17:0] D; + input [7:0] OPMODE; + input [47:0] PCIN; + input RSTA; + input RSTB; + input RSTC; + input RSTCARRYIN; + input RSTD; + input RSTM; + input RSTOPMODE; + input RSTP; +endmodule + +module BUFGCE (...); + parameter CE_TYPE = "SYNC"; + parameter [0:0] IS_CE_INVERTED = 1'b0; + parameter [0:0] IS_I_INVERTED = 1'b0; + (* clkbuf_driver *) + output O; + (* invertible_pin = "IS_CE_INVERTED" *) + input CE; + (* invertible_pin = "IS_I_INVERTED" *) + input I; +endmodule + +module BUFGCE_1 (...); + (* clkbuf_driver *) + output O; + input CE; + input I; +endmodule + +module BUFGMUX (...); + parameter CLK_SEL_TYPE = "SYNC"; + (* clkbuf_driver *) + output O; + input I0; + input I1; + input S; +endmodule + +module BUFGMUX_1 (...); + parameter CLK_SEL_TYPE = "SYNC"; + (* clkbuf_driver *) + output O; + input I0; + input I1; + input S; +endmodule + +module BUFH (...); + (* clkbuf_driver *) + output O; + input I; +endmodule + +module BUFIO2 (...); + parameter DIVIDE_BYPASS = "TRUE"; + parameter integer DIVIDE = 1; + parameter I_INVERT = "FALSE"; + parameter USE_DOUBLER = "FALSE"; + (* clkbuf_driver *) + output DIVCLK; + (* clkbuf_driver *) + output IOCLK; + output SERDESSTROBE; + input I; +endmodule + +module BUFIO2_2CLK (...); + parameter integer DIVIDE = 2; + (* clkbuf_driver *) + output DIVCLK; + (* clkbuf_driver *) + output IOCLK; + output SERDESSTROBE; + input I; + input IB; +endmodule + +module BUFIO2FB (...); + parameter DIVIDE_BYPASS = "TRUE"; + (* clkbuf_driver *) + output O; + input I; +endmodule + +module BUFPLL_MCB (...); + parameter integer DIVIDE = 2; + parameter LOCK_SRC = "LOCK_TO_0"; + (* clkbuf_driver *) + output IOCLK0; + (* clkbuf_driver *) + output IOCLK1; + output LOCK; + output SERDESSTROBE0; + output SERDESSTROBE1; + input GCLK; + input LOCKED; + input PLLIN0; + input PLLIN1; +endmodule + +module DCM_CLKGEN (...); + parameter SPREAD_SPECTRUM = "NONE"; + parameter STARTUP_WAIT = "FALSE"; + parameter integer CLKFXDV_DIVIDE = 2; + parameter integer CLKFX_DIVIDE = 1; + parameter integer CLKFX_MULTIPLY = 4; + parameter real CLKFX_MD_MAX = 0.0; + parameter real CLKIN_PERIOD = 0.0; + output CLKFX180; + output CLKFX; + output CLKFXDV; + output LOCKED; + output PROGDONE; + output [2:1] STATUS; + input CLKIN; + input FREEZEDCM; + input PROGCLK; + input PROGDATA; + input PROGEN; + input RST; +endmodule + +module DCM_SP (...); + parameter real CLKDV_DIVIDE = 2.0; + parameter integer CLKFX_DIVIDE = 1; + parameter integer CLKFX_MULTIPLY = 4; + parameter CLKIN_DIVIDE_BY_2 = "FALSE"; + parameter real CLKIN_PERIOD = 10.0; + parameter CLKOUT_PHASE_SHIFT = "NONE"; + parameter CLK_FEEDBACK = "1X"; + parameter DESKEW_ADJUST = "SYSTEM_SYNCHRONOUS"; + parameter DFS_FREQUENCY_MODE = "LOW"; + parameter DLL_FREQUENCY_MODE = "LOW"; + parameter DSS_MODE = "NONE"; + parameter DUTY_CYCLE_CORRECTION = "TRUE"; + parameter FACTORY_JF = 16'hC080; + parameter integer PHASE_SHIFT = 0; + parameter STARTUP_WAIT = "FALSE"; + input CLKFB; + input CLKIN; + input DSSEN; + input PSCLK; + input PSEN; + input PSINCDEC; + input RST; + output CLK0; + output CLK180; + output CLK270; + output CLK2X; + output CLK2X180; + output CLK90; + output CLKDV; + output CLKFX; + output CLKFX180; + output LOCKED; + output PSDONE; + output [7:0] STATUS; +endmodule + +module PLL_BASE (...); + parameter BANDWIDTH = "OPTIMIZED"; + parameter integer CLKFBOUT_MULT = 1; + parameter real CLKFBOUT_PHASE = 0.0; + parameter real CLKIN_PERIOD = 0.000; + parameter integer CLKOUT0_DIVIDE = 1; + parameter real CLKOUT0_DUTY_CYCLE = 0.5; + parameter real CLKOUT0_PHASE = 0.0; + parameter integer CLKOUT1_DIVIDE = 1; + parameter real CLKOUT1_DUTY_CYCLE = 0.5; + parameter real CLKOUT1_PHASE = 0.0; + parameter integer CLKOUT2_DIVIDE = 1; + parameter real CLKOUT2_DUTY_CYCLE = 0.5; + parameter real CLKOUT2_PHASE = 0.0; + parameter integer CLKOUT3_DIVIDE = 1; + parameter real CLKOUT3_DUTY_CYCLE = 0.5; + parameter real CLKOUT3_PHASE = 0.0; + parameter integer CLKOUT4_DIVIDE = 1; + parameter real CLKOUT4_DUTY_CYCLE = 0.5; + parameter real CLKOUT4_PHASE = 0.0; + parameter integer CLKOUT5_DIVIDE = 1; + parameter real CLKOUT5_DUTY_CYCLE = 0.5; + parameter real CLKOUT5_PHASE = 0.0; + parameter CLK_FEEDBACK = "CLKFBOUT"; + parameter COMPENSATION = "SYSTEM_SYNCHRONOUS"; + parameter integer DIVCLK_DIVIDE = 1; + parameter real REF_JITTER = 0.100; + parameter RESET_ON_LOSS_OF_LOCK = "FALSE"; + output CLKFBOUT; + output CLKOUT0; + output CLKOUT1; + output CLKOUT2; + output CLKOUT3; + output CLKOUT4; + output CLKOUT5; + output LOCKED; + input CLKFBIN; + input CLKIN; + input RST; +endmodule + +(* keep *) +module BSCAN_SPARTAN6 (...); + parameter integer JTAG_CHAIN = 1; + output CAPTURE; + output DRCK; + output RESET; + output RUNTEST; + output SEL; + output SHIFT; + output TCK; + output TDI; + output TMS; + output UPDATE; + input TDO; +endmodule + +module DNA_PORT (...); + parameter [56:0] SIM_DNA_VALUE = 57'h0; + output DOUT; + input CLK; + input DIN; + input READ; + input SHIFT; +endmodule + +(* keep *) +module ICAP_SPARTAN6 (...); + parameter DEVICE_ID = 32'h04000093; + parameter SIM_CFG_FILE_NAME = "NONE"; + output BUSY; + output [15:0] O; + input CLK; + input CE; + input WRITE; + input [15:0] I; +endmodule + +module POST_CRC_INTERNAL (...); + output CRCERROR; +endmodule + +(* keep *) +module STARTUP_SPARTAN6 (...); + output CFGCLK; + output CFGMCLK; + output EOS; + input CLK; + input GSR; + input GTS; + input KEYCLEARB; +endmodule + +(* keep *) +module SUSPEND_SYNC (...); + output SREQ; + input CLK; + input SACK; +endmodule + +module GTPA1_DUAL (...); + parameter AC_CAP_DIS_0 = "TRUE"; + parameter AC_CAP_DIS_1 = "TRUE"; + parameter integer ALIGN_COMMA_WORD_0 = 1; + parameter integer ALIGN_COMMA_WORD_1 = 1; + parameter integer CB2_INH_CC_PERIOD_0 = 8; + parameter integer CB2_INH_CC_PERIOD_1 = 8; + parameter [4:0] CDR_PH_ADJ_TIME_0 = 5'b01010; + parameter [4:0] CDR_PH_ADJ_TIME_1 = 5'b01010; + parameter integer CHAN_BOND_1_MAX_SKEW_0 = 7; + parameter integer CHAN_BOND_1_MAX_SKEW_1 = 7; + parameter integer CHAN_BOND_2_MAX_SKEW_0 = 1; + parameter integer CHAN_BOND_2_MAX_SKEW_1 = 1; + parameter CHAN_BOND_KEEP_ALIGN_0 = "FALSE"; + parameter CHAN_BOND_KEEP_ALIGN_1 = "FALSE"; + parameter [9:0] CHAN_BOND_SEQ_1_1_0 = 10'b0101111100; + parameter [9:0] CHAN_BOND_SEQ_1_1_1 = 10'b0101111100; + parameter [9:0] CHAN_BOND_SEQ_1_2_0 = 10'b0001001010; + parameter [9:0] CHAN_BOND_SEQ_1_2_1 = 10'b0001001010; + parameter [9:0] CHAN_BOND_SEQ_1_3_0 = 10'b0001001010; + parameter [9:0] CHAN_BOND_SEQ_1_3_1 = 10'b0001001010; + parameter [9:0] CHAN_BOND_SEQ_1_4_0 = 10'b0110111100; + parameter [9:0] CHAN_BOND_SEQ_1_4_1 = 10'b0110111100; + parameter [3:0] CHAN_BOND_SEQ_1_ENABLE_0 = 4'b1111; + parameter [3:0] CHAN_BOND_SEQ_1_ENABLE_1 = 4'b1111; + parameter [9:0] CHAN_BOND_SEQ_2_1_0 = 10'b0110111100; + parameter [9:0] CHAN_BOND_SEQ_2_1_1 = 10'b0110111100; + parameter [9:0] CHAN_BOND_SEQ_2_2_0 = 10'b0100111100; + parameter [9:0] CHAN_BOND_SEQ_2_2_1 = 10'b0100111100; + parameter [9:0] CHAN_BOND_SEQ_2_3_0 = 10'b0100111100; + parameter [9:0] CHAN_BOND_SEQ_2_3_1 = 10'b0100111100; + parameter [9:0] CHAN_BOND_SEQ_2_4_0 = 10'b0100111100; + parameter [9:0] CHAN_BOND_SEQ_2_4_1 = 10'b0100111100; + parameter [3:0] CHAN_BOND_SEQ_2_ENABLE_0 = 4'b1111; + parameter [3:0] CHAN_BOND_SEQ_2_ENABLE_1 = 4'b1111; + parameter CHAN_BOND_SEQ_2_USE_0 = "FALSE"; + parameter CHAN_BOND_SEQ_2_USE_1 = "FALSE"; + parameter integer CHAN_BOND_SEQ_LEN_0 = 1; + parameter integer CHAN_BOND_SEQ_LEN_1 = 1; + parameter integer CLK25_DIVIDER_0 = 4; + parameter integer CLK25_DIVIDER_1 = 4; + parameter CLKINDC_B_0 = "TRUE"; + parameter CLKINDC_B_1 = "TRUE"; + parameter CLKRCV_TRST_0 = "TRUE"; + parameter CLKRCV_TRST_1 = "TRUE"; + parameter CLK_CORRECT_USE_0 = "TRUE"; + parameter CLK_CORRECT_USE_1 = "TRUE"; + parameter integer CLK_COR_ADJ_LEN_0 = 1; + parameter integer CLK_COR_ADJ_LEN_1 = 1; + parameter integer CLK_COR_DET_LEN_0 = 1; + parameter integer CLK_COR_DET_LEN_1 = 1; + parameter CLK_COR_INSERT_IDLE_FLAG_0 = "FALSE"; + parameter CLK_COR_INSERT_IDLE_FLAG_1 = "FALSE"; + parameter CLK_COR_KEEP_IDLE_0 = "FALSE"; + parameter CLK_COR_KEEP_IDLE_1 = "FALSE"; + parameter integer CLK_COR_MAX_LAT_0 = 20; + parameter integer CLK_COR_MAX_LAT_1 = 20; + parameter integer CLK_COR_MIN_LAT_0 = 18; + parameter integer CLK_COR_MIN_LAT_1 = 18; + parameter CLK_COR_PRECEDENCE_0 = "TRUE"; + parameter CLK_COR_PRECEDENCE_1 = "TRUE"; + parameter integer CLK_COR_REPEAT_WAIT_0 = 0; + parameter integer CLK_COR_REPEAT_WAIT_1 = 0; + parameter [9:0] CLK_COR_SEQ_1_1_0 = 10'b0100011100; + parameter [9:0] CLK_COR_SEQ_1_1_1 = 10'b0100011100; + parameter [9:0] CLK_COR_SEQ_1_2_0 = 10'b0000000000; + parameter [9:0] CLK_COR_SEQ_1_2_1 = 10'b0000000000; + parameter [9:0] CLK_COR_SEQ_1_3_0 = 10'b0000000000; + parameter [9:0] CLK_COR_SEQ_1_3_1 = 10'b0000000000; + parameter [9:0] CLK_COR_SEQ_1_4_0 = 10'b0000000000; + parameter [9:0] CLK_COR_SEQ_1_4_1 = 10'b0000000000; + parameter [3:0] CLK_COR_SEQ_1_ENABLE_0 = 4'b1111; + parameter [3:0] CLK_COR_SEQ_1_ENABLE_1 = 4'b1111; + parameter [9:0] CLK_COR_SEQ_2_1_0 = 10'b0000000000; + parameter [9:0] CLK_COR_SEQ_2_1_1 = 10'b0000000000; + parameter [9:0] CLK_COR_SEQ_2_2_0 = 10'b0000000000; + parameter [9:0] CLK_COR_SEQ_2_2_1 = 10'b0000000000; + parameter [9:0] CLK_COR_SEQ_2_3_0 = 10'b0000000000; + parameter [9:0] CLK_COR_SEQ_2_3_1 = 10'b0000000000; + parameter [9:0] CLK_COR_SEQ_2_4_0 = 10'b0000000000; + parameter [9:0] CLK_COR_SEQ_2_4_1 = 10'b0000000000; + parameter [3:0] CLK_COR_SEQ_2_ENABLE_0 = 4'b1111; + parameter [3:0] CLK_COR_SEQ_2_ENABLE_1 = 4'b1111; + parameter CLK_COR_SEQ_2_USE_0 = "FALSE"; + parameter CLK_COR_SEQ_2_USE_1 = "FALSE"; + parameter CLK_OUT_GTP_SEL_0 = "REFCLKPLL0"; + parameter CLK_OUT_GTP_SEL_1 = "REFCLKPLL1"; + parameter [1:0] CM_TRIM_0 = 2'b00; + parameter [1:0] CM_TRIM_1 = 2'b00; + parameter [9:0] COMMA_10B_ENABLE_0 = 10'b1111111111; + parameter [9:0] COMMA_10B_ENABLE_1 = 10'b1111111111; + parameter [3:0] COM_BURST_VAL_0 = 4'b1111; + parameter [3:0] COM_BURST_VAL_1 = 4'b1111; + parameter DEC_MCOMMA_DETECT_0 = "TRUE"; + parameter DEC_MCOMMA_DETECT_1 = "TRUE"; + parameter DEC_PCOMMA_DETECT_0 = "TRUE"; + parameter DEC_PCOMMA_DETECT_1 = "TRUE"; + parameter DEC_VALID_COMMA_ONLY_0 = "TRUE"; + parameter DEC_VALID_COMMA_ONLY_1 = "TRUE"; + parameter GTP_CFG_PWRUP_0 = "TRUE"; + parameter GTP_CFG_PWRUP_1 = "TRUE"; + parameter [9:0] MCOMMA_10B_VALUE_0 = 10'b1010000011; + parameter [9:0] MCOMMA_10B_VALUE_1 = 10'b1010000011; + parameter MCOMMA_DETECT_0 = "TRUE"; + parameter MCOMMA_DETECT_1 = "TRUE"; + parameter [2:0] OOBDETECT_THRESHOLD_0 = 3'b110; + parameter [2:0] OOBDETECT_THRESHOLD_1 = 3'b110; + parameter integer OOB_CLK_DIVIDER_0 = 4; + parameter integer OOB_CLK_DIVIDER_1 = 4; + parameter PCI_EXPRESS_MODE_0 = "FALSE"; + parameter PCI_EXPRESS_MODE_1 = "FALSE"; + parameter [9:0] PCOMMA_10B_VALUE_0 = 10'b0101111100; + parameter [9:0] PCOMMA_10B_VALUE_1 = 10'b0101111100; + parameter PCOMMA_DETECT_0 = "TRUE"; + parameter PCOMMA_DETECT_1 = "TRUE"; + parameter [2:0] PLLLKDET_CFG_0 = 3'b101; + parameter [2:0] PLLLKDET_CFG_1 = 3'b101; + parameter [23:0] PLL_COM_CFG_0 = 24'h21680A; + parameter [23:0] PLL_COM_CFG_1 = 24'h21680A; + parameter [7:0] PLL_CP_CFG_0 = 8'h00; + parameter [7:0] PLL_CP_CFG_1 = 8'h00; + parameter integer PLL_DIVSEL_FB_0 = 5; + parameter integer PLL_DIVSEL_FB_1 = 5; + parameter integer PLL_DIVSEL_REF_0 = 2; + parameter integer PLL_DIVSEL_REF_1 = 2; + parameter integer PLL_RXDIVSEL_OUT_0 = 1; + parameter integer PLL_RXDIVSEL_OUT_1 = 1; + parameter PLL_SATA_0 = "FALSE"; + parameter PLL_SATA_1 = "FALSE"; + parameter PLL_SOURCE_0 = "PLL0"; + parameter PLL_SOURCE_1 = "PLL0"; + parameter integer PLL_TXDIVSEL_OUT_0 = 1; + parameter integer PLL_TXDIVSEL_OUT_1 = 1; + parameter [26:0] PMA_CDR_SCAN_0 = 27'h6404040; + parameter [26:0] PMA_CDR_SCAN_1 = 27'h6404040; + parameter [35:0] PMA_COM_CFG_EAST = 36'h000008000; + parameter [35:0] PMA_COM_CFG_WEST = 36'h00000A000; + parameter [6:0] PMA_RXSYNC_CFG_0 = 7'h00; + parameter [6:0] PMA_RXSYNC_CFG_1 = 7'h00; + parameter [24:0] PMA_RX_CFG_0 = 25'h05CE048; + parameter [24:0] PMA_RX_CFG_1 = 25'h05CE048; + parameter [19:0] PMA_TX_CFG_0 = 20'h00082; + parameter [19:0] PMA_TX_CFG_1 = 20'h00082; + parameter RCV_TERM_GND_0 = "FALSE"; + parameter RCV_TERM_GND_1 = "FALSE"; + parameter RCV_TERM_VTTRX_0 = "TRUE"; + parameter RCV_TERM_VTTRX_1 = "TRUE"; + parameter [7:0] RXEQ_CFG_0 = 8'b01111011; + parameter [7:0] RXEQ_CFG_1 = 8'b01111011; + parameter [0:0] RXPRBSERR_LOOPBACK_0 = 1'b0; + parameter [0:0] RXPRBSERR_LOOPBACK_1 = 1'b0; + parameter RX_BUFFER_USE_0 = "TRUE"; + parameter RX_BUFFER_USE_1 = "TRUE"; + parameter RX_DECODE_SEQ_MATCH_0 = "TRUE"; + parameter RX_DECODE_SEQ_MATCH_1 = "TRUE"; + parameter RX_EN_IDLE_HOLD_CDR_0 = "FALSE"; + parameter RX_EN_IDLE_HOLD_CDR_1 = "FALSE"; + parameter RX_EN_IDLE_RESET_BUF_0 = "TRUE"; + parameter RX_EN_IDLE_RESET_BUF_1 = "TRUE"; + parameter RX_EN_IDLE_RESET_FR_0 = "TRUE"; + parameter RX_EN_IDLE_RESET_FR_1 = "TRUE"; + parameter RX_EN_IDLE_RESET_PH_0 = "TRUE"; + parameter RX_EN_IDLE_RESET_PH_1 = "TRUE"; + parameter RX_EN_MODE_RESET_BUF_0 = "TRUE"; + parameter RX_EN_MODE_RESET_BUF_1 = "TRUE"; + parameter [3:0] RX_IDLE_HI_CNT_0 = 4'b1000; + parameter [3:0] RX_IDLE_HI_CNT_1 = 4'b1000; + parameter [3:0] RX_IDLE_LO_CNT_0 = 4'b0000; + parameter [3:0] RX_IDLE_LO_CNT_1 = 4'b0000; + parameter RX_LOSS_OF_SYNC_FSM_0 = "FALSE"; + parameter RX_LOSS_OF_SYNC_FSM_1 = "FALSE"; + parameter integer RX_LOS_INVALID_INCR_0 = 1; + parameter integer RX_LOS_INVALID_INCR_1 = 1; + parameter integer RX_LOS_THRESHOLD_0 = 4; + parameter integer RX_LOS_THRESHOLD_1 = 4; + parameter RX_SLIDE_MODE_0 = "PCS"; + parameter RX_SLIDE_MODE_1 = "PCS"; + parameter RX_STATUS_FMT_0 = "PCIE"; + parameter RX_STATUS_FMT_1 = "PCIE"; + parameter RX_XCLK_SEL_0 = "RXREC"; + parameter RX_XCLK_SEL_1 = "RXREC"; + parameter [2:0] SATA_BURST_VAL_0 = 3'b100; + parameter [2:0] SATA_BURST_VAL_1 = 3'b100; + parameter [2:0] SATA_IDLE_VAL_0 = 3'b011; + parameter [2:0] SATA_IDLE_VAL_1 = 3'b011; + parameter integer SATA_MAX_BURST_0 = 7; + parameter integer SATA_MAX_BURST_1 = 7; + parameter integer SATA_MAX_INIT_0 = 22; + parameter integer SATA_MAX_INIT_1 = 22; + parameter integer SATA_MAX_WAKE_0 = 7; + parameter integer SATA_MAX_WAKE_1 = 7; + parameter integer SATA_MIN_BURST_0 = 4; + parameter integer SATA_MIN_BURST_1 = 4; + parameter integer SATA_MIN_INIT_0 = 12; + parameter integer SATA_MIN_INIT_1 = 12; + parameter integer SATA_MIN_WAKE_0 = 4; + parameter integer SATA_MIN_WAKE_1 = 4; + parameter integer SIM_GTPRESET_SPEEDUP = 0; + parameter SIM_RECEIVER_DETECT_PASS = "FALSE"; + parameter [2:0] SIM_REFCLK0_SOURCE = 3'b000; + parameter [2:0] SIM_REFCLK1_SOURCE = 3'b000; + parameter SIM_TX_ELEC_IDLE_LEVEL = "X"; + parameter SIM_VERSION = "2.0"; + parameter [4:0] TERMINATION_CTRL_0 = 5'b10100; + parameter [4:0] TERMINATION_CTRL_1 = 5'b10100; + parameter TERMINATION_OVRD_0 = "FALSE"; + parameter TERMINATION_OVRD_1 = "FALSE"; + parameter [11:0] TRANS_TIME_FROM_P2_0 = 12'h03C; + parameter [11:0] TRANS_TIME_FROM_P2_1 = 12'h03C; + parameter [7:0] TRANS_TIME_NON_P2_0 = 8'h19; + parameter [7:0] TRANS_TIME_NON_P2_1 = 8'h19; + parameter [9:0] TRANS_TIME_TO_P2_0 = 10'h064; + parameter [9:0] TRANS_TIME_TO_P2_1 = 10'h064; + parameter [31:0] TST_ATTR_0 = 32'h00000000; + parameter [31:0] TST_ATTR_1 = 32'h00000000; + parameter [2:0] TXRX_INVERT_0 = 3'b011; + parameter [2:0] TXRX_INVERT_1 = 3'b011; + parameter TX_BUFFER_USE_0 = "FALSE"; + parameter TX_BUFFER_USE_1 = "FALSE"; + parameter [13:0] TX_DETECT_RX_CFG_0 = 14'h1832; + parameter [13:0] TX_DETECT_RX_CFG_1 = 14'h1832; + parameter [2:0] TX_IDLE_DELAY_0 = 3'b011; + parameter [2:0] TX_IDLE_DELAY_1 = 3'b011; + parameter [1:0] TX_TDCC_CFG_0 = 2'b00; + parameter [1:0] TX_TDCC_CFG_1 = 2'b00; + parameter TX_XCLK_SEL_0 = "TXUSR"; + parameter TX_XCLK_SEL_1 = "TXUSR"; + output DRDY; + output PHYSTATUS0; + output PHYSTATUS1; + output PLLLKDET0; + output PLLLKDET1; + output REFCLKOUT0; + output REFCLKOUT1; + output REFCLKPLL0; + output REFCLKPLL1; + output RESETDONE0; + output RESETDONE1; + output RXBYTEISALIGNED0; + output RXBYTEISALIGNED1; + output RXBYTEREALIGN0; + output RXBYTEREALIGN1; + output RXCHANBONDSEQ0; + output RXCHANBONDSEQ1; + output RXCHANISALIGNED0; + output RXCHANISALIGNED1; + output RXCHANREALIGN0; + output RXCHANREALIGN1; + output RXCOMMADET0; + output RXCOMMADET1; + output RXELECIDLE0; + output RXELECIDLE1; + output RXPRBSERR0; + output RXPRBSERR1; + output RXRECCLK0; + output RXRECCLK1; + output RXVALID0; + output RXVALID1; + output TXN0; + output TXN1; + output TXOUTCLK0; + output TXOUTCLK1; + output TXP0; + output TXP1; + output [15:0] DRPDO; + output [1:0] GTPCLKFBEAST; + output [1:0] GTPCLKFBWEST; + output [1:0] GTPCLKOUT0; + output [1:0] GTPCLKOUT1; + output [1:0] RXLOSSOFSYNC0; + output [1:0] RXLOSSOFSYNC1; + output [1:0] TXBUFSTATUS0; + output [1:0] TXBUFSTATUS1; + output [2:0] RXBUFSTATUS0; + output [2:0] RXBUFSTATUS1; + output [2:0] RXCHBONDO; + output [2:0] RXCLKCORCNT0; + output [2:0] RXCLKCORCNT1; + output [2:0] RXSTATUS0; + output [2:0] RXSTATUS1; + output [31:0] RXDATA0; + output [31:0] RXDATA1; + output [3:0] RXCHARISCOMMA0; + output [3:0] RXCHARISCOMMA1; + output [3:0] RXCHARISK0; + output [3:0] RXCHARISK1; + output [3:0] RXDISPERR0; + output [3:0] RXDISPERR1; + output [3:0] RXNOTINTABLE0; + output [3:0] RXNOTINTABLE1; + output [3:0] RXRUNDISP0; + output [3:0] RXRUNDISP1; + output [3:0] TXKERR0; + output [3:0] TXKERR1; + output [3:0] TXRUNDISP0; + output [3:0] TXRUNDISP1; + output [4:0] RCALOUTEAST; + output [4:0] RCALOUTWEST; + output [4:0] TSTOUT0; + output [4:0] TSTOUT1; + input CLK00; + input CLK01; + input CLK10; + input CLK11; + input CLKINEAST0; + input CLKINEAST1; + input CLKINWEST0; + input CLKINWEST1; + input DCLK; + input DEN; + input DWE; + input GATERXELECIDLE0; + input GATERXELECIDLE1; + input GCLK00; + input GCLK01; + input GCLK10; + input GCLK11; + input GTPRESET0; + input GTPRESET1; + input IGNORESIGDET0; + input IGNORESIGDET1; + input INTDATAWIDTH0; + input INTDATAWIDTH1; + input PLLCLK00; + input PLLCLK01; + input PLLCLK10; + input PLLCLK11; + input PLLLKDETEN0; + input PLLLKDETEN1; + input PLLPOWERDOWN0; + input PLLPOWERDOWN1; + input PRBSCNTRESET0; + input PRBSCNTRESET1; + input REFCLKPWRDNB0; + input REFCLKPWRDNB1; + input RXBUFRESET0; + input RXBUFRESET1; + input RXCDRRESET0; + input RXCDRRESET1; + input RXCHBONDMASTER0; + input RXCHBONDMASTER1; + input RXCHBONDSLAVE0; + input RXCHBONDSLAVE1; + input RXCOMMADETUSE0; + input RXCOMMADETUSE1; + input RXDEC8B10BUSE0; + input RXDEC8B10BUSE1; + input RXENCHANSYNC0; + input RXENCHANSYNC1; + input RXENMCOMMAALIGN0; + input RXENMCOMMAALIGN1; + input RXENPCOMMAALIGN0; + input RXENPCOMMAALIGN1; + input RXENPMAPHASEALIGN0; + input RXENPMAPHASEALIGN1; + input RXN0; + input RXN1; + input RXP0; + input RXP1; + input RXPMASETPHASE0; + input RXPMASETPHASE1; + input RXPOLARITY0; + input RXPOLARITY1; + input RXRESET0; + input RXRESET1; + input RXSLIDE0; + input RXSLIDE1; + input RXUSRCLK0; + input RXUSRCLK1; + input RXUSRCLK20; + input RXUSRCLK21; + input TSTCLK0; + input TSTCLK1; + input TXCOMSTART0; + input TXCOMSTART1; + input TXCOMTYPE0; + input TXCOMTYPE1; + input TXDETECTRX0; + input TXDETECTRX1; + input TXELECIDLE0; + input TXELECIDLE1; + input TXENC8B10BUSE0; + input TXENC8B10BUSE1; + input TXENPMAPHASEALIGN0; + input TXENPMAPHASEALIGN1; + input TXINHIBIT0; + input TXINHIBIT1; + input TXPDOWNASYNCH0; + input TXPDOWNASYNCH1; + input TXPMASETPHASE0; + input TXPMASETPHASE1; + input TXPOLARITY0; + input TXPOLARITY1; + input TXPRBSFORCEERR0; + input TXPRBSFORCEERR1; + input TXRESET0; + input TXRESET1; + input TXUSRCLK0; + input TXUSRCLK1; + input TXUSRCLK20; + input TXUSRCLK21; + input USRCODEERR0; + input USRCODEERR1; + input [11:0] TSTIN0; + input [11:0] TSTIN1; + input [15:0] DI; + input [1:0] GTPCLKFBSEL0EAST; + input [1:0] GTPCLKFBSEL0WEST; + input [1:0] GTPCLKFBSEL1EAST; + input [1:0] GTPCLKFBSEL1WEST; + input [1:0] RXDATAWIDTH0; + input [1:0] RXDATAWIDTH1; + input [1:0] RXEQMIX0; + input [1:0] RXEQMIX1; + input [1:0] RXPOWERDOWN0; + input [1:0] RXPOWERDOWN1; + input [1:0] TXDATAWIDTH0; + input [1:0] TXDATAWIDTH1; + input [1:0] TXPOWERDOWN0; + input [1:0] TXPOWERDOWN1; + input [2:0] LOOPBACK0; + input [2:0] LOOPBACK1; + input [2:0] REFSELDYPLL0; + input [2:0] REFSELDYPLL1; + input [2:0] RXCHBONDI; + input [2:0] RXENPRBSTST0; + input [2:0] RXENPRBSTST1; + input [2:0] TXBUFDIFFCTRL0; + input [2:0] TXBUFDIFFCTRL1; + input [2:0] TXENPRBSTST0; + input [2:0] TXENPRBSTST1; + input [2:0] TXPREEMPHASIS0; + input [2:0] TXPREEMPHASIS1; + input [31:0] TXDATA0; + input [31:0] TXDATA1; + input [3:0] TXBYPASS8B10B0; + input [3:0] TXBYPASS8B10B1; + input [3:0] TXCHARDISPMODE0; + input [3:0] TXCHARDISPMODE1; + input [3:0] TXCHARDISPVAL0; + input [3:0] TXCHARDISPVAL1; + input [3:0] TXCHARISK0; + input [3:0] TXCHARISK1; + input [3:0] TXDIFFCTRL0; + input [3:0] TXDIFFCTRL1; + input [4:0] RCALINEAST; + input [4:0] RCALINWEST; + input [7:0] DADDR; + input [7:0] GTPTEST0; + input [7:0] GTPTEST1; +endmodule + +module IBUFDS (...); + parameter CAPACITANCE = "DONT_CARE"; + parameter DIFF_TERM = "FALSE"; + parameter DQS_BIAS = "FALSE"; + parameter IBUF_DELAY_VALUE = "0"; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IFD_DELAY_VALUE = "AUTO"; + parameter IOSTANDARD = "DEFAULT"; + output O; + (* iopad_external_pin *) + input I; + (* iopad_external_pin *) + input IB; +endmodule + +module IBUFDS_DIFF_OUT (...); + parameter DIFF_TERM = "FALSE"; + parameter DQS_BIAS = "FALSE"; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + output O; + output OB; + (* iopad_external_pin *) + input I; + (* iopad_external_pin *) + input IB; +endmodule + +module IBUFG (...); + parameter CAPACITANCE = "DONT_CARE"; + parameter IBUF_DELAY_VALUE = "0"; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + output O; + (* iopad_external_pin *) + input I; +endmodule + +module IBUFGDS (...); + parameter CAPACITANCE = "DONT_CARE"; + parameter DIFF_TERM = "FALSE"; + parameter IBUF_DELAY_VALUE = "0"; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + output O; + (* iopad_external_pin *) + input I; + (* iopad_external_pin *) + input IB; +endmodule + +module IBUFGDS_DIFF_OUT (...); + parameter DIFF_TERM = "FALSE"; + parameter DQS_BIAS = "FALSE"; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + output O; + output OB; + (* iopad_external_pin *) + input I; + (* iopad_external_pin *) + input IB; +endmodule + +module IOBUF (...); + parameter integer DRIVE = 12; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + parameter SLEW = "SLOW"; + output O; + (* iopad_external_pin *) + inout IO; + input I; + input T; +endmodule + +module IOBUFDS (...); + parameter DIFF_TERM = "FALSE"; + parameter DQS_BIAS = "FALSE"; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + parameter SLEW = "SLOW"; + output O; + (* iopad_external_pin *) + inout IO; + inout IOB; + input I; + input T; +endmodule + +module IODELAY2 (...); + parameter COUNTER_WRAPAROUND = "WRAPAROUND"; + parameter DATA_RATE = "SDR"; + parameter DELAY_SRC = "IO"; + parameter integer IDELAY2_VALUE = 0; + parameter IDELAY_MODE = "NORMAL"; + parameter IDELAY_TYPE = "DEFAULT"; + parameter integer IDELAY_VALUE = 0; + parameter integer ODELAY_VALUE = 0; + parameter SERDES_MODE = "NONE"; + parameter integer SIM_TAPDELAY_VALUE = 75; + output BUSY; + output DATAOUT2; + output DATAOUT; + output DOUT; + output TOUT; + input CAL; + input CE; + (* clkbuf_sink *) + input CLK; + input IDATAIN; + input INC; + (* clkbuf_sink *) + input IOCLK0; + (* clkbuf_sink *) + input IOCLK1; + input ODATAIN; + input RST; + input T; +endmodule + +module IODRP2 (...); + parameter DATA_RATE = "SDR"; + parameter integer SIM_TAPDELAY_VALUE = 75; + output DATAOUT2; + output DATAOUT; + output DOUT; + output SDO; + output TOUT; + input ADD; + input BKST; + (* clkbuf_sink *) + input CLK; + input CS; + input IDATAIN; + (* clkbuf_sink *) + input IOCLK0; + (* clkbuf_sink *) + input IOCLK1; + input ODATAIN; + input SDI; + input T; +endmodule + +module IODRP2_MCB (...); + parameter DATA_RATE = "SDR"; + parameter integer IDELAY_VALUE = 0; + parameter integer MCB_ADDRESS = 0; + parameter integer ODELAY_VALUE = 0; + parameter SERDES_MODE = "NONE"; + parameter integer SIM_TAPDELAY_VALUE = 75; + output AUXSDO; + output DATAOUT2; + output DATAOUT; + output DOUT; + output DQSOUTN; + output DQSOUTP; + output SDO; + output TOUT; + input ADD; + input AUXSDOIN; + input BKST; + (* clkbuf_sink *) + input CLK; + input CS; + input IDATAIN; + (* clkbuf_sink *) + input IOCLK0; + (* clkbuf_sink *) + input IOCLK1; + input MEMUPDATE; + input ODATAIN; + input SDI; + input T; + input [4:0] AUXADDR; +endmodule + +module ISERDES2 (...); + parameter BITSLIP_ENABLE = "FALSE"; + parameter DATA_RATE = "SDR"; + parameter integer DATA_WIDTH = 1; + parameter INTERFACE_TYPE = "NETWORKING"; + parameter SERDES_MODE = "NONE"; + output CFB0; + output CFB1; + output DFB; + output FABRICOUT; + output INCDEC; + output Q1; + output Q2; + output Q3; + output Q4; + output SHIFTOUT; + output VALID; + input BITSLIP; + input CE0; + (* clkbuf_sink *) + input CLK0; + (* clkbuf_sink *) + input CLK1; + (* clkbuf_sink *) + input CLKDIV; + input D; + input IOCE; + input RST; + input SHIFTIN; +endmodule + +module KEEPER (...); + inout O; +endmodule + +module OBUFDS (...); + parameter CAPACITANCE = "DONT_CARE"; + parameter IOSTANDARD = "DEFAULT"; + parameter SLEW = "SLOW"; + (* iopad_external_pin *) + output O; + (* iopad_external_pin *) + output OB; + input I; +endmodule + +module OBUFT (...); + parameter CAPACITANCE = "DONT_CARE"; + parameter integer DRIVE = 12; + parameter IOSTANDARD = "DEFAULT"; + parameter SLEW = "SLOW"; + (* iopad_external_pin *) + output O; + input I; + input T; +endmodule + +module OBUFTDS (...); + parameter CAPACITANCE = "DONT_CARE"; + parameter IOSTANDARD = "DEFAULT"; + parameter SLEW = "SLOW"; + (* iopad_external_pin *) + output O; + (* iopad_external_pin *) + output OB; + input I; + input T; +endmodule + +module OSERDES2 (...); + parameter BYPASS_GCLK_FF = "FALSE"; + parameter DATA_RATE_OQ = "DDR"; + parameter DATA_RATE_OT = "DDR"; + parameter integer DATA_WIDTH = 2; + parameter OUTPUT_MODE = "SINGLE_ENDED"; + parameter SERDES_MODE = "NONE"; + parameter integer TRAIN_PATTERN = 0; + output OQ; + output SHIFTOUT1; + output SHIFTOUT2; + output SHIFTOUT3; + output SHIFTOUT4; + output TQ; + (* clkbuf_sink *) + input CLK0; + (* clkbuf_sink *) + input CLK1; + (* clkbuf_sink *) + input CLKDIV; + input D1; + input D2; + input D3; + input D4; + input IOCE; + input OCE; + input RST; + input SHIFTIN1; + input SHIFTIN2; + input SHIFTIN3; + input SHIFTIN4; + input T1; + input T2; + input T3; + input T4; + input TCE; + input TRAIN; +endmodule + +module PULLDOWN (...); + output O; +endmodule + +module PULLUP (...); + output O; +endmodule + +module RAM128X1S (...); + parameter [127:0] INIT = 128'h00000000000000000000000000000000; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + output O; + input A0; + input A1; + input A2; + input A3; + input A4; + input A5; + input A6; + input D; + (* clkbuf_sink *) + (* invertible_pin = "IS_WCLK_INVERTED" *) + input WCLK; + input WE; +endmodule + +module RAM256X1S (...); + parameter [255:0] INIT = 256'h0; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + output O; + input [7:0] A; + input D; + (* clkbuf_sink *) + (* invertible_pin = "IS_WCLK_INVERTED" *) + input WCLK; + input WE; +endmodule + +module RAM32M (...); + parameter [63:0] INIT_A = 64'h0000000000000000; + parameter [63:0] INIT_B = 64'h0000000000000000; + parameter [63:0] INIT_C = 64'h0000000000000000; + parameter [63:0] INIT_D = 64'h0000000000000000; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + output [1:0] DOA; + output [1:0] DOB; + output [1:0] DOC; + output [1:0] DOD; + input [4:0] ADDRA; + input [4:0] ADDRB; + input [4:0] ADDRC; + input [4:0] ADDRD; + input [1:0] DIA; + input [1:0] DIB; + input [1:0] DIC; + input [1:0] DID; + (* clkbuf_sink *) + (* invertible_pin = "IS_WCLK_INVERTED" *) + input WCLK; + input WE; +endmodule + +module RAM32X1S (...); + parameter [31:0] INIT = 32'h00000000; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + output O; + input A0; + input A1; + input A2; + input A3; + input A4; + input D; + (* clkbuf_sink *) + (* invertible_pin = "IS_WCLK_INVERTED" *) + input WCLK; + input WE; +endmodule + +module RAM32X1S_1 (...); + parameter [31:0] INIT = 32'h00000000; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + output O; + input A0; + input A1; + input A2; + input A3; + input A4; + input D; + (* clkbuf_sink *) + (* invertible_pin = "IS_WCLK_INVERTED" *) + input WCLK; + input WE; +endmodule + +module RAM32X2S (...); + parameter [31:0] INIT_00 = 32'h00000000; + parameter [31:0] INIT_01 = 32'h00000000; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + output O0; + output O1; + input A0; + input A1; + input A2; + input A3; + input A4; + input D0; + input D1; + (* clkbuf_sink *) + (* invertible_pin = "IS_WCLK_INVERTED" *) + input WCLK; + input WE; +endmodule + +module RAM64M (...); + parameter [63:0] INIT_A = 64'h0000000000000000; + parameter [63:0] INIT_B = 64'h0000000000000000; + parameter [63:0] INIT_C = 64'h0000000000000000; + parameter [63:0] INIT_D = 64'h0000000000000000; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + output DOA; + output DOB; + output DOC; + output DOD; + input [5:0] ADDRA; + input [5:0] ADDRB; + input [5:0] ADDRC; + input [5:0] ADDRD; + input DIA; + input DIB; + input DIC; + input DID; + (* clkbuf_sink *) + (* invertible_pin = "IS_WCLK_INVERTED" *) + input WCLK; + input WE; +endmodule + +module RAM64X1S (...); + parameter [63:0] INIT = 64'h0000000000000000; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + output O; + input A0; + input A1; + input A2; + input A3; + input A4; + input A5; + input D; + (* clkbuf_sink *) + (* invertible_pin = "IS_WCLK_INVERTED" *) + input WCLK; + input WE; +endmodule + +module RAM64X1S_1 (...); + parameter [63:0] INIT = 64'h0000000000000000; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + output O; + input A0; + input A1; + input A2; + input A3; + input A4; + input A5; + input D; + (* clkbuf_sink *) + (* invertible_pin = "IS_WCLK_INVERTED" *) + input WCLK; + input WE; +endmodule + +module RAM64X2S (...); + parameter [63:0] INIT_00 = 64'h0000000000000000; + parameter [63:0] INIT_01 = 64'h0000000000000000; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + output O0; + output O1; + input A0; + input A1; + input A2; + input A3; + input A4; + input A5; + input D0; + input D1; + (* clkbuf_sink *) + (* invertible_pin = "IS_WCLK_INVERTED" *) + input WCLK; + input WE; +endmodule + +module ROM128X1 (...); + parameter [127:0] INIT = 128'h00000000000000000000000000000000; + output O; + input A0; + input A1; + input A2; + input A3; + input A4; + input A5; + input A6; +endmodule + +module ROM256X1 (...); + parameter [255:0] INIT = 256'h0000000000000000000000000000000000000000000000000000000000000000; + output O; + input A0; + input A1; + input A2; + input A3; + input A4; + input A5; + input A6; + input A7; +endmodule + +module ROM32X1 (...); + parameter [31:0] INIT = 32'h00000000; + output O; + input A0; + input A1; + input A2; + input A3; + input A4; +endmodule + +module ROM64X1 (...); + parameter [63:0] INIT = 64'h0000000000000000; + output O; + input A0; + input A1; + input A2; + input A3; + input A4; + input A5; +endmodule + +module IDDR2 (...); + parameter DDR_ALIGNMENT = "NONE"; + parameter [0:0] INIT_Q0 = 1'b0; + parameter [0:0] INIT_Q1 = 1'b0; + parameter SRTYPE = "SYNC"; + output Q0; + output Q1; + (* clkbuf_sink *) + input C0; + (* clkbuf_sink *) + input C1; + input CE; + input D; + input R; + input S; +endmodule + +module LDCE (...); + parameter [0:0] INIT = 1'b0; + parameter [0:0] IS_CLR_INVERTED = 1'b0; + parameter [0:0] IS_G_INVERTED = 1'b0; + parameter MSGON = "TRUE"; + parameter XON = "TRUE"; + output Q; + (* invertible_pin = "IS_CLR_INVERTED" *) + input CLR; + input D; + (* invertible_pin = "IS_G_INVERTED" *) + input G; + input GE; +endmodule + +module LDPE (...); + parameter [0:0] INIT = 1'b1; + parameter [0:0] IS_G_INVERTED = 1'b0; + parameter [0:0] IS_PRE_INVERTED = 1'b0; + parameter MSGON = "TRUE"; + parameter XON = "TRUE"; + output Q; + input D; + (* invertible_pin = "IS_G_INVERTED" *) + input G; + input GE; + (* invertible_pin = "IS_PRE_INVERTED" *) + input PRE; +endmodule + +module ODDR2 (...); + parameter DDR_ALIGNMENT = "NONE"; + parameter [0:0] INIT = 1'b0; + parameter SRTYPE = "SYNC"; + output Q; + (* clkbuf_sink *) + input C0; + (* clkbuf_sink *) + input C1; + input CE; + input D0; + input D1; + input R; + input S; +endmodule + +module CFGLUT5 (...); + parameter [31:0] INIT = 32'h00000000; + parameter [0:0] IS_CLK_INVERTED = 1'b0; + output CDO; + output O5; + output O6; + input I4; + input I3; + input I2; + input I1; + input I0; + input CDI; + input CE; + (* clkbuf_sink *) + (* invertible_pin = "IS_CLK_INVERTED" *) + input CLK; +endmodule + diff --git a/techlibs/xilinx/xc6s_ff_map.v b/techlibs/xilinx/xc6s_ff_map.v new file mode 100644 index 000000000..520a67579 --- /dev/null +++ b/techlibs/xilinx/xc6s_ff_map.v @@ -0,0 +1,126 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * + * 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. + * + */ + +// ============================================================================ +// FF mapping + +`ifndef _NO_FFS + +module \$_DFF_N_ (input D, C, output Q); + parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; + generate if (_TECHMAP_WIREINIT_Q_ === 1'b1) + FDSE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .S(1'b0)); + else + FDRE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); + endgenerate +endmodule +module \$_DFF_P_ (input D, C, output Q); + parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; + generate if (_TECHMAP_WIREINIT_Q_ === 1'b1) + FDSE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .S(1'b0)); + else + FDRE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); + endgenerate +endmodule + +module \$_DFFE_NP_ (input D, C, E, output Q); + parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; + generate if (_TECHMAP_WIREINIT_Q_ === 1'b1) + FDSE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .S(1'b0)); + else + FDRE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); + endgenerate +endmodule +module \$_DFFE_PP_ (input D, C, E, output Q); + parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; + generate if (_TECHMAP_WIREINIT_Q_ === 1'b1) + FDSE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .S(1'b0)); + else + FDRE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); + endgenerate +endmodule + +module \$_DFF_NN0_ (input D, C, R, output Q); + parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; + generate if (_TECHMAP_WIREINIT_Q_ === 1'b1) + $error("Spartan 6 doesn't support FFs with asynchronous reset initialized to 1"); + else + FDCE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(!R)); + endgenerate +endmodule +module \$_DFF_NP0_ (input D, C, R, output Q); + parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; + generate if (_TECHMAP_WIREINIT_Q_ === 1'b1) + $error("Spartan 6 doesn't support FFs with asynchronous reset initialized to 1"); + else + FDCE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); + endgenerate +endmodule +module \$_DFF_PN0_ (input D, C, R, output Q); + parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; + generate if (_TECHMAP_WIREINIT_Q_ === 1'b1) + $error("Spartan 6 doesn't support FFs with asynchronous reset initialized to 1"); + else + FDCE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(!R)); + endgenerate +endmodule +module \$_DFF_PP0_ (input D, C, R, output Q); + parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; + generate if (_TECHMAP_WIREINIT_Q_ === 1'b1) + $error("Spartan 6 doesn't support FFs with asynchronous reset initialized to 1"); + else + FDCE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); + endgenerate +endmodule + +module \$_DFF_NN1_ (input D, C, R, output Q); + parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; + generate if (_TECHMAP_WIREINIT_Q_ === 1'b0) + $error("Spartan 6 doesn't support FFs with asynchronous set initialized to 0"); + else + FDPE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(!R)); + endgenerate +endmodule +module \$_DFF_NP1_ (input D, C, R, output Q); + parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; + generate if (_TECHMAP_WIREINIT_Q_ === 1'b0) + $error("Spartan 6 doesn't support FFs with asynchronous set initialized to 0"); + else + FDPE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); + endgenerate +endmodule +module \$_DFF_PN1_ (input D, C, R, output Q); + parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; + generate if (_TECHMAP_WIREINIT_Q_ === 1'b0) + $error("Spartan 6 doesn't support FFs with asynchronous set initialized to 0"); + else + FDPE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(!R)); + endgenerate +endmodule +module \$_DFF_PP1_ (input D, C, R, output Q); + parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; + generate if (_TECHMAP_WIREINIT_Q_ === 1'b0) + $error("Spartan 6 doesn't support FFs with asynchronous set initialized to 0"); + else + FDPE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); + endgenerate +endmodule + +`endif + diff --git a/techlibs/xilinx/xc6v_cells_xtra.v b/techlibs/xilinx/xc6v_cells_xtra.v new file mode 100644 index 000000000..263bcc69d --- /dev/null +++ b/techlibs/xilinx/xc6v_cells_xtra.v @@ -0,0 +1,2720 @@ +// Created by cells_xtra.py from Xilinx models + +module PCIE_2_0 (...); + parameter [11:0] AER_BASE_PTR = 12'h128; + parameter AER_CAP_ECRC_CHECK_CAPABLE = "FALSE"; + parameter AER_CAP_ECRC_GEN_CAPABLE = "FALSE"; + parameter [15:0] AER_CAP_ID = 16'h0001; + parameter [4:0] AER_CAP_INT_MSG_NUM_MSI = 5'h0A; + parameter [4:0] AER_CAP_INT_MSG_NUM_MSIX = 5'h15; + parameter [11:0] AER_CAP_NEXTPTR = 12'h160; + parameter AER_CAP_ON = "FALSE"; + parameter AER_CAP_PERMIT_ROOTERR_UPDATE = "TRUE"; + parameter [3:0] AER_CAP_VERSION = 4'h1; + parameter ALLOW_X8_GEN2 = "FALSE"; + parameter [31:0] BAR0 = 32'hFFFFFF00; + parameter [31:0] BAR1 = 32'hFFFF0000; + parameter [31:0] BAR2 = 32'hFFFF000C; + parameter [31:0] BAR3 = 32'hFFFFFFFF; + parameter [31:0] BAR4 = 32'h00000000; + parameter [31:0] BAR5 = 32'h00000000; + parameter [7:0] CAPABILITIES_PTR = 8'h40; + parameter [31:0] CARDBUS_CIS_POINTER = 32'h00000000; + parameter [23:0] CLASS_CODE = 24'h000000; + parameter CMD_INTX_IMPLEMENTED = "TRUE"; + parameter CPL_TIMEOUT_DISABLE_SUPPORTED = "FALSE"; + parameter [3:0] CPL_TIMEOUT_RANGES_SUPPORTED = 4'h0; + parameter [6:0] CRM_MODULE_RSTS = 7'h00; + parameter [15:0] DEVICE_ID = 16'h0007; + parameter DEV_CAP_ENABLE_SLOT_PWR_LIMIT_SCALE = "TRUE"; + parameter DEV_CAP_ENABLE_SLOT_PWR_LIMIT_VALUE = "TRUE"; + parameter integer DEV_CAP_ENDPOINT_L0S_LATENCY = 0; + parameter integer DEV_CAP_ENDPOINT_L1_LATENCY = 0; + parameter DEV_CAP_EXT_TAG_SUPPORTED = "TRUE"; + parameter DEV_CAP_FUNCTION_LEVEL_RESET_CAPABLE = "FALSE"; + parameter integer DEV_CAP_MAX_PAYLOAD_SUPPORTED = 2; + parameter integer DEV_CAP_PHANTOM_FUNCTIONS_SUPPORT = 0; + parameter DEV_CAP_ROLE_BASED_ERROR = "TRUE"; + parameter integer DEV_CAP_RSVD_14_12 = 0; + parameter integer DEV_CAP_RSVD_17_16 = 0; + parameter integer DEV_CAP_RSVD_31_29 = 0; + parameter DEV_CONTROL_AUX_POWER_SUPPORTED = "FALSE"; + parameter DISABLE_ASPM_L1_TIMER = "FALSE"; + parameter DISABLE_BAR_FILTERING = "FALSE"; + parameter DISABLE_ID_CHECK = "FALSE"; + parameter DISABLE_LANE_REVERSAL = "FALSE"; + parameter DISABLE_RX_TC_FILTER = "FALSE"; + parameter DISABLE_SCRAMBLING = "FALSE"; + parameter [7:0] DNSTREAM_LINK_NUM = 8'h00; + parameter [11:0] DSN_BASE_PTR = 12'h100; + parameter [15:0] DSN_CAP_ID = 16'h0003; + parameter [11:0] DSN_CAP_NEXTPTR = 12'h000; + parameter DSN_CAP_ON = "TRUE"; + parameter [3:0] DSN_CAP_VERSION = 4'h1; + parameter [10:0] ENABLE_MSG_ROUTE = 11'h000; + parameter ENABLE_RX_TD_ECRC_TRIM = "FALSE"; + parameter ENTER_RVRY_EI_L0 = "TRUE"; + parameter EXIT_LOOPBACK_ON_EI = "TRUE"; + parameter [31:0] EXPANSION_ROM = 32'hFFFFF001; + parameter [5:0] EXT_CFG_CAP_PTR = 6'h3F; + parameter [9:0] EXT_CFG_XP_CAP_PTR = 10'h3FF; + parameter [7:0] HEADER_TYPE = 8'h00; + parameter [4:0] INFER_EI = 5'h00; + parameter [7:0] INTERRUPT_PIN = 8'h01; + parameter IS_SWITCH = "FALSE"; + parameter [9:0] LAST_CONFIG_DWORD = 10'h042; + parameter integer LINK_CAP_ASPM_SUPPORT = 1; + parameter LINK_CAP_CLOCK_POWER_MANAGEMENT = "FALSE"; + parameter LINK_CAP_DLL_LINK_ACTIVE_REPORTING_CAP = "FALSE"; + parameter integer LINK_CAP_L0S_EXIT_LATENCY_COMCLK_GEN1 = 7; + parameter integer LINK_CAP_L0S_EXIT_LATENCY_COMCLK_GEN2 = 7; + parameter integer LINK_CAP_L0S_EXIT_LATENCY_GEN1 = 7; + parameter integer LINK_CAP_L0S_EXIT_LATENCY_GEN2 = 7; + parameter integer LINK_CAP_L1_EXIT_LATENCY_COMCLK_GEN1 = 7; + parameter integer LINK_CAP_L1_EXIT_LATENCY_COMCLK_GEN2 = 7; + parameter integer LINK_CAP_L1_EXIT_LATENCY_GEN1 = 7; + parameter integer LINK_CAP_L1_EXIT_LATENCY_GEN2 = 7; + parameter LINK_CAP_LINK_BANDWIDTH_NOTIFICATION_CAP = "FALSE"; + parameter [3:0] LINK_CAP_MAX_LINK_SPEED = 4'h1; + parameter [5:0] LINK_CAP_MAX_LINK_WIDTH = 6'h08; + parameter integer LINK_CAP_RSVD_23_22 = 0; + parameter LINK_CAP_SURPRISE_DOWN_ERROR_CAPABLE = "FALSE"; + parameter integer LINK_CONTROL_RCB = 0; + parameter LINK_CTRL2_DEEMPHASIS = "FALSE"; + parameter LINK_CTRL2_HW_AUTONOMOUS_SPEED_DISABLE = "FALSE"; + parameter [3:0] LINK_CTRL2_TARGET_LINK_SPEED = 4'h2; + parameter LINK_STATUS_SLOT_CLOCK_CONFIG = "TRUE"; + parameter [14:0] LL_ACK_TIMEOUT = 15'h0000; + parameter LL_ACK_TIMEOUT_EN = "FALSE"; + parameter integer LL_ACK_TIMEOUT_FUNC = 0; + parameter [14:0] LL_REPLAY_TIMEOUT = 15'h0000; + parameter LL_REPLAY_TIMEOUT_EN = "FALSE"; + parameter integer LL_REPLAY_TIMEOUT_FUNC = 0; + parameter [5:0] LTSSM_MAX_LINK_WIDTH = 6'h01; + parameter [7:0] MSIX_BASE_PTR = 8'h9C; + parameter [7:0] MSIX_CAP_ID = 8'h11; + parameter [7:0] MSIX_CAP_NEXTPTR = 8'h00; + parameter MSIX_CAP_ON = "FALSE"; + parameter integer MSIX_CAP_PBA_BIR = 0; + parameter [28:0] MSIX_CAP_PBA_OFFSET = 29'h00000050; + parameter integer MSIX_CAP_TABLE_BIR = 0; + parameter [28:0] MSIX_CAP_TABLE_OFFSET = 29'h00000040; + parameter [10:0] MSIX_CAP_TABLE_SIZE = 11'h000; + parameter [7:0] MSI_BASE_PTR = 8'h48; + parameter MSI_CAP_64_BIT_ADDR_CAPABLE = "TRUE"; + parameter [7:0] MSI_CAP_ID = 8'h05; + parameter integer MSI_CAP_MULTIMSGCAP = 0; + parameter integer MSI_CAP_MULTIMSG_EXTENSION = 0; + parameter [7:0] MSI_CAP_NEXTPTR = 8'h60; + parameter MSI_CAP_ON = "FALSE"; + parameter MSI_CAP_PER_VECTOR_MASKING_CAPABLE = "TRUE"; + parameter integer N_FTS_COMCLK_GEN1 = 255; + parameter integer N_FTS_COMCLK_GEN2 = 255; + parameter integer N_FTS_GEN1 = 255; + parameter integer N_FTS_GEN2 = 255; + parameter [7:0] PCIE_BASE_PTR = 8'h60; + parameter [7:0] PCIE_CAP_CAPABILITY_ID = 8'h10; + parameter [3:0] PCIE_CAP_CAPABILITY_VERSION = 4'h2; + parameter [3:0] PCIE_CAP_DEVICE_PORT_TYPE = 4'h0; + parameter [4:0] PCIE_CAP_INT_MSG_NUM = 5'h00; + parameter [7:0] PCIE_CAP_NEXTPTR = 8'h00; + parameter PCIE_CAP_ON = "TRUE"; + parameter integer PCIE_CAP_RSVD_15_14 = 0; + parameter PCIE_CAP_SLOT_IMPLEMENTED = "FALSE"; + parameter integer PCIE_REVISION = 2; + parameter integer PGL0_LANE = 0; + parameter integer PGL1_LANE = 1; + parameter integer PGL2_LANE = 2; + parameter integer PGL3_LANE = 3; + parameter integer PGL4_LANE = 4; + parameter integer PGL5_LANE = 5; + parameter integer PGL6_LANE = 6; + parameter integer PGL7_LANE = 7; + parameter integer PL_AUTO_CONFIG = 0; + parameter PL_FAST_TRAIN = "FALSE"; + parameter [7:0] PM_BASE_PTR = 8'h40; + parameter integer PM_CAP_AUXCURRENT = 0; + parameter PM_CAP_D1SUPPORT = "TRUE"; + parameter PM_CAP_D2SUPPORT = "TRUE"; + parameter PM_CAP_DSI = "FALSE"; + parameter [7:0] PM_CAP_ID = 8'h01; + parameter [7:0] PM_CAP_NEXTPTR = 8'h48; + parameter PM_CAP_ON = "TRUE"; + parameter [4:0] PM_CAP_PMESUPPORT = 5'h0F; + parameter PM_CAP_PME_CLOCK = "FALSE"; + parameter integer PM_CAP_RSVD_04 = 0; + parameter integer PM_CAP_VERSION = 3; + parameter PM_CSR_B2B3 = "FALSE"; + parameter PM_CSR_BPCCEN = "FALSE"; + parameter PM_CSR_NOSOFTRST = "TRUE"; + parameter [7:0] PM_DATA0 = 8'h01; + parameter [7:0] PM_DATA1 = 8'h01; + parameter [7:0] PM_DATA2 = 8'h01; + parameter [7:0] PM_DATA3 = 8'h01; + parameter [7:0] PM_DATA4 = 8'h01; + parameter [7:0] PM_DATA5 = 8'h01; + parameter [7:0] PM_DATA6 = 8'h01; + parameter [7:0] PM_DATA7 = 8'h01; + parameter [1:0] PM_DATA_SCALE0 = 2'h1; + parameter [1:0] PM_DATA_SCALE1 = 2'h1; + parameter [1:0] PM_DATA_SCALE2 = 2'h1; + parameter [1:0] PM_DATA_SCALE3 = 2'h1; + parameter [1:0] PM_DATA_SCALE4 = 2'h1; + parameter [1:0] PM_DATA_SCALE5 = 2'h1; + parameter [1:0] PM_DATA_SCALE6 = 2'h1; + parameter [1:0] PM_DATA_SCALE7 = 2'h1; + parameter integer RECRC_CHK = 0; + parameter RECRC_CHK_TRIM = "FALSE"; + parameter [7:0] REVISION_ID = 8'h00; + parameter ROOT_CAP_CRS_SW_VISIBILITY = "FALSE"; + parameter SELECT_DLL_IF = "FALSE"; + parameter SIM_VERSION = "1.0"; + parameter SLOT_CAP_ATT_BUTTON_PRESENT = "FALSE"; + parameter SLOT_CAP_ATT_INDICATOR_PRESENT = "FALSE"; + parameter SLOT_CAP_ELEC_INTERLOCK_PRESENT = "FALSE"; + parameter SLOT_CAP_HOTPLUG_CAPABLE = "FALSE"; + parameter SLOT_CAP_HOTPLUG_SURPRISE = "FALSE"; + parameter SLOT_CAP_MRL_SENSOR_PRESENT = "FALSE"; + parameter SLOT_CAP_NO_CMD_COMPLETED_SUPPORT = "FALSE"; + parameter [12:0] SLOT_CAP_PHYSICAL_SLOT_NUM = 13'h0000; + parameter SLOT_CAP_POWER_CONTROLLER_PRESENT = "FALSE"; + parameter SLOT_CAP_POWER_INDICATOR_PRESENT = "FALSE"; + parameter integer SLOT_CAP_SLOT_POWER_LIMIT_SCALE = 0; + parameter [7:0] SLOT_CAP_SLOT_POWER_LIMIT_VALUE = 8'h00; + parameter integer SPARE_BIT0 = 0; + parameter integer SPARE_BIT1 = 0; + parameter integer SPARE_BIT2 = 0; + parameter integer SPARE_BIT3 = 0; + parameter integer SPARE_BIT4 = 0; + parameter integer SPARE_BIT5 = 0; + parameter integer SPARE_BIT6 = 0; + parameter integer SPARE_BIT7 = 0; + parameter integer SPARE_BIT8 = 0; + parameter [7:0] SPARE_BYTE0 = 8'h00; + parameter [7:0] SPARE_BYTE1 = 8'h00; + parameter [7:0] SPARE_BYTE2 = 8'h00; + parameter [7:0] SPARE_BYTE3 = 8'h00; + parameter [31:0] SPARE_WORD0 = 32'h00000000; + parameter [31:0] SPARE_WORD1 = 32'h00000000; + parameter [31:0] SPARE_WORD2 = 32'h00000000; + parameter [31:0] SPARE_WORD3 = 32'h00000000; + parameter [15:0] SUBSYSTEM_ID = 16'h0007; + parameter [15:0] SUBSYSTEM_VENDOR_ID = 16'h10EE; + parameter TL_RBYPASS = "FALSE"; + parameter integer TL_RX_RAM_RADDR_LATENCY = 0; + parameter integer TL_RX_RAM_RDATA_LATENCY = 2; + parameter integer TL_RX_RAM_WRITE_LATENCY = 0; + parameter TL_TFC_DISABLE = "FALSE"; + parameter TL_TX_CHECKS_DISABLE = "FALSE"; + parameter integer TL_TX_RAM_RADDR_LATENCY = 0; + parameter integer TL_TX_RAM_RDATA_LATENCY = 2; + parameter integer TL_TX_RAM_WRITE_LATENCY = 0; + parameter UPCONFIG_CAPABLE = "TRUE"; + parameter UPSTREAM_FACING = "TRUE"; + parameter UR_INV_REQ = "TRUE"; + parameter integer USER_CLK_FREQ = 3; + parameter VC0_CPL_INFINITE = "TRUE"; + parameter [12:0] VC0_RX_RAM_LIMIT = 13'h03FF; + parameter integer VC0_TOTAL_CREDITS_CD = 127; + parameter integer VC0_TOTAL_CREDITS_CH = 31; + parameter integer VC0_TOTAL_CREDITS_NPH = 12; + parameter integer VC0_TOTAL_CREDITS_PD = 288; + parameter integer VC0_TOTAL_CREDITS_PH = 32; + parameter integer VC0_TX_LASTPACKET = 31; + parameter [11:0] VC_BASE_PTR = 12'h10C; + parameter [15:0] VC_CAP_ID = 16'h0002; + parameter [11:0] VC_CAP_NEXTPTR = 12'h000; + parameter VC_CAP_ON = "FALSE"; + parameter VC_CAP_REJECT_SNOOP_TRANSACTIONS = "FALSE"; + parameter [3:0] VC_CAP_VERSION = 4'h1; + parameter [15:0] VENDOR_ID = 16'h10EE; + parameter [11:0] VSEC_BASE_PTR = 12'h160; + parameter [15:0] VSEC_CAP_HDR_ID = 16'h1234; + parameter [11:0] VSEC_CAP_HDR_LENGTH = 12'h018; + parameter [3:0] VSEC_CAP_HDR_REVISION = 4'h1; + parameter [15:0] VSEC_CAP_ID = 16'h000B; + parameter VSEC_CAP_IS_LINK_VISIBLE = "TRUE"; + parameter [11:0] VSEC_CAP_NEXTPTR = 12'h000; + parameter VSEC_CAP_ON = "FALSE"; + parameter [3:0] VSEC_CAP_VERSION = 4'h1; + output CFGAERECRCCHECKEN; + output CFGAERECRCGENEN; + output CFGCOMMANDBUSMASTERENABLE; + output CFGCOMMANDINTERRUPTDISABLE; + output CFGCOMMANDIOENABLE; + output CFGCOMMANDMEMENABLE; + output CFGCOMMANDSERREN; + output CFGDEVCONTROL2CPLTIMEOUTDIS; + output CFGDEVCONTROLAUXPOWEREN; + output CFGDEVCONTROLCORRERRREPORTINGEN; + output CFGDEVCONTROLENABLERO; + output CFGDEVCONTROLEXTTAGEN; + output CFGDEVCONTROLFATALERRREPORTINGEN; + output CFGDEVCONTROLNONFATALREPORTINGEN; + output CFGDEVCONTROLNOSNOOPEN; + output CFGDEVCONTROLPHANTOMEN; + output CFGDEVCONTROLURERRREPORTINGEN; + output CFGDEVSTATUSCORRERRDETECTED; + output CFGDEVSTATUSFATALERRDETECTED; + output CFGDEVSTATUSNONFATALERRDETECTED; + output CFGDEVSTATUSURDETECTED; + output CFGERRAERHEADERLOGSETN; + output CFGERRCPLRDYN; + output CFGINTERRUPTMSIENABLE; + output CFGINTERRUPTMSIXENABLE; + output CFGINTERRUPTMSIXFM; + output CFGINTERRUPTRDYN; + output CFGLINKCONTROLAUTOBANDWIDTHINTEN; + output CFGLINKCONTROLBANDWIDTHINTEN; + output CFGLINKCONTROLCLOCKPMEN; + output CFGLINKCONTROLCOMMONCLOCK; + output CFGLINKCONTROLEXTENDEDSYNC; + output CFGLINKCONTROLHWAUTOWIDTHDIS; + output CFGLINKCONTROLLINKDISABLE; + output CFGLINKCONTROLRCB; + output CFGLINKCONTROLRETRAINLINK; + output CFGLINKSTATUSAUTOBANDWIDTHSTATUS; + output CFGLINKSTATUSBANDWITHSTATUS; + output CFGLINKSTATUSDLLACTIVE; + output CFGLINKSTATUSLINKTRAINING; + output CFGMSGRECEIVED; + output CFGMSGRECEIVEDASSERTINTA; + output CFGMSGRECEIVEDASSERTINTB; + output CFGMSGRECEIVEDASSERTINTC; + output CFGMSGRECEIVEDASSERTINTD; + output CFGMSGRECEIVEDDEASSERTINTA; + output CFGMSGRECEIVEDDEASSERTINTB; + output CFGMSGRECEIVEDDEASSERTINTC; + output CFGMSGRECEIVEDDEASSERTINTD; + output CFGMSGRECEIVEDERRCOR; + output CFGMSGRECEIVEDERRFATAL; + output CFGMSGRECEIVEDERRNONFATAL; + output CFGMSGRECEIVEDPMASNAK; + output CFGMSGRECEIVEDPMETO; + output CFGMSGRECEIVEDPMETOACK; + output CFGMSGRECEIVEDPMPME; + output CFGMSGRECEIVEDSETSLOTPOWERLIMIT; + output CFGMSGRECEIVEDUNLOCK; + output CFGPMCSRPMEEN; + output CFGPMCSRPMESTATUS; + output CFGPMRCVASREQL1N; + output CFGPMRCVENTERL1N; + output CFGPMRCVENTERL23N; + output CFGPMRCVREQACKN; + output CFGRDWRDONEN; + output CFGSLOTCONTROLELECTROMECHILCTLPULSE; + output CFGTRANSACTION; + output CFGTRANSACTIONTYPE; + output DBGSCLRA; + output DBGSCLRB; + output DBGSCLRC; + output DBGSCLRD; + output DBGSCLRE; + output DBGSCLRF; + output DBGSCLRG; + output DBGSCLRH; + output DBGSCLRI; + output DBGSCLRJ; + output DBGSCLRK; + output DRPDRDY; + output LL2BADDLLPERRN; + output LL2BADTLPERRN; + output LL2PROTOCOLERRN; + output LL2REPLAYROERRN; + output LL2REPLAYTOERRN; + output LL2SUSPENDOKN; + output LL2TFCINIT1SEQN; + output LL2TFCINIT2SEQN; + output LNKCLKEN; + output MIMRXRCE; + output MIMRXREN; + output MIMRXWEN; + output MIMTXRCE; + output MIMTXREN; + output MIMTXWEN; + output PIPERX0POLARITY; + output PIPERX1POLARITY; + output PIPERX2POLARITY; + output PIPERX3POLARITY; + output PIPERX4POLARITY; + output PIPERX5POLARITY; + output PIPERX6POLARITY; + output PIPERX7POLARITY; + output PIPETX0COMPLIANCE; + output PIPETX0ELECIDLE; + output PIPETX1COMPLIANCE; + output PIPETX1ELECIDLE; + output PIPETX2COMPLIANCE; + output PIPETX2ELECIDLE; + output PIPETX3COMPLIANCE; + output PIPETX3ELECIDLE; + output PIPETX4COMPLIANCE; + output PIPETX4ELECIDLE; + output PIPETX5COMPLIANCE; + output PIPETX5ELECIDLE; + output PIPETX6COMPLIANCE; + output PIPETX6ELECIDLE; + output PIPETX7COMPLIANCE; + output PIPETX7ELECIDLE; + output PIPETXDEEMPH; + output PIPETXRATE; + output PIPETXRCVRDET; + output PIPETXRESET; + output PL2LINKUPN; + output PL2RECEIVERERRN; + output PL2RECOVERYN; + output PL2RXELECIDLE; + output PL2SUSPENDOK; + output PLLINKGEN2CAP; + output PLLINKPARTNERGEN2SUPPORTED; + output PLLINKUPCFGCAP; + output PLPHYLNKUPN; + output PLRECEIVEDHOTRST; + output PLSELLNKRATE; + output RECEIVEDFUNCLVLRSTN; + output TL2ASPMSUSPENDCREDITCHECKOKN; + output TL2ASPMSUSPENDREQN; + output TL2PPMSUSPENDOKN; + output TRNLNKUPN; + output TRNRDLLPSRCRDYN; + output TRNRECRCERRN; + output TRNREOFN; + output TRNRERRFWDN; + output TRNRREMN; + output TRNRSOFN; + output TRNRSRCDSCN; + output TRNRSRCRDYN; + output TRNTCFGREQN; + output TRNTDLLPDSTRDYN; + output TRNTDSTRDYN; + output TRNTERRDROPN; + output USERRSTN; + output [11:0] DBGVECC; + output [11:0] PLDBGVEC; + output [11:0] TRNFCCPLD; + output [11:0] TRNFCNPD; + output [11:0] TRNFCPD; + output [12:0] MIMRXRADDR; + output [12:0] MIMRXWADDR; + output [12:0] MIMTXRADDR; + output [12:0] MIMTXWADDR; + output [15:0] CFGMSGDATA; + output [15:0] DRPDO; + output [15:0] PIPETX0DATA; + output [15:0] PIPETX1DATA; + output [15:0] PIPETX2DATA; + output [15:0] PIPETX3DATA; + output [15:0] PIPETX4DATA; + output [15:0] PIPETX5DATA; + output [15:0] PIPETX6DATA; + output [15:0] PIPETX7DATA; + output [1:0] CFGLINKCONTROLASPMCONTROL; + output [1:0] CFGLINKSTATUSCURRENTSPEED; + output [1:0] CFGPMCSRPOWERSTATE; + output [1:0] PIPETX0CHARISK; + output [1:0] PIPETX0POWERDOWN; + output [1:0] PIPETX1CHARISK; + output [1:0] PIPETX1POWERDOWN; + output [1:0] PIPETX2CHARISK; + output [1:0] PIPETX2POWERDOWN; + output [1:0] PIPETX3CHARISK; + output [1:0] PIPETX3POWERDOWN; + output [1:0] PIPETX4CHARISK; + output [1:0] PIPETX4POWERDOWN; + output [1:0] PIPETX5CHARISK; + output [1:0] PIPETX5POWERDOWN; + output [1:0] PIPETX6CHARISK; + output [1:0] PIPETX6POWERDOWN; + output [1:0] PIPETX7CHARISK; + output [1:0] PIPETX7POWERDOWN; + output [1:0] PLLANEREVERSALMODE; + output [1:0] PLRXPMSTATE; + output [1:0] PLSELLNKWIDTH; + output [2:0] CFGDEVCONTROLMAXPAYLOAD; + output [2:0] CFGDEVCONTROLMAXREADREQ; + output [2:0] CFGINTERRUPTMMENABLE; + output [2:0] CFGPCIELINKSTATE; + output [2:0] PIPETXMARGIN; + output [2:0] PLINITIALLINKWIDTH; + output [2:0] PLTXPMSTATE; + output [31:0] CFGDO; + output [31:0] TRNRDLLPDATA; + output [3:0] CFGDEVCONTROL2CPLTIMEOUTVAL; + output [3:0] CFGLINKSTATUSNEGOTIATEDWIDTH; + output [5:0] PLLTSSMSTATE; + output [5:0] TRNTBUFAV; + output [63:0] DBGVECA; + output [63:0] DBGVECB; + output [63:0] TRNRD; + output [67:0] MIMRXWDATA; + output [68:0] MIMTXWDATA; + output [6:0] CFGTRANSACTIONADDR; + output [6:0] CFGVCTCVCMAP; + output [6:0] TRNRBARHITN; + output [7:0] CFGINTERRUPTDO; + output [7:0] TRNFCCPLH; + output [7:0] TRNFCNPH; + output [7:0] TRNFCPH; + input CFGERRACSN; + input CFGERRCORN; + input CFGERRCPLABORTN; + input CFGERRCPLTIMEOUTN; + input CFGERRCPLUNEXPECTN; + input CFGERRECRCN; + input CFGERRLOCKEDN; + input CFGERRPOSTEDN; + input CFGERRURN; + input CFGINTERRUPTASSERTN; + input CFGINTERRUPTN; + input CFGPMDIRECTASPML1N; + input CFGPMSENDPMACKN; + input CFGPMSENDPMETON; + input CFGPMSENDPMNAKN; + input CFGPMTURNOFFOKN; + input CFGPMWAKEN; + input CFGRDENN; + input CFGTRNPENDINGN; + input CFGWRENN; + input CFGWRREADONLYN; + input CFGWRRW1CASRWN; + input CMRSTN; + input CMSTICKYRSTN; + input DBGSUBMODE; + input DLRSTN; + input DRPCLK; + input DRPDEN; + input DRPDWE; + input FUNCLVLRSTN; + input LL2SENDASREQL1N; + input LL2SENDENTERL1N; + input LL2SENDENTERL23N; + input LL2SUSPENDNOWN; + input LL2TLPRCVN; + input PIPECLK; + input PIPERX0CHANISALIGNED; + input PIPERX0ELECIDLE; + input PIPERX0PHYSTATUS; + input PIPERX0VALID; + input PIPERX1CHANISALIGNED; + input PIPERX1ELECIDLE; + input PIPERX1PHYSTATUS; + input PIPERX1VALID; + input PIPERX2CHANISALIGNED; + input PIPERX2ELECIDLE; + input PIPERX2PHYSTATUS; + input PIPERX2VALID; + input PIPERX3CHANISALIGNED; + input PIPERX3ELECIDLE; + input PIPERX3PHYSTATUS; + input PIPERX3VALID; + input PIPERX4CHANISALIGNED; + input PIPERX4ELECIDLE; + input PIPERX4PHYSTATUS; + input PIPERX4VALID; + input PIPERX5CHANISALIGNED; + input PIPERX5ELECIDLE; + input PIPERX5PHYSTATUS; + input PIPERX5VALID; + input PIPERX6CHANISALIGNED; + input PIPERX6ELECIDLE; + input PIPERX6PHYSTATUS; + input PIPERX6VALID; + input PIPERX7CHANISALIGNED; + input PIPERX7ELECIDLE; + input PIPERX7PHYSTATUS; + input PIPERX7VALID; + input PLDIRECTEDLINKAUTON; + input PLDIRECTEDLINKSPEED; + input PLDOWNSTREAMDEEMPHSOURCE; + input PLRSTN; + input PLTRANSMITHOTRST; + input PLUPSTREAMPREFERDEEMPH; + input SYSRSTN; + input TL2ASPMSUSPENDCREDITCHECKN; + input TL2PPMSUSPENDREQN; + input TLRSTN; + input TRNRDSTRDYN; + input TRNRNPOKN; + input TRNTCFGGNTN; + input TRNTDLLPSRCRDYN; + input TRNTECRCGENN; + input TRNTEOFN; + input TRNTERRFWDN; + input TRNTREMN; + input TRNTSOFN; + input TRNTSRCDSCN; + input TRNTSRCRDYN; + input TRNTSTRN; + input USERCLK; + input [127:0] CFGERRAERHEADERLOG; + input [15:0] DRPDI; + input [15:0] PIPERX0DATA; + input [15:0] PIPERX1DATA; + input [15:0] PIPERX2DATA; + input [15:0] PIPERX3DATA; + input [15:0] PIPERX4DATA; + input [15:0] PIPERX5DATA; + input [15:0] PIPERX6DATA; + input [15:0] PIPERX7DATA; + input [1:0] DBGMODE; + input [1:0] PIPERX0CHARISK; + input [1:0] PIPERX1CHARISK; + input [1:0] PIPERX2CHARISK; + input [1:0] PIPERX3CHARISK; + input [1:0] PIPERX4CHARISK; + input [1:0] PIPERX5CHARISK; + input [1:0] PIPERX6CHARISK; + input [1:0] PIPERX7CHARISK; + input [1:0] PLDIRECTEDLINKCHANGE; + input [1:0] PLDIRECTEDLINKWIDTH; + input [2:0] CFGDSFUNCTIONNUMBER; + input [2:0] PIPERX0STATUS; + input [2:0] PIPERX1STATUS; + input [2:0] PIPERX2STATUS; + input [2:0] PIPERX3STATUS; + input [2:0] PIPERX4STATUS; + input [2:0] PIPERX5STATUS; + input [2:0] PIPERX6STATUS; + input [2:0] PIPERX7STATUS; + input [2:0] PLDBGMODE; + input [2:0] TRNFCSEL; + input [31:0] CFGDI; + input [31:0] TRNTDLLPDATA; + input [3:0] CFGBYTEENN; + input [47:0] CFGERRTLPCPLHEADER; + input [4:0] CFGDSDEVICENUMBER; + input [4:0] PL2DIRECTEDLSTATE; + input [63:0] CFGDSN; + input [63:0] TRNTD; + input [67:0] MIMRXRDATA; + input [68:0] MIMTXRDATA; + input [7:0] CFGDSBUSNUMBER; + input [7:0] CFGINTERRUPTDI; + input [7:0] CFGPORTNUMBER; + input [8:0] DRPDADDR; + input [9:0] CFGDWADDR; +endmodule + +module SYSMON (...); + parameter [15:0] INIT_40 = 16'h0; + parameter [15:0] INIT_41 = 16'h0; + parameter [15:0] INIT_42 = 16'h0800; + parameter [15:0] INIT_43 = 16'h0; + parameter [15:0] INIT_44 = 16'h0; + parameter [15:0] INIT_45 = 16'h0; + parameter [15:0] INIT_46 = 16'h0; + parameter [15:0] INIT_47 = 16'h0; + parameter [15:0] INIT_48 = 16'h0; + parameter [15:0] INIT_49 = 16'h0; + parameter [15:0] INIT_4A = 16'h0; + parameter [15:0] INIT_4B = 16'h0; + parameter [15:0] INIT_4C = 16'h0; + parameter [15:0] INIT_4D = 16'h0; + parameter [15:0] INIT_4E = 16'h0; + parameter [15:0] INIT_4F = 16'h0; + parameter [15:0] INIT_50 = 16'h0; + parameter [15:0] INIT_51 = 16'h0; + parameter [15:0] INIT_52 = 16'h0; + parameter [15:0] INIT_53 = 16'h0; + parameter [15:0] INIT_54 = 16'h0; + parameter [15:0] INIT_55 = 16'h0; + parameter [15:0] INIT_56 = 16'h0; + parameter [15:0] INIT_57 = 16'h0; + parameter SIM_DEVICE = "VIRTEX5"; + parameter SIM_MONITOR_FILE = "design.txt"; + output BUSY; + output DRDY; + output EOC; + output EOS; + output JTAGBUSY; + output JTAGLOCKED; + output JTAGMODIFIED; + output OT; + output [15:0] DO; + output [2:0] ALM; + output [4:0] CHANNEL; + input CONVST; + input CONVSTCLK; + input DCLK; + input DEN; + input DWE; + input RESET; + input VN; + input VP; + input [15:0] DI; + input [15:0] VAUXN; + input [15:0] VAUXP; + input [6:0] DADDR; +endmodule + +module DSP48E1 (...); + parameter integer ACASCREG = 1; + parameter integer ADREG = 1; + parameter integer ALUMODEREG = 1; + parameter integer AREG = 1; + parameter AUTORESET_PATDET = "NO_RESET"; + parameter A_INPUT = "DIRECT"; + parameter integer BCASCREG = 1; + parameter integer BREG = 1; + parameter B_INPUT = "DIRECT"; + parameter integer CARRYINREG = 1; + parameter integer CARRYINSELREG = 1; + parameter integer CREG = 1; + parameter integer DREG = 1; + parameter integer INMODEREG = 1; + parameter integer MREG = 1; + parameter integer OPMODEREG = 1; + parameter integer PREG = 1; + parameter SEL_MASK = "MASK"; + parameter SEL_PATTERN = "PATTERN"; + parameter USE_DPORT = "FALSE"; + parameter USE_MULT = "MULTIPLY"; + parameter USE_PATTERN_DETECT = "NO_PATDET"; + parameter USE_SIMD = "ONE48"; + parameter [47:0] MASK = 48'h3FFFFFFFFFFF; + parameter [47:0] PATTERN = 48'h000000000000; + parameter [3:0] IS_ALUMODE_INVERTED = 4'b0; + parameter [0:0] IS_CARRYIN_INVERTED = 1'b0; + parameter [0:0] IS_CLK_INVERTED = 1'b0; + parameter [4:0] IS_INMODE_INVERTED = 5'b0; + parameter [6:0] IS_OPMODE_INVERTED = 7'b0; + output [29:0] ACOUT; + output [17:0] BCOUT; + output CARRYCASCOUT; + output [3:0] CARRYOUT; + output MULTSIGNOUT; + output OVERFLOW; + output [47:0] P; + output PATTERNBDETECT; + output PATTERNDETECT; + output [47:0] PCOUT; + output UNDERFLOW; + input [29:0] A; + input [29:0] ACIN; + (* invertible_pin = "IS_ALUMODE_INVERTED" *) + input [3:0] ALUMODE; + input [17:0] B; + input [17:0] BCIN; + input [47:0] C; + input CARRYCASCIN; + (* invertible_pin = "IS_CARRYIN_INVERTED" *) + input CARRYIN; + input [2:0] CARRYINSEL; + input CEA1; + input CEA2; + input CEAD; + input CEALUMODE; + input CEB1; + input CEB2; + input CEC; + input CECARRYIN; + input CECTRL; + input CED; + input CEINMODE; + input CEM; + input CEP; + (* clkbuf_sink *) + (* invertible_pin = "IS_CLK_INVERTED" *) + input CLK; + input [24:0] D; + (* invertible_pin = "IS_INMODE_INVERTED" *) + input [4:0] INMODE; + input MULTSIGNIN; + (* invertible_pin = "IS_OPMODE_INVERTED" *) + input [6:0] OPMODE; + input [47:0] PCIN; + input RSTA; + input RSTALLCARRYIN; + input RSTALUMODE; + input RSTB; + input RSTC; + input RSTCTRL; + input RSTD; + input RSTINMODE; + input RSTM; + input RSTP; +endmodule + +module BUFGCE (...); + parameter CE_TYPE = "SYNC"; + parameter [0:0] IS_CE_INVERTED = 1'b0; + parameter [0:0] IS_I_INVERTED = 1'b0; + (* clkbuf_driver *) + output O; + (* invertible_pin = "IS_CE_INVERTED" *) + input CE; + (* invertible_pin = "IS_I_INVERTED" *) + input I; +endmodule + +module BUFGCE_1 (...); + (* clkbuf_driver *) + output O; + input CE; + input I; +endmodule + +module BUFGMUX (...); + parameter CLK_SEL_TYPE = "SYNC"; + (* clkbuf_driver *) + output O; + input I0; + input I1; + input S; +endmodule + +module BUFGMUX_1 (...); + parameter CLK_SEL_TYPE = "SYNC"; + (* clkbuf_driver *) + output O; + input I0; + input I1; + input S; +endmodule + +module BUFGMUX_CTRL (...); + (* clkbuf_driver *) + output O; + input I0; + input I1; + input S; +endmodule + +module BUFH (...); + (* clkbuf_driver *) + output O; + input I; +endmodule + +module BUFIO (...); + (* clkbuf_driver *) + output O; + input I; +endmodule + +module BUFIODQS (...); + parameter DQSMASK_ENABLE = "FALSE"; + (* clkbuf_driver *) + output O; + input DQSMASK; + input I; +endmodule + +module BUFR (...); + parameter BUFR_DIVIDE = "BYPASS"; + parameter SIM_DEVICE = "7SERIES"; + (* clkbuf_driver *) + output O; + input CE; + input CLR; + input I; +endmodule + +module IBUFDS_GTXE1 (...); + parameter CLKCM_CFG = "TRUE"; + parameter CLKRCV_TRST = "TRUE"; + parameter [9:0] REFCLKOUT_DLY = 10'b0000000000; + output O; + output ODIV2; + input CEB; + (* iopad_external_pin *) + input I; + (* iopad_external_pin *) + input IB; +endmodule + +module MMCM_ADV (...); + parameter BANDWIDTH = "OPTIMIZED"; + parameter CLKFBOUT_USE_FINE_PS = "FALSE"; + parameter CLKOUT0_USE_FINE_PS = "FALSE"; + parameter CLKOUT1_USE_FINE_PS = "FALSE"; + parameter CLKOUT2_USE_FINE_PS = "FALSE"; + parameter CLKOUT3_USE_FINE_PS = "FALSE"; + parameter CLKOUT4_CASCADE = "FALSE"; + parameter CLKOUT4_USE_FINE_PS = "FALSE"; + parameter CLKOUT5_USE_FINE_PS = "FALSE"; + parameter CLKOUT6_USE_FINE_PS = "FALSE"; + parameter CLOCK_HOLD = "FALSE"; + parameter COMPENSATION = "ZHOLD"; + parameter STARTUP_WAIT = "FALSE"; + parameter integer CLKOUT1_DIVIDE = 1; + parameter integer CLKOUT2_DIVIDE = 1; + parameter integer CLKOUT3_DIVIDE = 1; + parameter integer CLKOUT4_DIVIDE = 1; + parameter integer CLKOUT5_DIVIDE = 1; + parameter integer CLKOUT6_DIVIDE = 1; + parameter integer DIVCLK_DIVIDE = 1; + parameter real CLKFBOUT_MULT_F = 5.000; + parameter real CLKFBOUT_PHASE = 0.000; + parameter real CLKIN1_PERIOD = 0.000; + parameter real CLKIN2_PERIOD = 0.000; + parameter real CLKOUT0_DIVIDE_F = 1.000; + parameter real CLKOUT0_DUTY_CYCLE = 0.500; + parameter real CLKOUT0_PHASE = 0.000; + parameter real CLKOUT1_DUTY_CYCLE = 0.500; + parameter real CLKOUT1_PHASE = 0.000; + parameter real CLKOUT2_DUTY_CYCLE = 0.500; + parameter real CLKOUT2_PHASE = 0.000; + parameter real CLKOUT3_DUTY_CYCLE = 0.500; + parameter real CLKOUT3_PHASE = 0.000; + parameter real CLKOUT4_DUTY_CYCLE = 0.500; + parameter real CLKOUT4_PHASE = 0.000; + parameter real CLKOUT5_DUTY_CYCLE = 0.500; + parameter real CLKOUT5_PHASE = 0.000; + parameter real CLKOUT6_DUTY_CYCLE = 0.500; + parameter real CLKOUT6_PHASE = 0.000; + parameter real REF_JITTER1 = 0.010; + parameter real REF_JITTER2 = 0.010; + parameter real VCOCLK_FREQ_MAX = 1600.0; + parameter real VCOCLK_FREQ_MIN = 600.0; + parameter real CLKIN_FREQ_MAX = 800.0; + parameter real CLKIN_FREQ_MIN = 10.0; + parameter real CLKPFD_FREQ_MAX = 550.0; + parameter real CLKPFD_FREQ_MIN = 10.0; + output CLKFBOUT; + output CLKFBOUTB; + output CLKFBSTOPPED; + output CLKINSTOPPED; + output CLKOUT0; + output CLKOUT0B; + output CLKOUT1; + output CLKOUT1B; + output CLKOUT2; + output CLKOUT2B; + output CLKOUT3; + output CLKOUT3B; + output CLKOUT4; + output CLKOUT5; + output CLKOUT6; + output DRDY; + output LOCKED; + output PSDONE; + output [15:0] DO; + input CLKFBIN; + input CLKIN1; + input CLKIN2; + input CLKINSEL; + input DCLK; + input DEN; + input DWE; + input PSCLK; + input PSEN; + input PSINCDEC; + input PWRDWN; + input RST; + input [15:0] DI; + input [6:0] DADDR; +endmodule + +module MMCM_BASE (...); + parameter BANDWIDTH = "OPTIMIZED"; + parameter real CLKFBOUT_MULT_F = 5.000; + parameter real CLKFBOUT_PHASE = 0.000; + parameter real CLKIN1_PERIOD = 0.000; + parameter real CLKOUT0_DIVIDE_F = 1.000; + parameter real CLKOUT0_DUTY_CYCLE = 0.500; + parameter real CLKOUT0_PHASE = 0.000; + parameter integer CLKOUT1_DIVIDE = 1; + parameter real CLKOUT1_DUTY_CYCLE = 0.500; + parameter real CLKOUT1_PHASE = 0.000; + parameter integer CLKOUT2_DIVIDE = 1; + parameter real CLKOUT2_DUTY_CYCLE = 0.500; + parameter real CLKOUT2_PHASE = 0.000; + parameter integer CLKOUT3_DIVIDE = 1; + parameter real CLKOUT3_DUTY_CYCLE = 0.500; + parameter real CLKOUT3_PHASE = 0.000; + parameter CLKOUT4_CASCADE = "FALSE"; + parameter integer CLKOUT4_DIVIDE = 1; + parameter real CLKOUT4_DUTY_CYCLE = 0.500; + parameter real CLKOUT4_PHASE = 0.000; + parameter integer CLKOUT5_DIVIDE = 1; + parameter real CLKOUT5_DUTY_CYCLE = 0.500; + parameter real CLKOUT5_PHASE = 0.000; + parameter integer CLKOUT6_DIVIDE = 1; + parameter real CLKOUT6_DUTY_CYCLE = 0.500; + parameter real CLKOUT6_PHASE = 0.000; + parameter CLOCK_HOLD = "FALSE"; + parameter integer DIVCLK_DIVIDE = 1; + parameter real REF_JITTER1 = 0.010; + parameter STARTUP_WAIT = "FALSE"; + output CLKFBOUT; + output CLKFBOUTB; + output CLKOUT0; + output CLKOUT0B; + output CLKOUT1; + output CLKOUT1B; + output CLKOUT2; + output CLKOUT2B; + output CLKOUT3; + output CLKOUT3B; + output CLKOUT4; + output CLKOUT5; + output CLKOUT6; + output LOCKED; + input CLKFBIN; + input CLKIN1; + input PWRDWN; + input RST; +endmodule + +(* keep *) +module BSCAN_VIRTEX6 (...); + parameter DISABLE_JTAG = "FALSE"; + parameter integer JTAG_CHAIN = 1; + output CAPTURE; + output DRCK; + output RESET; + output RUNTEST; + output SEL; + output SHIFT; + output TCK; + output TDI; + output TMS; + output UPDATE; + input TDO; +endmodule + +(* keep *) +module CAPTURE_VIRTEX6 (...); + parameter ONESHOT = "TRUE"; + input CAP; + input CLK; +endmodule + +module DNA_PORT (...); + parameter [56:0] SIM_DNA_VALUE = 57'h0; + output DOUT; + input CLK; + input DIN; + input READ; + input SHIFT; +endmodule + +module EFUSE_USR (...); + parameter [31:0] SIM_EFUSE_VALUE = 32'h00000000; + output [31:0] EFUSEUSR; +endmodule + +module FRAME_ECC_VIRTEX6 (...); + parameter FARSRC = "EFAR"; + parameter FRAME_RBT_IN_FILENAME = "NONE"; + output CRCERROR; + output ECCERROR; + output ECCERRORSINGLE; + output SYNDROMEVALID; + output [12:0] SYNDROME; + output [23:0] FAR; + output [4:0] SYNBIT; + output [6:0] SYNWORD; +endmodule + +(* keep *) +module ICAP_VIRTEX6 (...); + parameter [31:0] DEVICE_ID = 32'h04244093; + parameter ICAP_WIDTH = "X8"; + parameter SIM_CFG_FILE_NAME = "NONE"; + output BUSY; + output [31:0] O; + input CLK; + input CSB; + input RDWRB; + input [31:0] I; +endmodule + +(* keep *) +module STARTUP_VIRTEX6 (...); + parameter PROG_USR = "FALSE"; + output CFGCLK; + output CFGMCLK; + output DINSPI; + output EOS; + output PREQ; + output TCKSPI; + input CLK; + input GSR; + input GTS; + input KEYCLEARB; + input PACK; + input USRCCLKO; + input USRCCLKTS; + input USRDONEO; + input USRDONETS; +endmodule + +module USR_ACCESS_VIRTEX6 (...); + output CFGCLK; + output [31:0] DATA; + output DATAVALID; +endmodule + +(* keep *) +module DCIRESET (...); + output LOCKED; + input RST; +endmodule + +module GTHE1_QUAD (...); + parameter [15:0] BER_CONST_PTRN0 = 16'h0000; + parameter [15:0] BER_CONST_PTRN1 = 16'h0000; + parameter [15:0] BUFFER_CONFIG_LANE0 = 16'h4004; + parameter [15:0] BUFFER_CONFIG_LANE1 = 16'h4004; + parameter [15:0] BUFFER_CONFIG_LANE2 = 16'h4004; + parameter [15:0] BUFFER_CONFIG_LANE3 = 16'h4004; + parameter [15:0] DFE_TRAIN_CTRL_LANE0 = 16'h0000; + parameter [15:0] DFE_TRAIN_CTRL_LANE1 = 16'h0000; + parameter [15:0] DFE_TRAIN_CTRL_LANE2 = 16'h0000; + parameter [15:0] DFE_TRAIN_CTRL_LANE3 = 16'h0000; + parameter [15:0] DLL_CFG0 = 16'h8202; + parameter [15:0] DLL_CFG1 = 16'h0000; + parameter [15:0] E10GBASEKR_LD_COEFF_UPD_LANE0 = 16'h0000; + parameter [15:0] E10GBASEKR_LD_COEFF_UPD_LANE1 = 16'h0000; + parameter [15:0] E10GBASEKR_LD_COEFF_UPD_LANE2 = 16'h0000; + parameter [15:0] E10GBASEKR_LD_COEFF_UPD_LANE3 = 16'h0000; + parameter [15:0] E10GBASEKR_LP_COEFF_UPD_LANE0 = 16'h0000; + parameter [15:0] E10GBASEKR_LP_COEFF_UPD_LANE1 = 16'h0000; + parameter [15:0] E10GBASEKR_LP_COEFF_UPD_LANE2 = 16'h0000; + parameter [15:0] E10GBASEKR_LP_COEFF_UPD_LANE3 = 16'h0000; + parameter [15:0] E10GBASEKR_PMA_CTRL_LANE0 = 16'h0002; + parameter [15:0] E10GBASEKR_PMA_CTRL_LANE1 = 16'h0002; + parameter [15:0] E10GBASEKR_PMA_CTRL_LANE2 = 16'h0002; + parameter [15:0] E10GBASEKR_PMA_CTRL_LANE3 = 16'h0002; + parameter [15:0] E10GBASEKX_CTRL_LANE0 = 16'h0000; + parameter [15:0] E10GBASEKX_CTRL_LANE1 = 16'h0000; + parameter [15:0] E10GBASEKX_CTRL_LANE2 = 16'h0000; + parameter [15:0] E10GBASEKX_CTRL_LANE3 = 16'h0000; + parameter [15:0] E10GBASER_PCS_CFG_LANE0 = 16'h070C; + parameter [15:0] E10GBASER_PCS_CFG_LANE1 = 16'h070C; + parameter [15:0] E10GBASER_PCS_CFG_LANE2 = 16'h070C; + parameter [15:0] E10GBASER_PCS_CFG_LANE3 = 16'h070C; + parameter [15:0] E10GBASER_PCS_SEEDA0_LANE0 = 16'h0001; + parameter [15:0] E10GBASER_PCS_SEEDA0_LANE1 = 16'h0001; + parameter [15:0] E10GBASER_PCS_SEEDA0_LANE2 = 16'h0001; + parameter [15:0] E10GBASER_PCS_SEEDA0_LANE3 = 16'h0001; + parameter [15:0] E10GBASER_PCS_SEEDA1_LANE0 = 16'h0000; + parameter [15:0] E10GBASER_PCS_SEEDA1_LANE1 = 16'h0000; + parameter [15:0] E10GBASER_PCS_SEEDA1_LANE2 = 16'h0000; + parameter [15:0] E10GBASER_PCS_SEEDA1_LANE3 = 16'h0000; + parameter [15:0] E10GBASER_PCS_SEEDA2_LANE0 = 16'h0000; + parameter [15:0] E10GBASER_PCS_SEEDA2_LANE1 = 16'h0000; + parameter [15:0] E10GBASER_PCS_SEEDA2_LANE2 = 16'h0000; + parameter [15:0] E10GBASER_PCS_SEEDA2_LANE3 = 16'h0000; + parameter [15:0] E10GBASER_PCS_SEEDA3_LANE0 = 16'h0000; + parameter [15:0] E10GBASER_PCS_SEEDA3_LANE1 = 16'h0000; + parameter [15:0] E10GBASER_PCS_SEEDA3_LANE2 = 16'h0000; + parameter [15:0] E10GBASER_PCS_SEEDA3_LANE3 = 16'h0000; + parameter [15:0] E10GBASER_PCS_SEEDB0_LANE0 = 16'h0001; + parameter [15:0] E10GBASER_PCS_SEEDB0_LANE1 = 16'h0001; + parameter [15:0] E10GBASER_PCS_SEEDB0_LANE2 = 16'h0001; + parameter [15:0] E10GBASER_PCS_SEEDB0_LANE3 = 16'h0001; + parameter [15:0] E10GBASER_PCS_SEEDB1_LANE0 = 16'h0000; + parameter [15:0] E10GBASER_PCS_SEEDB1_LANE1 = 16'h0000; + parameter [15:0] E10GBASER_PCS_SEEDB1_LANE2 = 16'h0000; + parameter [15:0] E10GBASER_PCS_SEEDB1_LANE3 = 16'h0000; + parameter [15:0] E10GBASER_PCS_SEEDB2_LANE0 = 16'h0000; + parameter [15:0] E10GBASER_PCS_SEEDB2_LANE1 = 16'h0000; + parameter [15:0] E10GBASER_PCS_SEEDB2_LANE2 = 16'h0000; + parameter [15:0] E10GBASER_PCS_SEEDB2_LANE3 = 16'h0000; + parameter [15:0] E10GBASER_PCS_SEEDB3_LANE0 = 16'h0000; + parameter [15:0] E10GBASER_PCS_SEEDB3_LANE1 = 16'h0000; + parameter [15:0] E10GBASER_PCS_SEEDB3_LANE2 = 16'h0000; + parameter [15:0] E10GBASER_PCS_SEEDB3_LANE3 = 16'h0000; + parameter [15:0] E10GBASER_PCS_TEST_CTRL_LANE0 = 16'h0000; + parameter [15:0] E10GBASER_PCS_TEST_CTRL_LANE1 = 16'h0000; + parameter [15:0] E10GBASER_PCS_TEST_CTRL_LANE2 = 16'h0000; + parameter [15:0] E10GBASER_PCS_TEST_CTRL_LANE3 = 16'h0000; + parameter [15:0] E10GBASEX_PCS_TSTCTRL_LANE0 = 16'h0000; + parameter [15:0] E10GBASEX_PCS_TSTCTRL_LANE1 = 16'h0000; + parameter [15:0] E10GBASEX_PCS_TSTCTRL_LANE2 = 16'h0000; + parameter [15:0] E10GBASEX_PCS_TSTCTRL_LANE3 = 16'h0000; + parameter [15:0] GLBL0_NOISE_CTRL = 16'hF0B8; + parameter [15:0] GLBL_AMON_SEL = 16'h0000; + parameter [15:0] GLBL_DMON_SEL = 16'h0200; + parameter [15:0] GLBL_PWR_CTRL = 16'h0000; + parameter [0:0] GTH_CFG_PWRUP_LANE0 = 1'b1; + parameter [0:0] GTH_CFG_PWRUP_LANE1 = 1'b1; + parameter [0:0] GTH_CFG_PWRUP_LANE2 = 1'b1; + parameter [0:0] GTH_CFG_PWRUP_LANE3 = 1'b1; + parameter [15:0] LANE_AMON_SEL = 16'h00F0; + parameter [15:0] LANE_DMON_SEL = 16'h0000; + parameter [15:0] LANE_LNK_CFGOVRD = 16'h0000; + parameter [15:0] LANE_PWR_CTRL_LANE0 = 16'h0400; + parameter [15:0] LANE_PWR_CTRL_LANE1 = 16'h0400; + parameter [15:0] LANE_PWR_CTRL_LANE2 = 16'h0400; + parameter [15:0] LANE_PWR_CTRL_LANE3 = 16'h0400; + parameter [15:0] LNK_TRN_CFG_LANE0 = 16'h0000; + parameter [15:0] LNK_TRN_CFG_LANE1 = 16'h0000; + parameter [15:0] LNK_TRN_CFG_LANE2 = 16'h0000; + parameter [15:0] LNK_TRN_CFG_LANE3 = 16'h0000; + parameter [15:0] LNK_TRN_COEFF_REQ_LANE0 = 16'h0000; + parameter [15:0] LNK_TRN_COEFF_REQ_LANE1 = 16'h0000; + parameter [15:0] LNK_TRN_COEFF_REQ_LANE2 = 16'h0000; + parameter [15:0] LNK_TRN_COEFF_REQ_LANE3 = 16'h0000; + parameter [15:0] MISC_CFG = 16'h0008; + parameter [15:0] MODE_CFG1 = 16'h0000; + parameter [15:0] MODE_CFG2 = 16'h0000; + parameter [15:0] MODE_CFG3 = 16'h0000; + parameter [15:0] MODE_CFG4 = 16'h0000; + parameter [15:0] MODE_CFG5 = 16'h0000; + parameter [15:0] MODE_CFG6 = 16'h0000; + parameter [15:0] MODE_CFG7 = 16'h0000; + parameter [15:0] PCS_ABILITY_LANE0 = 16'h0010; + parameter [15:0] PCS_ABILITY_LANE1 = 16'h0010; + parameter [15:0] PCS_ABILITY_LANE2 = 16'h0010; + parameter [15:0] PCS_ABILITY_LANE3 = 16'h0010; + parameter [15:0] PCS_CTRL1_LANE0 = 16'h2040; + parameter [15:0] PCS_CTRL1_LANE1 = 16'h2040; + parameter [15:0] PCS_CTRL1_LANE2 = 16'h2040; + parameter [15:0] PCS_CTRL1_LANE3 = 16'h2040; + parameter [15:0] PCS_CTRL2_LANE0 = 16'h0000; + parameter [15:0] PCS_CTRL2_LANE1 = 16'h0000; + parameter [15:0] PCS_CTRL2_LANE2 = 16'h0000; + parameter [15:0] PCS_CTRL2_LANE3 = 16'h0000; + parameter [15:0] PCS_MISC_CFG_0_LANE0 = 16'h1116; + parameter [15:0] PCS_MISC_CFG_0_LANE1 = 16'h1116; + parameter [15:0] PCS_MISC_CFG_0_LANE2 = 16'h1116; + parameter [15:0] PCS_MISC_CFG_0_LANE3 = 16'h1116; + parameter [15:0] PCS_MISC_CFG_1_LANE0 = 16'h0000; + parameter [15:0] PCS_MISC_CFG_1_LANE1 = 16'h0000; + parameter [15:0] PCS_MISC_CFG_1_LANE2 = 16'h0000; + parameter [15:0] PCS_MISC_CFG_1_LANE3 = 16'h0000; + parameter [15:0] PCS_MODE_LANE0 = 16'h0000; + parameter [15:0] PCS_MODE_LANE1 = 16'h0000; + parameter [15:0] PCS_MODE_LANE2 = 16'h0000; + parameter [15:0] PCS_MODE_LANE3 = 16'h0000; + parameter [15:0] PCS_RESET_1_LANE0 = 16'h0002; + parameter [15:0] PCS_RESET_1_LANE1 = 16'h0002; + parameter [15:0] PCS_RESET_1_LANE2 = 16'h0002; + parameter [15:0] PCS_RESET_1_LANE3 = 16'h0002; + parameter [15:0] PCS_RESET_LANE0 = 16'h0000; + parameter [15:0] PCS_RESET_LANE1 = 16'h0000; + parameter [15:0] PCS_RESET_LANE2 = 16'h0000; + parameter [15:0] PCS_RESET_LANE3 = 16'h0000; + parameter [15:0] PCS_TYPE_LANE0 = 16'h002C; + parameter [15:0] PCS_TYPE_LANE1 = 16'h002C; + parameter [15:0] PCS_TYPE_LANE2 = 16'h002C; + parameter [15:0] PCS_TYPE_LANE3 = 16'h002C; + parameter [15:0] PLL_CFG0 = 16'h95DF; + parameter [15:0] PLL_CFG1 = 16'h81C0; + parameter [15:0] PLL_CFG2 = 16'h0424; + parameter [15:0] PMA_CTRL1_LANE0 = 16'h0000; + parameter [15:0] PMA_CTRL1_LANE1 = 16'h0000; + parameter [15:0] PMA_CTRL1_LANE2 = 16'h0000; + parameter [15:0] PMA_CTRL1_LANE3 = 16'h0000; + parameter [15:0] PMA_CTRL2_LANE0 = 16'h000B; + parameter [15:0] PMA_CTRL2_LANE1 = 16'h000B; + parameter [15:0] PMA_CTRL2_LANE2 = 16'h000B; + parameter [15:0] PMA_CTRL2_LANE3 = 16'h000B; + parameter [15:0] PMA_LPBK_CTRL_LANE0 = 16'h0004; + parameter [15:0] PMA_LPBK_CTRL_LANE1 = 16'h0004; + parameter [15:0] PMA_LPBK_CTRL_LANE2 = 16'h0004; + parameter [15:0] PMA_LPBK_CTRL_LANE3 = 16'h0004; + parameter [15:0] PRBS_BER_CFG0_LANE0 = 16'h0000; + parameter [15:0] PRBS_BER_CFG0_LANE1 = 16'h0000; + parameter [15:0] PRBS_BER_CFG0_LANE2 = 16'h0000; + parameter [15:0] PRBS_BER_CFG0_LANE3 = 16'h0000; + parameter [15:0] PRBS_BER_CFG1_LANE0 = 16'h0000; + parameter [15:0] PRBS_BER_CFG1_LANE1 = 16'h0000; + parameter [15:0] PRBS_BER_CFG1_LANE2 = 16'h0000; + parameter [15:0] PRBS_BER_CFG1_LANE3 = 16'h0000; + parameter [15:0] PRBS_CFG_LANE0 = 16'h000A; + parameter [15:0] PRBS_CFG_LANE1 = 16'h000A; + parameter [15:0] PRBS_CFG_LANE2 = 16'h000A; + parameter [15:0] PRBS_CFG_LANE3 = 16'h000A; + parameter [15:0] PTRN_CFG0_LSB = 16'h5555; + parameter [15:0] PTRN_CFG0_MSB = 16'h5555; + parameter [15:0] PTRN_LEN_CFG = 16'h001F; + parameter [15:0] PWRUP_DLY = 16'h0000; + parameter [15:0] RX_AEQ_VAL0_LANE0 = 16'h03C0; + parameter [15:0] RX_AEQ_VAL0_LANE1 = 16'h03C0; + parameter [15:0] RX_AEQ_VAL0_LANE2 = 16'h03C0; + parameter [15:0] RX_AEQ_VAL0_LANE3 = 16'h03C0; + parameter [15:0] RX_AEQ_VAL1_LANE0 = 16'h0000; + parameter [15:0] RX_AEQ_VAL1_LANE1 = 16'h0000; + parameter [15:0] RX_AEQ_VAL1_LANE2 = 16'h0000; + parameter [15:0] RX_AEQ_VAL1_LANE3 = 16'h0000; + parameter [15:0] RX_AGC_CTRL_LANE0 = 16'h0000; + parameter [15:0] RX_AGC_CTRL_LANE1 = 16'h0000; + parameter [15:0] RX_AGC_CTRL_LANE2 = 16'h0000; + parameter [15:0] RX_AGC_CTRL_LANE3 = 16'h0000; + parameter [15:0] RX_CDR_CTRL0_LANE0 = 16'h0005; + parameter [15:0] RX_CDR_CTRL0_LANE1 = 16'h0005; + parameter [15:0] RX_CDR_CTRL0_LANE2 = 16'h0005; + parameter [15:0] RX_CDR_CTRL0_LANE3 = 16'h0005; + parameter [15:0] RX_CDR_CTRL1_LANE0 = 16'h4200; + parameter [15:0] RX_CDR_CTRL1_LANE1 = 16'h4200; + parameter [15:0] RX_CDR_CTRL1_LANE2 = 16'h4200; + parameter [15:0] RX_CDR_CTRL1_LANE3 = 16'h4200; + parameter [15:0] RX_CDR_CTRL2_LANE0 = 16'h2000; + parameter [15:0] RX_CDR_CTRL2_LANE1 = 16'h2000; + parameter [15:0] RX_CDR_CTRL2_LANE2 = 16'h2000; + parameter [15:0] RX_CDR_CTRL2_LANE3 = 16'h2000; + parameter [15:0] RX_CFG0_LANE0 = 16'h0500; + parameter [15:0] RX_CFG0_LANE1 = 16'h0500; + parameter [15:0] RX_CFG0_LANE2 = 16'h0500; + parameter [15:0] RX_CFG0_LANE3 = 16'h0500; + parameter [15:0] RX_CFG1_LANE0 = 16'h821F; + parameter [15:0] RX_CFG1_LANE1 = 16'h821F; + parameter [15:0] RX_CFG1_LANE2 = 16'h821F; + parameter [15:0] RX_CFG1_LANE3 = 16'h821F; + parameter [15:0] RX_CFG2_LANE0 = 16'h1001; + parameter [15:0] RX_CFG2_LANE1 = 16'h1001; + parameter [15:0] RX_CFG2_LANE2 = 16'h1001; + parameter [15:0] RX_CFG2_LANE3 = 16'h1001; + parameter [15:0] RX_CTLE_CTRL_LANE0 = 16'h008F; + parameter [15:0] RX_CTLE_CTRL_LANE1 = 16'h008F; + parameter [15:0] RX_CTLE_CTRL_LANE2 = 16'h008F; + parameter [15:0] RX_CTLE_CTRL_LANE3 = 16'h008F; + parameter [15:0] RX_CTRL_OVRD_LANE0 = 16'h000C; + parameter [15:0] RX_CTRL_OVRD_LANE1 = 16'h000C; + parameter [15:0] RX_CTRL_OVRD_LANE2 = 16'h000C; + parameter [15:0] RX_CTRL_OVRD_LANE3 = 16'h000C; + parameter integer RX_FABRIC_WIDTH0 = 6466; + parameter integer RX_FABRIC_WIDTH1 = 6466; + parameter integer RX_FABRIC_WIDTH2 = 6466; + parameter integer RX_FABRIC_WIDTH3 = 6466; + parameter [15:0] RX_LOOP_CTRL_LANE0 = 16'h007F; + parameter [15:0] RX_LOOP_CTRL_LANE1 = 16'h007F; + parameter [15:0] RX_LOOP_CTRL_LANE2 = 16'h007F; + parameter [15:0] RX_LOOP_CTRL_LANE3 = 16'h007F; + parameter [15:0] RX_MVAL0_LANE0 = 16'h0000; + parameter [15:0] RX_MVAL0_LANE1 = 16'h0000; + parameter [15:0] RX_MVAL0_LANE2 = 16'h0000; + parameter [15:0] RX_MVAL0_LANE3 = 16'h0000; + parameter [15:0] RX_MVAL1_LANE0 = 16'h0000; + parameter [15:0] RX_MVAL1_LANE1 = 16'h0000; + parameter [15:0] RX_MVAL1_LANE2 = 16'h0000; + parameter [15:0] RX_MVAL1_LANE3 = 16'h0000; + parameter [15:0] RX_P0S_CTRL = 16'h1206; + parameter [15:0] RX_P0_CTRL = 16'h11F0; + parameter [15:0] RX_P1_CTRL = 16'h120F; + parameter [15:0] RX_P2_CTRL = 16'h0E0F; + parameter [15:0] RX_PI_CTRL0 = 16'hD2F0; + parameter [15:0] RX_PI_CTRL1 = 16'h0080; + parameter integer SIM_GTHRESET_SPEEDUP = 1; + parameter SIM_VERSION = "1.0"; + parameter [15:0] SLICE_CFG = 16'h0000; + parameter [15:0] SLICE_NOISE_CTRL_0_LANE01 = 16'h0000; + parameter [15:0] SLICE_NOISE_CTRL_0_LANE23 = 16'h0000; + parameter [15:0] SLICE_NOISE_CTRL_1_LANE01 = 16'h0000; + parameter [15:0] SLICE_NOISE_CTRL_1_LANE23 = 16'h0000; + parameter [15:0] SLICE_NOISE_CTRL_2_LANE01 = 16'h7FFF; + parameter [15:0] SLICE_NOISE_CTRL_2_LANE23 = 16'h7FFF; + parameter [15:0] SLICE_TX_RESET_LANE01 = 16'h0000; + parameter [15:0] SLICE_TX_RESET_LANE23 = 16'h0000; + parameter [15:0] TERM_CTRL_LANE0 = 16'h5007; + parameter [15:0] TERM_CTRL_LANE1 = 16'h5007; + parameter [15:0] TERM_CTRL_LANE2 = 16'h5007; + parameter [15:0] TERM_CTRL_LANE3 = 16'h5007; + parameter [15:0] TX_CFG0_LANE0 = 16'h203D; + parameter [15:0] TX_CFG0_LANE1 = 16'h203D; + parameter [15:0] TX_CFG0_LANE2 = 16'h203D; + parameter [15:0] TX_CFG0_LANE3 = 16'h203D; + parameter [15:0] TX_CFG1_LANE0 = 16'h0F00; + parameter [15:0] TX_CFG1_LANE1 = 16'h0F00; + parameter [15:0] TX_CFG1_LANE2 = 16'h0F00; + parameter [15:0] TX_CFG1_LANE3 = 16'h0F00; + parameter [15:0] TX_CFG2_LANE0 = 16'h0081; + parameter [15:0] TX_CFG2_LANE1 = 16'h0081; + parameter [15:0] TX_CFG2_LANE2 = 16'h0081; + parameter [15:0] TX_CFG2_LANE3 = 16'h0081; + parameter [15:0] TX_CLK_SEL0_LANE0 = 16'h2121; + parameter [15:0] TX_CLK_SEL0_LANE1 = 16'h2121; + parameter [15:0] TX_CLK_SEL0_LANE2 = 16'h2121; + parameter [15:0] TX_CLK_SEL0_LANE3 = 16'h2121; + parameter [15:0] TX_CLK_SEL1_LANE0 = 16'h2121; + parameter [15:0] TX_CLK_SEL1_LANE1 = 16'h2121; + parameter [15:0] TX_CLK_SEL1_LANE2 = 16'h2121; + parameter [15:0] TX_CLK_SEL1_LANE3 = 16'h2121; + parameter [15:0] TX_DISABLE_LANE0 = 16'h0000; + parameter [15:0] TX_DISABLE_LANE1 = 16'h0000; + parameter [15:0] TX_DISABLE_LANE2 = 16'h0000; + parameter [15:0] TX_DISABLE_LANE3 = 16'h0000; + parameter integer TX_FABRIC_WIDTH0 = 6466; + parameter integer TX_FABRIC_WIDTH1 = 6466; + parameter integer TX_FABRIC_WIDTH2 = 6466; + parameter integer TX_FABRIC_WIDTH3 = 6466; + parameter [15:0] TX_P0P0S_CTRL = 16'h060C; + parameter [15:0] TX_P1P2_CTRL = 16'h0C39; + parameter [15:0] TX_PREEMPH_LANE0 = 16'h00A1; + parameter [15:0] TX_PREEMPH_LANE1 = 16'h00A1; + parameter [15:0] TX_PREEMPH_LANE2 = 16'h00A1; + parameter [15:0] TX_PREEMPH_LANE3 = 16'h00A1; + parameter [15:0] TX_PWR_RATE_OVRD_LANE0 = 16'h0060; + parameter [15:0] TX_PWR_RATE_OVRD_LANE1 = 16'h0060; + parameter [15:0] TX_PWR_RATE_OVRD_LANE2 = 16'h0060; + parameter [15:0] TX_PWR_RATE_OVRD_LANE3 = 16'h0060; + output DRDY; + output GTHINITDONE; + output MGMTPCSRDACK; + output RXCTRLACK0; + output RXCTRLACK1; + output RXCTRLACK2; + output RXCTRLACK3; + output RXDATATAP0; + output RXDATATAP1; + output RXDATATAP2; + output RXDATATAP3; + output RXPCSCLKSMPL0; + output RXPCSCLKSMPL1; + output RXPCSCLKSMPL2; + output RXPCSCLKSMPL3; + output RXUSERCLKOUT0; + output RXUSERCLKOUT1; + output RXUSERCLKOUT2; + output RXUSERCLKOUT3; + output TSTPATH; + output TSTREFCLKFAB; + output TSTREFCLKOUT; + output TXCTRLACK0; + output TXCTRLACK1; + output TXCTRLACK2; + output TXCTRLACK3; + output TXDATATAP10; + output TXDATATAP11; + output TXDATATAP12; + output TXDATATAP13; + output TXDATATAP20; + output TXDATATAP21; + output TXDATATAP22; + output TXDATATAP23; + output TXN0; + output TXN1; + output TXN2; + output TXN3; + output TXP0; + output TXP1; + output TXP2; + output TXP3; + output TXPCSCLKSMPL0; + output TXPCSCLKSMPL1; + output TXPCSCLKSMPL2; + output TXPCSCLKSMPL3; + output TXUSERCLKOUT0; + output TXUSERCLKOUT1; + output TXUSERCLKOUT2; + output TXUSERCLKOUT3; + output [15:0] DRPDO; + output [15:0] MGMTPCSRDDATA; + output [63:0] RXDATA0; + output [63:0] RXDATA1; + output [63:0] RXDATA2; + output [63:0] RXDATA3; + output [7:0] RXCODEERR0; + output [7:0] RXCODEERR1; + output [7:0] RXCODEERR2; + output [7:0] RXCODEERR3; + output [7:0] RXCTRL0; + output [7:0] RXCTRL1; + output [7:0] RXCTRL2; + output [7:0] RXCTRL3; + output [7:0] RXDISPERR0; + output [7:0] RXDISPERR1; + output [7:0] RXDISPERR2; + output [7:0] RXDISPERR3; + output [7:0] RXVALID0; + output [7:0] RXVALID1; + output [7:0] RXVALID2; + output [7:0] RXVALID3; + input DCLK; + input DEN; + input DFETRAINCTRL0; + input DFETRAINCTRL1; + input DFETRAINCTRL2; + input DFETRAINCTRL3; + input DISABLEDRP; + input DWE; + input GTHINIT; + input GTHRESET; + input GTHX2LANE01; + input GTHX2LANE23; + input GTHX4LANE; + input MGMTPCSREGRD; + input MGMTPCSREGWR; + input POWERDOWN0; + input POWERDOWN1; + input POWERDOWN2; + input POWERDOWN3; + input REFCLK; + input RXBUFRESET0; + input RXBUFRESET1; + input RXBUFRESET2; + input RXBUFRESET3; + input RXENCOMMADET0; + input RXENCOMMADET1; + input RXENCOMMADET2; + input RXENCOMMADET3; + input RXN0; + input RXN1; + input RXN2; + input RXN3; + input RXP0; + input RXP1; + input RXP2; + input RXP3; + input RXPOLARITY0; + input RXPOLARITY1; + input RXPOLARITY2; + input RXPOLARITY3; + input RXSLIP0; + input RXSLIP1; + input RXSLIP2; + input RXSLIP3; + input RXUSERCLKIN0; + input RXUSERCLKIN1; + input RXUSERCLKIN2; + input RXUSERCLKIN3; + input TXBUFRESET0; + input TXBUFRESET1; + input TXBUFRESET2; + input TXBUFRESET3; + input TXDEEMPH0; + input TXDEEMPH1; + input TXDEEMPH2; + input TXDEEMPH3; + input TXUSERCLKIN0; + input TXUSERCLKIN1; + input TXUSERCLKIN2; + input TXUSERCLKIN3; + input [15:0] DADDR; + input [15:0] DI; + input [15:0] MGMTPCSREGADDR; + input [15:0] MGMTPCSWRDATA; + input [1:0] RXPOWERDOWN0; + input [1:0] RXPOWERDOWN1; + input [1:0] RXPOWERDOWN2; + input [1:0] RXPOWERDOWN3; + input [1:0] RXRATE0; + input [1:0] RXRATE1; + input [1:0] RXRATE2; + input [1:0] RXRATE3; + input [1:0] TXPOWERDOWN0; + input [1:0] TXPOWERDOWN1; + input [1:0] TXPOWERDOWN2; + input [1:0] TXPOWERDOWN3; + input [1:0] TXRATE0; + input [1:0] TXRATE1; + input [1:0] TXRATE2; + input [1:0] TXRATE3; + input [2:0] PLLREFCLKSEL; + input [2:0] SAMPLERATE0; + input [2:0] SAMPLERATE1; + input [2:0] SAMPLERATE2; + input [2:0] SAMPLERATE3; + input [2:0] TXMARGIN0; + input [2:0] TXMARGIN1; + input [2:0] TXMARGIN2; + input [2:0] TXMARGIN3; + input [3:0] MGMTPCSLANESEL; + input [4:0] MGMTPCSMMDADDR; + input [5:0] PLLPCSCLKDIV; + input [63:0] TXDATA0; + input [63:0] TXDATA1; + input [63:0] TXDATA2; + input [63:0] TXDATA3; + input [7:0] TXCTRL0; + input [7:0] TXCTRL1; + input [7:0] TXCTRL2; + input [7:0] TXCTRL3; + input [7:0] TXDATAMSB0; + input [7:0] TXDATAMSB1; + input [7:0] TXDATAMSB2; + input [7:0] TXDATAMSB3; +endmodule + +module GTXE1 (...); + parameter AC_CAP_DIS = "TRUE"; + parameter integer ALIGN_COMMA_WORD = 1; + parameter [1:0] BGTEST_CFG = 2'b00; + parameter [16:0] BIAS_CFG = 17'h00000; + parameter [4:0] CDR_PH_ADJ_TIME = 5'b10100; + parameter integer CHAN_BOND_1_MAX_SKEW = 7; + parameter integer CHAN_BOND_2_MAX_SKEW = 1; + parameter CHAN_BOND_KEEP_ALIGN = "FALSE"; + parameter [9:0] CHAN_BOND_SEQ_1_1 = 10'b0101111100; + parameter [9:0] CHAN_BOND_SEQ_1_2 = 10'b0001001010; + parameter [9:0] CHAN_BOND_SEQ_1_3 = 10'b0001001010; + parameter [9:0] CHAN_BOND_SEQ_1_4 = 10'b0110111100; + parameter [3:0] CHAN_BOND_SEQ_1_ENABLE = 4'b1111; + parameter [9:0] CHAN_BOND_SEQ_2_1 = 10'b0100111100; + parameter [9:0] CHAN_BOND_SEQ_2_2 = 10'b0100111100; + parameter [9:0] CHAN_BOND_SEQ_2_3 = 10'b0110111100; + parameter [9:0] CHAN_BOND_SEQ_2_4 = 10'b0100111100; + parameter [4:0] CHAN_BOND_SEQ_2_CFG = 5'b00000; + parameter [3:0] CHAN_BOND_SEQ_2_ENABLE = 4'b1111; + parameter CHAN_BOND_SEQ_2_USE = "FALSE"; + parameter integer CHAN_BOND_SEQ_LEN = 1; + parameter CLK_CORRECT_USE = "TRUE"; + parameter integer CLK_COR_ADJ_LEN = 1; + parameter integer CLK_COR_DET_LEN = 1; + parameter CLK_COR_INSERT_IDLE_FLAG = "FALSE"; + parameter CLK_COR_KEEP_IDLE = "FALSE"; + parameter integer CLK_COR_MAX_LAT = 20; + parameter integer CLK_COR_MIN_LAT = 18; + parameter CLK_COR_PRECEDENCE = "TRUE"; + parameter integer CLK_COR_REPEAT_WAIT = 0; + parameter [9:0] CLK_COR_SEQ_1_1 = 10'b0100011100; + parameter [9:0] CLK_COR_SEQ_1_2 = 10'b0000000000; + parameter [9:0] CLK_COR_SEQ_1_3 = 10'b0000000000; + parameter [9:0] CLK_COR_SEQ_1_4 = 10'b0000000000; + parameter [3:0] CLK_COR_SEQ_1_ENABLE = 4'b1111; + parameter [9:0] CLK_COR_SEQ_2_1 = 10'b0000000000; + parameter [9:0] CLK_COR_SEQ_2_2 = 10'b0000000000; + parameter [9:0] CLK_COR_SEQ_2_3 = 10'b0000000000; + parameter [9:0] CLK_COR_SEQ_2_4 = 10'b0000000000; + parameter [3:0] CLK_COR_SEQ_2_ENABLE = 4'b1111; + parameter CLK_COR_SEQ_2_USE = "FALSE"; + parameter [1:0] CM_TRIM = 2'b01; + parameter [9:0] COMMA_10B_ENABLE = 10'b1111111111; + parameter COMMA_DOUBLE = "FALSE"; + parameter [3:0] COM_BURST_VAL = 4'b1111; + parameter DEC_MCOMMA_DETECT = "TRUE"; + parameter DEC_PCOMMA_DETECT = "TRUE"; + parameter DEC_VALID_COMMA_ONLY = "TRUE"; + parameter [4:0] DFE_CAL_TIME = 5'b01100; + parameter [7:0] DFE_CFG = 8'b00011011; + parameter [2:0] GEARBOX_ENDEC = 3'b000; + parameter GEN_RXUSRCLK = "TRUE"; + parameter GEN_TXUSRCLK = "TRUE"; + parameter GTX_CFG_PWRUP = "TRUE"; + parameter [9:0] MCOMMA_10B_VALUE = 10'b1010000011; + parameter MCOMMA_DETECT = "TRUE"; + parameter [2:0] OOBDETECT_THRESHOLD = 3'b011; + parameter PCI_EXPRESS_MODE = "FALSE"; + parameter [9:0] PCOMMA_10B_VALUE = 10'b0101111100; + parameter PCOMMA_DETECT = "TRUE"; + parameter PMA_CAS_CLK_EN = "FALSE"; + parameter [26:0] PMA_CDR_SCAN = 27'h640404C; + parameter [75:0] PMA_CFG = 76'h0040000040000000003; + parameter [6:0] PMA_RXSYNC_CFG = 7'h00; + parameter [24:0] PMA_RX_CFG = 25'h05CE048; + parameter [19:0] PMA_TX_CFG = 20'h00082; + parameter [9:0] POWER_SAVE = 10'b0000110100; + parameter RCV_TERM_GND = "FALSE"; + parameter RCV_TERM_VTTRX = "TRUE"; + parameter RXGEARBOX_USE = "FALSE"; + parameter [23:0] RXPLL_COM_CFG = 24'h21680A; + parameter [7:0] RXPLL_CP_CFG = 8'h00; + parameter integer RXPLL_DIVSEL45_FB = 5; + parameter integer RXPLL_DIVSEL_FB = 2; + parameter integer RXPLL_DIVSEL_OUT = 1; + parameter integer RXPLL_DIVSEL_REF = 1; + parameter [2:0] RXPLL_LKDET_CFG = 3'b111; + parameter [0:0] RXPRBSERR_LOOPBACK = 1'b0; + parameter RXRECCLK_CTRL = "RXRECCLKPCS"; + parameter [9:0] RXRECCLK_DLY = 10'b0000000000; + parameter [15:0] RXUSRCLK_DLY = 16'h0000; + parameter RX_BUFFER_USE = "TRUE"; + parameter integer RX_CLK25_DIVIDER = 6; + parameter integer RX_DATA_WIDTH = 20; + parameter RX_DECODE_SEQ_MATCH = "TRUE"; + parameter [3:0] RX_DLYALIGN_CTRINC = 4'b0100; + parameter [4:0] RX_DLYALIGN_EDGESET = 5'b00110; + parameter [3:0] RX_DLYALIGN_LPFINC = 4'b0111; + parameter [2:0] RX_DLYALIGN_MONSEL = 3'b000; + parameter [7:0] RX_DLYALIGN_OVRDSETTING = 8'b00000000; + parameter RX_EN_IDLE_HOLD_CDR = "FALSE"; + parameter RX_EN_IDLE_HOLD_DFE = "TRUE"; + parameter RX_EN_IDLE_RESET_BUF = "TRUE"; + parameter RX_EN_IDLE_RESET_FR = "TRUE"; + parameter RX_EN_IDLE_RESET_PH = "TRUE"; + parameter RX_EN_MODE_RESET_BUF = "TRUE"; + parameter RX_EN_RATE_RESET_BUF = "TRUE"; + parameter RX_EN_REALIGN_RESET_BUF = "FALSE"; + parameter RX_EN_REALIGN_RESET_BUF2 = "FALSE"; + parameter [7:0] RX_EYE_OFFSET = 8'h4C; + parameter [1:0] RX_EYE_SCANMODE = 2'b00; + parameter RX_FIFO_ADDR_MODE = "FULL"; + parameter [3:0] RX_IDLE_HI_CNT = 4'b1000; + parameter [3:0] RX_IDLE_LO_CNT = 4'b0000; + parameter RX_LOSS_OF_SYNC_FSM = "FALSE"; + parameter integer RX_LOS_INVALID_INCR = 1; + parameter integer RX_LOS_THRESHOLD = 4; + parameter RX_OVERSAMPLE_MODE = "FALSE"; + parameter integer RX_SLIDE_AUTO_WAIT = 5; + parameter RX_SLIDE_MODE = "OFF"; + parameter RX_XCLK_SEL = "RXREC"; + parameter integer SAS_MAX_COMSAS = 52; + parameter integer SAS_MIN_COMSAS = 40; + parameter [2:0] SATA_BURST_VAL = 3'b100; + parameter [2:0] SATA_IDLE_VAL = 3'b100; + parameter integer SATA_MAX_BURST = 7; + parameter integer SATA_MAX_INIT = 22; + parameter integer SATA_MAX_WAKE = 7; + parameter integer SATA_MIN_BURST = 4; + parameter integer SATA_MIN_INIT = 12; + parameter integer SATA_MIN_WAKE = 4; + parameter SHOW_REALIGN_COMMA = "TRUE"; + parameter integer SIM_GTXRESET_SPEEDUP = 1; + parameter SIM_RECEIVER_DETECT_PASS = "TRUE"; + parameter [2:0] SIM_RXREFCLK_SOURCE = 3'b000; + parameter [2:0] SIM_TXREFCLK_SOURCE = 3'b000; + parameter SIM_TX_ELEC_IDLE_LEVEL = "X"; + parameter SIM_VERSION = "2.0"; + parameter [4:0] TERMINATION_CTRL = 5'b10100; + parameter TERMINATION_OVRD = "FALSE"; + parameter [11:0] TRANS_TIME_FROM_P2 = 12'h03C; + parameter [7:0] TRANS_TIME_NON_P2 = 8'h19; + parameter [7:0] TRANS_TIME_RATE = 8'h0E; + parameter [9:0] TRANS_TIME_TO_P2 = 10'h064; + parameter [31:0] TST_ATTR = 32'h00000000; + parameter TXDRIVE_LOOPBACK_HIZ = "FALSE"; + parameter TXDRIVE_LOOPBACK_PD = "FALSE"; + parameter TXGEARBOX_USE = "FALSE"; + parameter TXOUTCLK_CTRL = "TXOUTCLKPCS"; + parameter [9:0] TXOUTCLK_DLY = 10'b0000000000; + parameter [23:0] TXPLL_COM_CFG = 24'h21680A; + parameter [7:0] TXPLL_CP_CFG = 8'h00; + parameter integer TXPLL_DIVSEL45_FB = 5; + parameter integer TXPLL_DIVSEL_FB = 2; + parameter integer TXPLL_DIVSEL_OUT = 1; + parameter integer TXPLL_DIVSEL_REF = 1; + parameter [2:0] TXPLL_LKDET_CFG = 3'b111; + parameter [1:0] TXPLL_SATA = 2'b00; + parameter TX_BUFFER_USE = "TRUE"; + parameter [5:0] TX_BYTECLK_CFG = 6'h00; + parameter integer TX_CLK25_DIVIDER = 6; + parameter TX_CLK_SOURCE = "RXPLL"; + parameter integer TX_DATA_WIDTH = 20; + parameter [4:0] TX_DEEMPH_0 = 5'b11010; + parameter [4:0] TX_DEEMPH_1 = 5'b10000; + parameter [13:0] TX_DETECT_RX_CFG = 14'h1832; + parameter [3:0] TX_DLYALIGN_CTRINC = 4'b0100; + parameter [3:0] TX_DLYALIGN_LPFINC = 4'b0110; + parameter [2:0] TX_DLYALIGN_MONSEL = 3'b000; + parameter [7:0] TX_DLYALIGN_OVRDSETTING = 8'b10000000; + parameter TX_DRIVE_MODE = "DIRECT"; + parameter TX_EN_RATE_RESET_BUF = "TRUE"; + parameter [2:0] TX_IDLE_ASSERT_DELAY = 3'b100; + parameter [2:0] TX_IDLE_DEASSERT_DELAY = 3'b010; + parameter [6:0] TX_MARGIN_FULL_0 = 7'b1001110; + parameter [6:0] TX_MARGIN_FULL_1 = 7'b1001001; + parameter [6:0] TX_MARGIN_FULL_2 = 7'b1000101; + parameter [6:0] TX_MARGIN_FULL_3 = 7'b1000010; + parameter [6:0] TX_MARGIN_FULL_4 = 7'b1000000; + parameter [6:0] TX_MARGIN_LOW_0 = 7'b1000110; + parameter [6:0] TX_MARGIN_LOW_1 = 7'b1000100; + parameter [6:0] TX_MARGIN_LOW_2 = 7'b1000010; + parameter [6:0] TX_MARGIN_LOW_3 = 7'b1000000; + parameter [6:0] TX_MARGIN_LOW_4 = 7'b1000000; + parameter TX_OVERSAMPLE_MODE = "FALSE"; + parameter [0:0] TX_PMADATA_OPT = 1'b0; + parameter [1:0] TX_TDCC_CFG = 2'b11; + parameter [5:0] TX_USRCLK_CFG = 6'h00; + parameter TX_XCLK_SEL = "TXUSR"; + output COMFINISH; + output COMINITDET; + output COMSASDET; + output COMWAKEDET; + output DRDY; + output PHYSTATUS; + output RXBYTEISALIGNED; + output RXBYTEREALIGN; + output RXCHANBONDSEQ; + output RXCHANISALIGNED; + output RXCHANREALIGN; + output RXCOMMADET; + output RXDATAVALID; + output RXELECIDLE; + output RXHEADERVALID; + output RXOVERSAMPLEERR; + output RXPLLLKDET; + output RXPRBSERR; + output RXRATEDONE; + output RXRECCLK; + output RXRECCLKPCS; + output RXRESETDONE; + output RXSTARTOFSEQ; + output RXVALID; + output TXGEARBOXREADY; + output TXN; + output TXOUTCLK; + output TXOUTCLKPCS; + output TXP; + output TXPLLLKDET; + output TXRATEDONE; + output TXRESETDONE; + output [15:0] DRPDO; + output [1:0] MGTREFCLKFAB; + output [1:0] RXLOSSOFSYNC; + output [1:0] TXBUFSTATUS; + output [2:0] DFESENSCAL; + output [2:0] RXBUFSTATUS; + output [2:0] RXCLKCORCNT; + output [2:0] RXHEADER; + output [2:0] RXSTATUS; + output [31:0] RXDATA; + output [3:0] DFETAP3MONITOR; + output [3:0] DFETAP4MONITOR; + output [3:0] RXCHARISCOMMA; + output [3:0] RXCHARISK; + output [3:0] RXCHBONDO; + output [3:0] RXDISPERR; + output [3:0] RXNOTINTABLE; + output [3:0] RXRUNDISP; + output [3:0] TXKERR; + output [3:0] TXRUNDISP; + output [4:0] DFEEYEDACMON; + output [4:0] DFETAP1MONITOR; + output [4:0] DFETAP2MONITOR; + output [5:0] DFECLKDLYADJMON; + output [7:0] RXDLYALIGNMONITOR; + output [7:0] TXDLYALIGNMONITOR; + output [9:0] TSTOUT; + input DCLK; + input DEN; + input DFEDLYOVRD; + input DFETAPOVRD; + input DWE; + input GATERXELECIDLE; + input GREFCLKRX; + input GREFCLKTX; + input GTXRXRESET; + input GTXTXRESET; + input IGNORESIGDET; + input PERFCLKRX; + input PERFCLKTX; + input PLLRXRESET; + input PLLTXRESET; + input PRBSCNTRESET; + input RXBUFRESET; + input RXCDRRESET; + input RXCHBONDMASTER; + input RXCHBONDSLAVE; + input RXCOMMADETUSE; + input RXDEC8B10BUSE; + input RXDLYALIGNDISABLE; + input RXDLYALIGNMONENB; + input RXDLYALIGNOVERRIDE; + input RXDLYALIGNRESET; + input RXDLYALIGNSWPPRECURB; + input RXDLYALIGNUPDSW; + input RXENCHANSYNC; + input RXENMCOMMAALIGN; + input RXENPCOMMAALIGN; + input RXENPMAPHASEALIGN; + input RXENSAMPLEALIGN; + input RXGEARBOXSLIP; + input RXN; + input RXP; + input RXPLLLKDETEN; + input RXPLLPOWERDOWN; + input RXPMASETPHASE; + input RXPOLARITY; + input RXRESET; + input RXSLIDE; + input RXUSRCLK2; + input RXUSRCLK; + input TSTCLK0; + input TSTCLK1; + input TXCOMINIT; + input TXCOMSAS; + input TXCOMWAKE; + input TXDEEMPH; + input TXDETECTRX; + input TXDLYALIGNDISABLE; + input TXDLYALIGNMONENB; + input TXDLYALIGNOVERRIDE; + input TXDLYALIGNRESET; + input TXDLYALIGNUPDSW; + input TXELECIDLE; + input TXENC8B10BUSE; + input TXENPMAPHASEALIGN; + input TXINHIBIT; + input TXPDOWNASYNCH; + input TXPLLLKDETEN; + input TXPLLPOWERDOWN; + input TXPMASETPHASE; + input TXPOLARITY; + input TXPRBSFORCEERR; + input TXRESET; + input TXSTARTSEQ; + input TXSWING; + input TXUSRCLK2; + input TXUSRCLK; + input USRCODEERR; + input [12:0] GTXTEST; + input [15:0] DI; + input [19:0] TSTIN; + input [1:0] MGTREFCLKRX; + input [1:0] MGTREFCLKTX; + input [1:0] NORTHREFCLKRX; + input [1:0] NORTHREFCLKTX; + input [1:0] RXPOWERDOWN; + input [1:0] RXRATE; + input [1:0] SOUTHREFCLKRX; + input [1:0] SOUTHREFCLKTX; + input [1:0] TXPOWERDOWN; + input [1:0] TXRATE; + input [2:0] LOOPBACK; + input [2:0] RXCHBONDLEVEL; + input [2:0] RXENPRBSTST; + input [2:0] RXPLLREFSELDY; + input [2:0] TXBUFDIFFCTRL; + input [2:0] TXENPRBSTST; + input [2:0] TXHEADER; + input [2:0] TXMARGIN; + input [2:0] TXPLLREFSELDY; + input [31:0] TXDATA; + input [3:0] DFETAP3; + input [3:0] DFETAP4; + input [3:0] RXCHBONDI; + input [3:0] TXBYPASS8B10B; + input [3:0] TXCHARDISPMODE; + input [3:0] TXCHARDISPVAL; + input [3:0] TXCHARISK; + input [3:0] TXDIFFCTRL; + input [3:0] TXPREEMPHASIS; + input [4:0] DFETAP1; + input [4:0] DFETAP2; + input [4:0] TXPOSTEMPHASIS; + input [5:0] DFECLKDLYADJ; + input [6:0] TXSEQUENCE; + input [7:0] DADDR; + input [9:0] RXEQMIX; +endmodule + +module IBUFDS (...); + parameter CAPACITANCE = "DONT_CARE"; + parameter DIFF_TERM = "FALSE"; + parameter DQS_BIAS = "FALSE"; + parameter IBUF_DELAY_VALUE = "0"; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IFD_DELAY_VALUE = "AUTO"; + parameter IOSTANDARD = "DEFAULT"; + output O; + (* iopad_external_pin *) + input I; + (* iopad_external_pin *) + input IB; +endmodule + +module IBUFDS_DIFF_OUT (...); + parameter DIFF_TERM = "FALSE"; + parameter DQS_BIAS = "FALSE"; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + output O; + output OB; + (* iopad_external_pin *) + input I; + (* iopad_external_pin *) + input IB; +endmodule + +module IBUFDS_GTHE1 (...); + output O; + (* iopad_external_pin *) + input I; + (* iopad_external_pin *) + input IB; +endmodule + +module IBUFG (...); + parameter CAPACITANCE = "DONT_CARE"; + parameter IBUF_DELAY_VALUE = "0"; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + output O; + (* iopad_external_pin *) + input I; +endmodule + +module IBUFGDS (...); + parameter CAPACITANCE = "DONT_CARE"; + parameter DIFF_TERM = "FALSE"; + parameter IBUF_DELAY_VALUE = "0"; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + output O; + (* iopad_external_pin *) + input I; + (* iopad_external_pin *) + input IB; +endmodule + +module IBUFGDS_DIFF_OUT (...); + parameter DIFF_TERM = "FALSE"; + parameter DQS_BIAS = "FALSE"; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + output O; + output OB; + (* iopad_external_pin *) + input I; + (* iopad_external_pin *) + input IB; +endmodule + +(* keep *) +module IDELAYCTRL (...); + parameter SIM_DEVICE = "7SERIES"; + output RDY; + (* clkbuf_sink *) + input REFCLK; + input RST; +endmodule + +module IOBUF (...); + parameter integer DRIVE = 12; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + parameter SLEW = "SLOW"; + output O; + (* iopad_external_pin *) + inout IO; + input I; + input T; +endmodule + +module IOBUFDS (...); + parameter DIFF_TERM = "FALSE"; + parameter DQS_BIAS = "FALSE"; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + parameter SLEW = "SLOW"; + output O; + (* iopad_external_pin *) + inout IO; + inout IOB; + input I; + input T; +endmodule + +module IODELAYE1 (...); + parameter CINVCTRL_SEL = "FALSE"; + parameter DELAY_SRC = "I"; + parameter HIGH_PERFORMANCE_MODE = "FALSE"; + parameter IDELAY_TYPE = "DEFAULT"; + parameter integer IDELAY_VALUE = 0; + parameter ODELAY_TYPE = "FIXED"; + parameter integer ODELAY_VALUE = 0; + parameter real REFCLK_FREQUENCY = 200.0; + parameter SIGNAL_PATTERN = "DATA"; + output [4:0] CNTVALUEOUT; + output DATAOUT; + (* clkbuf_sink *) + input C; + input CE; + input CINVCTRL; + input CLKIN; + input [4:0] CNTVALUEIN; + input DATAIN; + input IDATAIN; + input INC; + input ODATAIN; + input RST; + input T; +endmodule + +module ISERDESE1 (...); + parameter DATA_RATE = "DDR"; + parameter integer DATA_WIDTH = 4; + parameter DYN_CLKDIV_INV_EN = "FALSE"; + parameter DYN_CLK_INV_EN = "FALSE"; + parameter [0:0] INIT_Q1 = 1'b0; + parameter [0:0] INIT_Q2 = 1'b0; + parameter [0:0] INIT_Q3 = 1'b0; + parameter [0:0] INIT_Q4 = 1'b0; + parameter INTERFACE_TYPE = "MEMORY"; + parameter integer NUM_CE = 2; + parameter IOBDELAY = "NONE"; + parameter OFB_USED = "FALSE"; + parameter SERDES_MODE = "MASTER"; + parameter [0:0] SRVAL_Q1 = 1'b0; + parameter [0:0] SRVAL_Q2 = 1'b0; + parameter [0:0] SRVAL_Q3 = 1'b0; + parameter [0:0] SRVAL_Q4 = 1'b0; + output O; + output Q1; + output Q2; + output Q3; + output Q4; + output Q5; + output Q6; + output SHIFTOUT1; + output SHIFTOUT2; + input BITSLIP; + input CE1; + input CE2; + (* clkbuf_sink *) + input CLK; + (* clkbuf_sink *) + input CLKB; + (* clkbuf_sink *) + input CLKDIV; + input D; + input DDLY; + input DYNCLKDIVSEL; + input DYNCLKSEL; + (* clkbuf_sink *) + input OCLK; + input OFB; + input RST; + input SHIFTIN1; + input SHIFTIN2; +endmodule + +module KEEPER (...); + inout O; +endmodule + +module OBUFDS (...); + parameter CAPACITANCE = "DONT_CARE"; + parameter IOSTANDARD = "DEFAULT"; + parameter SLEW = "SLOW"; + (* iopad_external_pin *) + output O; + (* iopad_external_pin *) + output OB; + input I; +endmodule + +module OBUFT (...); + parameter CAPACITANCE = "DONT_CARE"; + parameter integer DRIVE = 12; + parameter IOSTANDARD = "DEFAULT"; + parameter SLEW = "SLOW"; + (* iopad_external_pin *) + output O; + input I; + input T; +endmodule + +module OBUFTDS (...); + parameter CAPACITANCE = "DONT_CARE"; + parameter IOSTANDARD = "DEFAULT"; + parameter SLEW = "SLOW"; + (* iopad_external_pin *) + output O; + (* iopad_external_pin *) + output OB; + input I; + input T; +endmodule + +module OSERDESE1 (...); + parameter DATA_RATE_OQ = "DDR"; + parameter DATA_RATE_TQ = "DDR"; + parameter integer DATA_WIDTH = 4; + parameter integer DDR3_DATA = 1; + parameter [0:0] INIT_OQ = 1'b0; + parameter [0:0] INIT_TQ = 1'b0; + parameter INTERFACE_TYPE = "DEFAULT"; + parameter integer ODELAY_USED = 0; + parameter SERDES_MODE = "MASTER"; + parameter [0:0] SRVAL_OQ = 1'b0; + parameter [0:0] SRVAL_TQ = 1'b0; + parameter integer TRISTATE_WIDTH = 4; + output OCBEXTEND; + output OFB; + output OQ; + output SHIFTOUT1; + output SHIFTOUT2; + output TFB; + output TQ; + (* clkbuf_sink *) + input CLK; + (* clkbuf_sink *) + input CLKDIV; + input CLKPERF; + input CLKPERFDELAY; + input D1; + input D2; + input D3; + input D4; + input D5; + input D6; + input OCE; + input ODV; + input RST; + input SHIFTIN1; + input SHIFTIN2; + input T1; + input T2; + input T3; + input T4; + input TCE; + input WC; +endmodule + +module PULLDOWN (...); + output O; +endmodule + +module PULLUP (...); + output O; +endmodule + +module TEMAC_SINGLE (...); + parameter EMAC_1000BASEX_ENABLE = "FALSE"; + parameter EMAC_ADDRFILTER_ENABLE = "FALSE"; + parameter EMAC_BYTEPHY = "FALSE"; + parameter EMAC_CTRLLENCHECK_DISABLE = "FALSE"; + parameter [0:7] EMAC_DCRBASEADDR = 8'h00; + parameter EMAC_GTLOOPBACK = "FALSE"; + parameter EMAC_HOST_ENABLE = "FALSE"; + parameter [8:0] EMAC_LINKTIMERVAL = 9'h000; + parameter EMAC_LTCHECK_DISABLE = "FALSE"; + parameter EMAC_MDIO_ENABLE = "FALSE"; + parameter EMAC_MDIO_IGNORE_PHYADZERO = "FALSE"; + parameter [47:0] EMAC_PAUSEADDR = 48'h000000000000; + parameter EMAC_PHYINITAUTONEG_ENABLE = "FALSE"; + parameter EMAC_PHYISOLATE = "FALSE"; + parameter EMAC_PHYLOOPBACKMSB = "FALSE"; + parameter EMAC_PHYPOWERDOWN = "FALSE"; + parameter EMAC_PHYRESET = "FALSE"; + parameter EMAC_RGMII_ENABLE = "FALSE"; + parameter EMAC_RX16BITCLIENT_ENABLE = "FALSE"; + parameter EMAC_RXFLOWCTRL_ENABLE = "FALSE"; + parameter EMAC_RXHALFDUPLEX = "FALSE"; + parameter EMAC_RXINBANDFCS_ENABLE = "FALSE"; + parameter EMAC_RXJUMBOFRAME_ENABLE = "FALSE"; + parameter EMAC_RXRESET = "FALSE"; + parameter EMAC_RXVLAN_ENABLE = "FALSE"; + parameter EMAC_RX_ENABLE = "TRUE"; + parameter EMAC_SGMII_ENABLE = "FALSE"; + parameter EMAC_SPEED_LSB = "FALSE"; + parameter EMAC_SPEED_MSB = "FALSE"; + parameter EMAC_TX16BITCLIENT_ENABLE = "FALSE"; + parameter EMAC_TXFLOWCTRL_ENABLE = "FALSE"; + parameter EMAC_TXHALFDUPLEX = "FALSE"; + parameter EMAC_TXIFGADJUST_ENABLE = "FALSE"; + parameter EMAC_TXINBANDFCS_ENABLE = "FALSE"; + parameter EMAC_TXJUMBOFRAME_ENABLE = "FALSE"; + parameter EMAC_TXRESET = "FALSE"; + parameter EMAC_TXVLAN_ENABLE = "FALSE"; + parameter EMAC_TX_ENABLE = "TRUE"; + parameter [47:0] EMAC_UNICASTADDR = 48'h000000000000; + parameter EMAC_UNIDIRECTION_ENABLE = "FALSE"; + parameter EMAC_USECLKEN = "FALSE"; + parameter SIM_VERSION = "1.0"; + output DCRHOSTDONEIR; + output EMACCLIENTANINTERRUPT; + output EMACCLIENTRXBADFRAME; + output EMACCLIENTRXCLIENTCLKOUT; + output EMACCLIENTRXDVLD; + output EMACCLIENTRXDVLDMSW; + output EMACCLIENTRXFRAMEDROP; + output EMACCLIENTRXGOODFRAME; + output EMACCLIENTRXSTATSBYTEVLD; + output EMACCLIENTRXSTATSVLD; + output EMACCLIENTTXACK; + output EMACCLIENTTXCLIENTCLKOUT; + output EMACCLIENTTXCOLLISION; + output EMACCLIENTTXRETRANSMIT; + output EMACCLIENTTXSTATS; + output EMACCLIENTTXSTATSBYTEVLD; + output EMACCLIENTTXSTATSVLD; + output EMACDCRACK; + output EMACPHYENCOMMAALIGN; + output EMACPHYLOOPBACKMSB; + output EMACPHYMCLKOUT; + output EMACPHYMDOUT; + output EMACPHYMDTRI; + output EMACPHYMGTRXRESET; + output EMACPHYMGTTXRESET; + output EMACPHYPOWERDOWN; + output EMACPHYSYNCACQSTATUS; + output EMACPHYTXCHARDISPMODE; + output EMACPHYTXCHARDISPVAL; + output EMACPHYTXCHARISK; + output EMACPHYTXCLK; + output EMACPHYTXEN; + output EMACPHYTXER; + output EMACPHYTXGMIIMIICLKOUT; + output EMACSPEEDIS10100; + output HOSTMIIMRDY; + output [0:31] EMACDCRDBUS; + output [15:0] EMACCLIENTRXD; + output [31:0] HOSTRDDATA; + output [6:0] EMACCLIENTRXSTATS; + output [7:0] EMACPHYTXD; + input CLIENTEMACDCMLOCKED; + input CLIENTEMACPAUSEREQ; + input CLIENTEMACRXCLIENTCLKIN; + input CLIENTEMACTXCLIENTCLKIN; + input CLIENTEMACTXDVLD; + input CLIENTEMACTXDVLDMSW; + input CLIENTEMACTXFIRSTBYTE; + input CLIENTEMACTXUNDERRUN; + input DCREMACCLK; + input DCREMACENABLE; + input DCREMACREAD; + input DCREMACWRITE; + input HOSTCLK; + input HOSTMIIMSEL; + input HOSTREQ; + input PHYEMACCOL; + input PHYEMACCRS; + input PHYEMACGTXCLK; + input PHYEMACMCLKIN; + input PHYEMACMDIN; + input PHYEMACMIITXCLK; + input PHYEMACRXCHARISCOMMA; + input PHYEMACRXCHARISK; + input PHYEMACRXCLK; + input PHYEMACRXDISPERR; + input PHYEMACRXDV; + input PHYEMACRXER; + input PHYEMACRXNOTINTABLE; + input PHYEMACRXRUNDISP; + input PHYEMACSIGNALDET; + input PHYEMACTXBUFERR; + input PHYEMACTXGMIIMIICLKIN; + input RESET; + input [0:31] DCREMACDBUS; + input [0:9] DCREMACABUS; + input [15:0] CLIENTEMACPAUSEVAL; + input [15:0] CLIENTEMACTXD; + input [1:0] HOSTOPCODE; + input [1:0] PHYEMACRXBUFSTATUS; + input [2:0] PHYEMACRXCLKCORCNT; + input [31:0] HOSTWRDATA; + input [4:0] PHYEMACPHYAD; + input [7:0] CLIENTEMACTXIFGDELAY; + input [7:0] PHYEMACRXD; + input [9:0] HOSTADDR; +endmodule + +module FIFO18E1 (...); + parameter ALMOST_EMPTY_OFFSET = 13'h0080; + parameter ALMOST_FULL_OFFSET = 13'h0080; + parameter integer DATA_WIDTH = 4; + parameter integer DO_REG = 1; + parameter EN_SYN = "FALSE"; + parameter FIFO_MODE = "FIFO18"; + parameter FIRST_WORD_FALL_THROUGH = "FALSE"; + parameter INIT = 36'h0; + parameter SIM_DEVICE = "VIRTEX6"; + parameter SRVAL = 36'h0; + parameter IS_RDCLK_INVERTED = 1'b0; + parameter IS_RDEN_INVERTED = 1'b0; + parameter IS_RSTREG_INVERTED = 1'b0; + parameter IS_RST_INVERTED = 1'b0; + parameter IS_WRCLK_INVERTED = 1'b0; + parameter IS_WREN_INVERTED = 1'b0; + output ALMOSTEMPTY; + output ALMOSTFULL; + output [31:0] DO; + output [3:0] DOP; + output EMPTY; + output FULL; + output [11:0] RDCOUNT; + output RDERR; + output [11:0] WRCOUNT; + output WRERR; + input [31:0] DI; + input [3:0] DIP; + (* clkbuf_sink *) + (* invertible_pin = "IS_RDCLK_INVERTED" *) + input RDCLK; + (* invertible_pin = "IS_RDEN_INVERTED" *) + input RDEN; + input REGCE; + (* invertible_pin = "IS_RST_INVERTED" *) + input RST; + (* invertible_pin = "IS_RSTREG_INVERTED" *) + input RSTREG; + (* clkbuf_sink *) + (* invertible_pin = "IS_WRCLK_INVERTED" *) + input WRCLK; + (* invertible_pin = "IS_WREN_INVERTED" *) + input WREN; +endmodule + +module FIFO36E1 (...); + parameter ALMOST_EMPTY_OFFSET = 13'h0080; + parameter ALMOST_FULL_OFFSET = 13'h0080; + parameter integer DATA_WIDTH = 4; + parameter integer DO_REG = 1; + parameter EN_ECC_READ = "FALSE"; + parameter EN_ECC_WRITE = "FALSE"; + parameter EN_SYN = "FALSE"; + parameter FIFO_MODE = "FIFO36"; + parameter FIRST_WORD_FALL_THROUGH = "FALSE"; + parameter INIT = 72'h0; + parameter SIM_DEVICE = "VIRTEX6"; + parameter SRVAL = 72'h0; + parameter IS_RDCLK_INVERTED = 1'b0; + parameter IS_RDEN_INVERTED = 1'b0; + parameter IS_RSTREG_INVERTED = 1'b0; + parameter IS_RST_INVERTED = 1'b0; + parameter IS_WRCLK_INVERTED = 1'b0; + parameter IS_WREN_INVERTED = 1'b0; + output ALMOSTEMPTY; + output ALMOSTFULL; + output DBITERR; + output [63:0] DO; + output [7:0] DOP; + output [7:0] ECCPARITY; + output EMPTY; + output FULL; + output [12:0] RDCOUNT; + output RDERR; + output SBITERR; + output [12:0] WRCOUNT; + output WRERR; + input [63:0] DI; + input [7:0] DIP; + input INJECTDBITERR; + input INJECTSBITERR; + (* clkbuf_sink *) + (* invertible_pin = "IS_RDCLK_INVERTED" *) + input RDCLK; + (* invertible_pin = "IS_RDEN_INVERTED" *) + input RDEN; + input REGCE; + (* invertible_pin = "IS_RST_INVERTED" *) + input RST; + (* invertible_pin = "IS_RSTREG_INVERTED" *) + input RSTREG; + (* clkbuf_sink *) + (* invertible_pin = "IS_WRCLK_INVERTED" *) + input WRCLK; + (* invertible_pin = "IS_WREN_INVERTED" *) + input WREN; +endmodule + +module RAM128X1S (...); + parameter [127:0] INIT = 128'h00000000000000000000000000000000; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + output O; + input A0; + input A1; + input A2; + input A3; + input A4; + input A5; + input A6; + input D; + (* clkbuf_sink *) + (* invertible_pin = "IS_WCLK_INVERTED" *) + input WCLK; + input WE; +endmodule + +module RAM256X1S (...); + parameter [255:0] INIT = 256'h0; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + output O; + input [7:0] A; + input D; + (* clkbuf_sink *) + (* invertible_pin = "IS_WCLK_INVERTED" *) + input WCLK; + input WE; +endmodule + +module RAM32M (...); + parameter [63:0] INIT_A = 64'h0000000000000000; + parameter [63:0] INIT_B = 64'h0000000000000000; + parameter [63:0] INIT_C = 64'h0000000000000000; + parameter [63:0] INIT_D = 64'h0000000000000000; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + output [1:0] DOA; + output [1:0] DOB; + output [1:0] DOC; + output [1:0] DOD; + input [4:0] ADDRA; + input [4:0] ADDRB; + input [4:0] ADDRC; + input [4:0] ADDRD; + input [1:0] DIA; + input [1:0] DIB; + input [1:0] DIC; + input [1:0] DID; + (* clkbuf_sink *) + (* invertible_pin = "IS_WCLK_INVERTED" *) + input WCLK; + input WE; +endmodule + +module RAM32X1S (...); + parameter [31:0] INIT = 32'h00000000; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + output O; + input A0; + input A1; + input A2; + input A3; + input A4; + input D; + (* clkbuf_sink *) + (* invertible_pin = "IS_WCLK_INVERTED" *) + input WCLK; + input WE; +endmodule + +module RAM32X1S_1 (...); + parameter [31:0] INIT = 32'h00000000; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + output O; + input A0; + input A1; + input A2; + input A3; + input A4; + input D; + (* clkbuf_sink *) + (* invertible_pin = "IS_WCLK_INVERTED" *) + input WCLK; + input WE; +endmodule + +module RAM32X2S (...); + parameter [31:0] INIT_00 = 32'h00000000; + parameter [31:0] INIT_01 = 32'h00000000; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + output O0; + output O1; + input A0; + input A1; + input A2; + input A3; + input A4; + input D0; + input D1; + (* clkbuf_sink *) + (* invertible_pin = "IS_WCLK_INVERTED" *) + input WCLK; + input WE; +endmodule + +module RAM64M (...); + parameter [63:0] INIT_A = 64'h0000000000000000; + parameter [63:0] INIT_B = 64'h0000000000000000; + parameter [63:0] INIT_C = 64'h0000000000000000; + parameter [63:0] INIT_D = 64'h0000000000000000; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + output DOA; + output DOB; + output DOC; + output DOD; + input [5:0] ADDRA; + input [5:0] ADDRB; + input [5:0] ADDRC; + input [5:0] ADDRD; + input DIA; + input DIB; + input DIC; + input DID; + (* clkbuf_sink *) + (* invertible_pin = "IS_WCLK_INVERTED" *) + input WCLK; + input WE; +endmodule + +module RAM64X1S (...); + parameter [63:0] INIT = 64'h0000000000000000; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + output O; + input A0; + input A1; + input A2; + input A3; + input A4; + input A5; + input D; + (* clkbuf_sink *) + (* invertible_pin = "IS_WCLK_INVERTED" *) + input WCLK; + input WE; +endmodule + +module RAM64X1S_1 (...); + parameter [63:0] INIT = 64'h0000000000000000; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + output O; + input A0; + input A1; + input A2; + input A3; + input A4; + input A5; + input D; + (* clkbuf_sink *) + (* invertible_pin = "IS_WCLK_INVERTED" *) + input WCLK; + input WE; +endmodule + +module RAM64X2S (...); + parameter [63:0] INIT_00 = 64'h0000000000000000; + parameter [63:0] INIT_01 = 64'h0000000000000000; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + output O0; + output O1; + input A0; + input A1; + input A2; + input A3; + input A4; + input A5; + input D0; + input D1; + (* clkbuf_sink *) + (* invertible_pin = "IS_WCLK_INVERTED" *) + input WCLK; + input WE; +endmodule + +module ROM128X1 (...); + parameter [127:0] INIT = 128'h00000000000000000000000000000000; + output O; + input A0; + input A1; + input A2; + input A3; + input A4; + input A5; + input A6; +endmodule + +module ROM256X1 (...); + parameter [255:0] INIT = 256'h0000000000000000000000000000000000000000000000000000000000000000; + output O; + input A0; + input A1; + input A2; + input A3; + input A4; + input A5; + input A6; + input A7; +endmodule + +module ROM32X1 (...); + parameter [31:0] INIT = 32'h00000000; + output O; + input A0; + input A1; + input A2; + input A3; + input A4; +endmodule + +module ROM64X1 (...); + parameter [63:0] INIT = 64'h0000000000000000; + output O; + input A0; + input A1; + input A2; + input A3; + input A4; + input A5; +endmodule + +module IDDR (...); + parameter DDR_CLK_EDGE = "OPPOSITE_EDGE"; + parameter INIT_Q1 = 1'b0; + parameter INIT_Q2 = 1'b0; + parameter [0:0] IS_C_INVERTED = 1'b0; + parameter [0:0] IS_D_INVERTED = 1'b0; + parameter SRTYPE = "SYNC"; + parameter MSGON = "TRUE"; + parameter XON = "TRUE"; + output Q1; + output Q2; + (* clkbuf_sink *) + (* invertible_pin = "IS_C_INVERTED" *) + input C; + input CE; + (* invertible_pin = "IS_D_INVERTED" *) + input D; + input R; + input S; +endmodule + +module IDDR_2CLK (...); + parameter DDR_CLK_EDGE = "OPPOSITE_EDGE"; + parameter INIT_Q1 = 1'b0; + parameter INIT_Q2 = 1'b0; + parameter [0:0] IS_CB_INVERTED = 1'b0; + parameter [0:0] IS_C_INVERTED = 1'b0; + parameter [0:0] IS_D_INVERTED = 1'b0; + parameter SRTYPE = "SYNC"; + output Q1; + output Q2; + (* clkbuf_sink *) + (* invertible_pin = "IS_C_INVERTED" *) + input C; + (* clkbuf_sink *) + (* invertible_pin = "IS_CB_INVERTED" *) + input CB; + input CE; + (* invertible_pin = "IS_D_INVERTED" *) + input D; + input R; + input S; +endmodule + +module LDCE (...); + parameter [0:0] INIT = 1'b0; + parameter [0:0] IS_CLR_INVERTED = 1'b0; + parameter [0:0] IS_G_INVERTED = 1'b0; + parameter MSGON = "TRUE"; + parameter XON = "TRUE"; + output Q; + (* invertible_pin = "IS_CLR_INVERTED" *) + input CLR; + input D; + (* invertible_pin = "IS_G_INVERTED" *) + input G; + input GE; +endmodule + +module LDPE (...); + parameter [0:0] INIT = 1'b1; + parameter [0:0] IS_G_INVERTED = 1'b0; + parameter [0:0] IS_PRE_INVERTED = 1'b0; + parameter MSGON = "TRUE"; + parameter XON = "TRUE"; + output Q; + input D; + (* invertible_pin = "IS_G_INVERTED" *) + input G; + input GE; + (* invertible_pin = "IS_PRE_INVERTED" *) + input PRE; +endmodule + +module ODDR (...); + parameter DDR_CLK_EDGE = "OPPOSITE_EDGE"; + parameter INIT = 1'b0; + parameter [0:0] IS_C_INVERTED = 1'b0; + parameter [0:0] IS_D1_INVERTED = 1'b0; + parameter [0:0] IS_D2_INVERTED = 1'b0; + parameter SRTYPE = "SYNC"; + parameter MSGON = "TRUE"; + parameter XON = "TRUE"; + output Q; + (* clkbuf_sink *) + (* invertible_pin = "IS_C_INVERTED" *) + input C; + input CE; + (* invertible_pin = "IS_D1_INVERTED" *) + input D1; + (* invertible_pin = "IS_D2_INVERTED" *) + input D2; + input R; + input S; +endmodule + +module CFGLUT5 (...); + parameter [31:0] INIT = 32'h00000000; + parameter [0:0] IS_CLK_INVERTED = 1'b0; + output CDO; + output O5; + output O6; + input I4; + input I3; + input I2; + input I1; + input I0; + input CDI; + input CE; + (* clkbuf_sink *) + (* invertible_pin = "IS_CLK_INVERTED" *) + input CLK; +endmodule + diff --git a/techlibs/xilinx/brams.txt b/techlibs/xilinx/xc7_brams.txt index f1161114e..f1161114e 100644 --- a/techlibs/xilinx/brams.txt +++ b/techlibs/xilinx/xc7_brams.txt diff --git a/techlibs/xilinx/brams_bb.v b/techlibs/xilinx/xc7_brams_bb.v index a682ba4a7..a28ba5b14 100644 --- a/techlibs/xilinx/brams_bb.v +++ b/techlibs/xilinx/xc7_brams_bb.v @@ -1,13 +1,25 @@ +// Max delays from https://github.com/SymbiFlow/prjxray-db/blob/f8e0364116b2983ac72a3dc8c509ea1cc79e2e3d/artix7/timings/BRAM_L.sdf#L138-L147 + module RAMB18E1 ( + (* clkbuf_sink *) + (* invertible_pin = "IS_CLKARDCLK_INVERTED" *) input CLKARDCLK, + (* clkbuf_sink *) + (* invertible_pin = "IS_CLKBWRCLK_INVERTED" *) input CLKBWRCLK, + (* invertible_pin = "IS_ENARDEN_INVERTED" *) input ENARDEN, + (* invertible_pin = "IS_ENBWREN_INVERTED" *) input ENBWREN, input REGCEAREGCE, input REGCEB, + (* invertible_pin = "IS_RSTRAMARSTRAM_INVERTED" *) input RSTRAMARSTRAM, + (* invertible_pin = "IS_RSTRAMB_INVERTED" *) input RSTRAMB, + (* invertible_pin = "IS_RSTREGARSTREG_INVERTED" *) input RSTREGARSTREG, + (* invertible_pin = "IS_RSTREGB_INVERTED" *) input RSTREGB, input [13:0] ADDRARDADDR, @@ -19,9 +31,13 @@ module RAMB18E1 ( input [1:0] WEA, input [3:0] WEBWE, + (* abc_arrival=2454 *) output [15:0] DOADO, + (* abc_arrival=2454 *) output [15:0] DOBDO, + (* abc_arrival=2454 *) output [1:0] DOPADOP, + (* abc_arrival=2454 *) output [1:0] DOPBDOP ); parameter INITP_00 = 256'h0000000000000000000000000000000000000000000000000000000000000000; @@ -123,15 +139,25 @@ module RAMB18E1 ( endmodule module RAMB36E1 ( + (* clkbuf_sink *) + (* invertible_pin = "IS_CLKARDCLK_INVERTED" *) input CLKARDCLK, + (* clkbuf_sink *) + (* invertible_pin = "IS_CLKBWRCLK_INVERTED" *) input CLKBWRCLK, + (* invertible_pin = "IS_ENARDEN_INVERTED" *) input ENARDEN, + (* invertible_pin = "IS_ENBWREN_INVERTED" *) input ENBWREN, input REGCEAREGCE, input REGCEB, + (* invertible_pin = "IS_RSTRAMARSTRAM_INVERTED" *) input RSTRAMARSTRAM, + (* invertible_pin = "IS_RSTRAMB_INVERTED" *) input RSTRAMB, + (* invertible_pin = "IS_RSTREGARSTREG_INVERTED" *) input RSTREGARSTREG, + (* invertible_pin = "IS_RSTREGB_INVERTED" *) input RSTREGB, input [15:0] ADDRARDADDR, @@ -143,9 +169,13 @@ module RAMB36E1 ( input [3:0] WEA, input [7:0] WEBWE, + (* abc_arrival=2454 *) output [31:0] DOADO, + (* abc_arrival=2454 *) output [31:0] DOBDO, + (* abc_arrival=2454 *) output [3:0] DOPADOP, + (* abc_arrival=2454 *) output [3:0] DOPBDOP ); parameter INITP_00 = 256'h0000000000000000000000000000000000000000000000000000000000000000; diff --git a/techlibs/xilinx/brams_map.v b/techlibs/xilinx/xc7_brams_map.v index 7ea49158d..7ea49158d 100644 --- a/techlibs/xilinx/brams_map.v +++ b/techlibs/xilinx/xc7_brams_map.v diff --git a/techlibs/xilinx/cells_xtra.v b/techlibs/xilinx/xc7_cells_xtra.v index a2dd01ad5..817932e9f 100644 --- a/techlibs/xilinx/cells_xtra.v +++ b/techlibs/xilinx/xc7_cells_xtra.v @@ -1,328 +1,4 @@ -// Created by cells_xtra.sh from Xilinx models - -module BSCANE2 (...); - parameter DISABLE_JTAG = "FALSE"; - parameter integer JTAG_CHAIN = 1; - output CAPTURE; - output DRCK; - output RESET; - output RUNTEST; - output SEL; - output SHIFT; - output TCK; - output TDI; - output TMS; - output UPDATE; - input TDO; -endmodule - -module BUFGCE (...); - parameter CE_TYPE = "SYNC"; - parameter [0:0] IS_CE_INVERTED = 1'b0; - parameter [0:0] IS_I_INVERTED = 1'b0; - output O; - input CE; - input I; -endmodule - -module BUFGCE_1 (...); - output O; - input CE, I; -endmodule - -module BUFGCTRL (...); - output O; - input CE0; - input CE1; - input I0; - input I1; - input IGNORE0; - input IGNORE1; - input S0; - input S1; - parameter integer INIT_OUT = 0; - parameter PRESELECT_I0 = "FALSE"; - parameter PRESELECT_I1 = "FALSE"; - parameter [0:0] IS_CE0_INVERTED = 1'b0; - parameter [0:0] IS_CE1_INVERTED = 1'b0; - parameter [0:0] IS_I0_INVERTED = 1'b0; - parameter [0:0] IS_I1_INVERTED = 1'b0; - parameter [0:0] IS_IGNORE0_INVERTED = 1'b0; - parameter [0:0] IS_IGNORE1_INVERTED = 1'b0; - parameter [0:0] IS_S0_INVERTED = 1'b0; - parameter [0:0] IS_S1_INVERTED = 1'b0; -endmodule - -module BUFGMUX (...); - parameter CLK_SEL_TYPE = "SYNC"; - output O; - input I0, I1, S; -endmodule - -module BUFGMUX_1 (...); - parameter CLK_SEL_TYPE = "SYNC"; - output O; - input I0, I1, S; -endmodule - -module BUFGMUX_CTRL (...); - output O; - input I0; - input I1; - input S; -endmodule - -module BUFH (...); - output O; - input I; -endmodule - -module BUFHCE (...); - parameter CE_TYPE = "SYNC"; - parameter integer INIT_OUT = 0; - parameter [0:0] IS_CE_INVERTED = 1'b0; - output O; - input CE; - input I; -endmodule - -module BUFIO (...); - output O; - input I; -endmodule - -module BUFMR (...); - output O; - input I; -endmodule - -module BUFMRCE (...); - parameter CE_TYPE = "SYNC"; - parameter integer INIT_OUT = 0; - parameter [0:0] IS_CE_INVERTED = 1'b0; - output O; - input CE; - input I; -endmodule - -module BUFR (...); - output O; - input CE; - input CLR; - input I; - parameter BUFR_DIVIDE = "BYPASS"; - parameter SIM_DEVICE = "7SERIES"; -endmodule - -module CAPTUREE2 (...); - parameter ONESHOT = "TRUE"; - input CAP; - input CLK; -endmodule - -module CFGLUT5 (...); - parameter [31:0] INIT = 32'h00000000; - parameter [0:0] IS_CLK_INVERTED = 1'b0; - output CDO; - output O5; - output O6; - input I4, I3, I2, I1, I0; - input CDI, CE, CLK; -endmodule - -module DCIRESET (...); - output LOCKED; - input RST; -endmodule - -module DNA_PORT (...); - parameter [56:0] SIM_DNA_VALUE = 57'h0; - output DOUT; - input CLK, DIN, READ, SHIFT; -endmodule - -module DSP48E1 (...); - parameter integer ACASCREG = 1; - parameter integer ADREG = 1; - parameter integer ALUMODEREG = 1; - parameter integer AREG = 1; - parameter AUTORESET_PATDET = "NO_RESET"; - parameter A_INPUT = "DIRECT"; - parameter integer BCASCREG = 1; - parameter integer BREG = 1; - parameter B_INPUT = "DIRECT"; - parameter integer CARRYINREG = 1; - parameter integer CARRYINSELREG = 1; - parameter integer CREG = 1; - parameter integer DREG = 1; - parameter integer INMODEREG = 1; - parameter integer MREG = 1; - parameter integer OPMODEREG = 1; - parameter integer PREG = 1; - parameter SEL_MASK = "MASK"; - parameter SEL_PATTERN = "PATTERN"; - parameter USE_DPORT = "FALSE"; - parameter USE_MULT = "MULTIPLY"; - parameter USE_PATTERN_DETECT = "NO_PATDET"; - parameter USE_SIMD = "ONE48"; - parameter [47:0] MASK = 48'h3FFFFFFFFFFF; - parameter [47:0] PATTERN = 48'h000000000000; - parameter [3:0] IS_ALUMODE_INVERTED = 4'b0; - parameter [0:0] IS_CARRYIN_INVERTED = 1'b0; - parameter [0:0] IS_CLK_INVERTED = 1'b0; - parameter [4:0] IS_INMODE_INVERTED = 5'b0; - parameter [6:0] IS_OPMODE_INVERTED = 7'b0; - output [29:0] ACOUT; - output [17:0] BCOUT; - output CARRYCASCOUT; - output [3:0] CARRYOUT; - output MULTSIGNOUT; - output OVERFLOW; - output [47:0] P; - output PATTERNBDETECT; - output PATTERNDETECT; - output [47:0] PCOUT; - output UNDERFLOW; - input [29:0] A; - input [29:0] ACIN; - input [3:0] ALUMODE; - input [17:0] B; - input [17:0] BCIN; - input [47:0] C; - input CARRYCASCIN; - input CARRYIN; - input [2:0] CARRYINSEL; - input CEA1; - input CEA2; - input CEAD; - input CEALUMODE; - input CEB1; - input CEB2; - input CEC; - input CECARRYIN; - input CECTRL; - input CED; - input CEINMODE; - input CEM; - input CEP; - input CLK; - input [24:0] D; - input [4:0] INMODE; - input MULTSIGNIN; - input [6:0] OPMODE; - input [47:0] PCIN; - input RSTA; - input RSTALLCARRYIN; - input RSTALUMODE; - input RSTB; - input RSTC; - input RSTCTRL; - input RSTD; - input RSTINMODE; - input RSTM; - input RSTP; -endmodule - -module EFUSE_USR (...); - parameter [31:0] SIM_EFUSE_VALUE = 32'h00000000; - output [31:0] EFUSEUSR; -endmodule - -module FIFO18E1 (...); - parameter ALMOST_EMPTY_OFFSET = 13'h0080; - parameter ALMOST_FULL_OFFSET = 13'h0080; - parameter integer DATA_WIDTH = 4; - parameter integer DO_REG = 1; - parameter EN_SYN = "FALSE"; - parameter FIFO_MODE = "FIFO18"; - parameter FIRST_WORD_FALL_THROUGH = "FALSE"; - parameter INIT = 36'h0; - parameter SIM_DEVICE = "VIRTEX6"; - parameter SRVAL = 36'h0; - parameter IS_RDCLK_INVERTED = 1'b0; - parameter IS_RDEN_INVERTED = 1'b0; - parameter IS_RSTREG_INVERTED = 1'b0; - parameter IS_RST_INVERTED = 1'b0; - parameter IS_WRCLK_INVERTED = 1'b0; - parameter IS_WREN_INVERTED = 1'b0; - output ALMOSTEMPTY; - output ALMOSTFULL; - output [31:0] DO; - output [3:0] DOP; - output EMPTY; - output FULL; - output [11:0] RDCOUNT; - output RDERR; - output [11:0] WRCOUNT; - output WRERR; - input [31:0] DI; - input [3:0] DIP; - input RDCLK; - input RDEN; - input REGCE; - input RST; - input RSTREG; - input WRCLK; - input WREN; -endmodule - -module FIFO36E1 (...); - parameter ALMOST_EMPTY_OFFSET = 13'h0080; - parameter ALMOST_FULL_OFFSET = 13'h0080; - parameter integer DATA_WIDTH = 4; - parameter integer DO_REG = 1; - parameter EN_ECC_READ = "FALSE"; - parameter EN_ECC_WRITE = "FALSE"; - parameter EN_SYN = "FALSE"; - parameter FIFO_MODE = "FIFO36"; - parameter FIRST_WORD_FALL_THROUGH = "FALSE"; - parameter INIT = 72'h0; - parameter SIM_DEVICE = "VIRTEX6"; - parameter SRVAL = 72'h0; - parameter IS_RDCLK_INVERTED = 1'b0; - parameter IS_RDEN_INVERTED = 1'b0; - parameter IS_RSTREG_INVERTED = 1'b0; - parameter IS_RST_INVERTED = 1'b0; - parameter IS_WRCLK_INVERTED = 1'b0; - parameter IS_WREN_INVERTED = 1'b0; - output ALMOSTEMPTY; - output ALMOSTFULL; - output DBITERR; - output [63:0] DO; - output [7:0] DOP; - output [7:0] ECCPARITY; - output EMPTY; - output FULL; - output [12:0] RDCOUNT; - output RDERR; - output SBITERR; - output [12:0] WRCOUNT; - output WRERR; - input [63:0] DI; - input [7:0] DIP; - input INJECTDBITERR; - input INJECTSBITERR; - input RDCLK; - input RDEN; - input REGCE; - input RST; - input RSTREG; - input WRCLK; - input WREN; -endmodule - -module FRAME_ECCE2 (...); - parameter FARSRC = "EFAR"; - parameter FRAME_RBT_IN_FILENAME = "NONE"; - output CRCERROR; - output ECCERROR; - output ECCERRORSINGLE; - output SYNDROMEVALID; - output [12:0] SYNDROME; - output [25:0] FAR; - output [4:0] SYNBIT; - output [6:0] SYNWORD; -endmodule +// Created by cells_xtra.py from Xilinx models module GTHE2_CHANNEL (...); parameter [0:0] ACJTAG_DEBUG_MODE = 1'b0; @@ -671,20 +347,26 @@ module GTHE2_CHANNEL (...); output [7:0] RXDISPERR; output [7:0] RXNOTINTABLE; input CFGRESET; + (* invertible_pin = "IS_CLKRSVD0_INVERTED" *) input CLKRSVD0; + (* invertible_pin = "IS_CLKRSVD1_INVERTED" *) input CLKRSVD1; + (* invertible_pin = "IS_CPLLLOCKDETCLK_INVERTED" *) input CPLLLOCKDETCLK; input CPLLLOCKEN; input CPLLPD; input CPLLRESET; input DMONFIFORESET; + (* invertible_pin = "IS_DMONITORCLK_INVERTED" *) input DMONITORCLK; + (* invertible_pin = "IS_DRPCLK_INVERTED" *) input DRPCLK; input DRPEN; input DRPWE; input EYESCANMODE; input EYESCANRESET; input EYESCANTRIGGER; + (* invertible_pin = "IS_GTGREFCLK_INVERTED" *) input GTGREFCLK; input GTHRXN; input GTHRXP; @@ -780,9 +462,12 @@ module GTHE2_CHANNEL (...); input RXSYNCIN; input RXSYNCMODE; input RXUSERRDY; + (* invertible_pin = "IS_RXUSRCLK2_INVERTED" *) input RXUSRCLK2; + (* invertible_pin = "IS_RXUSRCLK_INVERTED" *) input RXUSRCLK; input SETERRSTATUS; + (* invertible_pin = "IS_SIGVALIDCLK_INVERTED" *) input SIGVALIDCLK; input TX8B10BEN; input TXCOMINIT; @@ -805,6 +490,7 @@ module GTHE2_CHANNEL (...); input TXPHALIGNEN; input TXPHDLYPD; input TXPHDLYRESET; + (* invertible_pin = "IS_TXPHDLYTSTCLK_INVERTED" *) input TXPHDLYTSTCLK; input TXPHINIT; input TXPHOVRDEN; @@ -828,7 +514,9 @@ module GTHE2_CHANNEL (...); input TXSYNCIN; input TXSYNCMODE; input TXUSERRDY; + (* invertible_pin = "IS_TXUSRCLK2_INVERTED" *) input TXUSRCLK2; + (* invertible_pin = "IS_TXUSRCLK_INVERTED" *) input TXUSRCLK; input [13:0] RXADAPTSELTEST; input [15:0] DRPDI; @@ -917,9 +605,11 @@ module GTHE2_COMMON (...); input BGMONITORENB; input BGPDB; input BGRCALOVRDENB; + (* invertible_pin = "IS_DRPCLK_INVERTED" *) input DRPCLK; input DRPEN; input DRPWE; + (* invertible_pin = "IS_GTGREFCLK_INVERTED" *) input GTGREFCLK; input GTNORTHREFCLK0; input GTNORTHREFCLK1; @@ -927,6 +617,7 @@ module GTHE2_COMMON (...); input GTREFCLK1; input GTSOUTHREFCLK0; input GTSOUTHREFCLK1; + (* invertible_pin = "IS_QPLLLOCKDETCLK_INVERTED" *) input QPLLLOCKDETCLK; input QPLLLOCKEN; input QPLLOUTRESET; @@ -1252,10 +943,14 @@ module GTPE2_CHANNEL (...); output [4:0] RXPHMONITOR; output [4:0] RXPHSLIPMONITOR; input CFGRESET; + (* invertible_pin = "IS_CLKRSVD0_INVERTED" *) input CLKRSVD0; + (* invertible_pin = "IS_CLKRSVD1_INVERTED" *) input CLKRSVD1; input DMONFIFORESET; + (* invertible_pin = "IS_DMONITORCLK_INVERTED" *) input DMONITORCLK; + (* invertible_pin = "IS_DRPCLK_INVERTED" *) input DRPCLK; input DRPEN; input DRPWE; @@ -1329,9 +1024,12 @@ module GTPE2_CHANNEL (...); input RXSYNCIN; input RXSYNCMODE; input RXUSERRDY; + (* invertible_pin = "IS_RXUSRCLK2_INVERTED" *) input RXUSRCLK2; + (* invertible_pin = "IS_RXUSRCLK_INVERTED" *) input RXUSRCLK; input SETERRSTATUS; + (* invertible_pin = "IS_SIGVALIDCLK_INVERTED" *) input SIGVALIDCLK; input TX8B10BEN; input TXCOMINIT; @@ -1354,6 +1052,7 @@ module GTPE2_CHANNEL (...); input TXPHALIGNEN; input TXPHDLYPD; input TXPHDLYRESET; + (* invertible_pin = "IS_TXPHDLYTSTCLK_INVERTED" *) input TXPHDLYTSTCLK; input TXPHINIT; input TXPHOVRDEN; @@ -1374,7 +1073,9 @@ module GTPE2_CHANNEL (...); input TXSYNCIN; input TXSYNCMODE; input TXUSERRDY; + (* invertible_pin = "IS_TXUSRCLK2_INVERTED" *) input TXUSRCLK2; + (* invertible_pin = "IS_TXUSRCLK_INVERTED" *) input TXUSRCLK; input [13:0] RXADAPTSELTEST; input [15:0] DRPDI; @@ -1463,21 +1164,26 @@ module GTPE2_COMMON (...); input BGMONITORENB; input BGPDB; input BGRCALOVRDENB; + (* invertible_pin = "IS_DRPCLK_INVERTED" *) input DRPCLK; input DRPEN; input DRPWE; input GTEASTREFCLK0; input GTEASTREFCLK1; + (* invertible_pin = "IS_GTGREFCLK0_INVERTED" *) input GTGREFCLK0; + (* invertible_pin = "IS_GTGREFCLK1_INVERTED" *) input GTGREFCLK1; input GTREFCLK0; input GTREFCLK1; input GTWESTREFCLK0; input GTWESTREFCLK1; + (* invertible_pin = "IS_PLL0LOCKDETCLK_INVERTED" *) input PLL0LOCKDETCLK; input PLL0LOCKEN; input PLL0PD; input PLL0RESET; + (* invertible_pin = "IS_PLL1LOCKDETCLK_INVERTED" *) input PLL1LOCKDETCLK; input PLL1LOCKEN; input PLL1PD; @@ -1766,16 +1472,19 @@ module GTXE2_CHANNEL (...); output [7:0] RXNOTINTABLE; output [9:0] TSTOUT; input CFGRESET; + (* invertible_pin = "IS_CPLLLOCKDETCLK_INVERTED" *) input CPLLLOCKDETCLK; input CPLLLOCKEN; input CPLLPD; input CPLLRESET; + (* invertible_pin = "IS_DRPCLK_INVERTED" *) input DRPCLK; input DRPEN; input DRPWE; input EYESCANMODE; input EYESCANRESET; input EYESCANTRIGGER; + (* invertible_pin = "IS_GTGREFCLK_INVERTED" *) input GTGREFCLK; input GTNORTHREFCLK0; input GTNORTHREFCLK1; @@ -1852,7 +1561,9 @@ module GTXE2_CHANNEL (...); input RXQPIEN; input RXSLIDE; input RXUSERRDY; + (* invertible_pin = "IS_RXUSRCLK2_INVERTED" *) input RXUSRCLK2; + (* invertible_pin = "IS_RXUSRCLK_INVERTED" *) input RXUSRCLK; input SETERRSTATUS; input TX8B10BEN; @@ -1876,6 +1587,7 @@ module GTXE2_CHANNEL (...); input TXPHALIGNEN; input TXPHDLYPD; input TXPHDLYRESET; + (* invertible_pin = "IS_TXPHDLYTSTCLK_INVERTED" *) input TXPHDLYTSTCLK; input TXPHINIT; input TXPHOVRDEN; @@ -1891,7 +1603,9 @@ module GTXE2_CHANNEL (...); input TXSTARTSEQ; input TXSWING; input TXUSERRDY; + (* invertible_pin = "IS_TXUSRCLK2_INVERTED" *) input TXUSRCLK2; + (* invertible_pin = "IS_TXUSRCLK_INVERTED" *) input TXUSRCLK; input [15:0] DRPDI; input [15:0] GTRSVD; @@ -1968,9 +1682,11 @@ module GTXE2_COMMON (...); input BGBYPASSB; input BGMONITORENB; input BGPDB; + (* invertible_pin = "IS_DRPCLK_INVERTED" *) input DRPCLK; input DRPEN; input DRPWE; + (* invertible_pin = "IS_GTGREFCLK_INVERTED" *) input GTGREFCLK; input GTNORTHREFCLK0; input GTNORTHREFCLK1; @@ -1978,6 +1694,7 @@ module GTXE2_COMMON (...); input GTREFCLK1; input GTSOUTHREFCLK0; input GTSOUTHREFCLK1; + (* invertible_pin = "IS_QPLLLOCKDETCLK_INVERTED" *) input QPLLLOCKDETCLK; input QPLLLOCKEN; input QPLLOUTRESET; @@ -1993,12 +1710,2195 @@ module GTXE2_COMMON (...); input [7:0] PMARSVD; endmodule +module PCIE_2_1 (...); + parameter [11:0] AER_BASE_PTR = 12'h140; + parameter AER_CAP_ECRC_CHECK_CAPABLE = "FALSE"; + parameter AER_CAP_ECRC_GEN_CAPABLE = "FALSE"; + parameter [15:0] AER_CAP_ID = 16'h0001; + parameter AER_CAP_MULTIHEADER = "FALSE"; + parameter [11:0] AER_CAP_NEXTPTR = 12'h178; + parameter AER_CAP_ON = "FALSE"; + parameter [23:0] AER_CAP_OPTIONAL_ERR_SUPPORT = 24'h000000; + parameter AER_CAP_PERMIT_ROOTERR_UPDATE = "TRUE"; + parameter [3:0] AER_CAP_VERSION = 4'h2; + parameter ALLOW_X8_GEN2 = "FALSE"; + parameter [31:0] BAR0 = 32'hFFFFFF00; + parameter [31:0] BAR1 = 32'hFFFF0000; + parameter [31:0] BAR2 = 32'hFFFF000C; + parameter [31:0] BAR3 = 32'hFFFFFFFF; + parameter [31:0] BAR4 = 32'h00000000; + parameter [31:0] BAR5 = 32'h00000000; + parameter [7:0] CAPABILITIES_PTR = 8'h40; + parameter [31:0] CARDBUS_CIS_POINTER = 32'h00000000; + parameter integer CFG_ECRC_ERR_CPLSTAT = 0; + parameter [23:0] CLASS_CODE = 24'h000000; + parameter CMD_INTX_IMPLEMENTED = "TRUE"; + parameter CPL_TIMEOUT_DISABLE_SUPPORTED = "FALSE"; + parameter [3:0] CPL_TIMEOUT_RANGES_SUPPORTED = 4'h0; + parameter [6:0] CRM_MODULE_RSTS = 7'h00; + parameter DEV_CAP2_ARI_FORWARDING_SUPPORTED = "FALSE"; + parameter DEV_CAP2_ATOMICOP32_COMPLETER_SUPPORTED = "FALSE"; + parameter DEV_CAP2_ATOMICOP64_COMPLETER_SUPPORTED = "FALSE"; + parameter DEV_CAP2_ATOMICOP_ROUTING_SUPPORTED = "FALSE"; + parameter DEV_CAP2_CAS128_COMPLETER_SUPPORTED = "FALSE"; + parameter DEV_CAP2_ENDEND_TLP_PREFIX_SUPPORTED = "FALSE"; + parameter DEV_CAP2_EXTENDED_FMT_FIELD_SUPPORTED = "FALSE"; + parameter DEV_CAP2_LTR_MECHANISM_SUPPORTED = "FALSE"; + parameter [1:0] DEV_CAP2_MAX_ENDEND_TLP_PREFIXES = 2'h0; + parameter DEV_CAP2_NO_RO_ENABLED_PRPR_PASSING = "FALSE"; + parameter [1:0] DEV_CAP2_TPH_COMPLETER_SUPPORTED = 2'h0; + parameter DEV_CAP_ENABLE_SLOT_PWR_LIMIT_SCALE = "TRUE"; + parameter DEV_CAP_ENABLE_SLOT_PWR_LIMIT_VALUE = "TRUE"; + parameter integer DEV_CAP_ENDPOINT_L0S_LATENCY = 0; + parameter integer DEV_CAP_ENDPOINT_L1_LATENCY = 0; + parameter DEV_CAP_EXT_TAG_SUPPORTED = "TRUE"; + parameter DEV_CAP_FUNCTION_LEVEL_RESET_CAPABLE = "FALSE"; + parameter integer DEV_CAP_MAX_PAYLOAD_SUPPORTED = 2; + parameter integer DEV_CAP_PHANTOM_FUNCTIONS_SUPPORT = 0; + parameter DEV_CAP_ROLE_BASED_ERROR = "TRUE"; + parameter integer DEV_CAP_RSVD_14_12 = 0; + parameter integer DEV_CAP_RSVD_17_16 = 0; + parameter integer DEV_CAP_RSVD_31_29 = 0; + parameter DEV_CONTROL_AUX_POWER_SUPPORTED = "FALSE"; + parameter DEV_CONTROL_EXT_TAG_DEFAULT = "FALSE"; + parameter DISABLE_ASPM_L1_TIMER = "FALSE"; + parameter DISABLE_BAR_FILTERING = "FALSE"; + parameter DISABLE_ERR_MSG = "FALSE"; + parameter DISABLE_ID_CHECK = "FALSE"; + parameter DISABLE_LANE_REVERSAL = "FALSE"; + parameter DISABLE_LOCKED_FILTER = "FALSE"; + parameter DISABLE_PPM_FILTER = "FALSE"; + parameter DISABLE_RX_POISONED_RESP = "FALSE"; + parameter DISABLE_RX_TC_FILTER = "FALSE"; + parameter DISABLE_SCRAMBLING = "FALSE"; + parameter [7:0] DNSTREAM_LINK_NUM = 8'h00; + parameter [11:0] DSN_BASE_PTR = 12'h100; + parameter [15:0] DSN_CAP_ID = 16'h0003; + parameter [11:0] DSN_CAP_NEXTPTR = 12'h10C; + parameter DSN_CAP_ON = "TRUE"; + parameter [3:0] DSN_CAP_VERSION = 4'h1; + parameter [10:0] ENABLE_MSG_ROUTE = 11'h000; + parameter ENABLE_RX_TD_ECRC_TRIM = "FALSE"; + parameter ENDEND_TLP_PREFIX_FORWARDING_SUPPORTED = "FALSE"; + parameter ENTER_RVRY_EI_L0 = "TRUE"; + parameter EXIT_LOOPBACK_ON_EI = "TRUE"; + parameter [31:0] EXPANSION_ROM = 32'hFFFFF001; + parameter [5:0] EXT_CFG_CAP_PTR = 6'h3F; + parameter [9:0] EXT_CFG_XP_CAP_PTR = 10'h3FF; + parameter [7:0] HEADER_TYPE = 8'h00; + parameter [4:0] INFER_EI = 5'h00; + parameter [7:0] INTERRUPT_PIN = 8'h01; + parameter INTERRUPT_STAT_AUTO = "TRUE"; + parameter IS_SWITCH = "FALSE"; + parameter [9:0] LAST_CONFIG_DWORD = 10'h3FF; + parameter LINK_CAP_ASPM_OPTIONALITY = "TRUE"; + parameter integer LINK_CAP_ASPM_SUPPORT = 1; + parameter LINK_CAP_CLOCK_POWER_MANAGEMENT = "FALSE"; + parameter LINK_CAP_DLL_LINK_ACTIVE_REPORTING_CAP = "FALSE"; + parameter integer LINK_CAP_L0S_EXIT_LATENCY_COMCLK_GEN1 = 7; + parameter integer LINK_CAP_L0S_EXIT_LATENCY_COMCLK_GEN2 = 7; + parameter integer LINK_CAP_L0S_EXIT_LATENCY_GEN1 = 7; + parameter integer LINK_CAP_L0S_EXIT_LATENCY_GEN2 = 7; + parameter integer LINK_CAP_L1_EXIT_LATENCY_COMCLK_GEN1 = 7; + parameter integer LINK_CAP_L1_EXIT_LATENCY_COMCLK_GEN2 = 7; + parameter integer LINK_CAP_L1_EXIT_LATENCY_GEN1 = 7; + parameter integer LINK_CAP_L1_EXIT_LATENCY_GEN2 = 7; + parameter LINK_CAP_LINK_BANDWIDTH_NOTIFICATION_CAP = "FALSE"; + parameter [3:0] LINK_CAP_MAX_LINK_SPEED = 4'h1; + parameter [5:0] LINK_CAP_MAX_LINK_WIDTH = 6'h08; + parameter integer LINK_CAP_RSVD_23 = 0; + parameter LINK_CAP_SURPRISE_DOWN_ERROR_CAPABLE = "FALSE"; + parameter integer LINK_CONTROL_RCB = 0; + parameter LINK_CTRL2_DEEMPHASIS = "FALSE"; + parameter LINK_CTRL2_HW_AUTONOMOUS_SPEED_DISABLE = "FALSE"; + parameter [3:0] LINK_CTRL2_TARGET_LINK_SPEED = 4'h2; + parameter LINK_STATUS_SLOT_CLOCK_CONFIG = "TRUE"; + parameter [14:0] LL_ACK_TIMEOUT = 15'h0000; + parameter LL_ACK_TIMEOUT_EN = "FALSE"; + parameter integer LL_ACK_TIMEOUT_FUNC = 0; + parameter [14:0] LL_REPLAY_TIMEOUT = 15'h0000; + parameter LL_REPLAY_TIMEOUT_EN = "FALSE"; + parameter integer LL_REPLAY_TIMEOUT_FUNC = 0; + parameter [5:0] LTSSM_MAX_LINK_WIDTH = 6'h01; + parameter MPS_FORCE = "FALSE"; + parameter [7:0] MSIX_BASE_PTR = 8'h9C; + parameter [7:0] MSIX_CAP_ID = 8'h11; + parameter [7:0] MSIX_CAP_NEXTPTR = 8'h00; + parameter MSIX_CAP_ON = "FALSE"; + parameter integer MSIX_CAP_PBA_BIR = 0; + parameter [28:0] MSIX_CAP_PBA_OFFSET = 29'h00000050; + parameter integer MSIX_CAP_TABLE_BIR = 0; + parameter [28:0] MSIX_CAP_TABLE_OFFSET = 29'h00000040; + parameter [10:0] MSIX_CAP_TABLE_SIZE = 11'h000; + parameter [7:0] MSI_BASE_PTR = 8'h48; + parameter MSI_CAP_64_BIT_ADDR_CAPABLE = "TRUE"; + parameter [7:0] MSI_CAP_ID = 8'h05; + parameter integer MSI_CAP_MULTIMSGCAP = 0; + parameter integer MSI_CAP_MULTIMSG_EXTENSION = 0; + parameter [7:0] MSI_CAP_NEXTPTR = 8'h60; + parameter MSI_CAP_ON = "FALSE"; + parameter MSI_CAP_PER_VECTOR_MASKING_CAPABLE = "TRUE"; + parameter integer N_FTS_COMCLK_GEN1 = 255; + parameter integer N_FTS_COMCLK_GEN2 = 255; + parameter integer N_FTS_GEN1 = 255; + parameter integer N_FTS_GEN2 = 255; + parameter [7:0] PCIE_BASE_PTR = 8'h60; + parameter [7:0] PCIE_CAP_CAPABILITY_ID = 8'h10; + parameter [3:0] PCIE_CAP_CAPABILITY_VERSION = 4'h2; + parameter [3:0] PCIE_CAP_DEVICE_PORT_TYPE = 4'h0; + parameter [7:0] PCIE_CAP_NEXTPTR = 8'h9C; + parameter PCIE_CAP_ON = "TRUE"; + parameter integer PCIE_CAP_RSVD_15_14 = 0; + parameter PCIE_CAP_SLOT_IMPLEMENTED = "FALSE"; + parameter integer PCIE_REVISION = 2; + parameter integer PL_AUTO_CONFIG = 0; + parameter PL_FAST_TRAIN = "FALSE"; + parameter [14:0] PM_ASPML0S_TIMEOUT = 15'h0000; + parameter PM_ASPML0S_TIMEOUT_EN = "FALSE"; + parameter integer PM_ASPML0S_TIMEOUT_FUNC = 0; + parameter PM_ASPM_FASTEXIT = "FALSE"; + parameter [7:0] PM_BASE_PTR = 8'h40; + parameter integer PM_CAP_AUXCURRENT = 0; + parameter PM_CAP_D1SUPPORT = "TRUE"; + parameter PM_CAP_D2SUPPORT = "TRUE"; + parameter PM_CAP_DSI = "FALSE"; + parameter [7:0] PM_CAP_ID = 8'h01; + parameter [7:0] PM_CAP_NEXTPTR = 8'h48; + parameter PM_CAP_ON = "TRUE"; + parameter [4:0] PM_CAP_PMESUPPORT = 5'h0F; + parameter PM_CAP_PME_CLOCK = "FALSE"; + parameter integer PM_CAP_RSVD_04 = 0; + parameter integer PM_CAP_VERSION = 3; + parameter PM_CSR_B2B3 = "FALSE"; + parameter PM_CSR_BPCCEN = "FALSE"; + parameter PM_CSR_NOSOFTRST = "TRUE"; + parameter [7:0] PM_DATA0 = 8'h01; + parameter [7:0] PM_DATA1 = 8'h01; + parameter [7:0] PM_DATA2 = 8'h01; + parameter [7:0] PM_DATA3 = 8'h01; + parameter [7:0] PM_DATA4 = 8'h01; + parameter [7:0] PM_DATA5 = 8'h01; + parameter [7:0] PM_DATA6 = 8'h01; + parameter [7:0] PM_DATA7 = 8'h01; + parameter [1:0] PM_DATA_SCALE0 = 2'h1; + parameter [1:0] PM_DATA_SCALE1 = 2'h1; + parameter [1:0] PM_DATA_SCALE2 = 2'h1; + parameter [1:0] PM_DATA_SCALE3 = 2'h1; + parameter [1:0] PM_DATA_SCALE4 = 2'h1; + parameter [1:0] PM_DATA_SCALE5 = 2'h1; + parameter [1:0] PM_DATA_SCALE6 = 2'h1; + parameter [1:0] PM_DATA_SCALE7 = 2'h1; + parameter PM_MF = "FALSE"; + parameter [11:0] RBAR_BASE_PTR = 12'h178; + parameter [4:0] RBAR_CAP_CONTROL_ENCODEDBAR0 = 5'h00; + parameter [4:0] RBAR_CAP_CONTROL_ENCODEDBAR1 = 5'h00; + parameter [4:0] RBAR_CAP_CONTROL_ENCODEDBAR2 = 5'h00; + parameter [4:0] RBAR_CAP_CONTROL_ENCODEDBAR3 = 5'h00; + parameter [4:0] RBAR_CAP_CONTROL_ENCODEDBAR4 = 5'h00; + parameter [4:0] RBAR_CAP_CONTROL_ENCODEDBAR5 = 5'h00; + parameter [15:0] RBAR_CAP_ID = 16'h0015; + parameter [2:0] RBAR_CAP_INDEX0 = 3'h0; + parameter [2:0] RBAR_CAP_INDEX1 = 3'h0; + parameter [2:0] RBAR_CAP_INDEX2 = 3'h0; + parameter [2:0] RBAR_CAP_INDEX3 = 3'h0; + parameter [2:0] RBAR_CAP_INDEX4 = 3'h0; + parameter [2:0] RBAR_CAP_INDEX5 = 3'h0; + parameter [11:0] RBAR_CAP_NEXTPTR = 12'h000; + parameter RBAR_CAP_ON = "FALSE"; + parameter [31:0] RBAR_CAP_SUP0 = 32'h00000000; + parameter [31:0] RBAR_CAP_SUP1 = 32'h00000000; + parameter [31:0] RBAR_CAP_SUP2 = 32'h00000000; + parameter [31:0] RBAR_CAP_SUP3 = 32'h00000000; + parameter [31:0] RBAR_CAP_SUP4 = 32'h00000000; + parameter [31:0] RBAR_CAP_SUP5 = 32'h00000000; + parameter [3:0] RBAR_CAP_VERSION = 4'h1; + parameter [2:0] RBAR_NUM = 3'h1; + parameter integer RECRC_CHK = 0; + parameter RECRC_CHK_TRIM = "FALSE"; + parameter ROOT_CAP_CRS_SW_VISIBILITY = "FALSE"; + parameter [1:0] RP_AUTO_SPD = 2'h1; + parameter [4:0] RP_AUTO_SPD_LOOPCNT = 5'h1F; + parameter SELECT_DLL_IF = "FALSE"; + parameter SIM_VERSION = "1.0"; + parameter SLOT_CAP_ATT_BUTTON_PRESENT = "FALSE"; + parameter SLOT_CAP_ATT_INDICATOR_PRESENT = "FALSE"; + parameter SLOT_CAP_ELEC_INTERLOCK_PRESENT = "FALSE"; + parameter SLOT_CAP_HOTPLUG_CAPABLE = "FALSE"; + parameter SLOT_CAP_HOTPLUG_SURPRISE = "FALSE"; + parameter SLOT_CAP_MRL_SENSOR_PRESENT = "FALSE"; + parameter SLOT_CAP_NO_CMD_COMPLETED_SUPPORT = "FALSE"; + parameter [12:0] SLOT_CAP_PHYSICAL_SLOT_NUM = 13'h0000; + parameter SLOT_CAP_POWER_CONTROLLER_PRESENT = "FALSE"; + parameter SLOT_CAP_POWER_INDICATOR_PRESENT = "FALSE"; + parameter integer SLOT_CAP_SLOT_POWER_LIMIT_SCALE = 0; + parameter [7:0] SLOT_CAP_SLOT_POWER_LIMIT_VALUE = 8'h00; + parameter integer SPARE_BIT0 = 0; + parameter integer SPARE_BIT1 = 0; + parameter integer SPARE_BIT2 = 0; + parameter integer SPARE_BIT3 = 0; + parameter integer SPARE_BIT4 = 0; + parameter integer SPARE_BIT5 = 0; + parameter integer SPARE_BIT6 = 0; + parameter integer SPARE_BIT7 = 0; + parameter integer SPARE_BIT8 = 0; + parameter [7:0] SPARE_BYTE0 = 8'h00; + parameter [7:0] SPARE_BYTE1 = 8'h00; + parameter [7:0] SPARE_BYTE2 = 8'h00; + parameter [7:0] SPARE_BYTE3 = 8'h00; + parameter [31:0] SPARE_WORD0 = 32'h00000000; + parameter [31:0] SPARE_WORD1 = 32'h00000000; + parameter [31:0] SPARE_WORD2 = 32'h00000000; + parameter [31:0] SPARE_WORD3 = 32'h00000000; + parameter SSL_MESSAGE_AUTO = "FALSE"; + parameter TECRC_EP_INV = "FALSE"; + parameter TL_RBYPASS = "FALSE"; + parameter integer TL_RX_RAM_RADDR_LATENCY = 0; + parameter integer TL_RX_RAM_RDATA_LATENCY = 2; + parameter integer TL_RX_RAM_WRITE_LATENCY = 0; + parameter TL_TFC_DISABLE = "FALSE"; + parameter TL_TX_CHECKS_DISABLE = "FALSE"; + parameter integer TL_TX_RAM_RADDR_LATENCY = 0; + parameter integer TL_TX_RAM_RDATA_LATENCY = 2; + parameter integer TL_TX_RAM_WRITE_LATENCY = 0; + parameter TRN_DW = "FALSE"; + parameter TRN_NP_FC = "FALSE"; + parameter UPCONFIG_CAPABLE = "TRUE"; + parameter UPSTREAM_FACING = "TRUE"; + parameter UR_ATOMIC = "TRUE"; + parameter UR_CFG1 = "TRUE"; + parameter UR_INV_REQ = "TRUE"; + parameter UR_PRS_RESPONSE = "TRUE"; + parameter USER_CLK2_DIV2 = "FALSE"; + parameter integer USER_CLK_FREQ = 3; + parameter USE_RID_PINS = "FALSE"; + parameter VC0_CPL_INFINITE = "TRUE"; + parameter [12:0] VC0_RX_RAM_LIMIT = 13'h03FF; + parameter integer VC0_TOTAL_CREDITS_CD = 127; + parameter integer VC0_TOTAL_CREDITS_CH = 31; + parameter integer VC0_TOTAL_CREDITS_NPD = 24; + parameter integer VC0_TOTAL_CREDITS_NPH = 12; + parameter integer VC0_TOTAL_CREDITS_PD = 288; + parameter integer VC0_TOTAL_CREDITS_PH = 32; + parameter integer VC0_TX_LASTPACKET = 31; + parameter [11:0] VC_BASE_PTR = 12'h10C; + parameter [15:0] VC_CAP_ID = 16'h0002; + parameter [11:0] VC_CAP_NEXTPTR = 12'h000; + parameter VC_CAP_ON = "FALSE"; + parameter VC_CAP_REJECT_SNOOP_TRANSACTIONS = "FALSE"; + parameter [3:0] VC_CAP_VERSION = 4'h1; + parameter [11:0] VSEC_BASE_PTR = 12'h128; + parameter [15:0] VSEC_CAP_HDR_ID = 16'h1234; + parameter [11:0] VSEC_CAP_HDR_LENGTH = 12'h018; + parameter [3:0] VSEC_CAP_HDR_REVISION = 4'h1; + parameter [15:0] VSEC_CAP_ID = 16'h000B; + parameter VSEC_CAP_IS_LINK_VISIBLE = "TRUE"; + parameter [11:0] VSEC_CAP_NEXTPTR = 12'h140; + parameter VSEC_CAP_ON = "FALSE"; + parameter [3:0] VSEC_CAP_VERSION = 4'h1; + output CFGAERECRCCHECKEN; + output CFGAERECRCGENEN; + output CFGAERROOTERRCORRERRRECEIVED; + output CFGAERROOTERRCORRERRREPORTINGEN; + output CFGAERROOTERRFATALERRRECEIVED; + output CFGAERROOTERRFATALERRREPORTINGEN; + output CFGAERROOTERRNONFATALERRRECEIVED; + output CFGAERROOTERRNONFATALERRREPORTINGEN; + output CFGBRIDGESERREN; + output CFGCOMMANDBUSMASTERENABLE; + output CFGCOMMANDINTERRUPTDISABLE; + output CFGCOMMANDIOENABLE; + output CFGCOMMANDMEMENABLE; + output CFGCOMMANDSERREN; + output CFGDEVCONTROL2ARIFORWARDEN; + output CFGDEVCONTROL2ATOMICEGRESSBLOCK; + output CFGDEVCONTROL2ATOMICREQUESTEREN; + output CFGDEVCONTROL2CPLTIMEOUTDIS; + output CFGDEVCONTROL2IDOCPLEN; + output CFGDEVCONTROL2IDOREQEN; + output CFGDEVCONTROL2LTREN; + output CFGDEVCONTROL2TLPPREFIXBLOCK; + output CFGDEVCONTROLAUXPOWEREN; + output CFGDEVCONTROLCORRERRREPORTINGEN; + output CFGDEVCONTROLENABLERO; + output CFGDEVCONTROLEXTTAGEN; + output CFGDEVCONTROLFATALERRREPORTINGEN; + output CFGDEVCONTROLNONFATALREPORTINGEN; + output CFGDEVCONTROLNOSNOOPEN; + output CFGDEVCONTROLPHANTOMEN; + output CFGDEVCONTROLURERRREPORTINGEN; + output CFGDEVSTATUSCORRERRDETECTED; + output CFGDEVSTATUSFATALERRDETECTED; + output CFGDEVSTATUSNONFATALERRDETECTED; + output CFGDEVSTATUSURDETECTED; + output CFGERRAERHEADERLOGSETN; + output CFGERRCPLRDYN; + output CFGINTERRUPTMSIENABLE; + output CFGINTERRUPTMSIXENABLE; + output CFGINTERRUPTMSIXFM; + output CFGINTERRUPTRDYN; + output CFGLINKCONTROLAUTOBANDWIDTHINTEN; + output CFGLINKCONTROLBANDWIDTHINTEN; + output CFGLINKCONTROLCLOCKPMEN; + output CFGLINKCONTROLCOMMONCLOCK; + output CFGLINKCONTROLEXTENDEDSYNC; + output CFGLINKCONTROLHWAUTOWIDTHDIS; + output CFGLINKCONTROLLINKDISABLE; + output CFGLINKCONTROLRCB; + output CFGLINKCONTROLRETRAINLINK; + output CFGLINKSTATUSAUTOBANDWIDTHSTATUS; + output CFGLINKSTATUSBANDWIDTHSTATUS; + output CFGLINKSTATUSDLLACTIVE; + output CFGLINKSTATUSLINKTRAINING; + output CFGMGMTRDWRDONEN; + output CFGMSGRECEIVED; + output CFGMSGRECEIVEDASSERTINTA; + output CFGMSGRECEIVEDASSERTINTB; + output CFGMSGRECEIVEDASSERTINTC; + output CFGMSGRECEIVEDASSERTINTD; + output CFGMSGRECEIVEDDEASSERTINTA; + output CFGMSGRECEIVEDDEASSERTINTB; + output CFGMSGRECEIVEDDEASSERTINTC; + output CFGMSGRECEIVEDDEASSERTINTD; + output CFGMSGRECEIVEDERRCOR; + output CFGMSGRECEIVEDERRFATAL; + output CFGMSGRECEIVEDERRNONFATAL; + output CFGMSGRECEIVEDPMASNAK; + output CFGMSGRECEIVEDPMETO; + output CFGMSGRECEIVEDPMETOACK; + output CFGMSGRECEIVEDPMPME; + output CFGMSGRECEIVEDSETSLOTPOWERLIMIT; + output CFGMSGRECEIVEDUNLOCK; + output CFGPMCSRPMEEN; + output CFGPMCSRPMESTATUS; + output CFGPMRCVASREQL1N; + output CFGPMRCVENTERL1N; + output CFGPMRCVENTERL23N; + output CFGPMRCVREQACKN; + output CFGROOTCONTROLPMEINTEN; + output CFGROOTCONTROLSYSERRCORRERREN; + output CFGROOTCONTROLSYSERRFATALERREN; + output CFGROOTCONTROLSYSERRNONFATALERREN; + output CFGSLOTCONTROLELECTROMECHILCTLPULSE; + output CFGTRANSACTION; + output CFGTRANSACTIONTYPE; + output DBGSCLRA; + output DBGSCLRB; + output DBGSCLRC; + output DBGSCLRD; + output DBGSCLRE; + output DBGSCLRF; + output DBGSCLRG; + output DBGSCLRH; + output DBGSCLRI; + output DBGSCLRJ; + output DBGSCLRK; + output DRPRDY; + output LL2BADDLLPERR; + output LL2BADTLPERR; + output LL2PROTOCOLERR; + output LL2RECEIVERERR; + output LL2REPLAYROERR; + output LL2REPLAYTOERR; + output LL2SUSPENDOK; + output LL2TFCINIT1SEQ; + output LL2TFCINIT2SEQ; + output LL2TXIDLE; + output LNKCLKEN; + output MIMRXREN; + output MIMRXWEN; + output MIMTXREN; + output MIMTXWEN; + output PIPERX0POLARITY; + output PIPERX1POLARITY; + output PIPERX2POLARITY; + output PIPERX3POLARITY; + output PIPERX4POLARITY; + output PIPERX5POLARITY; + output PIPERX6POLARITY; + output PIPERX7POLARITY; + output PIPETX0COMPLIANCE; + output PIPETX0ELECIDLE; + output PIPETX1COMPLIANCE; + output PIPETX1ELECIDLE; + output PIPETX2COMPLIANCE; + output PIPETX2ELECIDLE; + output PIPETX3COMPLIANCE; + output PIPETX3ELECIDLE; + output PIPETX4COMPLIANCE; + output PIPETX4ELECIDLE; + output PIPETX5COMPLIANCE; + output PIPETX5ELECIDLE; + output PIPETX6COMPLIANCE; + output PIPETX6ELECIDLE; + output PIPETX7COMPLIANCE; + output PIPETX7ELECIDLE; + output PIPETXDEEMPH; + output PIPETXRATE; + output PIPETXRCVRDET; + output PIPETXRESET; + output PL2L0REQ; + output PL2LINKUP; + output PL2RECEIVERERR; + output PL2RECOVERY; + output PL2RXELECIDLE; + output PL2SUSPENDOK; + output PLDIRECTEDCHANGEDONE; + output PLLINKGEN2CAP; + output PLLINKPARTNERGEN2SUPPORTED; + output PLLINKUPCFGCAP; + output PLPHYLNKUPN; + output PLRECEIVEDHOTRST; + output PLSELLNKRATE; + output RECEIVEDFUNCLVLRSTN; + output TL2ASPMSUSPENDCREDITCHECKOK; + output TL2ASPMSUSPENDREQ; + output TL2ERRFCPE; + output TL2ERRMALFORMED; + output TL2ERRRXOVERFLOW; + output TL2PPMSUSPENDOK; + output TRNLNKUP; + output TRNRECRCERR; + output TRNREOF; + output TRNRERRFWD; + output TRNRSOF; + output TRNRSRCDSC; + output TRNRSRCRDY; + output TRNTCFGREQ; + output TRNTDLLPDSTRDY; + output TRNTERRDROP; + output USERRSTN; + output [11:0] DBGVECC; + output [11:0] PLDBGVEC; + output [11:0] TRNFCCPLD; + output [11:0] TRNFCNPD; + output [11:0] TRNFCPD; + output [127:0] TRNRD; + output [12:0] MIMRXRADDR; + output [12:0] MIMRXWADDR; + output [12:0] MIMTXRADDR; + output [12:0] MIMTXWADDR; + output [15:0] CFGMSGDATA; + output [15:0] DRPDO; + output [15:0] PIPETX0DATA; + output [15:0] PIPETX1DATA; + output [15:0] PIPETX2DATA; + output [15:0] PIPETX3DATA; + output [15:0] PIPETX4DATA; + output [15:0] PIPETX5DATA; + output [15:0] PIPETX6DATA; + output [15:0] PIPETX7DATA; + output [1:0] CFGLINKCONTROLASPMCONTROL; + output [1:0] CFGLINKSTATUSCURRENTSPEED; + output [1:0] CFGPMCSRPOWERSTATE; + output [1:0] PIPETX0CHARISK; + output [1:0] PIPETX0POWERDOWN; + output [1:0] PIPETX1CHARISK; + output [1:0] PIPETX1POWERDOWN; + output [1:0] PIPETX2CHARISK; + output [1:0] PIPETX2POWERDOWN; + output [1:0] PIPETX3CHARISK; + output [1:0] PIPETX3POWERDOWN; + output [1:0] PIPETX4CHARISK; + output [1:0] PIPETX4POWERDOWN; + output [1:0] PIPETX5CHARISK; + output [1:0] PIPETX5POWERDOWN; + output [1:0] PIPETX6CHARISK; + output [1:0] PIPETX6POWERDOWN; + output [1:0] PIPETX7CHARISK; + output [1:0] PIPETX7POWERDOWN; + output [1:0] PL2RXPMSTATE; + output [1:0] PLLANEREVERSALMODE; + output [1:0] PLRXPMSTATE; + output [1:0] PLSELLNKWIDTH; + output [1:0] TRNRDLLPSRCRDY; + output [1:0] TRNRREM; + output [2:0] CFGDEVCONTROLMAXPAYLOAD; + output [2:0] CFGDEVCONTROLMAXREADREQ; + output [2:0] CFGINTERRUPTMMENABLE; + output [2:0] CFGPCIELINKSTATE; + output [2:0] PIPETXMARGIN; + output [2:0] PLINITIALLINKWIDTH; + output [2:0] PLTXPMSTATE; + output [31:0] CFGMGMTDO; + output [3:0] CFGDEVCONTROL2CPLTIMEOUTVAL; + output [3:0] CFGLINKSTATUSNEGOTIATEDWIDTH; + output [3:0] TRNTDSTRDY; + output [4:0] LL2LINKSTATUS; + output [5:0] PLLTSSMSTATE; + output [5:0] TRNTBUFAV; + output [63:0] DBGVECA; + output [63:0] DBGVECB; + output [63:0] TL2ERRHDR; + output [63:0] TRNRDLLPDATA; + output [67:0] MIMRXWDATA; + output [68:0] MIMTXWDATA; + output [6:0] CFGTRANSACTIONADDR; + output [6:0] CFGVCTCVCMAP; + output [7:0] CFGINTERRUPTDO; + output [7:0] TRNFCCPLH; + output [7:0] TRNFCNPH; + output [7:0] TRNFCPH; + output [7:0] TRNRBARHIT; + input CFGERRACSN; + input CFGERRATOMICEGRESSBLOCKEDN; + input CFGERRCORN; + input CFGERRCPLABORTN; + input CFGERRCPLTIMEOUTN; + input CFGERRCPLUNEXPECTN; + input CFGERRECRCN; + input CFGERRINTERNALCORN; + input CFGERRINTERNALUNCORN; + input CFGERRLOCKEDN; + input CFGERRMALFORMEDN; + input CFGERRMCBLOCKEDN; + input CFGERRNORECOVERYN; + input CFGERRPOISONEDN; + input CFGERRPOSTEDN; + input CFGERRURN; + input CFGFORCECOMMONCLOCKOFF; + input CFGFORCEEXTENDEDSYNCON; + input CFGINTERRUPTASSERTN; + input CFGINTERRUPTN; + input CFGINTERRUPTSTATN; + input CFGMGMTRDENN; + input CFGMGMTWRENN; + input CFGMGMTWRREADONLYN; + input CFGMGMTWRRW1CASRWN; + input CFGPMFORCESTATEENN; + input CFGPMHALTASPML0SN; + input CFGPMHALTASPML1N; + input CFGPMSENDPMETON; + input CFGPMTURNOFFOKN; + input CFGPMWAKEN; + input CFGTRNPENDINGN; + input CMRSTN; + input CMSTICKYRSTN; + input DBGSUBMODE; + input DLRSTN; + input DRPCLK; + input DRPEN; + input DRPWE; + input FUNCLVLRSTN; + input LL2SENDASREQL1; + input LL2SENDENTERL1; + input LL2SENDENTERL23; + input LL2SENDPMACK; + input LL2SUSPENDNOW; + input LL2TLPRCV; + input PIPECLK; + input PIPERX0CHANISALIGNED; + input PIPERX0ELECIDLE; + input PIPERX0PHYSTATUS; + input PIPERX0VALID; + input PIPERX1CHANISALIGNED; + input PIPERX1ELECIDLE; + input PIPERX1PHYSTATUS; + input PIPERX1VALID; + input PIPERX2CHANISALIGNED; + input PIPERX2ELECIDLE; + input PIPERX2PHYSTATUS; + input PIPERX2VALID; + input PIPERX3CHANISALIGNED; + input PIPERX3ELECIDLE; + input PIPERX3PHYSTATUS; + input PIPERX3VALID; + input PIPERX4CHANISALIGNED; + input PIPERX4ELECIDLE; + input PIPERX4PHYSTATUS; + input PIPERX4VALID; + input PIPERX5CHANISALIGNED; + input PIPERX5ELECIDLE; + input PIPERX5PHYSTATUS; + input PIPERX5VALID; + input PIPERX6CHANISALIGNED; + input PIPERX6ELECIDLE; + input PIPERX6PHYSTATUS; + input PIPERX6VALID; + input PIPERX7CHANISALIGNED; + input PIPERX7ELECIDLE; + input PIPERX7PHYSTATUS; + input PIPERX7VALID; + input PLDIRECTEDLINKAUTON; + input PLDIRECTEDLINKSPEED; + input PLDIRECTEDLTSSMNEWVLD; + input PLDIRECTEDLTSSMSTALL; + input PLDOWNSTREAMDEEMPHSOURCE; + input PLRSTN; + input PLTRANSMITHOTRST; + input PLUPSTREAMPREFERDEEMPH; + input SYSRSTN; + input TL2ASPMSUSPENDCREDITCHECK; + input TL2PPMSUSPENDREQ; + input TLRSTN; + input TRNRDSTRDY; + input TRNRFCPRET; + input TRNRNPOK; + input TRNRNPREQ; + input TRNTCFGGNT; + input TRNTDLLPSRCRDY; + input TRNTECRCGEN; + input TRNTEOF; + input TRNTERRFWD; + input TRNTSOF; + input TRNTSRCDSC; + input TRNTSRCRDY; + input TRNTSTR; + input USERCLK2; + input USERCLK; + input [127:0] CFGERRAERHEADERLOG; + input [127:0] TRNTD; + input [15:0] CFGDEVID; + input [15:0] CFGSUBSYSID; + input [15:0] CFGSUBSYSVENDID; + input [15:0] CFGVENDID; + input [15:0] DRPDI; + input [15:0] PIPERX0DATA; + input [15:0] PIPERX1DATA; + input [15:0] PIPERX2DATA; + input [15:0] PIPERX3DATA; + input [15:0] PIPERX4DATA; + input [15:0] PIPERX5DATA; + input [15:0] PIPERX6DATA; + input [15:0] PIPERX7DATA; + input [1:0] CFGPMFORCESTATE; + input [1:0] DBGMODE; + input [1:0] PIPERX0CHARISK; + input [1:0] PIPERX1CHARISK; + input [1:0] PIPERX2CHARISK; + input [1:0] PIPERX3CHARISK; + input [1:0] PIPERX4CHARISK; + input [1:0] PIPERX5CHARISK; + input [1:0] PIPERX6CHARISK; + input [1:0] PIPERX7CHARISK; + input [1:0] PLDIRECTEDLINKCHANGE; + input [1:0] PLDIRECTEDLINKWIDTH; + input [1:0] TRNTREM; + input [2:0] CFGDSFUNCTIONNUMBER; + input [2:0] CFGFORCEMPS; + input [2:0] PIPERX0STATUS; + input [2:0] PIPERX1STATUS; + input [2:0] PIPERX2STATUS; + input [2:0] PIPERX3STATUS; + input [2:0] PIPERX4STATUS; + input [2:0] PIPERX5STATUS; + input [2:0] PIPERX6STATUS; + input [2:0] PIPERX7STATUS; + input [2:0] PLDBGMODE; + input [2:0] TRNFCSEL; + input [31:0] CFGMGMTDI; + input [31:0] TRNTDLLPDATA; + input [3:0] CFGMGMTBYTEENN; + input [47:0] CFGERRTLPCPLHEADER; + input [4:0] CFGAERINTERRUPTMSGNUM; + input [4:0] CFGDSDEVICENUMBER; + input [4:0] CFGPCIECAPINTERRUPTMSGNUM; + input [4:0] PL2DIRECTEDLSTATE; + input [5:0] PLDIRECTEDLTSSMNEW; + input [63:0] CFGDSN; + input [67:0] MIMRXRDATA; + input [68:0] MIMTXRDATA; + input [7:0] CFGDSBUSNUMBER; + input [7:0] CFGINTERRUPTDI; + input [7:0] CFGPORTNUMBER; + input [7:0] CFGREVID; + input [8:0] DRPADDR; + input [9:0] CFGMGMTDWADDR; +endmodule + +module PCIE_3_0 (...); + parameter ARI_CAP_ENABLE = "FALSE"; + parameter AXISTEN_IF_CC_ALIGNMENT_MODE = "FALSE"; + parameter AXISTEN_IF_CC_PARITY_CHK = "TRUE"; + parameter AXISTEN_IF_CQ_ALIGNMENT_MODE = "FALSE"; + parameter AXISTEN_IF_ENABLE_CLIENT_TAG = "FALSE"; + parameter [17:0] AXISTEN_IF_ENABLE_MSG_ROUTE = 18'h00000; + parameter AXISTEN_IF_ENABLE_RX_MSG_INTFC = "FALSE"; + parameter AXISTEN_IF_RC_ALIGNMENT_MODE = "FALSE"; + parameter AXISTEN_IF_RC_STRADDLE = "FALSE"; + parameter AXISTEN_IF_RQ_ALIGNMENT_MODE = "FALSE"; + parameter AXISTEN_IF_RQ_PARITY_CHK = "TRUE"; + parameter [1:0] AXISTEN_IF_WIDTH = 2'h2; + parameter CRM_CORE_CLK_FREQ_500 = "TRUE"; + parameter [1:0] CRM_USER_CLK_FREQ = 2'h2; + parameter [7:0] DNSTREAM_LINK_NUM = 8'h00; + parameter [1:0] GEN3_PCS_AUTO_REALIGN = 2'h1; + parameter GEN3_PCS_RX_ELECIDLE_INTERNAL = "TRUE"; + parameter [8:0] LL_ACK_TIMEOUT = 9'h000; + parameter LL_ACK_TIMEOUT_EN = "FALSE"; + parameter integer LL_ACK_TIMEOUT_FUNC = 0; + parameter [15:0] LL_CPL_FC_UPDATE_TIMER = 16'h0000; + parameter LL_CPL_FC_UPDATE_TIMER_OVERRIDE = "FALSE"; + parameter [15:0] LL_FC_UPDATE_TIMER = 16'h0000; + parameter LL_FC_UPDATE_TIMER_OVERRIDE = "FALSE"; + parameter [15:0] LL_NP_FC_UPDATE_TIMER = 16'h0000; + parameter LL_NP_FC_UPDATE_TIMER_OVERRIDE = "FALSE"; + parameter [15:0] LL_P_FC_UPDATE_TIMER = 16'h0000; + parameter LL_P_FC_UPDATE_TIMER_OVERRIDE = "FALSE"; + parameter [8:0] LL_REPLAY_TIMEOUT = 9'h000; + parameter LL_REPLAY_TIMEOUT_EN = "FALSE"; + parameter integer LL_REPLAY_TIMEOUT_FUNC = 0; + parameter [9:0] LTR_TX_MESSAGE_MINIMUM_INTERVAL = 10'h0FA; + parameter LTR_TX_MESSAGE_ON_FUNC_POWER_STATE_CHANGE = "FALSE"; + parameter LTR_TX_MESSAGE_ON_LTR_ENABLE = "FALSE"; + parameter PF0_AER_CAP_ECRC_CHECK_CAPABLE = "FALSE"; + parameter PF0_AER_CAP_ECRC_GEN_CAPABLE = "FALSE"; + parameter [11:0] PF0_AER_CAP_NEXTPTR = 12'h000; + parameter [11:0] PF0_ARI_CAP_NEXTPTR = 12'h000; + parameter [7:0] PF0_ARI_CAP_NEXT_FUNC = 8'h00; + parameter [3:0] PF0_ARI_CAP_VER = 4'h1; + parameter [4:0] PF0_BAR0_APERTURE_SIZE = 5'h03; + parameter [2:0] PF0_BAR0_CONTROL = 3'h4; + parameter [4:0] PF0_BAR1_APERTURE_SIZE = 5'h00; + parameter [2:0] PF0_BAR1_CONTROL = 3'h0; + parameter [4:0] PF0_BAR2_APERTURE_SIZE = 5'h03; + parameter [2:0] PF0_BAR2_CONTROL = 3'h4; + parameter [4:0] PF0_BAR3_APERTURE_SIZE = 5'h03; + parameter [2:0] PF0_BAR3_CONTROL = 3'h0; + parameter [4:0] PF0_BAR4_APERTURE_SIZE = 5'h03; + parameter [2:0] PF0_BAR4_CONTROL = 3'h4; + parameter [4:0] PF0_BAR5_APERTURE_SIZE = 5'h03; + parameter [2:0] PF0_BAR5_CONTROL = 3'h0; + parameter [7:0] PF0_BIST_REGISTER = 8'h00; + parameter [7:0] PF0_CAPABILITY_POINTER = 8'h50; + parameter [23:0] PF0_CLASS_CODE = 24'h000000; + parameter [15:0] PF0_DEVICE_ID = 16'h0000; + parameter PF0_DEV_CAP2_128B_CAS_ATOMIC_COMPLETER_SUPPORT = "TRUE"; + parameter PF0_DEV_CAP2_32B_ATOMIC_COMPLETER_SUPPORT = "TRUE"; + parameter PF0_DEV_CAP2_64B_ATOMIC_COMPLETER_SUPPORT = "TRUE"; + parameter PF0_DEV_CAP2_CPL_TIMEOUT_DISABLE = "TRUE"; + parameter PF0_DEV_CAP2_LTR_SUPPORT = "TRUE"; + parameter [1:0] PF0_DEV_CAP2_OBFF_SUPPORT = 2'h0; + parameter PF0_DEV_CAP2_TPH_COMPLETER_SUPPORT = "FALSE"; + parameter integer PF0_DEV_CAP_ENDPOINT_L0S_LATENCY = 0; + parameter integer PF0_DEV_CAP_ENDPOINT_L1_LATENCY = 0; + parameter PF0_DEV_CAP_EXT_TAG_SUPPORTED = "TRUE"; + parameter PF0_DEV_CAP_FUNCTION_LEVEL_RESET_CAPABLE = "TRUE"; + parameter [2:0] PF0_DEV_CAP_MAX_PAYLOAD_SIZE = 3'h3; + parameter [11:0] PF0_DPA_CAP_NEXTPTR = 12'h000; + parameter [4:0] PF0_DPA_CAP_SUB_STATE_CONTROL = 5'h00; + parameter PF0_DPA_CAP_SUB_STATE_CONTROL_EN = "TRUE"; + parameter [7:0] PF0_DPA_CAP_SUB_STATE_POWER_ALLOCATION0 = 8'h00; + parameter [7:0] PF0_DPA_CAP_SUB_STATE_POWER_ALLOCATION1 = 8'h00; + parameter [7:0] PF0_DPA_CAP_SUB_STATE_POWER_ALLOCATION2 = 8'h00; + parameter [7:0] PF0_DPA_CAP_SUB_STATE_POWER_ALLOCATION3 = 8'h00; + parameter [7:0] PF0_DPA_CAP_SUB_STATE_POWER_ALLOCATION4 = 8'h00; + parameter [7:0] PF0_DPA_CAP_SUB_STATE_POWER_ALLOCATION5 = 8'h00; + parameter [7:0] PF0_DPA_CAP_SUB_STATE_POWER_ALLOCATION6 = 8'h00; + parameter [7:0] PF0_DPA_CAP_SUB_STATE_POWER_ALLOCATION7 = 8'h00; + parameter [3:0] PF0_DPA_CAP_VER = 4'h1; + parameter [11:0] PF0_DSN_CAP_NEXTPTR = 12'h10C; + parameter [4:0] PF0_EXPANSION_ROM_APERTURE_SIZE = 5'h03; + parameter PF0_EXPANSION_ROM_ENABLE = "FALSE"; + parameter [7:0] PF0_INTERRUPT_LINE = 8'h00; + parameter [2:0] PF0_INTERRUPT_PIN = 3'h1; + parameter integer PF0_LINK_CAP_ASPM_SUPPORT = 0; + parameter integer PF0_LINK_CAP_L0S_EXIT_LATENCY_COMCLK_GEN1 = 7; + parameter integer PF0_LINK_CAP_L0S_EXIT_LATENCY_COMCLK_GEN2 = 7; + parameter integer PF0_LINK_CAP_L0S_EXIT_LATENCY_COMCLK_GEN3 = 7; + parameter integer PF0_LINK_CAP_L0S_EXIT_LATENCY_GEN1 = 7; + parameter integer PF0_LINK_CAP_L0S_EXIT_LATENCY_GEN2 = 7; + parameter integer PF0_LINK_CAP_L0S_EXIT_LATENCY_GEN3 = 7; + parameter integer PF0_LINK_CAP_L1_EXIT_LATENCY_COMCLK_GEN1 = 7; + parameter integer PF0_LINK_CAP_L1_EXIT_LATENCY_COMCLK_GEN2 = 7; + parameter integer PF0_LINK_CAP_L1_EXIT_LATENCY_COMCLK_GEN3 = 7; + parameter integer PF0_LINK_CAP_L1_EXIT_LATENCY_GEN1 = 7; + parameter integer PF0_LINK_CAP_L1_EXIT_LATENCY_GEN2 = 7; + parameter integer PF0_LINK_CAP_L1_EXIT_LATENCY_GEN3 = 7; + parameter PF0_LINK_STATUS_SLOT_CLOCK_CONFIG = "TRUE"; + parameter [9:0] PF0_LTR_CAP_MAX_NOSNOOP_LAT = 10'h000; + parameter [9:0] PF0_LTR_CAP_MAX_SNOOP_LAT = 10'h000; + parameter [11:0] PF0_LTR_CAP_NEXTPTR = 12'h000; + parameter [3:0] PF0_LTR_CAP_VER = 4'h1; + parameter [7:0] PF0_MSIX_CAP_NEXTPTR = 8'h00; + parameter integer PF0_MSIX_CAP_PBA_BIR = 0; + parameter [28:0] PF0_MSIX_CAP_PBA_OFFSET = 29'h00000050; + parameter integer PF0_MSIX_CAP_TABLE_BIR = 0; + parameter [28:0] PF0_MSIX_CAP_TABLE_OFFSET = 29'h00000040; + parameter [10:0] PF0_MSIX_CAP_TABLE_SIZE = 11'h000; + parameter integer PF0_MSI_CAP_MULTIMSGCAP = 0; + parameter [7:0] PF0_MSI_CAP_NEXTPTR = 8'h00; + parameter [11:0] PF0_PB_CAP_NEXTPTR = 12'h000; + parameter PF0_PB_CAP_SYSTEM_ALLOCATED = "FALSE"; + parameter [3:0] PF0_PB_CAP_VER = 4'h1; + parameter [7:0] PF0_PM_CAP_ID = 8'h01; + parameter [7:0] PF0_PM_CAP_NEXTPTR = 8'h00; + parameter PF0_PM_CAP_PMESUPPORT_D0 = "TRUE"; + parameter PF0_PM_CAP_PMESUPPORT_D1 = "TRUE"; + parameter PF0_PM_CAP_PMESUPPORT_D3HOT = "TRUE"; + parameter PF0_PM_CAP_SUPP_D1_STATE = "TRUE"; + parameter [2:0] PF0_PM_CAP_VER_ID = 3'h3; + parameter PF0_PM_CSR_NOSOFTRESET = "TRUE"; + parameter PF0_RBAR_CAP_ENABLE = "FALSE"; + parameter [2:0] PF0_RBAR_CAP_INDEX0 = 3'h0; + parameter [2:0] PF0_RBAR_CAP_INDEX1 = 3'h0; + parameter [2:0] PF0_RBAR_CAP_INDEX2 = 3'h0; + parameter [11:0] PF0_RBAR_CAP_NEXTPTR = 12'h000; + parameter [19:0] PF0_RBAR_CAP_SIZE0 = 20'h00000; + parameter [19:0] PF0_RBAR_CAP_SIZE1 = 20'h00000; + parameter [19:0] PF0_RBAR_CAP_SIZE2 = 20'h00000; + parameter [3:0] PF0_RBAR_CAP_VER = 4'h1; + parameter [2:0] PF0_RBAR_NUM = 3'h1; + parameter [7:0] PF0_REVISION_ID = 8'h00; + parameter [4:0] PF0_SRIOV_BAR0_APERTURE_SIZE = 5'h03; + parameter [2:0] PF0_SRIOV_BAR0_CONTROL = 3'h4; + parameter [4:0] PF0_SRIOV_BAR1_APERTURE_SIZE = 5'h00; + parameter [2:0] PF0_SRIOV_BAR1_CONTROL = 3'h0; + parameter [4:0] PF0_SRIOV_BAR2_APERTURE_SIZE = 5'h03; + parameter [2:0] PF0_SRIOV_BAR2_CONTROL = 3'h4; + parameter [4:0] PF0_SRIOV_BAR3_APERTURE_SIZE = 5'h03; + parameter [2:0] PF0_SRIOV_BAR3_CONTROL = 3'h0; + parameter [4:0] PF0_SRIOV_BAR4_APERTURE_SIZE = 5'h03; + parameter [2:0] PF0_SRIOV_BAR4_CONTROL = 3'h4; + parameter [4:0] PF0_SRIOV_BAR5_APERTURE_SIZE = 5'h03; + parameter [2:0] PF0_SRIOV_BAR5_CONTROL = 3'h0; + parameter [15:0] PF0_SRIOV_CAP_INITIAL_VF = 16'h0000; + parameter [11:0] PF0_SRIOV_CAP_NEXTPTR = 12'h000; + parameter [15:0] PF0_SRIOV_CAP_TOTAL_VF = 16'h0000; + parameter [3:0] PF0_SRIOV_CAP_VER = 4'h1; + parameter [15:0] PF0_SRIOV_FIRST_VF_OFFSET = 16'h0000; + parameter [15:0] PF0_SRIOV_FUNC_DEP_LINK = 16'h0000; + parameter [31:0] PF0_SRIOV_SUPPORTED_PAGE_SIZE = 32'h00000000; + parameter [15:0] PF0_SRIOV_VF_DEVICE_ID = 16'h0000; + parameter [15:0] PF0_SUBSYSTEM_ID = 16'h0000; + parameter PF0_TPHR_CAP_DEV_SPECIFIC_MODE = "TRUE"; + parameter PF0_TPHR_CAP_ENABLE = "FALSE"; + parameter PF0_TPHR_CAP_INT_VEC_MODE = "TRUE"; + parameter [11:0] PF0_TPHR_CAP_NEXTPTR = 12'h000; + parameter [2:0] PF0_TPHR_CAP_ST_MODE_SEL = 3'h0; + parameter [1:0] PF0_TPHR_CAP_ST_TABLE_LOC = 2'h0; + parameter [10:0] PF0_TPHR_CAP_ST_TABLE_SIZE = 11'h000; + parameter [3:0] PF0_TPHR_CAP_VER = 4'h1; + parameter [11:0] PF0_VC_CAP_NEXTPTR = 12'h000; + parameter [3:0] PF0_VC_CAP_VER = 4'h1; + parameter PF1_AER_CAP_ECRC_CHECK_CAPABLE = "FALSE"; + parameter PF1_AER_CAP_ECRC_GEN_CAPABLE = "FALSE"; + parameter [11:0] PF1_AER_CAP_NEXTPTR = 12'h000; + parameter [11:0] PF1_ARI_CAP_NEXTPTR = 12'h000; + parameter [7:0] PF1_ARI_CAP_NEXT_FUNC = 8'h00; + parameter [4:0] PF1_BAR0_APERTURE_SIZE = 5'h03; + parameter [2:0] PF1_BAR0_CONTROL = 3'h4; + parameter [4:0] PF1_BAR1_APERTURE_SIZE = 5'h00; + parameter [2:0] PF1_BAR1_CONTROL = 3'h0; + parameter [4:0] PF1_BAR2_APERTURE_SIZE = 5'h03; + parameter [2:0] PF1_BAR2_CONTROL = 3'h4; + parameter [4:0] PF1_BAR3_APERTURE_SIZE = 5'h03; + parameter [2:0] PF1_BAR3_CONTROL = 3'h0; + parameter [4:0] PF1_BAR4_APERTURE_SIZE = 5'h03; + parameter [2:0] PF1_BAR4_CONTROL = 3'h4; + parameter [4:0] PF1_BAR5_APERTURE_SIZE = 5'h03; + parameter [2:0] PF1_BAR5_CONTROL = 3'h0; + parameter [7:0] PF1_BIST_REGISTER = 8'h00; + parameter [7:0] PF1_CAPABILITY_POINTER = 8'h50; + parameter [23:0] PF1_CLASS_CODE = 24'h000000; + parameter [15:0] PF1_DEVICE_ID = 16'h0000; + parameter [2:0] PF1_DEV_CAP_MAX_PAYLOAD_SIZE = 3'h3; + parameter [11:0] PF1_DPA_CAP_NEXTPTR = 12'h000; + parameter [4:0] PF1_DPA_CAP_SUB_STATE_CONTROL = 5'h00; + parameter PF1_DPA_CAP_SUB_STATE_CONTROL_EN = "TRUE"; + parameter [7:0] PF1_DPA_CAP_SUB_STATE_POWER_ALLOCATION0 = 8'h00; + parameter [7:0] PF1_DPA_CAP_SUB_STATE_POWER_ALLOCATION1 = 8'h00; + parameter [7:0] PF1_DPA_CAP_SUB_STATE_POWER_ALLOCATION2 = 8'h00; + parameter [7:0] PF1_DPA_CAP_SUB_STATE_POWER_ALLOCATION3 = 8'h00; + parameter [7:0] PF1_DPA_CAP_SUB_STATE_POWER_ALLOCATION4 = 8'h00; + parameter [7:0] PF1_DPA_CAP_SUB_STATE_POWER_ALLOCATION5 = 8'h00; + parameter [7:0] PF1_DPA_CAP_SUB_STATE_POWER_ALLOCATION6 = 8'h00; + parameter [7:0] PF1_DPA_CAP_SUB_STATE_POWER_ALLOCATION7 = 8'h00; + parameter [3:0] PF1_DPA_CAP_VER = 4'h1; + parameter [11:0] PF1_DSN_CAP_NEXTPTR = 12'h10C; + parameter [4:0] PF1_EXPANSION_ROM_APERTURE_SIZE = 5'h03; + parameter PF1_EXPANSION_ROM_ENABLE = "FALSE"; + parameter [7:0] PF1_INTERRUPT_LINE = 8'h00; + parameter [2:0] PF1_INTERRUPT_PIN = 3'h1; + parameter [7:0] PF1_MSIX_CAP_NEXTPTR = 8'h00; + parameter integer PF1_MSIX_CAP_PBA_BIR = 0; + parameter [28:0] PF1_MSIX_CAP_PBA_OFFSET = 29'h00000050; + parameter integer PF1_MSIX_CAP_TABLE_BIR = 0; + parameter [28:0] PF1_MSIX_CAP_TABLE_OFFSET = 29'h00000040; + parameter [10:0] PF1_MSIX_CAP_TABLE_SIZE = 11'h000; + parameter integer PF1_MSI_CAP_MULTIMSGCAP = 0; + parameter [7:0] PF1_MSI_CAP_NEXTPTR = 8'h00; + parameter [11:0] PF1_PB_CAP_NEXTPTR = 12'h000; + parameter PF1_PB_CAP_SYSTEM_ALLOCATED = "FALSE"; + parameter [3:0] PF1_PB_CAP_VER = 4'h1; + parameter [7:0] PF1_PM_CAP_ID = 8'h01; + parameter [7:0] PF1_PM_CAP_NEXTPTR = 8'h00; + parameter [2:0] PF1_PM_CAP_VER_ID = 3'h3; + parameter PF1_RBAR_CAP_ENABLE = "FALSE"; + parameter [2:0] PF1_RBAR_CAP_INDEX0 = 3'h0; + parameter [2:0] PF1_RBAR_CAP_INDEX1 = 3'h0; + parameter [2:0] PF1_RBAR_CAP_INDEX2 = 3'h0; + parameter [11:0] PF1_RBAR_CAP_NEXTPTR = 12'h000; + parameter [19:0] PF1_RBAR_CAP_SIZE0 = 20'h00000; + parameter [19:0] PF1_RBAR_CAP_SIZE1 = 20'h00000; + parameter [19:0] PF1_RBAR_CAP_SIZE2 = 20'h00000; + parameter [3:0] PF1_RBAR_CAP_VER = 4'h1; + parameter [2:0] PF1_RBAR_NUM = 3'h1; + parameter [7:0] PF1_REVISION_ID = 8'h00; + parameter [4:0] PF1_SRIOV_BAR0_APERTURE_SIZE = 5'h03; + parameter [2:0] PF1_SRIOV_BAR0_CONTROL = 3'h4; + parameter [4:0] PF1_SRIOV_BAR1_APERTURE_SIZE = 5'h00; + parameter [2:0] PF1_SRIOV_BAR1_CONTROL = 3'h0; + parameter [4:0] PF1_SRIOV_BAR2_APERTURE_SIZE = 5'h03; + parameter [2:0] PF1_SRIOV_BAR2_CONTROL = 3'h4; + parameter [4:0] PF1_SRIOV_BAR3_APERTURE_SIZE = 5'h03; + parameter [2:0] PF1_SRIOV_BAR3_CONTROL = 3'h0; + parameter [4:0] PF1_SRIOV_BAR4_APERTURE_SIZE = 5'h03; + parameter [2:0] PF1_SRIOV_BAR4_CONTROL = 3'h4; + parameter [4:0] PF1_SRIOV_BAR5_APERTURE_SIZE = 5'h03; + parameter [2:0] PF1_SRIOV_BAR5_CONTROL = 3'h0; + parameter [15:0] PF1_SRIOV_CAP_INITIAL_VF = 16'h0000; + parameter [11:0] PF1_SRIOV_CAP_NEXTPTR = 12'h000; + parameter [15:0] PF1_SRIOV_CAP_TOTAL_VF = 16'h0000; + parameter [3:0] PF1_SRIOV_CAP_VER = 4'h1; + parameter [15:0] PF1_SRIOV_FIRST_VF_OFFSET = 16'h0000; + parameter [15:0] PF1_SRIOV_FUNC_DEP_LINK = 16'h0000; + parameter [31:0] PF1_SRIOV_SUPPORTED_PAGE_SIZE = 32'h00000000; + parameter [15:0] PF1_SRIOV_VF_DEVICE_ID = 16'h0000; + parameter [15:0] PF1_SUBSYSTEM_ID = 16'h0000; + parameter PF1_TPHR_CAP_DEV_SPECIFIC_MODE = "TRUE"; + parameter PF1_TPHR_CAP_ENABLE = "FALSE"; + parameter PF1_TPHR_CAP_INT_VEC_MODE = "TRUE"; + parameter [11:0] PF1_TPHR_CAP_NEXTPTR = 12'h000; + parameter [2:0] PF1_TPHR_CAP_ST_MODE_SEL = 3'h0; + parameter [1:0] PF1_TPHR_CAP_ST_TABLE_LOC = 2'h0; + parameter [10:0] PF1_TPHR_CAP_ST_TABLE_SIZE = 11'h000; + parameter [3:0] PF1_TPHR_CAP_VER = 4'h1; + parameter PL_DISABLE_EI_INFER_IN_L0 = "FALSE"; + parameter PL_DISABLE_GEN3_DC_BALANCE = "FALSE"; + parameter PL_DISABLE_SCRAMBLING = "FALSE"; + parameter PL_DISABLE_UPCONFIG_CAPABLE = "FALSE"; + parameter PL_EQ_ADAPT_DISABLE_COEFF_CHECK = "FALSE"; + parameter PL_EQ_ADAPT_DISABLE_PRESET_CHECK = "FALSE"; + parameter [4:0] PL_EQ_ADAPT_ITER_COUNT = 5'h02; + parameter [1:0] PL_EQ_ADAPT_REJECT_RETRY_COUNT = 2'h1; + parameter PL_EQ_BYPASS_PHASE23 = "FALSE"; + parameter PL_EQ_SHORT_ADAPT_PHASE = "FALSE"; + parameter [15:0] PL_LANE0_EQ_CONTROL = 16'h3F00; + parameter [15:0] PL_LANE1_EQ_CONTROL = 16'h3F00; + parameter [15:0] PL_LANE2_EQ_CONTROL = 16'h3F00; + parameter [15:0] PL_LANE3_EQ_CONTROL = 16'h3F00; + parameter [15:0] PL_LANE4_EQ_CONTROL = 16'h3F00; + parameter [15:0] PL_LANE5_EQ_CONTROL = 16'h3F00; + parameter [15:0] PL_LANE6_EQ_CONTROL = 16'h3F00; + parameter [15:0] PL_LANE7_EQ_CONTROL = 16'h3F00; + parameter [2:0] PL_LINK_CAP_MAX_LINK_SPEED = 3'h4; + parameter [3:0] PL_LINK_CAP_MAX_LINK_WIDTH = 4'h8; + parameter integer PL_N_FTS_COMCLK_GEN1 = 255; + parameter integer PL_N_FTS_COMCLK_GEN2 = 255; + parameter integer PL_N_FTS_COMCLK_GEN3 = 255; + parameter integer PL_N_FTS_GEN1 = 255; + parameter integer PL_N_FTS_GEN2 = 255; + parameter integer PL_N_FTS_GEN3 = 255; + parameter PL_SIM_FAST_LINK_TRAINING = "FALSE"; + parameter PL_UPSTREAM_FACING = "TRUE"; + parameter [15:0] PM_ASPML0S_TIMEOUT = 16'h05DC; + parameter [19:0] PM_ASPML1_ENTRY_DELAY = 20'h00000; + parameter PM_ENABLE_SLOT_POWER_CAPTURE = "TRUE"; + parameter [31:0] PM_L1_REENTRY_DELAY = 32'h00000000; + parameter [19:0] PM_PME_SERVICE_TIMEOUT_DELAY = 20'h186A0; + parameter [15:0] PM_PME_TURNOFF_ACK_DELAY = 16'h0064; + parameter SIM_VERSION = "1.0"; + parameter integer SPARE_BIT0 = 0; + parameter integer SPARE_BIT1 = 0; + parameter integer SPARE_BIT2 = 0; + parameter integer SPARE_BIT3 = 0; + parameter integer SPARE_BIT4 = 0; + parameter integer SPARE_BIT5 = 0; + parameter integer SPARE_BIT6 = 0; + parameter integer SPARE_BIT7 = 0; + parameter integer SPARE_BIT8 = 0; + parameter [7:0] SPARE_BYTE0 = 8'h00; + parameter [7:0] SPARE_BYTE1 = 8'h00; + parameter [7:0] SPARE_BYTE2 = 8'h00; + parameter [7:0] SPARE_BYTE3 = 8'h00; + parameter [31:0] SPARE_WORD0 = 32'h00000000; + parameter [31:0] SPARE_WORD1 = 32'h00000000; + parameter [31:0] SPARE_WORD2 = 32'h00000000; + parameter [31:0] SPARE_WORD3 = 32'h00000000; + parameter SRIOV_CAP_ENABLE = "FALSE"; + parameter [23:0] TL_COMPL_TIMEOUT_REG0 = 24'hBEBC20; + parameter [27:0] TL_COMPL_TIMEOUT_REG1 = 28'h0000000; + parameter [11:0] TL_CREDITS_CD = 12'h3E0; + parameter [7:0] TL_CREDITS_CH = 8'h20; + parameter [11:0] TL_CREDITS_NPD = 12'h028; + parameter [7:0] TL_CREDITS_NPH = 8'h20; + parameter [11:0] TL_CREDITS_PD = 12'h198; + parameter [7:0] TL_CREDITS_PH = 8'h20; + parameter TL_ENABLE_MESSAGE_RID_CHECK_ENABLE = "TRUE"; + parameter TL_EXTENDED_CFG_EXTEND_INTERFACE_ENABLE = "FALSE"; + parameter TL_LEGACY_CFG_EXTEND_INTERFACE_ENABLE = "FALSE"; + parameter TL_LEGACY_MODE_ENABLE = "FALSE"; + parameter TL_PF_ENABLE_REG = "FALSE"; + parameter TL_TAG_MGMT_ENABLE = "TRUE"; + parameter [11:0] VF0_ARI_CAP_NEXTPTR = 12'h000; + parameter [7:0] VF0_CAPABILITY_POINTER = 8'h50; + parameter integer VF0_MSIX_CAP_PBA_BIR = 0; + parameter [28:0] VF0_MSIX_CAP_PBA_OFFSET = 29'h00000050; + parameter integer VF0_MSIX_CAP_TABLE_BIR = 0; + parameter [28:0] VF0_MSIX_CAP_TABLE_OFFSET = 29'h00000040; + parameter [10:0] VF0_MSIX_CAP_TABLE_SIZE = 11'h000; + parameter integer VF0_MSI_CAP_MULTIMSGCAP = 0; + parameter [7:0] VF0_PM_CAP_ID = 8'h01; + parameter [7:0] VF0_PM_CAP_NEXTPTR = 8'h00; + parameter [2:0] VF0_PM_CAP_VER_ID = 3'h3; + parameter VF0_TPHR_CAP_DEV_SPECIFIC_MODE = "TRUE"; + parameter VF0_TPHR_CAP_ENABLE = "FALSE"; + parameter VF0_TPHR_CAP_INT_VEC_MODE = "TRUE"; + parameter [11:0] VF0_TPHR_CAP_NEXTPTR = 12'h000; + parameter [2:0] VF0_TPHR_CAP_ST_MODE_SEL = 3'h0; + parameter [1:0] VF0_TPHR_CAP_ST_TABLE_LOC = 2'h0; + parameter [10:0] VF0_TPHR_CAP_ST_TABLE_SIZE = 11'h000; + parameter [3:0] VF0_TPHR_CAP_VER = 4'h1; + parameter [11:0] VF1_ARI_CAP_NEXTPTR = 12'h000; + parameter integer VF1_MSIX_CAP_PBA_BIR = 0; + parameter [28:0] VF1_MSIX_CAP_PBA_OFFSET = 29'h00000050; + parameter integer VF1_MSIX_CAP_TABLE_BIR = 0; + parameter [28:0] VF1_MSIX_CAP_TABLE_OFFSET = 29'h00000040; + parameter [10:0] VF1_MSIX_CAP_TABLE_SIZE = 11'h000; + parameter integer VF1_MSI_CAP_MULTIMSGCAP = 0; + parameter [7:0] VF1_PM_CAP_ID = 8'h01; + parameter [7:0] VF1_PM_CAP_NEXTPTR = 8'h00; + parameter [2:0] VF1_PM_CAP_VER_ID = 3'h3; + parameter VF1_TPHR_CAP_DEV_SPECIFIC_MODE = "TRUE"; + parameter VF1_TPHR_CAP_ENABLE = "FALSE"; + parameter VF1_TPHR_CAP_INT_VEC_MODE = "TRUE"; + parameter [11:0] VF1_TPHR_CAP_NEXTPTR = 12'h000; + parameter [2:0] VF1_TPHR_CAP_ST_MODE_SEL = 3'h0; + parameter [1:0] VF1_TPHR_CAP_ST_TABLE_LOC = 2'h0; + parameter [10:0] VF1_TPHR_CAP_ST_TABLE_SIZE = 11'h000; + parameter [3:0] VF1_TPHR_CAP_VER = 4'h1; + parameter [11:0] VF2_ARI_CAP_NEXTPTR = 12'h000; + parameter integer VF2_MSIX_CAP_PBA_BIR = 0; + parameter [28:0] VF2_MSIX_CAP_PBA_OFFSET = 29'h00000050; + parameter integer VF2_MSIX_CAP_TABLE_BIR = 0; + parameter [28:0] VF2_MSIX_CAP_TABLE_OFFSET = 29'h00000040; + parameter [10:0] VF2_MSIX_CAP_TABLE_SIZE = 11'h000; + parameter integer VF2_MSI_CAP_MULTIMSGCAP = 0; + parameter [7:0] VF2_PM_CAP_ID = 8'h01; + parameter [7:0] VF2_PM_CAP_NEXTPTR = 8'h00; + parameter [2:0] VF2_PM_CAP_VER_ID = 3'h3; + parameter VF2_TPHR_CAP_DEV_SPECIFIC_MODE = "TRUE"; + parameter VF2_TPHR_CAP_ENABLE = "FALSE"; + parameter VF2_TPHR_CAP_INT_VEC_MODE = "TRUE"; + parameter [11:0] VF2_TPHR_CAP_NEXTPTR = 12'h000; + parameter [2:0] VF2_TPHR_CAP_ST_MODE_SEL = 3'h0; + parameter [1:0] VF2_TPHR_CAP_ST_TABLE_LOC = 2'h0; + parameter [10:0] VF2_TPHR_CAP_ST_TABLE_SIZE = 11'h000; + parameter [3:0] VF2_TPHR_CAP_VER = 4'h1; + parameter [11:0] VF3_ARI_CAP_NEXTPTR = 12'h000; + parameter integer VF3_MSIX_CAP_PBA_BIR = 0; + parameter [28:0] VF3_MSIX_CAP_PBA_OFFSET = 29'h00000050; + parameter integer VF3_MSIX_CAP_TABLE_BIR = 0; + parameter [28:0] VF3_MSIX_CAP_TABLE_OFFSET = 29'h00000040; + parameter [10:0] VF3_MSIX_CAP_TABLE_SIZE = 11'h000; + parameter integer VF3_MSI_CAP_MULTIMSGCAP = 0; + parameter [7:0] VF3_PM_CAP_ID = 8'h01; + parameter [7:0] VF3_PM_CAP_NEXTPTR = 8'h00; + parameter [2:0] VF3_PM_CAP_VER_ID = 3'h3; + parameter VF3_TPHR_CAP_DEV_SPECIFIC_MODE = "TRUE"; + parameter VF3_TPHR_CAP_ENABLE = "FALSE"; + parameter VF3_TPHR_CAP_INT_VEC_MODE = "TRUE"; + parameter [11:0] VF3_TPHR_CAP_NEXTPTR = 12'h000; + parameter [2:0] VF3_TPHR_CAP_ST_MODE_SEL = 3'h0; + parameter [1:0] VF3_TPHR_CAP_ST_TABLE_LOC = 2'h0; + parameter [10:0] VF3_TPHR_CAP_ST_TABLE_SIZE = 11'h000; + parameter [3:0] VF3_TPHR_CAP_VER = 4'h1; + parameter [11:0] VF4_ARI_CAP_NEXTPTR = 12'h000; + parameter integer VF4_MSIX_CAP_PBA_BIR = 0; + parameter [28:0] VF4_MSIX_CAP_PBA_OFFSET = 29'h00000050; + parameter integer VF4_MSIX_CAP_TABLE_BIR = 0; + parameter [28:0] VF4_MSIX_CAP_TABLE_OFFSET = 29'h00000040; + parameter [10:0] VF4_MSIX_CAP_TABLE_SIZE = 11'h000; + parameter integer VF4_MSI_CAP_MULTIMSGCAP = 0; + parameter [7:0] VF4_PM_CAP_ID = 8'h01; + parameter [7:0] VF4_PM_CAP_NEXTPTR = 8'h00; + parameter [2:0] VF4_PM_CAP_VER_ID = 3'h3; + parameter VF4_TPHR_CAP_DEV_SPECIFIC_MODE = "TRUE"; + parameter VF4_TPHR_CAP_ENABLE = "FALSE"; + parameter VF4_TPHR_CAP_INT_VEC_MODE = "TRUE"; + parameter [11:0] VF4_TPHR_CAP_NEXTPTR = 12'h000; + parameter [2:0] VF4_TPHR_CAP_ST_MODE_SEL = 3'h0; + parameter [1:0] VF4_TPHR_CAP_ST_TABLE_LOC = 2'h0; + parameter [10:0] VF4_TPHR_CAP_ST_TABLE_SIZE = 11'h000; + parameter [3:0] VF4_TPHR_CAP_VER = 4'h1; + parameter [11:0] VF5_ARI_CAP_NEXTPTR = 12'h000; + parameter integer VF5_MSIX_CAP_PBA_BIR = 0; + parameter [28:0] VF5_MSIX_CAP_PBA_OFFSET = 29'h00000050; + parameter integer VF5_MSIX_CAP_TABLE_BIR = 0; + parameter [28:0] VF5_MSIX_CAP_TABLE_OFFSET = 29'h00000040; + parameter [10:0] VF5_MSIX_CAP_TABLE_SIZE = 11'h000; + parameter integer VF5_MSI_CAP_MULTIMSGCAP = 0; + parameter [7:0] VF5_PM_CAP_ID = 8'h01; + parameter [7:0] VF5_PM_CAP_NEXTPTR = 8'h00; + parameter [2:0] VF5_PM_CAP_VER_ID = 3'h3; + parameter VF5_TPHR_CAP_DEV_SPECIFIC_MODE = "TRUE"; + parameter VF5_TPHR_CAP_ENABLE = "FALSE"; + parameter VF5_TPHR_CAP_INT_VEC_MODE = "TRUE"; + parameter [11:0] VF5_TPHR_CAP_NEXTPTR = 12'h000; + parameter [2:0] VF5_TPHR_CAP_ST_MODE_SEL = 3'h0; + parameter [1:0] VF5_TPHR_CAP_ST_TABLE_LOC = 2'h0; + parameter [10:0] VF5_TPHR_CAP_ST_TABLE_SIZE = 11'h000; + parameter [3:0] VF5_TPHR_CAP_VER = 4'h1; + output CFGERRCOROUT; + output CFGERRFATALOUT; + output CFGERRNONFATALOUT; + output CFGEXTREADRECEIVED; + output CFGEXTWRITERECEIVED; + output CFGHOTRESETOUT; + output CFGINPUTUPDATEDONE; + output CFGINTERRUPTAOUTPUT; + output CFGINTERRUPTBOUTPUT; + output CFGINTERRUPTCOUTPUT; + output CFGINTERRUPTDOUTPUT; + output CFGINTERRUPTMSIFAIL; + output CFGINTERRUPTMSIMASKUPDATE; + output CFGINTERRUPTMSISENT; + output CFGINTERRUPTMSIXFAIL; + output CFGINTERRUPTMSIXSENT; + output CFGINTERRUPTSENT; + output CFGLOCALERROR; + output CFGLTRENABLE; + output CFGMCUPDATEDONE; + output CFGMGMTREADWRITEDONE; + output CFGMSGRECEIVED; + output CFGMSGTRANSMITDONE; + output CFGPERFUNCTIONUPDATEDONE; + output CFGPHYLINKDOWN; + output CFGPLSTATUSCHANGE; + output CFGPOWERSTATECHANGEINTERRUPT; + output CFGTPHSTTREADENABLE; + output CFGTPHSTTWRITEENABLE; + output DRPRDY; + output MAXISCQTLAST; + output MAXISCQTVALID; + output MAXISRCTLAST; + output MAXISRCTVALID; + output PCIERQSEQNUMVLD; + output PCIERQTAGVLD; + output PIPERX0POLARITY; + output PIPERX1POLARITY; + output PIPERX2POLARITY; + output PIPERX3POLARITY; + output PIPERX4POLARITY; + output PIPERX5POLARITY; + output PIPERX6POLARITY; + output PIPERX7POLARITY; + output PIPETX0COMPLIANCE; + output PIPETX0DATAVALID; + output PIPETX0ELECIDLE; + output PIPETX0STARTBLOCK; + output PIPETX1COMPLIANCE; + output PIPETX1DATAVALID; + output PIPETX1ELECIDLE; + output PIPETX1STARTBLOCK; + output PIPETX2COMPLIANCE; + output PIPETX2DATAVALID; + output PIPETX2ELECIDLE; + output PIPETX2STARTBLOCK; + output PIPETX3COMPLIANCE; + output PIPETX3DATAVALID; + output PIPETX3ELECIDLE; + output PIPETX3STARTBLOCK; + output PIPETX4COMPLIANCE; + output PIPETX4DATAVALID; + output PIPETX4ELECIDLE; + output PIPETX4STARTBLOCK; + output PIPETX5COMPLIANCE; + output PIPETX5DATAVALID; + output PIPETX5ELECIDLE; + output PIPETX5STARTBLOCK; + output PIPETX6COMPLIANCE; + output PIPETX6DATAVALID; + output PIPETX6ELECIDLE; + output PIPETX6STARTBLOCK; + output PIPETX7COMPLIANCE; + output PIPETX7DATAVALID; + output PIPETX7ELECIDLE; + output PIPETX7STARTBLOCK; + output PIPETXDEEMPH; + output PIPETXRCVRDET; + output PIPETXRESET; + output PIPETXSWING; + output PLEQINPROGRESS; + output [11:0] CFGFCCPLD; + output [11:0] CFGFCNPD; + output [11:0] CFGFCPD; + output [11:0] CFGVFSTATUS; + output [143:0] MIREPLAYRAMWRITEDATA; + output [143:0] MIREQUESTRAMWRITEDATA; + output [15:0] CFGPERFUNCSTATUSDATA; + output [15:0] DBGDATAOUT; + output [15:0] DRPDO; + output [17:0] CFGVFPOWERSTATE; + output [17:0] CFGVFTPHSTMODE; + output [1:0] CFGDPASUBSTATECHANGE; + output [1:0] CFGFLRINPROCESS; + output [1:0] CFGINTERRUPTMSIENABLE; + output [1:0] CFGINTERRUPTMSIXENABLE; + output [1:0] CFGINTERRUPTMSIXMASK; + output [1:0] CFGLINKPOWERSTATE; + output [1:0] CFGOBFFENABLE; + output [1:0] CFGPHYLINKSTATUS; + output [1:0] CFGRCBSTATUS; + output [1:0] CFGTPHREQUESTERENABLE; + output [1:0] MIREPLAYRAMREADENABLE; + output [1:0] MIREPLAYRAMWRITEENABLE; + output [1:0] PCIERQTAGAV; + output [1:0] PCIETFCNPDAV; + output [1:0] PCIETFCNPHAV; + output [1:0] PIPERX0EQCONTROL; + output [1:0] PIPERX1EQCONTROL; + output [1:0] PIPERX2EQCONTROL; + output [1:0] PIPERX3EQCONTROL; + output [1:0] PIPERX4EQCONTROL; + output [1:0] PIPERX5EQCONTROL; + output [1:0] PIPERX6EQCONTROL; + output [1:0] PIPERX7EQCONTROL; + output [1:0] PIPETX0CHARISK; + output [1:0] PIPETX0EQCONTROL; + output [1:0] PIPETX0POWERDOWN; + output [1:0] PIPETX0SYNCHEADER; + output [1:0] PIPETX1CHARISK; + output [1:0] PIPETX1EQCONTROL; + output [1:0] PIPETX1POWERDOWN; + output [1:0] PIPETX1SYNCHEADER; + output [1:0] PIPETX2CHARISK; + output [1:0] PIPETX2EQCONTROL; + output [1:0] PIPETX2POWERDOWN; + output [1:0] PIPETX2SYNCHEADER; + output [1:0] PIPETX3CHARISK; + output [1:0] PIPETX3EQCONTROL; + output [1:0] PIPETX3POWERDOWN; + output [1:0] PIPETX3SYNCHEADER; + output [1:0] PIPETX4CHARISK; + output [1:0] PIPETX4EQCONTROL; + output [1:0] PIPETX4POWERDOWN; + output [1:0] PIPETX4SYNCHEADER; + output [1:0] PIPETX5CHARISK; + output [1:0] PIPETX5EQCONTROL; + output [1:0] PIPETX5POWERDOWN; + output [1:0] PIPETX5SYNCHEADER; + output [1:0] PIPETX6CHARISK; + output [1:0] PIPETX6EQCONTROL; + output [1:0] PIPETX6POWERDOWN; + output [1:0] PIPETX6SYNCHEADER; + output [1:0] PIPETX7CHARISK; + output [1:0] PIPETX7EQCONTROL; + output [1:0] PIPETX7POWERDOWN; + output [1:0] PIPETX7SYNCHEADER; + output [1:0] PIPETXRATE; + output [1:0] PLEQPHASE; + output [255:0] MAXISCQTDATA; + output [255:0] MAXISRCTDATA; + output [2:0] CFGCURRENTSPEED; + output [2:0] CFGMAXPAYLOAD; + output [2:0] CFGMAXREADREQ; + output [2:0] CFGTPHFUNCTIONNUM; + output [2:0] PIPERX0EQPRESET; + output [2:0] PIPERX1EQPRESET; + output [2:0] PIPERX2EQPRESET; + output [2:0] PIPERX3EQPRESET; + output [2:0] PIPERX4EQPRESET; + output [2:0] PIPERX5EQPRESET; + output [2:0] PIPERX6EQPRESET; + output [2:0] PIPERX7EQPRESET; + output [2:0] PIPETXMARGIN; + output [31:0] CFGEXTWRITEDATA; + output [31:0] CFGINTERRUPTMSIDATA; + output [31:0] CFGMGMTREADDATA; + output [31:0] CFGTPHSTTWRITEDATA; + output [31:0] PIPETX0DATA; + output [31:0] PIPETX1DATA; + output [31:0] PIPETX2DATA; + output [31:0] PIPETX3DATA; + output [31:0] PIPETX4DATA; + output [31:0] PIPETX5DATA; + output [31:0] PIPETX6DATA; + output [31:0] PIPETX7DATA; + output [3:0] CFGEXTWRITEBYTEENABLE; + output [3:0] CFGNEGOTIATEDWIDTH; + output [3:0] CFGTPHSTTWRITEBYTEVALID; + output [3:0] MICOMPLETIONRAMREADENABLEL; + output [3:0] MICOMPLETIONRAMREADENABLEU; + output [3:0] MICOMPLETIONRAMWRITEENABLEL; + output [3:0] MICOMPLETIONRAMWRITEENABLEU; + output [3:0] MIREQUESTRAMREADENABLE; + output [3:0] MIREQUESTRAMWRITEENABLE; + output [3:0] PCIERQSEQNUM; + output [3:0] PIPERX0EQLPTXPRESET; + output [3:0] PIPERX1EQLPTXPRESET; + output [3:0] PIPERX2EQLPTXPRESET; + output [3:0] PIPERX3EQLPTXPRESET; + output [3:0] PIPERX4EQLPTXPRESET; + output [3:0] PIPERX5EQLPTXPRESET; + output [3:0] PIPERX6EQLPTXPRESET; + output [3:0] PIPERX7EQLPTXPRESET; + output [3:0] PIPETX0EQPRESET; + output [3:0] PIPETX1EQPRESET; + output [3:0] PIPETX2EQPRESET; + output [3:0] PIPETX3EQPRESET; + output [3:0] PIPETX4EQPRESET; + output [3:0] PIPETX5EQPRESET; + output [3:0] PIPETX6EQPRESET; + output [3:0] PIPETX7EQPRESET; + output [3:0] SAXISCCTREADY; + output [3:0] SAXISRQTREADY; + output [4:0] CFGMSGRECEIVEDTYPE; + output [4:0] CFGTPHSTTADDRESS; + output [5:0] CFGFUNCTIONPOWERSTATE; + output [5:0] CFGINTERRUPTMSIMMENABLE; + output [5:0] CFGINTERRUPTMSIVFENABLE; + output [5:0] CFGINTERRUPTMSIXVFENABLE; + output [5:0] CFGINTERRUPTMSIXVFMASK; + output [5:0] CFGLTSSMSTATE; + output [5:0] CFGTPHSTMODE; + output [5:0] CFGVFFLRINPROCESS; + output [5:0] CFGVFTPHREQUESTERENABLE; + output [5:0] PCIECQNPREQCOUNT; + output [5:0] PCIERQTAG; + output [5:0] PIPERX0EQLPLFFS; + output [5:0] PIPERX1EQLPLFFS; + output [5:0] PIPERX2EQLPLFFS; + output [5:0] PIPERX3EQLPLFFS; + output [5:0] PIPERX4EQLPLFFS; + output [5:0] PIPERX5EQLPLFFS; + output [5:0] PIPERX6EQLPLFFS; + output [5:0] PIPERX7EQLPLFFS; + output [5:0] PIPETX0EQDEEMPH; + output [5:0] PIPETX1EQDEEMPH; + output [5:0] PIPETX2EQDEEMPH; + output [5:0] PIPETX3EQDEEMPH; + output [5:0] PIPETX4EQDEEMPH; + output [5:0] PIPETX5EQDEEMPH; + output [5:0] PIPETX6EQDEEMPH; + output [5:0] PIPETX7EQDEEMPH; + output [71:0] MICOMPLETIONRAMWRITEDATAL; + output [71:0] MICOMPLETIONRAMWRITEDATAU; + output [74:0] MAXISRCTUSER; + output [7:0] CFGEXTFUNCTIONNUMBER; + output [7:0] CFGFCCPLH; + output [7:0] CFGFCNPH; + output [7:0] CFGFCPH; + output [7:0] CFGFUNCTIONSTATUS; + output [7:0] CFGMSGRECEIVEDDATA; + output [7:0] MAXISCQTKEEP; + output [7:0] MAXISRCTKEEP; + output [7:0] PLGEN3PCSRXSLIDE; + output [84:0] MAXISCQTUSER; + output [8:0] MIREPLAYRAMADDRESS; + output [8:0] MIREQUESTRAMREADADDRESSA; + output [8:0] MIREQUESTRAMREADADDRESSB; + output [8:0] MIREQUESTRAMWRITEADDRESSA; + output [8:0] MIREQUESTRAMWRITEADDRESSB; + output [9:0] CFGEXTREGISTERNUMBER; + output [9:0] MICOMPLETIONRAMREADADDRESSAL; + output [9:0] MICOMPLETIONRAMREADADDRESSAU; + output [9:0] MICOMPLETIONRAMREADADDRESSBL; + output [9:0] MICOMPLETIONRAMREADADDRESSBU; + output [9:0] MICOMPLETIONRAMWRITEADDRESSAL; + output [9:0] MICOMPLETIONRAMWRITEADDRESSAU; + output [9:0] MICOMPLETIONRAMWRITEADDRESSBL; + output [9:0] MICOMPLETIONRAMWRITEADDRESSBU; + input CFGCONFIGSPACEENABLE; + input CFGERRCORIN; + input CFGERRUNCORIN; + input CFGEXTREADDATAVALID; + input CFGHOTRESETIN; + input CFGINPUTUPDATEREQUEST; + input CFGINTERRUPTMSITPHPRESENT; + input CFGINTERRUPTMSIXINT; + input CFGLINKTRAININGENABLE; + input CFGMCUPDATEREQUEST; + input CFGMGMTREAD; + input CFGMGMTTYPE1CFGREGACCESS; + input CFGMGMTWRITE; + input CFGMSGTRANSMIT; + input CFGPERFUNCTIONOUTPUTREQUEST; + input CFGPOWERSTATECHANGEACK; + input CFGREQPMTRANSITIONL23READY; + input CFGTPHSTTREADDATAVALID; + input CORECLK; + input CORECLKMICOMPLETIONRAML; + input CORECLKMICOMPLETIONRAMU; + input CORECLKMIREPLAYRAM; + input CORECLKMIREQUESTRAM; + input DRPCLK; + input DRPEN; + input DRPWE; + input MGMTRESETN; + input MGMTSTICKYRESETN; + input PCIECQNPREQ; + input PIPECLK; + input PIPERESETN; + input PIPERX0DATAVALID; + input PIPERX0ELECIDLE; + input PIPERX0EQDONE; + input PIPERX0EQLPADAPTDONE; + input PIPERX0EQLPLFFSSEL; + input PIPERX0PHYSTATUS; + input PIPERX0STARTBLOCK; + input PIPERX0VALID; + input PIPERX1DATAVALID; + input PIPERX1ELECIDLE; + input PIPERX1EQDONE; + input PIPERX1EQLPADAPTDONE; + input PIPERX1EQLPLFFSSEL; + input PIPERX1PHYSTATUS; + input PIPERX1STARTBLOCK; + input PIPERX1VALID; + input PIPERX2DATAVALID; + input PIPERX2ELECIDLE; + input PIPERX2EQDONE; + input PIPERX2EQLPADAPTDONE; + input PIPERX2EQLPLFFSSEL; + input PIPERX2PHYSTATUS; + input PIPERX2STARTBLOCK; + input PIPERX2VALID; + input PIPERX3DATAVALID; + input PIPERX3ELECIDLE; + input PIPERX3EQDONE; + input PIPERX3EQLPADAPTDONE; + input PIPERX3EQLPLFFSSEL; + input PIPERX3PHYSTATUS; + input PIPERX3STARTBLOCK; + input PIPERX3VALID; + input PIPERX4DATAVALID; + input PIPERX4ELECIDLE; + input PIPERX4EQDONE; + input PIPERX4EQLPADAPTDONE; + input PIPERX4EQLPLFFSSEL; + input PIPERX4PHYSTATUS; + input PIPERX4STARTBLOCK; + input PIPERX4VALID; + input PIPERX5DATAVALID; + input PIPERX5ELECIDLE; + input PIPERX5EQDONE; + input PIPERX5EQLPADAPTDONE; + input PIPERX5EQLPLFFSSEL; + input PIPERX5PHYSTATUS; + input PIPERX5STARTBLOCK; + input PIPERX5VALID; + input PIPERX6DATAVALID; + input PIPERX6ELECIDLE; + input PIPERX6EQDONE; + input PIPERX6EQLPADAPTDONE; + input PIPERX6EQLPLFFSSEL; + input PIPERX6PHYSTATUS; + input PIPERX6STARTBLOCK; + input PIPERX6VALID; + input PIPERX7DATAVALID; + input PIPERX7ELECIDLE; + input PIPERX7EQDONE; + input PIPERX7EQLPADAPTDONE; + input PIPERX7EQLPLFFSSEL; + input PIPERX7PHYSTATUS; + input PIPERX7STARTBLOCK; + input PIPERX7VALID; + input PIPETX0EQDONE; + input PIPETX1EQDONE; + input PIPETX2EQDONE; + input PIPETX3EQDONE; + input PIPETX4EQDONE; + input PIPETX5EQDONE; + input PIPETX6EQDONE; + input PIPETX7EQDONE; + input PLDISABLESCRAMBLER; + input PLEQRESETEIEOSCOUNT; + input PLGEN3PCSDISABLE; + input RECCLK; + input RESETN; + input SAXISCCTLAST; + input SAXISCCTVALID; + input SAXISRQTLAST; + input SAXISRQTVALID; + input USERCLK; + input [10:0] DRPADDR; + input [143:0] MICOMPLETIONRAMREADDATA; + input [143:0] MIREPLAYRAMREADDATA; + input [143:0] MIREQUESTRAMREADDATA; + input [15:0] CFGDEVID; + input [15:0] CFGSUBSYSID; + input [15:0] CFGSUBSYSVENDID; + input [15:0] CFGVENDID; + input [15:0] DRPDI; + input [17:0] PIPERX0EQLPNEWTXCOEFFORPRESET; + input [17:0] PIPERX1EQLPNEWTXCOEFFORPRESET; + input [17:0] PIPERX2EQLPNEWTXCOEFFORPRESET; + input [17:0] PIPERX3EQLPNEWTXCOEFFORPRESET; + input [17:0] PIPERX4EQLPNEWTXCOEFFORPRESET; + input [17:0] PIPERX5EQLPNEWTXCOEFFORPRESET; + input [17:0] PIPERX6EQLPNEWTXCOEFFORPRESET; + input [17:0] PIPERX7EQLPNEWTXCOEFFORPRESET; + input [17:0] PIPETX0EQCOEFF; + input [17:0] PIPETX1EQCOEFF; + input [17:0] PIPETX2EQCOEFF; + input [17:0] PIPETX3EQCOEFF; + input [17:0] PIPETX4EQCOEFF; + input [17:0] PIPETX5EQCOEFF; + input [17:0] PIPETX6EQCOEFF; + input [17:0] PIPETX7EQCOEFF; + input [18:0] CFGMGMTADDR; + input [1:0] CFGFLRDONE; + input [1:0] CFGINTERRUPTMSITPHTYPE; + input [1:0] CFGINTERRUPTPENDING; + input [1:0] PIPERX0CHARISK; + input [1:0] PIPERX0SYNCHEADER; + input [1:0] PIPERX1CHARISK; + input [1:0] PIPERX1SYNCHEADER; + input [1:0] PIPERX2CHARISK; + input [1:0] PIPERX2SYNCHEADER; + input [1:0] PIPERX3CHARISK; + input [1:0] PIPERX3SYNCHEADER; + input [1:0] PIPERX4CHARISK; + input [1:0] PIPERX4SYNCHEADER; + input [1:0] PIPERX5CHARISK; + input [1:0] PIPERX5SYNCHEADER; + input [1:0] PIPERX6CHARISK; + input [1:0] PIPERX6SYNCHEADER; + input [1:0] PIPERX7CHARISK; + input [1:0] PIPERX7SYNCHEADER; + input [21:0] MAXISCQTREADY; + input [21:0] MAXISRCTREADY; + input [255:0] SAXISCCTDATA; + input [255:0] SAXISRQTDATA; + input [2:0] CFGDSFUNCTIONNUMBER; + input [2:0] CFGFCSEL; + input [2:0] CFGINTERRUPTMSIATTR; + input [2:0] CFGINTERRUPTMSIFUNCTIONNUMBER; + input [2:0] CFGMSGTRANSMITTYPE; + input [2:0] CFGPERFUNCSTATUSCONTROL; + input [2:0] CFGPERFUNCTIONNUMBER; + input [2:0] PIPERX0STATUS; + input [2:0] PIPERX1STATUS; + input [2:0] PIPERX2STATUS; + input [2:0] PIPERX3STATUS; + input [2:0] PIPERX4STATUS; + input [2:0] PIPERX5STATUS; + input [2:0] PIPERX6STATUS; + input [2:0] PIPERX7STATUS; + input [31:0] CFGEXTREADDATA; + input [31:0] CFGINTERRUPTMSIINT; + input [31:0] CFGINTERRUPTMSIXDATA; + input [31:0] CFGMGMTWRITEDATA; + input [31:0] CFGMSGTRANSMITDATA; + input [31:0] CFGTPHSTTREADDATA; + input [31:0] PIPERX0DATA; + input [31:0] PIPERX1DATA; + input [31:0] PIPERX2DATA; + input [31:0] PIPERX3DATA; + input [31:0] PIPERX4DATA; + input [31:0] PIPERX5DATA; + input [31:0] PIPERX6DATA; + input [31:0] PIPERX7DATA; + input [32:0] SAXISCCTUSER; + input [3:0] CFGINTERRUPTINT; + input [3:0] CFGINTERRUPTMSISELECT; + input [3:0] CFGMGMTBYTEENABLE; + input [4:0] CFGDSDEVICENUMBER; + input [59:0] SAXISRQTUSER; + input [5:0] CFGVFFLRDONE; + input [5:0] PIPEEQFS; + input [5:0] PIPEEQLF; + input [63:0] CFGDSN; + input [63:0] CFGINTERRUPTMSIPENDINGSTATUS; + input [63:0] CFGINTERRUPTMSIXADDRESS; + input [7:0] CFGDSBUSNUMBER; + input [7:0] CFGDSPORTNUMBER; + input [7:0] CFGREVID; + input [7:0] PLGEN3PCSRXSYNCDONE; + input [7:0] SAXISCCTKEEP; + input [7:0] SAXISRQTKEEP; + input [8:0] CFGINTERRUPTMSITPHSTTAG; +endmodule + +module XADC (...); + parameter [15:0] INIT_40 = 16'h0; + parameter [15:0] INIT_41 = 16'h0; + parameter [15:0] INIT_42 = 16'h0800; + parameter [15:0] INIT_43 = 16'h0; + parameter [15:0] INIT_44 = 16'h0; + parameter [15:0] INIT_45 = 16'h0; + parameter [15:0] INIT_46 = 16'h0; + parameter [15:0] INIT_47 = 16'h0; + parameter [15:0] INIT_48 = 16'h0; + parameter [15:0] INIT_49 = 16'h0; + parameter [15:0] INIT_4A = 16'h0; + parameter [15:0] INIT_4B = 16'h0; + parameter [15:0] INIT_4C = 16'h0; + parameter [15:0] INIT_4D = 16'h0; + parameter [15:0] INIT_4E = 16'h0; + parameter [15:0] INIT_4F = 16'h0; + parameter [15:0] INIT_50 = 16'h0; + parameter [15:0] INIT_51 = 16'h0; + parameter [15:0] INIT_52 = 16'h0; + parameter [15:0] INIT_53 = 16'h0; + parameter [15:0] INIT_54 = 16'h0; + parameter [15:0] INIT_55 = 16'h0; + parameter [15:0] INIT_56 = 16'h0; + parameter [15:0] INIT_57 = 16'h0; + parameter [15:0] INIT_58 = 16'h0; + parameter [15:0] INIT_59 = 16'h0; + parameter [15:0] INIT_5A = 16'h0; + parameter [15:0] INIT_5B = 16'h0; + parameter [15:0] INIT_5C = 16'h0; + parameter [15:0] INIT_5D = 16'h0; + parameter [15:0] INIT_5E = 16'h0; + parameter [15:0] INIT_5F = 16'h0; + parameter IS_CONVSTCLK_INVERTED = 1'b0; + parameter IS_DCLK_INVERTED = 1'b0; + parameter SIM_DEVICE = "7SERIES"; + parameter SIM_MONITOR_FILE = "design.txt"; + output BUSY; + output DRDY; + output EOC; + output EOS; + output JTAGBUSY; + output JTAGLOCKED; + output JTAGMODIFIED; + output OT; + output [15:0] DO; + output [7:0] ALM; + output [4:0] CHANNEL; + output [4:0] MUXADDR; + input CONVST; + (* invertible_pin = "IS_CONVSTCLK_INVERTED" *) + input CONVSTCLK; + (* invertible_pin = "IS_DCLK_INVERTED" *) + input DCLK; + input DEN; + input DWE; + input RESET; + input VN; + input VP; + input [15:0] DI; + input [15:0] VAUXN; + input [15:0] VAUXP; + input [6:0] DADDR; +endmodule + +module DSP48E1 (...); + parameter integer ACASCREG = 1; + parameter integer ADREG = 1; + parameter integer ALUMODEREG = 1; + parameter integer AREG = 1; + parameter AUTORESET_PATDET = "NO_RESET"; + parameter A_INPUT = "DIRECT"; + parameter integer BCASCREG = 1; + parameter integer BREG = 1; + parameter B_INPUT = "DIRECT"; + parameter integer CARRYINREG = 1; + parameter integer CARRYINSELREG = 1; + parameter integer CREG = 1; + parameter integer DREG = 1; + parameter integer INMODEREG = 1; + parameter integer MREG = 1; + parameter integer OPMODEREG = 1; + parameter integer PREG = 1; + parameter SEL_MASK = "MASK"; + parameter SEL_PATTERN = "PATTERN"; + parameter USE_DPORT = "FALSE"; + parameter USE_MULT = "MULTIPLY"; + parameter USE_PATTERN_DETECT = "NO_PATDET"; + parameter USE_SIMD = "ONE48"; + parameter [47:0] MASK = 48'h3FFFFFFFFFFF; + parameter [47:0] PATTERN = 48'h000000000000; + parameter [3:0] IS_ALUMODE_INVERTED = 4'b0; + parameter [0:0] IS_CARRYIN_INVERTED = 1'b0; + parameter [0:0] IS_CLK_INVERTED = 1'b0; + parameter [4:0] IS_INMODE_INVERTED = 5'b0; + parameter [6:0] IS_OPMODE_INVERTED = 7'b0; + output [29:0] ACOUT; + output [17:0] BCOUT; + output CARRYCASCOUT; + output [3:0] CARRYOUT; + output MULTSIGNOUT; + output OVERFLOW; + output [47:0] P; + output PATTERNBDETECT; + output PATTERNDETECT; + output [47:0] PCOUT; + output UNDERFLOW; + input [29:0] A; + input [29:0] ACIN; + (* invertible_pin = "IS_ALUMODE_INVERTED" *) + input [3:0] ALUMODE; + input [17:0] B; + input [17:0] BCIN; + input [47:0] C; + input CARRYCASCIN; + (* invertible_pin = "IS_CARRYIN_INVERTED" *) + input CARRYIN; + input [2:0] CARRYINSEL; + input CEA1; + input CEA2; + input CEAD; + input CEALUMODE; + input CEB1; + input CEB2; + input CEC; + input CECARRYIN; + input CECTRL; + input CED; + input CEINMODE; + input CEM; + input CEP; + (* clkbuf_sink *) + (* invertible_pin = "IS_CLK_INVERTED" *) + input CLK; + input [24:0] D; + (* invertible_pin = "IS_INMODE_INVERTED" *) + input [4:0] INMODE; + input MULTSIGNIN; + (* invertible_pin = "IS_OPMODE_INVERTED" *) + input [6:0] OPMODE; + input [47:0] PCIN; + input RSTA; + input RSTALLCARRYIN; + input RSTALUMODE; + input RSTB; + input RSTC; + input RSTCTRL; + input RSTD; + input RSTINMODE; + input RSTM; + input RSTP; +endmodule + +module BUFGCE (...); + parameter CE_TYPE = "SYNC"; + parameter [0:0] IS_CE_INVERTED = 1'b0; + parameter [0:0] IS_I_INVERTED = 1'b0; + (* clkbuf_driver *) + output O; + (* invertible_pin = "IS_CE_INVERTED" *) + input CE; + (* invertible_pin = "IS_I_INVERTED" *) + input I; +endmodule + +module BUFGCE_1 (...); + (* clkbuf_driver *) + output O; + input CE; + input I; +endmodule + +module BUFGMUX (...); + parameter CLK_SEL_TYPE = "SYNC"; + (* clkbuf_driver *) + output O; + input I0; + input I1; + input S; +endmodule + +module BUFGMUX_1 (...); + parameter CLK_SEL_TYPE = "SYNC"; + (* clkbuf_driver *) + output O; + input I0; + input I1; + input S; +endmodule + +module BUFGMUX_CTRL (...); + (* clkbuf_driver *) + output O; + input I0; + input I1; + input S; +endmodule + +module BUFH (...); + (* clkbuf_driver *) + output O; + input I; +endmodule + +module BUFIO (...); + (* clkbuf_driver *) + output O; + input I; +endmodule + +module BUFMR (...); + (* clkbuf_driver *) + output O; + input I; +endmodule + +module BUFMRCE (...); + parameter CE_TYPE = "SYNC"; + parameter integer INIT_OUT = 0; + parameter [0:0] IS_CE_INVERTED = 1'b0; + (* clkbuf_driver *) + output O; + (* invertible_pin = "IS_CE_INVERTED" *) + input CE; + input I; +endmodule + +module BUFR (...); + parameter BUFR_DIVIDE = "BYPASS"; + parameter SIM_DEVICE = "7SERIES"; + (* clkbuf_driver *) + output O; + input CE; + input CLR; + input I; +endmodule + +module MMCME2_ADV (...); + parameter BANDWIDTH = "OPTIMIZED"; + parameter real CLKFBOUT_MULT_F = 5.000; + parameter real CLKFBOUT_PHASE = 0.000; + parameter CLKFBOUT_USE_FINE_PS = "FALSE"; + parameter real CLKIN1_PERIOD = 0.000; + parameter real CLKIN2_PERIOD = 0.000; + parameter real CLKIN_FREQ_MAX = 1066.000; + parameter real CLKIN_FREQ_MIN = 10.000; + parameter real CLKOUT0_DIVIDE_F = 1.000; + parameter real CLKOUT0_DUTY_CYCLE = 0.500; + parameter real CLKOUT0_PHASE = 0.000; + parameter CLKOUT0_USE_FINE_PS = "FALSE"; + parameter integer CLKOUT1_DIVIDE = 1; + parameter real CLKOUT1_DUTY_CYCLE = 0.500; + parameter real CLKOUT1_PHASE = 0.000; + parameter CLKOUT1_USE_FINE_PS = "FALSE"; + parameter integer CLKOUT2_DIVIDE = 1; + parameter real CLKOUT2_DUTY_CYCLE = 0.500; + parameter real CLKOUT2_PHASE = 0.000; + parameter CLKOUT2_USE_FINE_PS = "FALSE"; + parameter integer CLKOUT3_DIVIDE = 1; + parameter real CLKOUT3_DUTY_CYCLE = 0.500; + parameter real CLKOUT3_PHASE = 0.000; + parameter CLKOUT3_USE_FINE_PS = "FALSE"; + parameter CLKOUT4_CASCADE = "FALSE"; + parameter integer CLKOUT4_DIVIDE = 1; + parameter real CLKOUT4_DUTY_CYCLE = 0.500; + parameter real CLKOUT4_PHASE = 0.000; + parameter CLKOUT4_USE_FINE_PS = "FALSE"; + parameter integer CLKOUT5_DIVIDE = 1; + parameter real CLKOUT5_DUTY_CYCLE = 0.500; + parameter real CLKOUT5_PHASE = 0.000; + parameter CLKOUT5_USE_FINE_PS = "FALSE"; + parameter integer CLKOUT6_DIVIDE = 1; + parameter real CLKOUT6_DUTY_CYCLE = 0.500; + parameter real CLKOUT6_PHASE = 0.000; + parameter CLKOUT6_USE_FINE_PS = "FALSE"; + parameter real CLKPFD_FREQ_MAX = 550.000; + parameter real CLKPFD_FREQ_MIN = 10.000; + parameter COMPENSATION = "ZHOLD"; + parameter integer DIVCLK_DIVIDE = 1; + parameter [0:0] IS_CLKINSEL_INVERTED = 1'b0; + parameter [0:0] IS_PSEN_INVERTED = 1'b0; + parameter [0:0] IS_PSINCDEC_INVERTED = 1'b0; + parameter [0:0] IS_PWRDWN_INVERTED = 1'b0; + parameter [0:0] IS_RST_INVERTED = 1'b0; + parameter real REF_JITTER1 = 0.010; + parameter real REF_JITTER2 = 0.010; + parameter SS_EN = "FALSE"; + parameter SS_MODE = "CENTER_HIGH"; + parameter integer SS_MOD_PERIOD = 10000; + parameter STARTUP_WAIT = "FALSE"; + parameter real VCOCLK_FREQ_MAX = 1600.000; + parameter real VCOCLK_FREQ_MIN = 600.000; + parameter STARTUP_WAIT = "FALSE"; + output CLKFBOUT; + output CLKFBOUTB; + output CLKFBSTOPPED; + output CLKINSTOPPED; + output CLKOUT0; + output CLKOUT0B; + output CLKOUT1; + output CLKOUT1B; + output CLKOUT2; + output CLKOUT2B; + output CLKOUT3; + output CLKOUT3B; + output CLKOUT4; + output CLKOUT5; + output CLKOUT6; + output [15:0] DO; + output DRDY; + output LOCKED; + output PSDONE; + input CLKFBIN; + input CLKIN1; + input CLKIN2; + (* invertible_pin = "IS_CLKINSEL_INVERTED" *) + input CLKINSEL; + input [6:0] DADDR; + input DCLK; + input DEN; + input [15:0] DI; + input DWE; + input PSCLK; + (* invertible_pin = "IS_PSEN_INVERTED" *) + input PSEN; + (* invertible_pin = "IS_PSINCDEC_INVERTED" *) + input PSINCDEC; + (* invertible_pin = "IS_PWRDWN_INVERTED" *) + input PWRDWN; + (* invertible_pin = "IS_RST_INVERTED" *) + input RST; +endmodule + +module MMCME2_BASE (...); + parameter BANDWIDTH = "OPTIMIZED"; + parameter real CLKFBOUT_MULT_F = 5.000; + parameter real CLKFBOUT_PHASE = 0.000; + parameter real CLKIN1_PERIOD = 0.000; + parameter real CLKOUT0_DIVIDE_F = 1.000; + parameter real CLKOUT0_DUTY_CYCLE = 0.500; + parameter real CLKOUT0_PHASE = 0.000; + parameter integer CLKOUT1_DIVIDE = 1; + parameter real CLKOUT1_DUTY_CYCLE = 0.500; + parameter real CLKOUT1_PHASE = 0.000; + parameter integer CLKOUT2_DIVIDE = 1; + parameter real CLKOUT2_DUTY_CYCLE = 0.500; + parameter real CLKOUT2_PHASE = 0.000; + parameter integer CLKOUT3_DIVIDE = 1; + parameter real CLKOUT3_DUTY_CYCLE = 0.500; + parameter real CLKOUT3_PHASE = 0.000; + parameter CLKOUT4_CASCADE = "FALSE"; + parameter integer CLKOUT4_DIVIDE = 1; + parameter real CLKOUT4_DUTY_CYCLE = 0.500; + parameter real CLKOUT4_PHASE = 0.000; + parameter integer CLKOUT5_DIVIDE = 1; + parameter real CLKOUT5_DUTY_CYCLE = 0.500; + parameter real CLKOUT5_PHASE = 0.000; + parameter integer CLKOUT6_DIVIDE = 1; + parameter real CLKOUT6_DUTY_CYCLE = 0.500; + parameter real CLKOUT6_PHASE = 0.000; + parameter integer DIVCLK_DIVIDE = 1; + parameter real REF_JITTER1 = 0.010; + parameter STARTUP_WAIT = "FALSE"; + output CLKFBOUT; + output CLKFBOUTB; + output CLKOUT0; + output CLKOUT0B; + output CLKOUT1; + output CLKOUT1B; + output CLKOUT2; + output CLKOUT2B; + output CLKOUT3; + output CLKOUT3B; + output CLKOUT4; + output CLKOUT5; + output CLKOUT6; + output LOCKED; + input CLKFBIN; + input CLKIN1; + input PWRDWN; + input RST; +endmodule + +module PLLE2_ADV (...); + parameter BANDWIDTH = "OPTIMIZED"; + parameter COMPENSATION = "ZHOLD"; + parameter STARTUP_WAIT = "FALSE"; + parameter integer CLKOUT0_DIVIDE = 1; + parameter integer CLKOUT1_DIVIDE = 1; + parameter integer CLKOUT2_DIVIDE = 1; + parameter integer CLKOUT3_DIVIDE = 1; + parameter integer CLKOUT4_DIVIDE = 1; + parameter integer CLKOUT5_DIVIDE = 1; + parameter integer DIVCLK_DIVIDE = 1; + parameter integer CLKFBOUT_MULT = 5; + parameter real CLKFBOUT_PHASE = 0.000; + parameter real CLKIN1_PERIOD = 0.000; + parameter real CLKIN2_PERIOD = 0.000; + parameter real CLKOUT0_DUTY_CYCLE = 0.500; + parameter real CLKOUT0_PHASE = 0.000; + parameter real CLKOUT1_DUTY_CYCLE = 0.500; + parameter real CLKOUT1_PHASE = 0.000; + parameter real CLKOUT2_DUTY_CYCLE = 0.500; + parameter real CLKOUT2_PHASE = 0.000; + parameter real CLKOUT3_DUTY_CYCLE = 0.500; + parameter real CLKOUT3_PHASE = 0.000; + parameter real CLKOUT4_DUTY_CYCLE = 0.500; + parameter real CLKOUT4_PHASE = 0.000; + parameter real CLKOUT5_DUTY_CYCLE = 0.500; + parameter real CLKOUT5_PHASE = 0.000; + parameter [0:0] IS_CLKINSEL_INVERTED = 1'b0; + parameter [0:0] IS_PWRDWN_INVERTED = 1'b0; + parameter [0:0] IS_RST_INVERTED = 1'b0; + parameter real REF_JITTER1 = 0.010; + parameter real REF_JITTER2 = 0.010; + parameter real VCOCLK_FREQ_MAX = 2133.000; + parameter real VCOCLK_FREQ_MIN = 800.000; + parameter real CLKIN_FREQ_MAX = 1066.000; + parameter real CLKIN_FREQ_MIN = 19.000; + parameter real CLKPFD_FREQ_MAX = 550.0; + parameter real CLKPFD_FREQ_MIN = 19.0; + output CLKFBOUT; + output CLKOUT0; + output CLKOUT1; + output CLKOUT2; + output CLKOUT3; + output CLKOUT4; + output CLKOUT5; + output DRDY; + output LOCKED; + output [15:0] DO; + input CLKFBIN; + input CLKIN1; + input CLKIN2; + (* invertible_pin = "IS_CLKINSEL_INVERTED" *) + input CLKINSEL; + input DCLK; + input DEN; + input DWE; + (* invertible_pin = "IS_PWRDWN_INVERTED" *) + input PWRDWN; + (* invertible_pin = "IS_RST_INVERTED" *) + input RST; + input [15:0] DI; + input [6:0] DADDR; +endmodule + +module PLLE2_BASE (...); + parameter BANDWIDTH = "OPTIMIZED"; + parameter integer CLKFBOUT_MULT = 5; + parameter real CLKFBOUT_PHASE = 0.000; + parameter real CLKIN1_PERIOD = 0.000; + parameter integer CLKOUT0_DIVIDE = 1; + parameter real CLKOUT0_DUTY_CYCLE = 0.500; + parameter real CLKOUT0_PHASE = 0.000; + parameter integer CLKOUT1_DIVIDE = 1; + parameter real CLKOUT1_DUTY_CYCLE = 0.500; + parameter real CLKOUT1_PHASE = 0.000; + parameter integer CLKOUT2_DIVIDE = 1; + parameter real CLKOUT2_DUTY_CYCLE = 0.500; + parameter real CLKOUT2_PHASE = 0.000; + parameter integer CLKOUT3_DIVIDE = 1; + parameter real CLKOUT3_DUTY_CYCLE = 0.500; + parameter real CLKOUT3_PHASE = 0.000; + parameter integer CLKOUT4_DIVIDE = 1; + parameter real CLKOUT4_DUTY_CYCLE = 0.500; + parameter real CLKOUT4_PHASE = 0.000; + parameter integer CLKOUT5_DIVIDE = 1; + parameter real CLKOUT5_DUTY_CYCLE = 0.500; + parameter real CLKOUT5_PHASE = 0.000; + parameter integer DIVCLK_DIVIDE = 1; + parameter real REF_JITTER1 = 0.010; + parameter STARTUP_WAIT = "FALSE"; + output CLKFBOUT; + output CLKOUT0; + output CLKOUT1; + output CLKOUT2; + output CLKOUT3; + output CLKOUT4; + output CLKOUT5; + output LOCKED; + input CLKFBIN; + input CLKIN1; + input PWRDWN; + input RST; +endmodule + +(* keep *) +module BSCANE2 (...); + parameter DISABLE_JTAG = "FALSE"; + parameter integer JTAG_CHAIN = 1; + output CAPTURE; + output DRCK; + output RESET; + output RUNTEST; + output SEL; + output SHIFT; + output TCK; + output TDI; + output TMS; + output UPDATE; + input TDO; +endmodule + +(* keep *) +module CAPTUREE2 (...); + parameter ONESHOT = "TRUE"; + input CAP; + input CLK; +endmodule + +module DNA_PORT (...); + parameter [56:0] SIM_DNA_VALUE = 57'h0; + output DOUT; + input CLK; + input DIN; + input READ; + input SHIFT; +endmodule + +module EFUSE_USR (...); + parameter [31:0] SIM_EFUSE_VALUE = 32'h00000000; + output [31:0] EFUSEUSR; +endmodule + +module FRAME_ECCE2 (...); + parameter FARSRC = "EFAR"; + parameter FRAME_RBT_IN_FILENAME = "NONE"; + output CRCERROR; + output ECCERROR; + output ECCERRORSINGLE; + output SYNDROMEVALID; + output [12:0] SYNDROME; + output [25:0] FAR; + output [4:0] SYNBIT; + output [6:0] SYNWORD; +endmodule + +(* keep *) +module ICAPE2 (...); + parameter [31:0] DEVICE_ID = 32'h04244093; + parameter ICAP_WIDTH = "X32"; + parameter SIM_CFG_FILE_NAME = "NONE"; + output [31:0] O; + input CLK; + input CSIB; + input RDWRB; + input [31:0] I; +endmodule + +(* keep *) +module STARTUPE2 (...); + parameter PROG_USR = "FALSE"; + parameter real SIM_CCLK_FREQ = 0.0; + output CFGCLK; + output CFGMCLK; + output EOS; + output PREQ; + input CLK; + input GSR; + input GTS; + input KEYCLEARB; + input PACK; + input USRCCLKO; + input USRCCLKTS; + input USRDONEO; + input USRDONETS; +endmodule + +module USR_ACCESSE2 (...); + output CFGCLK; + output DATAVALID; + output [31:0] DATA; +endmodule + +(* keep *) +module DCIRESET (...); + output LOCKED; + input RST; +endmodule + module IBUF_IBUFDISABLE (...); parameter IBUF_LOW_PWR = "TRUE"; parameter IOSTANDARD = "DEFAULT"; parameter SIM_DEVICE = "7SERIES"; parameter USE_IBUFDISABLE = "TRUE"; output O; + (* iopad_external_pin *) input I; input IBUFDISABLE; endmodule @@ -2009,6 +3909,7 @@ module IBUF_INTERMDISABLE (...); parameter SIM_DEVICE = "7SERIES"; parameter USE_IBUFDISABLE = "TRUE"; output O; + (* iopad_external_pin *) input I; input IBUFDISABLE; input INTERMDISABLE; @@ -2023,7 +3924,10 @@ module IBUFDS (...); parameter IFD_DELAY_VALUE = "AUTO"; parameter IOSTANDARD = "DEFAULT"; output O; - input I, IB; + (* iopad_external_pin *) + input I; + (* iopad_external_pin *) + input IB; endmodule module IBUFDS_DIFF_OUT (...); @@ -2031,8 +3935,12 @@ module IBUFDS_DIFF_OUT (...); parameter DQS_BIAS = "FALSE"; parameter IBUF_LOW_PWR = "TRUE"; parameter IOSTANDARD = "DEFAULT"; - output O, OB; - input I, IB; + output O; + output OB; + (* iopad_external_pin *) + input I; + (* iopad_external_pin *) + input IB; endmodule module IBUFDS_DIFF_OUT_IBUFDISABLE (...); @@ -2044,7 +3952,9 @@ module IBUFDS_DIFF_OUT_IBUFDISABLE (...); parameter USE_IBUFDISABLE = "TRUE"; output O; output OB; + (* iopad_external_pin *) input I; + (* iopad_external_pin *) input IB; input IBUFDISABLE; endmodule @@ -2058,7 +3968,9 @@ module IBUFDS_DIFF_OUT_INTERMDISABLE (...); parameter USE_IBUFDISABLE = "TRUE"; output O; output OB; + (* iopad_external_pin *) input I; + (* iopad_external_pin *) input IB; input IBUFDISABLE; input INTERMDISABLE; @@ -2071,7 +3983,9 @@ module IBUFDS_GTE2 (...); output O; output ODIV2; input CEB; + (* iopad_external_pin *) input I; + (* iopad_external_pin *) input IB; endmodule @@ -2083,7 +3997,9 @@ module IBUFDS_IBUFDISABLE (...); parameter SIM_DEVICE = "7SERIES"; parameter USE_IBUFDISABLE = "TRUE"; output O; + (* iopad_external_pin *) input I; + (* iopad_external_pin *) input IB; input IBUFDISABLE; endmodule @@ -2096,62 +4012,55 @@ module IBUFDS_INTERMDISABLE (...); parameter SIM_DEVICE = "7SERIES"; parameter USE_IBUFDISABLE = "TRUE"; output O; + (* iopad_external_pin *) input I; + (* iopad_external_pin *) input IB; input IBUFDISABLE; input INTERMDISABLE; endmodule -module ICAPE2 (...); - parameter [31:0] DEVICE_ID = 32'h04244093; - parameter ICAP_WIDTH = "X32"; - parameter SIM_CFG_FILE_NAME = "NONE"; - output [31:0] O; - input CLK; - input CSIB; - input RDWRB; - input [31:0] I; +module IBUFG (...); + parameter CAPACITANCE = "DONT_CARE"; + parameter IBUF_DELAY_VALUE = "0"; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + output O; + (* iopad_external_pin *) + input I; endmodule -module IDDR (...); - parameter DDR_CLK_EDGE = "OPPOSITE_EDGE"; - parameter INIT_Q1 = 1'b0; - parameter INIT_Q2 = 1'b0; - parameter [0:0] IS_C_INVERTED = 1'b0; - parameter [0:0] IS_D_INVERTED = 1'b0; - parameter SRTYPE = "SYNC"; - parameter MSGON = "TRUE"; - parameter XON = "TRUE"; - output Q1; - output Q2; - input C; - input CE; - input D; - input R; - input S; +module IBUFGDS (...); + parameter CAPACITANCE = "DONT_CARE"; + parameter DIFF_TERM = "FALSE"; + parameter IBUF_DELAY_VALUE = "0"; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + output O; + (* iopad_external_pin *) + input I; + (* iopad_external_pin *) + input IB; endmodule -module IDDR_2CLK (...); - parameter DDR_CLK_EDGE = "OPPOSITE_EDGE"; - parameter INIT_Q1 = 1'b0; - parameter INIT_Q2 = 1'b0; - parameter [0:0] IS_CB_INVERTED = 1'b0; - parameter [0:0] IS_C_INVERTED = 1'b0; - parameter [0:0] IS_D_INVERTED = 1'b0; - parameter SRTYPE = "SYNC"; - output Q1; - output Q2; - input C; - input CB; - input CE; - input D; - input R; - input S; +module IBUFGDS_DIFF_OUT (...); + parameter DIFF_TERM = "FALSE"; + parameter DQS_BIAS = "FALSE"; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + output O; + output OB; + (* iopad_external_pin *) + input I; + (* iopad_external_pin *) + input IB; endmodule +(* keep *) module IDELAYCTRL (...); parameter SIM_DEVICE = "7SERIES"; output RDY; + (* clkbuf_sink *) input REFCLK; input RST; endmodule @@ -2171,11 +4080,15 @@ module IDELAYE2 (...); parameter integer SIM_DELAY_D = 0; output [4:0] CNTVALUEOUT; output DATAOUT; + (* clkbuf_sink *) + (* invertible_pin = "IS_C_INVERTED" *) input C; input CE; input CINVCTRL; input [4:0] CNTVALUEIN; + (* invertible_pin = "IS_DATAIN_INVERTED" *) input DATAIN; + (* invertible_pin = "IS_IDATAIN_INVERTED" *) input IDATAIN; input INC; input LD; @@ -2202,9 +4115,11 @@ module IN_FIFO (...); output [7:0] Q7; output [7:0] Q8; output [7:0] Q9; + (* clkbuf_sink *) input RDCLK; input RDEN; input RESET; + (* clkbuf_sink *) input WRCLK; input WREN; input [3:0] D0; @@ -2225,7 +4140,10 @@ module IOBUF (...); parameter IOSTANDARD = "DEFAULT"; parameter SLEW = "SLOW"; output O; - input I, T; + (* iopad_external_pin *) + inout IO; + input I; + input T; endmodule module IOBUF_DCIEN (...); @@ -2236,6 +4154,8 @@ module IOBUF_DCIEN (...); parameter SLEW = "SLOW"; parameter USE_IBUFDISABLE = "TRUE"; output O; + (* iopad_external_pin *) + inout IO; input DCITERMDISABLE; input I; input IBUFDISABLE; @@ -2250,6 +4170,8 @@ module IOBUF_INTERMDISABLE (...); parameter SLEW = "SLOW"; parameter USE_IBUFDISABLE = "TRUE"; output O; + (* iopad_external_pin *) + inout IO; input I; input IBUFDISABLE; input INTERMDISABLE; @@ -2263,7 +4185,11 @@ module IOBUFDS (...); parameter IOSTANDARD = "DEFAULT"; parameter SLEW = "SLOW"; output O; - input I, T; + (* iopad_external_pin *) + inout IO; + inout IOB; + input I; + input T; endmodule module IOBUFDS_DCIEN (...); @@ -2275,6 +4201,10 @@ module IOBUFDS_DCIEN (...); parameter SLEW = "SLOW"; parameter USE_IBUFDISABLE = "TRUE"; output O; + (* iopad_external_pin *) + inout IO; + (* iopad_external_pin *) + inout IOB; input DCITERMDISABLE; input I; input IBUFDISABLE; @@ -2288,6 +4218,10 @@ module IOBUFDS_DIFF_OUT (...); parameter IOSTANDARD = "DEFAULT"; output O; output OB; + (* iopad_external_pin *) + inout IO; + (* iopad_external_pin *) + inout IOB; input I; input TM; input TS; @@ -2302,6 +4236,10 @@ module IOBUFDS_DIFF_OUT_DCIEN (...); parameter USE_IBUFDISABLE = "TRUE"; output O; output OB; + (* iopad_external_pin *) + inout IO; + (* iopad_external_pin *) + inout IOB; input DCITERMDISABLE; input I; input IBUFDISABLE; @@ -2318,6 +4256,10 @@ module IOBUFDS_DIFF_OUT_INTERMDISABLE (...); parameter USE_IBUFDISABLE = "TRUE"; output O; output OB; + (* iopad_external_pin *) + inout IO; + (* iopad_external_pin *) + inout IOB; input I; input IBUFDISABLE; input INTERMDISABLE; @@ -2325,6 +4267,25 @@ module IOBUFDS_DIFF_OUT_INTERMDISABLE (...); input TS; endmodule +module IOBUFDS_INTERMDISABLE (...); + parameter DIFF_TERM = "FALSE"; + parameter DQS_BIAS = "FALSE"; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + parameter SIM_DEVICE = "7SERIES"; + parameter SLEW = "SLOW"; + parameter USE_IBUFDISABLE = "TRUE"; + output O; + (* iopad_external_pin *) + inout IO; + (* iopad_external_pin *) + inout IOB; + input I; + input IBUFDISABLE; + input INTERMDISABLE; + input T; +endmodule + module ISERDESE2 (...); parameter DATA_RATE = "DDR"; parameter integer DATA_WIDTH = 4; @@ -2364,15 +4325,28 @@ module ISERDESE2 (...); input BITSLIP; input CE1; input CE2; + (* clkbuf_sink *) + (* invertible_pin = "IS_CLK_INVERTED" *) input CLK; + (* clkbuf_sink *) + (* invertible_pin = "IS_CLKB_INVERTED" *) input CLKB; + (* clkbuf_sink *) + (* invertible_pin = "IS_CLKDIV_INVERTED" *) input CLKDIV; + (* clkbuf_sink *) + (* invertible_pin = "IS_CLKDIVP_INVERTED" *) input CLKDIVP; + (* invertible_pin = "IS_D_INVERTED" *) input D; input DDLY; input DYNCLKDIVSEL; input DYNCLKSEL; + (* clkbuf_sink *) + (* invertible_pin = "IS_OCLK_INVERTED" *) input OCLK; + (* clkbuf_sink *) + (* invertible_pin = "IS_OCLKB_INVERTED" *) input OCLKB; input OFB; input RST; @@ -2381,180 +4355,17 @@ module ISERDESE2 (...); endmodule module KEEPER (...); -endmodule - -module LDCE (...); - parameter [0:0] INIT = 1'b0; - parameter [0:0] IS_CLR_INVERTED = 1'b0; - parameter [0:0] IS_G_INVERTED = 1'b0; - parameter MSGON = "TRUE"; - parameter XON = "TRUE"; - output Q; - input CLR, D, G, GE; -endmodule - -module LDPE (...); - parameter [0:0] INIT = 1'b1; - parameter [0:0] IS_G_INVERTED = 1'b0; - parameter [0:0] IS_PRE_INVERTED = 1'b0; - parameter MSGON = "TRUE"; - parameter XON = "TRUE"; - output Q; - input D, G, GE, PRE; -endmodule - -module LUT6_2 (...); - parameter [63:0] INIT = 64'h0000000000000000; - input I0, I1, I2, I3, I4, I5; - output O5, O6; -endmodule - -module MMCME2_ADV (...); - parameter BANDWIDTH = "OPTIMIZED"; - parameter real CLKFBOUT_MULT_F = 5.000; - parameter real CLKFBOUT_PHASE = 0.000; - parameter CLKFBOUT_USE_FINE_PS = "FALSE"; - parameter real CLKIN1_PERIOD = 0.000; - parameter real CLKIN2_PERIOD = 0.000; - parameter real CLKIN_FREQ_MAX = 1066.000; - parameter real CLKIN_FREQ_MIN = 10.000; - parameter real CLKOUT0_DIVIDE_F = 1.000; - parameter real CLKOUT0_DUTY_CYCLE = 0.500; - parameter real CLKOUT0_PHASE = 0.000; - parameter CLKOUT0_USE_FINE_PS = "FALSE"; - parameter integer CLKOUT1_DIVIDE = 1; - parameter real CLKOUT1_DUTY_CYCLE = 0.500; - parameter real CLKOUT1_PHASE = 0.000; - parameter CLKOUT1_USE_FINE_PS = "FALSE"; - parameter integer CLKOUT2_DIVIDE = 1; - parameter real CLKOUT2_DUTY_CYCLE = 0.500; - parameter real CLKOUT2_PHASE = 0.000; - parameter CLKOUT2_USE_FINE_PS = "FALSE"; - parameter integer CLKOUT3_DIVIDE = 1; - parameter real CLKOUT3_DUTY_CYCLE = 0.500; - parameter real CLKOUT3_PHASE = 0.000; - parameter CLKOUT3_USE_FINE_PS = "FALSE"; - parameter CLKOUT4_CASCADE = "FALSE"; - parameter integer CLKOUT4_DIVIDE = 1; - parameter real CLKOUT4_DUTY_CYCLE = 0.500; - parameter real CLKOUT4_PHASE = 0.000; - parameter CLKOUT4_USE_FINE_PS = "FALSE"; - parameter integer CLKOUT5_DIVIDE = 1; - parameter real CLKOUT5_DUTY_CYCLE = 0.500; - parameter real CLKOUT5_PHASE = 0.000; - parameter CLKOUT5_USE_FINE_PS = "FALSE"; - parameter integer CLKOUT6_DIVIDE = 1; - parameter real CLKOUT6_DUTY_CYCLE = 0.500; - parameter real CLKOUT6_PHASE = 0.000; - parameter CLKOUT6_USE_FINE_PS = "FALSE"; - parameter real CLKPFD_FREQ_MAX = 550.000; - parameter real CLKPFD_FREQ_MIN = 10.000; - parameter COMPENSATION = "ZHOLD"; - parameter integer DIVCLK_DIVIDE = 1; - parameter [0:0] IS_CLKINSEL_INVERTED = 1'b0; - parameter [0:0] IS_PSEN_INVERTED = 1'b0; - parameter [0:0] IS_PSINCDEC_INVERTED = 1'b0; - parameter [0:0] IS_PWRDWN_INVERTED = 1'b0; - parameter [0:0] IS_RST_INVERTED = 1'b0; - parameter real REF_JITTER1 = 0.010; - parameter real REF_JITTER2 = 0.010; - parameter SS_EN = "FALSE"; - parameter SS_MODE = "CENTER_HIGH"; - parameter integer SS_MOD_PERIOD = 10000; - parameter STARTUP_WAIT = "FALSE"; - parameter real VCOCLK_FREQ_MAX = 1600.000; - parameter real VCOCLK_FREQ_MIN = 600.000; - parameter STARTUP_WAIT = "FALSE"; - output CLKFBOUT; - output CLKFBOUTB; - output CLKFBSTOPPED; - output CLKINSTOPPED; - output CLKOUT0; - output CLKOUT0B; - output CLKOUT1; - output CLKOUT1B; - output CLKOUT2; - output CLKOUT2B; - output CLKOUT3; - output CLKOUT3B; - output CLKOUT4; - output CLKOUT5; - output CLKOUT6; - output [15:0] DO; - output DRDY; - output LOCKED; - output PSDONE; - input CLKFBIN; - input CLKIN1; - input CLKIN2; - input CLKINSEL; - input [6:0] DADDR; - input DCLK; - input DEN; - input [15:0] DI; - input DWE; - input PSCLK; - input PSEN; - input PSINCDEC; - input PWRDWN; - input RST; -endmodule - -module MMCME2_BASE (...); - parameter BANDWIDTH = "OPTIMIZED"; - parameter real CLKFBOUT_MULT_F = 5.000; - parameter real CLKFBOUT_PHASE = 0.000; - parameter real CLKIN1_PERIOD = 0.000; - parameter real CLKOUT0_DIVIDE_F = 1.000; - parameter real CLKOUT0_DUTY_CYCLE = 0.500; - parameter real CLKOUT0_PHASE = 0.000; - parameter integer CLKOUT1_DIVIDE = 1; - parameter real CLKOUT1_DUTY_CYCLE = 0.500; - parameter real CLKOUT1_PHASE = 0.000; - parameter integer CLKOUT2_DIVIDE = 1; - parameter real CLKOUT2_DUTY_CYCLE = 0.500; - parameter real CLKOUT2_PHASE = 0.000; - parameter integer CLKOUT3_DIVIDE = 1; - parameter real CLKOUT3_DUTY_CYCLE = 0.500; - parameter real CLKOUT3_PHASE = 0.000; - parameter CLKOUT4_CASCADE = "FALSE"; - parameter integer CLKOUT4_DIVIDE = 1; - parameter real CLKOUT4_DUTY_CYCLE = 0.500; - parameter real CLKOUT4_PHASE = 0.000; - parameter integer CLKOUT5_DIVIDE = 1; - parameter real CLKOUT5_DUTY_CYCLE = 0.500; - parameter real CLKOUT5_PHASE = 0.000; - parameter integer CLKOUT6_DIVIDE = 1; - parameter real CLKOUT6_DUTY_CYCLE = 0.500; - parameter real CLKOUT6_PHASE = 0.000; - parameter integer DIVCLK_DIVIDE = 1; - parameter real REF_JITTER1 = 0.010; - parameter STARTUP_WAIT = "FALSE"; - output CLKFBOUT; - output CLKFBOUTB; - output CLKOUT0; - output CLKOUT0B; - output CLKOUT1; - output CLKOUT1B; - output CLKOUT2; - output CLKOUT2B; - output CLKOUT3; - output CLKOUT3B; - output CLKOUT4; - output CLKOUT5; - output CLKOUT6; - output LOCKED; - input CLKFBIN; - input CLKIN1; - input PWRDWN; - input RST; + inout O; endmodule module OBUFDS (...); parameter CAPACITANCE = "DONT_CARE"; parameter IOSTANDARD = "DEFAULT"; parameter SLEW = "SLOW"; - output O, OB; + (* iopad_external_pin *) + output O; + (* iopad_external_pin *) + output OB; input I; endmodule @@ -2563,34 +4374,22 @@ module OBUFT (...); parameter integer DRIVE = 12; parameter IOSTANDARD = "DEFAULT"; parameter SLEW = "SLOW"; + (* iopad_external_pin *) output O; - input I, T; + input I; + input T; endmodule module OBUFTDS (...); parameter CAPACITANCE = "DONT_CARE"; parameter IOSTANDARD = "DEFAULT"; parameter SLEW = "SLOW"; - output O, OB; - input I, T; -endmodule - -module ODDR (...); - output Q; - input C; - input CE; - input D1; - input D2; - input R; - input S; - parameter DDR_CLK_EDGE = "OPPOSITE_EDGE"; - parameter INIT = 1'b0; - parameter [0:0] IS_C_INVERTED = 1'b0; - parameter [0:0] IS_D1_INVERTED = 1'b0; - parameter [0:0] IS_D2_INVERTED = 1'b0; - parameter SRTYPE = "SYNC"; - parameter MSGON = "TRUE"; - parameter XON = "TRUE"; + (* iopad_external_pin *) + output O; + (* iopad_external_pin *) + output OB; + input I; + input T; endmodule module ODELAYE2 (...); @@ -2607,6 +4406,8 @@ module ODELAYE2 (...); parameter integer SIM_DELAY_D = 0; output [4:0] CNTVALUEOUT; output DATAOUT; + (* clkbuf_sink *) + (* invertible_pin = "IS_C_INVERTED" *) input C; input CE; input CINVCTRL; @@ -2615,6 +4416,7 @@ module ODELAYE2 (...); input INC; input LD; input LDPIPEEN; + (* invertible_pin = "IS_ODATAIN_INVERTED" *) input ODATAIN; input REGRST; endmodule @@ -2652,23 +4454,39 @@ module OSERDESE2 (...); output TBYTEOUT; output TFB; output TQ; + (* clkbuf_sink *) + (* invertible_pin = "IS_CLK_INVERTED" *) input CLK; + (* clkbuf_sink *) + (* invertible_pin = "IS_CLKDIV_INVERTED" *) input CLKDIV; + (* invertible_pin = "IS_D1_INVERTED" *) input D1; + (* invertible_pin = "IS_D2_INVERTED" *) input D2; + (* invertible_pin = "IS_D3_INVERTED" *) input D3; + (* invertible_pin = "IS_D4_INVERTED" *) input D4; + (* invertible_pin = "IS_D5_INVERTED" *) input D5; + (* invertible_pin = "IS_D6_INVERTED" *) input D6; + (* invertible_pin = "IS_D7_INVERTED" *) input D7; + (* invertible_pin = "IS_D8_INVERTED" *) input D8; input OCE; input RST; input SHIFTIN1; input SHIFTIN2; + (* invertible_pin = "IS_T1_INVERTED" *) input T1; + (* invertible_pin = "IS_T2_INVERTED" *) input T2; + (* invertible_pin = "IS_T3_INVERTED" *) input T3; + (* invertible_pin = "IS_T4_INVERTED" *) input T4; input TBYTEIN; input TCE; @@ -2694,9 +4512,11 @@ module OUT_FIFO (...); output [3:0] Q9; output [7:0] Q5; output [7:0] Q6; + (* clkbuf_sink *) input RDCLK; input RDEN; input RESET; + (* clkbuf_sink *) input WRCLK; input WREN; input [7:0] D0; @@ -2739,6 +4559,7 @@ module PHASER_IN (...); input FREQREFCLK; input MEMREFCLK; input PHASEREFCLK; + (* invertible_pin = "IS_RST_INVERTED" *) input RST; input SYNCIN; input SYSCLK; @@ -2780,6 +4601,7 @@ module PHASER_IN_PHY (...); input FREQREFCLK; input MEMREFCLK; input PHASEREFCLK; + (* invertible_pin = "IS_RST_INVERTED" *) input RST; input RSTDQSFIND; input SYNCIN; @@ -2822,6 +4644,7 @@ module PHASER_OUT (...); input FREQREFCLK; input MEMREFCLK; input PHASEREFCLK; + (* invertible_pin = "IS_RST_INVERTED" *) input RST; input SELFINEOCLKDELAY; input SYNCIN; @@ -2866,6 +4689,7 @@ module PHASER_OUT_PHY (...); input FREQREFCLK; input MEMREFCLK; input PHASEREFCLK; + (* invertible_pin = "IS_RST_INVERTED" *) input RST; input SELFINEOCLKDELAY; input SYNCIN; @@ -2879,7 +4703,9 @@ module PHASER_REF (...); parameter [0:0] IS_PWRDWN_INVERTED = 1'b0; output LOCKED; input CLKIN; + (* invertible_pin = "IS_PWRDWN_INVERTED" *) input PWRDWN; + (* invertible_pin = "IS_RST_INVERTED" *) input RST; endmodule @@ -2943,107 +4769,6 @@ module PHY_CONTROL (...); input [31:0] PHYCTLWD; endmodule -module PLLE2_ADV (...); - parameter BANDWIDTH = "OPTIMIZED"; - parameter COMPENSATION = "ZHOLD"; - parameter STARTUP_WAIT = "FALSE"; - parameter integer CLKOUT0_DIVIDE = 1; - parameter integer CLKOUT1_DIVIDE = 1; - parameter integer CLKOUT2_DIVIDE = 1; - parameter integer CLKOUT3_DIVIDE = 1; - parameter integer CLKOUT4_DIVIDE = 1; - parameter integer CLKOUT5_DIVIDE = 1; - parameter integer DIVCLK_DIVIDE = 1; - parameter integer CLKFBOUT_MULT = 5; - parameter real CLKFBOUT_PHASE = 0.000; - parameter real CLKIN1_PERIOD = 0.000; - parameter real CLKIN2_PERIOD = 0.000; - parameter real CLKOUT0_DUTY_CYCLE = 0.500; - parameter real CLKOUT0_PHASE = 0.000; - parameter real CLKOUT1_DUTY_CYCLE = 0.500; - parameter real CLKOUT1_PHASE = 0.000; - parameter real CLKOUT2_DUTY_CYCLE = 0.500; - parameter real CLKOUT2_PHASE = 0.000; - parameter real CLKOUT3_DUTY_CYCLE = 0.500; - parameter real CLKOUT3_PHASE = 0.000; - parameter real CLKOUT4_DUTY_CYCLE = 0.500; - parameter real CLKOUT4_PHASE = 0.000; - parameter real CLKOUT5_DUTY_CYCLE = 0.500; - parameter real CLKOUT5_PHASE = 0.000; - parameter [0:0] IS_CLKINSEL_INVERTED = 1'b0; - parameter [0:0] IS_PWRDWN_INVERTED = 1'b0; - parameter [0:0] IS_RST_INVERTED = 1'b0; - parameter real REF_JITTER1 = 0.010; - parameter real REF_JITTER2 = 0.010; - parameter real VCOCLK_FREQ_MAX = 2133.000; - parameter real VCOCLK_FREQ_MIN = 800.000; - parameter real CLKIN_FREQ_MAX = 1066.000; - parameter real CLKIN_FREQ_MIN = 19.000; - parameter real CLKPFD_FREQ_MAX = 550.0; - parameter real CLKPFD_FREQ_MIN = 19.0; - output CLKFBOUT; - output CLKOUT0; - output CLKOUT1; - output CLKOUT2; - output CLKOUT3; - output CLKOUT4; - output CLKOUT5; - output DRDY; - output LOCKED; - output [15:0] DO; - input CLKFBIN; - input CLKIN1; - input CLKIN2; - input CLKINSEL; - input DCLK; - input DEN; - input DWE; - input PWRDWN; - input RST; - input [15:0] DI; - input [6:0] DADDR; -endmodule - -module PLLE2_BASE (...); - parameter BANDWIDTH = "OPTIMIZED"; - parameter integer CLKFBOUT_MULT = 5; - parameter real CLKFBOUT_PHASE = 0.000; - parameter real CLKIN1_PERIOD = 0.000; - parameter integer CLKOUT0_DIVIDE = 1; - parameter real CLKOUT0_DUTY_CYCLE = 0.500; - parameter real CLKOUT0_PHASE = 0.000; - parameter integer CLKOUT1_DIVIDE = 1; - parameter real CLKOUT1_DUTY_CYCLE = 0.500; - parameter real CLKOUT1_PHASE = 0.000; - parameter integer CLKOUT2_DIVIDE = 1; - parameter real CLKOUT2_DUTY_CYCLE = 0.500; - parameter real CLKOUT2_PHASE = 0.000; - parameter integer CLKOUT3_DIVIDE = 1; - parameter real CLKOUT3_DUTY_CYCLE = 0.500; - parameter real CLKOUT3_PHASE = 0.000; - parameter integer CLKOUT4_DIVIDE = 1; - parameter real CLKOUT4_DUTY_CYCLE = 0.500; - parameter real CLKOUT4_PHASE = 0.000; - parameter integer CLKOUT5_DIVIDE = 1; - parameter real CLKOUT5_DUTY_CYCLE = 0.500; - parameter real CLKOUT5_PHASE = 0.000; - parameter integer DIVCLK_DIVIDE = 1; - parameter real REF_JITTER1 = 0.010; - parameter STARTUP_WAIT = "FALSE"; - output CLKFBOUT; - output CLKOUT0; - output CLKOUT1; - output CLKOUT2; - output CLKOUT3; - output CLKOUT4; - output CLKOUT5; - output LOCKED; - input CLKFBIN; - input CLKIN1; - input PWRDWN; - input RST; -endmodule - module PULLDOWN (...); output O; endmodule @@ -3052,11 +4777,121 @@ module PULLUP (...); output O; endmodule +module FIFO18E1 (...); + parameter ALMOST_EMPTY_OFFSET = 13'h0080; + parameter ALMOST_FULL_OFFSET = 13'h0080; + parameter integer DATA_WIDTH = 4; + parameter integer DO_REG = 1; + parameter EN_SYN = "FALSE"; + parameter FIFO_MODE = "FIFO18"; + parameter FIRST_WORD_FALL_THROUGH = "FALSE"; + parameter INIT = 36'h0; + parameter SIM_DEVICE = "VIRTEX6"; + parameter SRVAL = 36'h0; + parameter IS_RDCLK_INVERTED = 1'b0; + parameter IS_RDEN_INVERTED = 1'b0; + parameter IS_RSTREG_INVERTED = 1'b0; + parameter IS_RST_INVERTED = 1'b0; + parameter IS_WRCLK_INVERTED = 1'b0; + parameter IS_WREN_INVERTED = 1'b0; + output ALMOSTEMPTY; + output ALMOSTFULL; + output [31:0] DO; + output [3:0] DOP; + output EMPTY; + output FULL; + output [11:0] RDCOUNT; + output RDERR; + output [11:0] WRCOUNT; + output WRERR; + input [31:0] DI; + input [3:0] DIP; + (* clkbuf_sink *) + (* invertible_pin = "IS_RDCLK_INVERTED" *) + input RDCLK; + (* invertible_pin = "IS_RDEN_INVERTED" *) + input RDEN; + input REGCE; + (* invertible_pin = "IS_RST_INVERTED" *) + input RST; + (* invertible_pin = "IS_RSTREG_INVERTED" *) + input RSTREG; + (* clkbuf_sink *) + (* invertible_pin = "IS_WRCLK_INVERTED" *) + input WRCLK; + (* invertible_pin = "IS_WREN_INVERTED" *) + input WREN; +endmodule + +module FIFO36E1 (...); + parameter ALMOST_EMPTY_OFFSET = 13'h0080; + parameter ALMOST_FULL_OFFSET = 13'h0080; + parameter integer DATA_WIDTH = 4; + parameter integer DO_REG = 1; + parameter EN_ECC_READ = "FALSE"; + parameter EN_ECC_WRITE = "FALSE"; + parameter EN_SYN = "FALSE"; + parameter FIFO_MODE = "FIFO36"; + parameter FIRST_WORD_FALL_THROUGH = "FALSE"; + parameter INIT = 72'h0; + parameter SIM_DEVICE = "VIRTEX6"; + parameter SRVAL = 72'h0; + parameter IS_RDCLK_INVERTED = 1'b0; + parameter IS_RDEN_INVERTED = 1'b0; + parameter IS_RSTREG_INVERTED = 1'b0; + parameter IS_RST_INVERTED = 1'b0; + parameter IS_WRCLK_INVERTED = 1'b0; + parameter IS_WREN_INVERTED = 1'b0; + output ALMOSTEMPTY; + output ALMOSTFULL; + output DBITERR; + output [63:0] DO; + output [7:0] DOP; + output [7:0] ECCPARITY; + output EMPTY; + output FULL; + output [12:0] RDCOUNT; + output RDERR; + output SBITERR; + output [12:0] WRCOUNT; + output WRERR; + input [63:0] DI; + input [7:0] DIP; + input INJECTDBITERR; + input INJECTSBITERR; + (* clkbuf_sink *) + (* invertible_pin = "IS_RDCLK_INVERTED" *) + input RDCLK; + (* invertible_pin = "IS_RDEN_INVERTED" *) + input RDEN; + input REGCE; + (* invertible_pin = "IS_RST_INVERTED" *) + input RST; + (* invertible_pin = "IS_RSTREG_INVERTED" *) + input RSTREG; + (* clkbuf_sink *) + (* invertible_pin = "IS_WRCLK_INVERTED" *) + input WRCLK; + (* invertible_pin = "IS_WREN_INVERTED" *) + input WREN; +endmodule + module RAM128X1S (...); parameter [127:0] INIT = 128'h00000000000000000000000000000000; parameter [0:0] IS_WCLK_INVERTED = 1'b0; output O; - input A0, A1, A2, A3, A4, A5, A6, D, WCLK, WE; + input A0; + input A1; + input A2; + input A3; + input A4; + input A5; + input A6; + input D; + (* clkbuf_sink *) + (* invertible_pin = "IS_WCLK_INVERTED" *) + input WCLK; + input WE; endmodule module RAM256X1S (...); @@ -3065,6 +4900,8 @@ module RAM256X1S (...); output O; input [7:0] A; input D; + (* clkbuf_sink *) + (* invertible_pin = "IS_WCLK_INVERTED" *) input WCLK; input WE; endmodule @@ -3087,37 +4924,61 @@ module RAM32M (...); input [1:0] DIB; input [1:0] DIC; input [1:0] DID; + (* clkbuf_sink *) + (* invertible_pin = "IS_WCLK_INVERTED" *) input WCLK; 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; output O; - input A0, A1, A2, A3, A4, D, WCLK, WE; + input A0; + input A1; + input A2; + input A3; + input A4; + input D; + (* clkbuf_sink *) + (* invertible_pin = "IS_WCLK_INVERTED" *) + input WCLK; + input WE; endmodule module RAM32X1S_1 (...); parameter [31:0] INIT = 32'h00000000; parameter [0:0] IS_WCLK_INVERTED = 1'b0; output O; - input A0, A1, A2, A3, A4, D, WCLK, WE; + input A0; + input A1; + input A2; + input A3; + input A4; + input D; + (* clkbuf_sink *) + (* invertible_pin = "IS_WCLK_INVERTED" *) + input WCLK; + input WE; endmodule module RAM32X2S (...); parameter [31:0] INIT_00 = 32'h00000000; parameter [31:0] INIT_01 = 32'h00000000; parameter [0:0] IS_WCLK_INVERTED = 1'b0; - output O0, O1; - input A0, A1, A2, A3, A4, D0, D1, WCLK, WE; + output O0; + output O1; + input A0; + input A1; + input A2; + input A3; + input A4; + input D0; + input D1; + (* clkbuf_sink *) + (* invertible_pin = "IS_WCLK_INVERTED" *) + input WCLK; + input WE; endmodule module RAM64M (...); @@ -3138,6 +4999,8 @@ module RAM64M (...); input DIB; input DIC; input DID; + (* clkbuf_sink *) + (* invertible_pin = "IS_WCLK_INVERTED" *) input WCLK; input WE; endmodule @@ -3146,148 +5009,837 @@ module RAM64X1S (...); parameter [63:0] INIT = 64'h0000000000000000; parameter [0:0] IS_WCLK_INVERTED = 1'b0; output O; - input A0, A1, A2, A3, A4, A5, D, WCLK, WE; + input A0; + input A1; + input A2; + input A3; + input A4; + input A5; + input D; + (* clkbuf_sink *) + (* invertible_pin = "IS_WCLK_INVERTED" *) + input WCLK; + input WE; endmodule module RAM64X1S_1 (...); parameter [63:0] INIT = 64'h0000000000000000; parameter [0:0] IS_WCLK_INVERTED = 1'b0; output O; - input A0, A1, A2, A3, A4, A5, D, WCLK, WE; + input A0; + input A1; + input A2; + input A3; + input A4; + input A5; + input D; + (* clkbuf_sink *) + (* invertible_pin = "IS_WCLK_INVERTED" *) + input WCLK; + input WE; endmodule module RAM64X2S (...); parameter [63:0] INIT_00 = 64'h0000000000000000; parameter [63:0] INIT_01 = 64'h0000000000000000; parameter [0:0] IS_WCLK_INVERTED = 1'b0; - output O0, O1; - input A0, A1, A2, A3, A4, A5, D0, D1, WCLK, WE; + output O0; + output O1; + input A0; + input A1; + input A2; + input A3; + input A4; + input A5; + input D0; + input D1; + (* clkbuf_sink *) + (* invertible_pin = "IS_WCLK_INVERTED" *) + input WCLK; + input WE; endmodule module ROM128X1 (...); parameter [127:0] INIT = 128'h00000000000000000000000000000000; output O; - input A0, A1, A2, A3, A4, A5, A6; + input A0; + input A1; + input A2; + input A3; + input A4; + input A5; + input A6; endmodule module ROM256X1 (...); parameter [255:0] INIT = 256'h0000000000000000000000000000000000000000000000000000000000000000; output O; - input A0, A1, A2, A3, A4, A5, A6, A7; + input A0; + input A1; + input A2; + input A3; + input A4; + input A5; + input A6; + input A7; endmodule module ROM32X1 (...); parameter [31:0] INIT = 32'h00000000; output O; - input A0, A1, A2, A3, A4; + input A0; + input A1; + input A2; + input A3; + input A4; endmodule module ROM64X1 (...); parameter [63:0] INIT = 64'h0000000000000000; output O; - input A0, A1, A2, A3, A4, A5; + input A0; + input A1; + input A2; + input A3; + input A4; + input A5; endmodule -module SRL16E (...); - parameter [15:0] INIT = 16'h0000; - parameter [0:0] IS_CLK_INVERTED = 1'b0; +module IDDR (...); + parameter DDR_CLK_EDGE = "OPPOSITE_EDGE"; + parameter INIT_Q1 = 1'b0; + parameter INIT_Q2 = 1'b0; + parameter [0:0] IS_C_INVERTED = 1'b0; + parameter [0:0] IS_D_INVERTED = 1'b0; + parameter SRTYPE = "SYNC"; + parameter MSGON = "TRUE"; + parameter XON = "TRUE"; + output Q1; + output Q2; + (* clkbuf_sink *) + (* invertible_pin = "IS_C_INVERTED" *) + input C; + input CE; + (* invertible_pin = "IS_D_INVERTED" *) + input D; + input R; + input S; +endmodule + +module IDDR_2CLK (...); + parameter DDR_CLK_EDGE = "OPPOSITE_EDGE"; + parameter INIT_Q1 = 1'b0; + parameter INIT_Q2 = 1'b0; + parameter [0:0] IS_CB_INVERTED = 1'b0; + parameter [0:0] IS_C_INVERTED = 1'b0; + parameter [0:0] IS_D_INVERTED = 1'b0; + parameter SRTYPE = "SYNC"; + output Q1; + output Q2; + (* clkbuf_sink *) + (* invertible_pin = "IS_C_INVERTED" *) + input C; + (* clkbuf_sink *) + (* invertible_pin = "IS_CB_INVERTED" *) + input CB; + input CE; + (* invertible_pin = "IS_D_INVERTED" *) + input D; + input R; + input S; +endmodule + +module LDCE (...); + parameter [0:0] INIT = 1'b0; + parameter [0:0] IS_CLR_INVERTED = 1'b0; + parameter [0:0] IS_G_INVERTED = 1'b0; + parameter MSGON = "TRUE"; + parameter XON = "TRUE"; output Q; - input A0, A1, A2, A3, CE, CLK, D; + (* invertible_pin = "IS_CLR_INVERTED" *) + input CLR; + input D; + (* invertible_pin = "IS_G_INVERTED" *) + input G; + input GE; endmodule -module SRLC32E (...); - parameter [31:0] INIT = 32'h00000000; - parameter [0:0] IS_CLK_INVERTED = 1'b0; +module LDPE (...); + parameter [0:0] INIT = 1'b1; + parameter [0:0] IS_G_INVERTED = 1'b0; + parameter [0:0] IS_PRE_INVERTED = 1'b0; + parameter MSGON = "TRUE"; + parameter XON = "TRUE"; output Q; - output Q31; - input [4:0] A; - input CE, CLK, D; + input D; + (* invertible_pin = "IS_G_INVERTED" *) + input G; + input GE; + (* invertible_pin = "IS_PRE_INVERTED" *) + input PRE; endmodule -module STARTUPE2 (...); - parameter PROG_USR = "FALSE"; - parameter real SIM_CCLK_FREQ = 0.0; - output CFGCLK; - output CFGMCLK; - output EOS; - output PREQ; - input CLK; - input GSR; - input GTS; - input KEYCLEARB; - input PACK; - input USRCCLKO; - input USRCCLKTS; - input USRDONEO; - input USRDONETS; +module ODDR (...); + parameter DDR_CLK_EDGE = "OPPOSITE_EDGE"; + parameter INIT = 1'b0; + parameter [0:0] IS_C_INVERTED = 1'b0; + parameter [0:0] IS_D1_INVERTED = 1'b0; + parameter [0:0] IS_D2_INVERTED = 1'b0; + parameter SRTYPE = "SYNC"; + parameter MSGON = "TRUE"; + parameter XON = "TRUE"; + output Q; + (* clkbuf_sink *) + (* invertible_pin = "IS_C_INVERTED" *) + input C; + input CE; + (* invertible_pin = "IS_D1_INVERTED" *) + input D1; + (* invertible_pin = "IS_D2_INVERTED" *) + input D2; + input R; + input S; endmodule -module USR_ACCESSE2 (...); - output CFGCLK; - output DATAVALID; - output [31:0] DATA; +module CFGLUT5 (...); + parameter [31:0] INIT = 32'h00000000; + parameter [0:0] IS_CLK_INVERTED = 1'b0; + output CDO; + output O5; + output O6; + input I4; + input I3; + input I2; + input I1; + input I0; + input CDI; + input CE; + (* clkbuf_sink *) + (* invertible_pin = "IS_CLK_INVERTED" *) + input CLK; endmodule -module XADC (...); - output BUSY; - output DRDY; - output EOC; - output EOS; - output JTAGBUSY; - output JTAGLOCKED; - output JTAGMODIFIED; - output OT; - output [15:0] DO; - output [7:0] ALM; - output [4:0] CHANNEL; - output [4:0] MUXADDR; - input CONVST; - input CONVSTCLK; - input DCLK; - input DEN; - input DWE; - input RESET; - input VN; - input VP; - input [15:0] DI; - input [15:0] VAUXN; - input [15:0] VAUXP; - input [6:0] DADDR; - parameter [15:0] INIT_40 = 16'h0; - parameter [15:0] INIT_41 = 16'h0; - parameter [15:0] INIT_42 = 16'h0800; - parameter [15:0] INIT_43 = 16'h0; - parameter [15:0] INIT_44 = 16'h0; - parameter [15:0] INIT_45 = 16'h0; - parameter [15:0] INIT_46 = 16'h0; - parameter [15:0] INIT_47 = 16'h0; - parameter [15:0] INIT_48 = 16'h0; - parameter [15:0] INIT_49 = 16'h0; - parameter [15:0] INIT_4A = 16'h0; - parameter [15:0] INIT_4B = 16'h0; - parameter [15:0] INIT_4C = 16'h0; - parameter [15:0] INIT_4D = 16'h0; - parameter [15:0] INIT_4E = 16'h0; - parameter [15:0] INIT_4F = 16'h0; - parameter [15:0] INIT_50 = 16'h0; - parameter [15:0] INIT_51 = 16'h0; - parameter [15:0] INIT_52 = 16'h0; - parameter [15:0] INIT_53 = 16'h0; - parameter [15:0] INIT_54 = 16'h0; - parameter [15:0] INIT_55 = 16'h0; - parameter [15:0] INIT_56 = 16'h0; - parameter [15:0] INIT_57 = 16'h0; - parameter [15:0] INIT_58 = 16'h0; - parameter [15:0] INIT_59 = 16'h0; - parameter [15:0] INIT_5A = 16'h0; - parameter [15:0] INIT_5B = 16'h0; - parameter [15:0] INIT_5C = 16'h0; - parameter [15:0] INIT_5D = 16'h0; - parameter [15:0] INIT_5E = 16'h0; - parameter [15:0] INIT_5F = 16'h0; - parameter IS_CONVSTCLK_INVERTED = 1'b0; - parameter IS_DCLK_INVERTED = 1'b0; - parameter SIM_DEVICE = "7SERIES"; - parameter SIM_MONITOR_FILE = "design.txt"; +(* keep *) +module PS7 (...); + output DMA0DAVALID; + output DMA0DRREADY; + output DMA0RSTN; + output DMA1DAVALID; + output DMA1DRREADY; + output DMA1RSTN; + output DMA2DAVALID; + output DMA2DRREADY; + output DMA2RSTN; + output DMA3DAVALID; + output DMA3DRREADY; + output DMA3RSTN; + output EMIOCAN0PHYTX; + output EMIOCAN1PHYTX; + output EMIOENET0GMIITXEN; + output EMIOENET0GMIITXER; + output EMIOENET0MDIOMDC; + output EMIOENET0MDIOO; + output EMIOENET0MDIOTN; + output EMIOENET0PTPDELAYREQRX; + output EMIOENET0PTPDELAYREQTX; + output EMIOENET0PTPPDELAYREQRX; + output EMIOENET0PTPPDELAYREQTX; + output EMIOENET0PTPPDELAYRESPRX; + output EMIOENET0PTPPDELAYRESPTX; + output EMIOENET0PTPSYNCFRAMERX; + output EMIOENET0PTPSYNCFRAMETX; + output EMIOENET0SOFRX; + output EMIOENET0SOFTX; + output EMIOENET1GMIITXEN; + output EMIOENET1GMIITXER; + output EMIOENET1MDIOMDC; + output EMIOENET1MDIOO; + output EMIOENET1MDIOTN; + output EMIOENET1PTPDELAYREQRX; + output EMIOENET1PTPDELAYREQTX; + output EMIOENET1PTPPDELAYREQRX; + output EMIOENET1PTPPDELAYREQTX; + output EMIOENET1PTPPDELAYRESPRX; + output EMIOENET1PTPPDELAYRESPTX; + output EMIOENET1PTPSYNCFRAMERX; + output EMIOENET1PTPSYNCFRAMETX; + output EMIOENET1SOFRX; + output EMIOENET1SOFTX; + output EMIOI2C0SCLO; + output EMIOI2C0SCLTN; + output EMIOI2C0SDAO; + output EMIOI2C0SDATN; + output EMIOI2C1SCLO; + output EMIOI2C1SCLTN; + output EMIOI2C1SDAO; + output EMIOI2C1SDATN; + output EMIOPJTAGTDO; + output EMIOPJTAGTDTN; + output EMIOSDIO0BUSPOW; + output EMIOSDIO0CLK; + output EMIOSDIO0CMDO; + output EMIOSDIO0CMDTN; + output EMIOSDIO0LED; + output EMIOSDIO1BUSPOW; + output EMIOSDIO1CLK; + output EMIOSDIO1CMDO; + output EMIOSDIO1CMDTN; + output EMIOSDIO1LED; + output EMIOSPI0MO; + output EMIOSPI0MOTN; + output EMIOSPI0SCLKO; + output EMIOSPI0SCLKTN; + output EMIOSPI0SO; + output EMIOSPI0SSNTN; + output EMIOSPI0STN; + output EMIOSPI1MO; + output EMIOSPI1MOTN; + output EMIOSPI1SCLKO; + output EMIOSPI1SCLKTN; + output EMIOSPI1SO; + output EMIOSPI1SSNTN; + output EMIOSPI1STN; + output EMIOTRACECTL; + output EMIOUART0DTRN; + output EMIOUART0RTSN; + output EMIOUART0TX; + output EMIOUART1DTRN; + output EMIOUART1RTSN; + output EMIOUART1TX; + output EMIOUSB0VBUSPWRSELECT; + output EMIOUSB1VBUSPWRSELECT; + output EMIOWDTRSTO; + output EVENTEVENTO; + output MAXIGP0ARESETN; + output MAXIGP0ARVALID; + output MAXIGP0AWVALID; + output MAXIGP0BREADY; + output MAXIGP0RREADY; + output MAXIGP0WLAST; + output MAXIGP0WVALID; + output MAXIGP1ARESETN; + output MAXIGP1ARVALID; + output MAXIGP1AWVALID; + output MAXIGP1BREADY; + output MAXIGP1RREADY; + output MAXIGP1WLAST; + output MAXIGP1WVALID; + output SAXIACPARESETN; + output SAXIACPARREADY; + output SAXIACPAWREADY; + output SAXIACPBVALID; + output SAXIACPRLAST; + output SAXIACPRVALID; + output SAXIACPWREADY; + output SAXIGP0ARESETN; + output SAXIGP0ARREADY; + output SAXIGP0AWREADY; + output SAXIGP0BVALID; + output SAXIGP0RLAST; + output SAXIGP0RVALID; + output SAXIGP0WREADY; + output SAXIGP1ARESETN; + output SAXIGP1ARREADY; + output SAXIGP1AWREADY; + output SAXIGP1BVALID; + output SAXIGP1RLAST; + output SAXIGP1RVALID; + output SAXIGP1WREADY; + output SAXIHP0ARESETN; + output SAXIHP0ARREADY; + output SAXIHP0AWREADY; + output SAXIHP0BVALID; + output SAXIHP0RLAST; + output SAXIHP0RVALID; + output SAXIHP0WREADY; + output SAXIHP1ARESETN; + output SAXIHP1ARREADY; + output SAXIHP1AWREADY; + output SAXIHP1BVALID; + output SAXIHP1RLAST; + output SAXIHP1RVALID; + output SAXIHP1WREADY; + output SAXIHP2ARESETN; + output SAXIHP2ARREADY; + output SAXIHP2AWREADY; + output SAXIHP2BVALID; + output SAXIHP2RLAST; + output SAXIHP2RVALID; + output SAXIHP2WREADY; + output SAXIHP3ARESETN; + output SAXIHP3ARREADY; + output SAXIHP3AWREADY; + output SAXIHP3BVALID; + output SAXIHP3RLAST; + output SAXIHP3RVALID; + output SAXIHP3WREADY; + output [11:0] MAXIGP0ARID; + output [11:0] MAXIGP0AWID; + output [11:0] MAXIGP0WID; + output [11:0] MAXIGP1ARID; + output [11:0] MAXIGP1AWID; + output [11:0] MAXIGP1WID; + output [1:0] DMA0DATYPE; + output [1:0] DMA1DATYPE; + output [1:0] DMA2DATYPE; + output [1:0] DMA3DATYPE; + output [1:0] EMIOUSB0PORTINDCTL; + output [1:0] EMIOUSB1PORTINDCTL; + output [1:0] EVENTSTANDBYWFE; + output [1:0] EVENTSTANDBYWFI; + output [1:0] MAXIGP0ARBURST; + output [1:0] MAXIGP0ARLOCK; + output [1:0] MAXIGP0ARSIZE; + output [1:0] MAXIGP0AWBURST; + output [1:0] MAXIGP0AWLOCK; + output [1:0] MAXIGP0AWSIZE; + output [1:0] MAXIGP1ARBURST; + output [1:0] MAXIGP1ARLOCK; + output [1:0] MAXIGP1ARSIZE; + output [1:0] MAXIGP1AWBURST; + output [1:0] MAXIGP1AWLOCK; + output [1:0] MAXIGP1AWSIZE; + output [1:0] SAXIACPBRESP; + output [1:0] SAXIACPRRESP; + output [1:0] SAXIGP0BRESP; + output [1:0] SAXIGP0RRESP; + output [1:0] SAXIGP1BRESP; + output [1:0] SAXIGP1RRESP; + output [1:0] SAXIHP0BRESP; + output [1:0] SAXIHP0RRESP; + output [1:0] SAXIHP1BRESP; + output [1:0] SAXIHP1RRESP; + output [1:0] SAXIHP2BRESP; + output [1:0] SAXIHP2RRESP; + output [1:0] SAXIHP3BRESP; + output [1:0] SAXIHP3RRESP; + output [28:0] IRQP2F; + output [2:0] EMIOSDIO0BUSVOLT; + output [2:0] EMIOSDIO1BUSVOLT; + output [2:0] EMIOSPI0SSON; + output [2:0] EMIOSPI1SSON; + output [2:0] EMIOTTC0WAVEO; + output [2:0] EMIOTTC1WAVEO; + output [2:0] MAXIGP0ARPROT; + output [2:0] MAXIGP0AWPROT; + output [2:0] MAXIGP1ARPROT; + output [2:0] MAXIGP1AWPROT; + output [2:0] SAXIACPBID; + output [2:0] SAXIACPRID; + output [2:0] SAXIHP0RACOUNT; + output [2:0] SAXIHP1RACOUNT; + output [2:0] SAXIHP2RACOUNT; + output [2:0] SAXIHP3RACOUNT; + output [31:0] EMIOTRACEDATA; + output [31:0] FTMTP2FDEBUG; + output [31:0] MAXIGP0ARADDR; + output [31:0] MAXIGP0AWADDR; + output [31:0] MAXIGP0WDATA; + output [31:0] MAXIGP1ARADDR; + output [31:0] MAXIGP1AWADDR; + output [31:0] MAXIGP1WDATA; + output [31:0] SAXIGP0RDATA; + output [31:0] SAXIGP1RDATA; + output [3:0] EMIOSDIO0DATAO; + output [3:0] EMIOSDIO0DATATN; + output [3:0] EMIOSDIO1DATAO; + output [3:0] EMIOSDIO1DATATN; + output [3:0] FCLKCLK; + output [3:0] FCLKRESETN; + output [3:0] FTMTF2PTRIGACK; + output [3:0] FTMTP2FTRIG; + output [3:0] MAXIGP0ARCACHE; + output [3:0] MAXIGP0ARLEN; + output [3:0] MAXIGP0ARQOS; + output [3:0] MAXIGP0AWCACHE; + output [3:0] MAXIGP0AWLEN; + output [3:0] MAXIGP0AWQOS; + output [3:0] MAXIGP0WSTRB; + output [3:0] MAXIGP1ARCACHE; + output [3:0] MAXIGP1ARLEN; + output [3:0] MAXIGP1ARQOS; + output [3:0] MAXIGP1AWCACHE; + output [3:0] MAXIGP1AWLEN; + output [3:0] MAXIGP1AWQOS; + output [3:0] MAXIGP1WSTRB; + output [5:0] SAXIGP0BID; + output [5:0] SAXIGP0RID; + output [5:0] SAXIGP1BID; + output [5:0] SAXIGP1RID; + output [5:0] SAXIHP0BID; + output [5:0] SAXIHP0RID; + output [5:0] SAXIHP0WACOUNT; + output [5:0] SAXIHP1BID; + output [5:0] SAXIHP1RID; + output [5:0] SAXIHP1WACOUNT; + output [5:0] SAXIHP2BID; + output [5:0] SAXIHP2RID; + output [5:0] SAXIHP2WACOUNT; + output [5:0] SAXIHP3BID; + output [5:0] SAXIHP3RID; + output [5:0] SAXIHP3WACOUNT; + output [63:0] EMIOGPIOO; + output [63:0] EMIOGPIOTN; + output [63:0] SAXIACPRDATA; + output [63:0] SAXIHP0RDATA; + output [63:0] SAXIHP1RDATA; + output [63:0] SAXIHP2RDATA; + output [63:0] SAXIHP3RDATA; + output [7:0] EMIOENET0GMIITXD; + output [7:0] EMIOENET1GMIITXD; + output [7:0] SAXIHP0RCOUNT; + output [7:0] SAXIHP0WCOUNT; + output [7:0] SAXIHP1RCOUNT; + output [7:0] SAXIHP1WCOUNT; + output [7:0] SAXIHP2RCOUNT; + output [7:0] SAXIHP2WCOUNT; + output [7:0] SAXIHP3RCOUNT; + output [7:0] SAXIHP3WCOUNT; + inout DDRCASB; + inout DDRCKE; + inout DDRCKN; + inout DDRCKP; + inout DDRCSB; + inout DDRDRSTB; + inout DDRODT; + inout DDRRASB; + inout DDRVRN; + inout DDRVRP; + inout DDRWEB; + inout PSCLK; + inout PSPORB; + inout PSSRSTB; + inout [14:0] DDRA; + inout [2:0] DDRBA; + inout [31:0] DDRDQ; + inout [3:0] DDRDM; + inout [3:0] DDRDQSN; + inout [3:0] DDRDQSP; + inout [53:0] MIO; + input DMA0ACLK; + input DMA0DAREADY; + input DMA0DRLAST; + input DMA0DRVALID; + input DMA1ACLK; + input DMA1DAREADY; + input DMA1DRLAST; + input DMA1DRVALID; + input DMA2ACLK; + input DMA2DAREADY; + input DMA2DRLAST; + input DMA2DRVALID; + input DMA3ACLK; + input DMA3DAREADY; + input DMA3DRLAST; + input DMA3DRVALID; + input EMIOCAN0PHYRX; + input EMIOCAN1PHYRX; + input EMIOENET0EXTINTIN; + input EMIOENET0GMIICOL; + input EMIOENET0GMIICRS; + input EMIOENET0GMIIRXCLK; + input EMIOENET0GMIIRXDV; + input EMIOENET0GMIIRXER; + input EMIOENET0GMIITXCLK; + input EMIOENET0MDIOI; + input EMIOENET1EXTINTIN; + input EMIOENET1GMIICOL; + input EMIOENET1GMIICRS; + input EMIOENET1GMIIRXCLK; + input EMIOENET1GMIIRXDV; + input EMIOENET1GMIIRXER; + input EMIOENET1GMIITXCLK; + input EMIOENET1MDIOI; + input EMIOI2C0SCLI; + input EMIOI2C0SDAI; + input EMIOI2C1SCLI; + input EMIOI2C1SDAI; + input EMIOPJTAGTCK; + input EMIOPJTAGTDI; + input EMIOPJTAGTMS; + input EMIOSDIO0CDN; + input EMIOSDIO0CLKFB; + input EMIOSDIO0CMDI; + input EMIOSDIO0WP; + input EMIOSDIO1CDN; + input EMIOSDIO1CLKFB; + input EMIOSDIO1CMDI; + input EMIOSDIO1WP; + input EMIOSPI0MI; + input EMIOSPI0SCLKI; + input EMIOSPI0SI; + input EMIOSPI0SSIN; + input EMIOSPI1MI; + input EMIOSPI1SCLKI; + input EMIOSPI1SI; + input EMIOSPI1SSIN; + input EMIOSRAMINTIN; + input EMIOTRACECLK; + input EMIOUART0CTSN; + input EMIOUART0DCDN; + input EMIOUART0DSRN; + input EMIOUART0RIN; + input EMIOUART0RX; + input EMIOUART1CTSN; + input EMIOUART1DCDN; + input EMIOUART1DSRN; + input EMIOUART1RIN; + input EMIOUART1RX; + input EMIOUSB0VBUSPWRFAULT; + input EMIOUSB1VBUSPWRFAULT; + input EMIOWDTCLKI; + input EVENTEVENTI; + input FPGAIDLEN; + input FTMDTRACEINCLOCK; + input FTMDTRACEINVALID; + input MAXIGP0ACLK; + input MAXIGP0ARREADY; + input MAXIGP0AWREADY; + input MAXIGP0BVALID; + input MAXIGP0RLAST; + input MAXIGP0RVALID; + input MAXIGP0WREADY; + input MAXIGP1ACLK; + input MAXIGP1ARREADY; + input MAXIGP1AWREADY; + input MAXIGP1BVALID; + input MAXIGP1RLAST; + input MAXIGP1RVALID; + input MAXIGP1WREADY; + input SAXIACPACLK; + input SAXIACPARVALID; + input SAXIACPAWVALID; + input SAXIACPBREADY; + input SAXIACPRREADY; + input SAXIACPWLAST; + input SAXIACPWVALID; + input SAXIGP0ACLK; + input SAXIGP0ARVALID; + input SAXIGP0AWVALID; + input SAXIGP0BREADY; + input SAXIGP0RREADY; + input SAXIGP0WLAST; + input SAXIGP0WVALID; + input SAXIGP1ACLK; + input SAXIGP1ARVALID; + input SAXIGP1AWVALID; + input SAXIGP1BREADY; + input SAXIGP1RREADY; + input SAXIGP1WLAST; + input SAXIGP1WVALID; + input SAXIHP0ACLK; + input SAXIHP0ARVALID; + input SAXIHP0AWVALID; + input SAXIHP0BREADY; + input SAXIHP0RDISSUECAP1EN; + input SAXIHP0RREADY; + input SAXIHP0WLAST; + input SAXIHP0WRISSUECAP1EN; + input SAXIHP0WVALID; + input SAXIHP1ACLK; + input SAXIHP1ARVALID; + input SAXIHP1AWVALID; + input SAXIHP1BREADY; + input SAXIHP1RDISSUECAP1EN; + input SAXIHP1RREADY; + input SAXIHP1WLAST; + input SAXIHP1WRISSUECAP1EN; + input SAXIHP1WVALID; + input SAXIHP2ACLK; + input SAXIHP2ARVALID; + input SAXIHP2AWVALID; + input SAXIHP2BREADY; + input SAXIHP2RDISSUECAP1EN; + input SAXIHP2RREADY; + input SAXIHP2WLAST; + input SAXIHP2WRISSUECAP1EN; + input SAXIHP2WVALID; + input SAXIHP3ACLK; + input SAXIHP3ARVALID; + input SAXIHP3AWVALID; + input SAXIHP3BREADY; + input SAXIHP3RDISSUECAP1EN; + input SAXIHP3RREADY; + input SAXIHP3WLAST; + input SAXIHP3WRISSUECAP1EN; + input SAXIHP3WVALID; + input [11:0] MAXIGP0BID; + input [11:0] MAXIGP0RID; + input [11:0] MAXIGP1BID; + input [11:0] MAXIGP1RID; + input [19:0] IRQF2P; + input [1:0] DMA0DRTYPE; + input [1:0] DMA1DRTYPE; + input [1:0] DMA2DRTYPE; + input [1:0] DMA3DRTYPE; + input [1:0] MAXIGP0BRESP; + input [1:0] MAXIGP0RRESP; + input [1:0] MAXIGP1BRESP; + input [1:0] MAXIGP1RRESP; + input [1:0] SAXIACPARBURST; + input [1:0] SAXIACPARLOCK; + input [1:0] SAXIACPARSIZE; + input [1:0] SAXIACPAWBURST; + input [1:0] SAXIACPAWLOCK; + input [1:0] SAXIACPAWSIZE; + input [1:0] SAXIGP0ARBURST; + input [1:0] SAXIGP0ARLOCK; + input [1:0] SAXIGP0ARSIZE; + input [1:0] SAXIGP0AWBURST; + input [1:0] SAXIGP0AWLOCK; + input [1:0] SAXIGP0AWSIZE; + input [1:0] SAXIGP1ARBURST; + input [1:0] SAXIGP1ARLOCK; + input [1:0] SAXIGP1ARSIZE; + input [1:0] SAXIGP1AWBURST; + input [1:0] SAXIGP1AWLOCK; + input [1:0] SAXIGP1AWSIZE; + input [1:0] SAXIHP0ARBURST; + input [1:0] SAXIHP0ARLOCK; + input [1:0] SAXIHP0ARSIZE; + input [1:0] SAXIHP0AWBURST; + input [1:0] SAXIHP0AWLOCK; + input [1:0] SAXIHP0AWSIZE; + input [1:0] SAXIHP1ARBURST; + input [1:0] SAXIHP1ARLOCK; + input [1:0] SAXIHP1ARSIZE; + input [1:0] SAXIHP1AWBURST; + input [1:0] SAXIHP1AWLOCK; + input [1:0] SAXIHP1AWSIZE; + input [1:0] SAXIHP2ARBURST; + input [1:0] SAXIHP2ARLOCK; + input [1:0] SAXIHP2ARSIZE; + input [1:0] SAXIHP2AWBURST; + input [1:0] SAXIHP2AWLOCK; + input [1:0] SAXIHP2AWSIZE; + input [1:0] SAXIHP3ARBURST; + input [1:0] SAXIHP3ARLOCK; + input [1:0] SAXIHP3ARSIZE; + input [1:0] SAXIHP3AWBURST; + input [1:0] SAXIHP3AWLOCK; + input [1:0] SAXIHP3AWSIZE; + input [2:0] EMIOTTC0CLKI; + input [2:0] EMIOTTC1CLKI; + input [2:0] SAXIACPARID; + input [2:0] SAXIACPARPROT; + input [2:0] SAXIACPAWID; + input [2:0] SAXIACPAWPROT; + input [2:0] SAXIACPWID; + input [2:0] SAXIGP0ARPROT; + input [2:0] SAXIGP0AWPROT; + input [2:0] SAXIGP1ARPROT; + input [2:0] SAXIGP1AWPROT; + input [2:0] SAXIHP0ARPROT; + input [2:0] SAXIHP0AWPROT; + input [2:0] SAXIHP1ARPROT; + input [2:0] SAXIHP1AWPROT; + input [2:0] SAXIHP2ARPROT; + input [2:0] SAXIHP2AWPROT; + input [2:0] SAXIHP3ARPROT; + input [2:0] SAXIHP3AWPROT; + input [31:0] FTMDTRACEINDATA; + input [31:0] FTMTF2PDEBUG; + input [31:0] MAXIGP0RDATA; + input [31:0] MAXIGP1RDATA; + input [31:0] SAXIACPARADDR; + input [31:0] SAXIACPAWADDR; + input [31:0] SAXIGP0ARADDR; + input [31:0] SAXIGP0AWADDR; + input [31:0] SAXIGP0WDATA; + input [31:0] SAXIGP1ARADDR; + input [31:0] SAXIGP1AWADDR; + input [31:0] SAXIGP1WDATA; + input [31:0] SAXIHP0ARADDR; + input [31:0] SAXIHP0AWADDR; + input [31:0] SAXIHP1ARADDR; + input [31:0] SAXIHP1AWADDR; + input [31:0] SAXIHP2ARADDR; + input [31:0] SAXIHP2AWADDR; + input [31:0] SAXIHP3ARADDR; + input [31:0] SAXIHP3AWADDR; + input [3:0] DDRARB; + input [3:0] EMIOSDIO0DATAI; + input [3:0] EMIOSDIO1DATAI; + input [3:0] FCLKCLKTRIGN; + input [3:0] FTMDTRACEINATID; + input [3:0] FTMTF2PTRIG; + input [3:0] FTMTP2FTRIGACK; + input [3:0] SAXIACPARCACHE; + input [3:0] SAXIACPARLEN; + input [3:0] SAXIACPARQOS; + input [3:0] SAXIACPAWCACHE; + input [3:0] SAXIACPAWLEN; + input [3:0] SAXIACPAWQOS; + input [3:0] SAXIGP0ARCACHE; + input [3:0] SAXIGP0ARLEN; + input [3:0] SAXIGP0ARQOS; + input [3:0] SAXIGP0AWCACHE; + input [3:0] SAXIGP0AWLEN; + input [3:0] SAXIGP0AWQOS; + input [3:0] SAXIGP0WSTRB; + input [3:0] SAXIGP1ARCACHE; + input [3:0] SAXIGP1ARLEN; + input [3:0] SAXIGP1ARQOS; + input [3:0] SAXIGP1AWCACHE; + input [3:0] SAXIGP1AWLEN; + input [3:0] SAXIGP1AWQOS; + input [3:0] SAXIGP1WSTRB; + input [3:0] SAXIHP0ARCACHE; + input [3:0] SAXIHP0ARLEN; + input [3:0] SAXIHP0ARQOS; + input [3:0] SAXIHP0AWCACHE; + input [3:0] SAXIHP0AWLEN; + input [3:0] SAXIHP0AWQOS; + input [3:0] SAXIHP1ARCACHE; + input [3:0] SAXIHP1ARLEN; + input [3:0] SAXIHP1ARQOS; + input [3:0] SAXIHP1AWCACHE; + input [3:0] SAXIHP1AWLEN; + input [3:0] SAXIHP1AWQOS; + input [3:0] SAXIHP2ARCACHE; + input [3:0] SAXIHP2ARLEN; + input [3:0] SAXIHP2ARQOS; + input [3:0] SAXIHP2AWCACHE; + input [3:0] SAXIHP2AWLEN; + input [3:0] SAXIHP2AWQOS; + input [3:0] SAXIHP3ARCACHE; + input [3:0] SAXIHP3ARLEN; + input [3:0] SAXIHP3ARQOS; + input [3:0] SAXIHP3AWCACHE; + input [3:0] SAXIHP3AWLEN; + input [3:0] SAXIHP3AWQOS; + input [4:0] SAXIACPARUSER; + input [4:0] SAXIACPAWUSER; + input [5:0] SAXIGP0ARID; + input [5:0] SAXIGP0AWID; + input [5:0] SAXIGP0WID; + input [5:0] SAXIGP1ARID; + input [5:0] SAXIGP1AWID; + input [5:0] SAXIGP1WID; + input [5:0] SAXIHP0ARID; + input [5:0] SAXIHP0AWID; + input [5:0] SAXIHP0WID; + input [5:0] SAXIHP1ARID; + input [5:0] SAXIHP1AWID; + input [5:0] SAXIHP1WID; + input [5:0] SAXIHP2ARID; + input [5:0] SAXIHP2AWID; + input [5:0] SAXIHP2WID; + input [5:0] SAXIHP3ARID; + input [5:0] SAXIHP3AWID; + input [5:0] SAXIHP3WID; + input [63:0] EMIOGPIOI; + input [63:0] SAXIACPWDATA; + input [63:0] SAXIHP0WDATA; + input [63:0] SAXIHP1WDATA; + input [63:0] SAXIHP2WDATA; + input [63:0] SAXIHP3WDATA; + input [7:0] EMIOENET0GMIIRXD; + input [7:0] EMIOENET1GMIIRXD; + input [7:0] SAXIACPWSTRB; + input [7:0] SAXIHP0WSTRB; + input [7:0] SAXIHP1WSTRB; + input [7:0] SAXIHP2WSTRB; + input [7:0] SAXIHP3WSTRB; endmodule diff --git a/techlibs/xilinx/xc7_ff_map.v b/techlibs/xilinx/xc7_ff_map.v new file mode 100644 index 000000000..f6197b78b --- /dev/null +++ b/techlibs/xilinx/xc7_ff_map.v @@ -0,0 +1,78 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * + * 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. + * + */ + +// ============================================================================ +// FF mapping + +`ifndef _NO_FFS + +module \$_DFF_N_ (input D, C, output Q); + parameter _TECHMAP_WIREINIT_Q_ = 1'bx; + FDRE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); +endmodule +module \$_DFF_P_ (input D, C, output Q); + parameter _TECHMAP_WIREINIT_Q_ = 1'bx; + FDRE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); +endmodule + +module \$_DFFE_NP_ (input D, C, E, output Q); + parameter _TECHMAP_WIREINIT_Q_ = 1'bx; + FDRE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); +endmodule +module \$_DFFE_PP_ (input D, C, E, output Q); + parameter _TECHMAP_WIREINIT_Q_ = 1'bx; + FDRE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); +endmodule + +module \$_DFF_NN0_ (input D, C, R, output Q); + parameter _TECHMAP_WIREINIT_Q_ = 1'bx; + FDCE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(!R)); +endmodule +module \$_DFF_NP0_ (input D, C, R, output Q); + parameter _TECHMAP_WIREINIT_Q_ = 1'bx; + FDCE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); +endmodule +module \$_DFF_PN0_ (input D, C, R, output Q); + parameter _TECHMAP_WIREINIT_Q_ = 1'bx; + FDCE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(!R)); +endmodule +module \$_DFF_PP0_ (input D, C, R, output Q); + parameter _TECHMAP_WIREINIT_Q_ = 1'bx; + FDCE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); +endmodule + +module \$_DFF_NN1_ (input D, C, R, output Q); + parameter _TECHMAP_WIREINIT_Q_ = 1'bx; + FDPE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(!R)); +endmodule +module \$_DFF_NP1_ (input D, C, R, output Q); + parameter _TECHMAP_WIREINIT_Q_ = 1'bx; + FDPE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); +endmodule +module \$_DFF_PN1_ (input D, C, R, output Q); + parameter _TECHMAP_WIREINIT_Q_ = 1'bx; + FDPE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(!R)); +endmodule +module \$_DFF_PP1_ (input D, C, R, output Q); + parameter _TECHMAP_WIREINIT_Q_ = 1'bx; + FDPE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); +endmodule + +`endif + diff --git a/techlibs/xilinx/xcu_cells_xtra.v b/techlibs/xilinx/xcu_cells_xtra.v new file mode 100644 index 000000000..2d331a221 --- /dev/null +++ b/techlibs/xilinx/xcu_cells_xtra.v @@ -0,0 +1,11798 @@ +// Created by cells_xtra.py from Xilinx models + +module CMAC (...); + parameter CTL_PTP_TRANSPCLK_MODE = "FALSE"; + parameter CTL_RX_CHECK_ACK = "TRUE"; + parameter CTL_RX_CHECK_PREAMBLE = "FALSE"; + parameter CTL_RX_CHECK_SFD = "FALSE"; + parameter CTL_RX_DELETE_FCS = "TRUE"; + parameter [15:0] CTL_RX_ETYPE_GCP = 16'h8808; + parameter [15:0] CTL_RX_ETYPE_GPP = 16'h8808; + parameter [15:0] CTL_RX_ETYPE_PCP = 16'h8808; + parameter [15:0] CTL_RX_ETYPE_PPP = 16'h8808; + parameter CTL_RX_FORWARD_CONTROL = "FALSE"; + parameter CTL_RX_IGNORE_FCS = "FALSE"; + parameter [14:0] CTL_RX_MAX_PACKET_LEN = 15'h2580; + parameter [7:0] CTL_RX_MIN_PACKET_LEN = 8'h40; + parameter [15:0] CTL_RX_OPCODE_GPP = 16'h0001; + parameter [15:0] CTL_RX_OPCODE_MAX_GCP = 16'hFFFF; + parameter [15:0] CTL_RX_OPCODE_MAX_PCP = 16'hFFFF; + parameter [15:0] CTL_RX_OPCODE_MIN_GCP = 16'h0000; + parameter [15:0] CTL_RX_OPCODE_MIN_PCP = 16'h0000; + parameter [15:0] CTL_RX_OPCODE_PPP = 16'h0001; + parameter [47:0] CTL_RX_PAUSE_DA_MCAST = 48'h0180C2000001; + parameter [47:0] CTL_RX_PAUSE_DA_UCAST = 48'h000000000000; + parameter [47:0] CTL_RX_PAUSE_SA = 48'h000000000000; + parameter CTL_RX_PROCESS_LFI = "FALSE"; + parameter [15:0] CTL_RX_VL_LENGTH_MINUS1 = 16'h3FFF; + parameter [63:0] CTL_RX_VL_MARKER_ID0 = 64'hC16821003E97DE00; + parameter [63:0] CTL_RX_VL_MARKER_ID1 = 64'h9D718E00628E7100; + parameter [63:0] CTL_RX_VL_MARKER_ID10 = 64'hFD6C990002936600; + parameter [63:0] CTL_RX_VL_MARKER_ID11 = 64'hB9915500466EAA00; + parameter [63:0] CTL_RX_VL_MARKER_ID12 = 64'h5CB9B200A3464D00; + parameter [63:0] CTL_RX_VL_MARKER_ID13 = 64'h1AF8BD00E5074200; + parameter [63:0] CTL_RX_VL_MARKER_ID14 = 64'h83C7CA007C383500; + parameter [63:0] CTL_RX_VL_MARKER_ID15 = 64'h3536CD00CAC93200; + parameter [63:0] CTL_RX_VL_MARKER_ID16 = 64'hC4314C003BCEB300; + parameter [63:0] CTL_RX_VL_MARKER_ID17 = 64'hADD6B70052294800; + parameter [63:0] CTL_RX_VL_MARKER_ID18 = 64'h5F662A00A099D500; + parameter [63:0] CTL_RX_VL_MARKER_ID19 = 64'hC0F0E5003F0F1A00; + parameter [63:0] CTL_RX_VL_MARKER_ID2 = 64'h594BE800A6B41700; + parameter [63:0] CTL_RX_VL_MARKER_ID3 = 64'h4D957B00B26A8400; + parameter [63:0] CTL_RX_VL_MARKER_ID4 = 64'hF50709000AF8F600; + parameter [63:0] CTL_RX_VL_MARKER_ID5 = 64'hDD14C20022EB3D00; + parameter [63:0] CTL_RX_VL_MARKER_ID6 = 64'h9A4A260065B5D900; + parameter [63:0] CTL_RX_VL_MARKER_ID7 = 64'h7B45660084BA9900; + parameter [63:0] CTL_RX_VL_MARKER_ID8 = 64'hA02476005FDB8900; + parameter [63:0] CTL_RX_VL_MARKER_ID9 = 64'h68C9FB0097360400; + parameter CTL_TEST_MODE_PIN_CHAR = "FALSE"; + parameter [47:0] CTL_TX_DA_GPP = 48'h0180C2000001; + parameter [47:0] CTL_TX_DA_PPP = 48'h0180C2000001; + parameter [15:0] CTL_TX_ETHERTYPE_GPP = 16'h8808; + parameter [15:0] CTL_TX_ETHERTYPE_PPP = 16'h8808; + parameter CTL_TX_FCS_INS_ENABLE = "TRUE"; + parameter CTL_TX_IGNORE_FCS = "FALSE"; + parameter [15:0] CTL_TX_OPCODE_GPP = 16'h0001; + parameter [15:0] CTL_TX_OPCODE_PPP = 16'h0001; + parameter CTL_TX_PTP_1STEP_ENABLE = "FALSE"; + parameter [10:0] CTL_TX_PTP_LATENCY_ADJUST = 11'h2C1; + parameter [47:0] CTL_TX_SA_GPP = 48'h000000000000; + parameter [47:0] CTL_TX_SA_PPP = 48'h000000000000; + parameter [15:0] CTL_TX_VL_LENGTH_MINUS1 = 16'h3FFF; + parameter [63:0] CTL_TX_VL_MARKER_ID0 = 64'hC16821003E97DE00; + parameter [63:0] CTL_TX_VL_MARKER_ID1 = 64'h9D718E00628E7100; + parameter [63:0] CTL_TX_VL_MARKER_ID10 = 64'hFD6C990002936600; + parameter [63:0] CTL_TX_VL_MARKER_ID11 = 64'hB9915500466EAA00; + parameter [63:0] CTL_TX_VL_MARKER_ID12 = 64'h5CB9B200A3464D00; + parameter [63:0] CTL_TX_VL_MARKER_ID13 = 64'h1AF8BD00E5074200; + parameter [63:0] CTL_TX_VL_MARKER_ID14 = 64'h83C7CA007C383500; + parameter [63:0] CTL_TX_VL_MARKER_ID15 = 64'h3536CD00CAC93200; + parameter [63:0] CTL_TX_VL_MARKER_ID16 = 64'hC4314C003BCEB300; + parameter [63:0] CTL_TX_VL_MARKER_ID17 = 64'hADD6B70052294800; + parameter [63:0] CTL_TX_VL_MARKER_ID18 = 64'h5F662A00A099D500; + parameter [63:0] CTL_TX_VL_MARKER_ID19 = 64'hC0F0E5003F0F1A00; + parameter [63:0] CTL_TX_VL_MARKER_ID2 = 64'h594BE800A6B41700; + parameter [63:0] CTL_TX_VL_MARKER_ID3 = 64'h4D957B00B26A8400; + parameter [63:0] CTL_TX_VL_MARKER_ID4 = 64'hF50709000AF8F600; + parameter [63:0] CTL_TX_VL_MARKER_ID5 = 64'hDD14C20022EB3D00; + parameter [63:0] CTL_TX_VL_MARKER_ID6 = 64'h9A4A260065B5D900; + parameter [63:0] CTL_TX_VL_MARKER_ID7 = 64'h7B45660084BA9900; + parameter [63:0] CTL_TX_VL_MARKER_ID8 = 64'hA02476005FDB8900; + parameter [63:0] CTL_TX_VL_MARKER_ID9 = 64'h68C9FB0097360400; + parameter SIM_VERSION = "2.0"; + parameter TEST_MODE_PIN_CHAR = "FALSE"; + output [15:0] DRP_DO; + output DRP_RDY; + output [127:0] RX_DATAOUT0; + output [127:0] RX_DATAOUT1; + output [127:0] RX_DATAOUT2; + output [127:0] RX_DATAOUT3; + output RX_ENAOUT0; + output RX_ENAOUT1; + output RX_ENAOUT2; + output RX_ENAOUT3; + output RX_EOPOUT0; + output RX_EOPOUT1; + output RX_EOPOUT2; + output RX_EOPOUT3; + output RX_ERROUT0; + output RX_ERROUT1; + output RX_ERROUT2; + output RX_ERROUT3; + output [6:0] RX_LANE_ALIGNER_FILL_0; + output [6:0] RX_LANE_ALIGNER_FILL_1; + output [6:0] RX_LANE_ALIGNER_FILL_10; + output [6:0] RX_LANE_ALIGNER_FILL_11; + output [6:0] RX_LANE_ALIGNER_FILL_12; + output [6:0] RX_LANE_ALIGNER_FILL_13; + output [6:0] RX_LANE_ALIGNER_FILL_14; + output [6:0] RX_LANE_ALIGNER_FILL_15; + output [6:0] RX_LANE_ALIGNER_FILL_16; + output [6:0] RX_LANE_ALIGNER_FILL_17; + output [6:0] RX_LANE_ALIGNER_FILL_18; + output [6:0] RX_LANE_ALIGNER_FILL_19; + output [6:0] RX_LANE_ALIGNER_FILL_2; + output [6:0] RX_LANE_ALIGNER_FILL_3; + output [6:0] RX_LANE_ALIGNER_FILL_4; + output [6:0] RX_LANE_ALIGNER_FILL_5; + output [6:0] RX_LANE_ALIGNER_FILL_6; + output [6:0] RX_LANE_ALIGNER_FILL_7; + output [6:0] RX_LANE_ALIGNER_FILL_8; + output [6:0] RX_LANE_ALIGNER_FILL_9; + output [3:0] RX_MTYOUT0; + output [3:0] RX_MTYOUT1; + output [3:0] RX_MTYOUT2; + output [3:0] RX_MTYOUT3; + output [4:0] RX_PTP_PCSLANE_OUT; + output [79:0] RX_PTP_TSTAMP_OUT; + output RX_SOPOUT0; + output RX_SOPOUT1; + output RX_SOPOUT2; + output RX_SOPOUT3; + output STAT_RX_ALIGNED; + output STAT_RX_ALIGNED_ERR; + output [6:0] STAT_RX_BAD_CODE; + output [3:0] STAT_RX_BAD_FCS; + output STAT_RX_BAD_PREAMBLE; + output STAT_RX_BAD_SFD; + output STAT_RX_BIP_ERR_0; + output STAT_RX_BIP_ERR_1; + output STAT_RX_BIP_ERR_10; + output STAT_RX_BIP_ERR_11; + output STAT_RX_BIP_ERR_12; + output STAT_RX_BIP_ERR_13; + output STAT_RX_BIP_ERR_14; + output STAT_RX_BIP_ERR_15; + output STAT_RX_BIP_ERR_16; + output STAT_RX_BIP_ERR_17; + output STAT_RX_BIP_ERR_18; + output STAT_RX_BIP_ERR_19; + output STAT_RX_BIP_ERR_2; + output STAT_RX_BIP_ERR_3; + output STAT_RX_BIP_ERR_4; + output STAT_RX_BIP_ERR_5; + output STAT_RX_BIP_ERR_6; + output STAT_RX_BIP_ERR_7; + output STAT_RX_BIP_ERR_8; + output STAT_RX_BIP_ERR_9; + output [19:0] STAT_RX_BLOCK_LOCK; + output STAT_RX_BROADCAST; + output [3:0] STAT_RX_FRAGMENT; + output [3:0] STAT_RX_FRAMING_ERR_0; + output [3:0] STAT_RX_FRAMING_ERR_1; + output [3:0] STAT_RX_FRAMING_ERR_10; + output [3:0] STAT_RX_FRAMING_ERR_11; + output [3:0] STAT_RX_FRAMING_ERR_12; + output [3:0] STAT_RX_FRAMING_ERR_13; + output [3:0] STAT_RX_FRAMING_ERR_14; + output [3:0] STAT_RX_FRAMING_ERR_15; + output [3:0] STAT_RX_FRAMING_ERR_16; + output [3:0] STAT_RX_FRAMING_ERR_17; + output [3:0] STAT_RX_FRAMING_ERR_18; + output [3:0] STAT_RX_FRAMING_ERR_19; + output [3:0] STAT_RX_FRAMING_ERR_2; + output [3:0] STAT_RX_FRAMING_ERR_3; + output [3:0] STAT_RX_FRAMING_ERR_4; + output [3:0] STAT_RX_FRAMING_ERR_5; + output [3:0] STAT_RX_FRAMING_ERR_6; + output [3:0] STAT_RX_FRAMING_ERR_7; + output [3:0] STAT_RX_FRAMING_ERR_8; + output [3:0] STAT_RX_FRAMING_ERR_9; + output STAT_RX_FRAMING_ERR_VALID_0; + output STAT_RX_FRAMING_ERR_VALID_1; + output STAT_RX_FRAMING_ERR_VALID_10; + output STAT_RX_FRAMING_ERR_VALID_11; + output STAT_RX_FRAMING_ERR_VALID_12; + output STAT_RX_FRAMING_ERR_VALID_13; + output STAT_RX_FRAMING_ERR_VALID_14; + output STAT_RX_FRAMING_ERR_VALID_15; + output STAT_RX_FRAMING_ERR_VALID_16; + output STAT_RX_FRAMING_ERR_VALID_17; + output STAT_RX_FRAMING_ERR_VALID_18; + output STAT_RX_FRAMING_ERR_VALID_19; + output STAT_RX_FRAMING_ERR_VALID_2; + output STAT_RX_FRAMING_ERR_VALID_3; + output STAT_RX_FRAMING_ERR_VALID_4; + output STAT_RX_FRAMING_ERR_VALID_5; + output STAT_RX_FRAMING_ERR_VALID_6; + output STAT_RX_FRAMING_ERR_VALID_7; + output STAT_RX_FRAMING_ERR_VALID_8; + output STAT_RX_FRAMING_ERR_VALID_9; + output STAT_RX_GOT_SIGNAL_OS; + output STAT_RX_HI_BER; + output STAT_RX_INRANGEERR; + output STAT_RX_INTERNAL_LOCAL_FAULT; + output STAT_RX_JABBER; + output [7:0] STAT_RX_LANE0_VLM_BIP7; + output STAT_RX_LANE0_VLM_BIP7_VALID; + output STAT_RX_LOCAL_FAULT; + output [19:0] STAT_RX_MF_ERR; + output [19:0] STAT_RX_MF_LEN_ERR; + output [19:0] STAT_RX_MF_REPEAT_ERR; + output STAT_RX_MISALIGNED; + output STAT_RX_MULTICAST; + output STAT_RX_OVERSIZE; + output STAT_RX_PACKET_1024_1518_BYTES; + output STAT_RX_PACKET_128_255_BYTES; + output STAT_RX_PACKET_1519_1522_BYTES; + output STAT_RX_PACKET_1523_1548_BYTES; + output STAT_RX_PACKET_1549_2047_BYTES; + output STAT_RX_PACKET_2048_4095_BYTES; + output STAT_RX_PACKET_256_511_BYTES; + output STAT_RX_PACKET_4096_8191_BYTES; + output STAT_RX_PACKET_512_1023_BYTES; + output STAT_RX_PACKET_64_BYTES; + output STAT_RX_PACKET_65_127_BYTES; + output STAT_RX_PACKET_8192_9215_BYTES; + output STAT_RX_PACKET_BAD_FCS; + output STAT_RX_PACKET_LARGE; + output [3:0] STAT_RX_PACKET_SMALL; + output STAT_RX_PAUSE; + output [15:0] STAT_RX_PAUSE_QUANTA0; + output [15:0] STAT_RX_PAUSE_QUANTA1; + output [15:0] STAT_RX_PAUSE_QUANTA2; + output [15:0] STAT_RX_PAUSE_QUANTA3; + output [15:0] STAT_RX_PAUSE_QUANTA4; + output [15:0] STAT_RX_PAUSE_QUANTA5; + output [15:0] STAT_RX_PAUSE_QUANTA6; + output [15:0] STAT_RX_PAUSE_QUANTA7; + output [15:0] STAT_RX_PAUSE_QUANTA8; + output [8:0] STAT_RX_PAUSE_REQ; + output [8:0] STAT_RX_PAUSE_VALID; + output STAT_RX_RECEIVED_LOCAL_FAULT; + output STAT_RX_REMOTE_FAULT; + output STAT_RX_STATUS; + output [3:0] STAT_RX_STOMPED_FCS; + output [19:0] STAT_RX_SYNCED; + output [19:0] STAT_RX_SYNCED_ERR; + output [2:0] STAT_RX_TEST_PATTERN_MISMATCH; + output STAT_RX_TOOLONG; + output [7:0] STAT_RX_TOTAL_BYTES; + output [13:0] STAT_RX_TOTAL_GOOD_BYTES; + output STAT_RX_TOTAL_GOOD_PACKETS; + output [3:0] STAT_RX_TOTAL_PACKETS; + output STAT_RX_TRUNCATED; + output [3:0] STAT_RX_UNDERSIZE; + output STAT_RX_UNICAST; + output STAT_RX_USER_PAUSE; + output STAT_RX_VLAN; + output [19:0] STAT_RX_VL_DEMUXED; + output [4:0] STAT_RX_VL_NUMBER_0; + output [4:0] STAT_RX_VL_NUMBER_1; + output [4:0] STAT_RX_VL_NUMBER_10; + output [4:0] STAT_RX_VL_NUMBER_11; + output [4:0] STAT_RX_VL_NUMBER_12; + output [4:0] STAT_RX_VL_NUMBER_13; + output [4:0] STAT_RX_VL_NUMBER_14; + output [4:0] STAT_RX_VL_NUMBER_15; + output [4:0] STAT_RX_VL_NUMBER_16; + output [4:0] STAT_RX_VL_NUMBER_17; + output [4:0] STAT_RX_VL_NUMBER_18; + output [4:0] STAT_RX_VL_NUMBER_19; + output [4:0] STAT_RX_VL_NUMBER_2; + output [4:0] STAT_RX_VL_NUMBER_3; + output [4:0] STAT_RX_VL_NUMBER_4; + output [4:0] STAT_RX_VL_NUMBER_5; + output [4:0] STAT_RX_VL_NUMBER_6; + output [4:0] STAT_RX_VL_NUMBER_7; + output [4:0] STAT_RX_VL_NUMBER_8; + output [4:0] STAT_RX_VL_NUMBER_9; + output STAT_TX_BAD_FCS; + output STAT_TX_BROADCAST; + output STAT_TX_FRAME_ERROR; + output STAT_TX_LOCAL_FAULT; + output STAT_TX_MULTICAST; + output STAT_TX_PACKET_1024_1518_BYTES; + output STAT_TX_PACKET_128_255_BYTES; + output STAT_TX_PACKET_1519_1522_BYTES; + output STAT_TX_PACKET_1523_1548_BYTES; + output STAT_TX_PACKET_1549_2047_BYTES; + output STAT_TX_PACKET_2048_4095_BYTES; + output STAT_TX_PACKET_256_511_BYTES; + output STAT_TX_PACKET_4096_8191_BYTES; + output STAT_TX_PACKET_512_1023_BYTES; + output STAT_TX_PACKET_64_BYTES; + output STAT_TX_PACKET_65_127_BYTES; + output STAT_TX_PACKET_8192_9215_BYTES; + output STAT_TX_PACKET_LARGE; + output STAT_TX_PACKET_SMALL; + output STAT_TX_PAUSE; + output [8:0] STAT_TX_PAUSE_VALID; + output STAT_TX_PTP_FIFO_READ_ERROR; + output STAT_TX_PTP_FIFO_WRITE_ERROR; + output [6:0] STAT_TX_TOTAL_BYTES; + output [13:0] STAT_TX_TOTAL_GOOD_BYTES; + output STAT_TX_TOTAL_GOOD_PACKETS; + output STAT_TX_TOTAL_PACKETS; + output STAT_TX_UNICAST; + output STAT_TX_USER_PAUSE; + output STAT_TX_VLAN; + output TX_OVFOUT; + output [4:0] TX_PTP_PCSLANE_OUT; + output [79:0] TX_PTP_TSTAMP_OUT; + output [15:0] TX_PTP_TSTAMP_TAG_OUT; + output TX_PTP_TSTAMP_VALID_OUT; + output TX_RDYOUT; + output [15:0] TX_SERDES_ALT_DATA0; + output [15:0] TX_SERDES_ALT_DATA1; + output [15:0] TX_SERDES_ALT_DATA2; + output [15:0] TX_SERDES_ALT_DATA3; + output [63:0] TX_SERDES_DATA0; + output [63:0] TX_SERDES_DATA1; + output [63:0] TX_SERDES_DATA2; + output [63:0] TX_SERDES_DATA3; + output [31:0] TX_SERDES_DATA4; + output [31:0] TX_SERDES_DATA5; + output [31:0] TX_SERDES_DATA6; + output [31:0] TX_SERDES_DATA7; + output [31:0] TX_SERDES_DATA8; + output [31:0] TX_SERDES_DATA9; + output TX_UNFOUT; + input CTL_CAUI4_MODE; + input CTL_RX_CHECK_ETYPE_GCP; + input CTL_RX_CHECK_ETYPE_GPP; + input CTL_RX_CHECK_ETYPE_PCP; + input CTL_RX_CHECK_ETYPE_PPP; + input CTL_RX_CHECK_MCAST_GCP; + input CTL_RX_CHECK_MCAST_GPP; + input CTL_RX_CHECK_MCAST_PCP; + input CTL_RX_CHECK_MCAST_PPP; + input CTL_RX_CHECK_OPCODE_GCP; + input CTL_RX_CHECK_OPCODE_GPP; + input CTL_RX_CHECK_OPCODE_PCP; + input CTL_RX_CHECK_OPCODE_PPP; + input CTL_RX_CHECK_SA_GCP; + input CTL_RX_CHECK_SA_GPP; + input CTL_RX_CHECK_SA_PCP; + input CTL_RX_CHECK_SA_PPP; + input CTL_RX_CHECK_UCAST_GCP; + input CTL_RX_CHECK_UCAST_GPP; + input CTL_RX_CHECK_UCAST_PCP; + input CTL_RX_CHECK_UCAST_PPP; + input CTL_RX_ENABLE; + input CTL_RX_ENABLE_GCP; + input CTL_RX_ENABLE_GPP; + input CTL_RX_ENABLE_PCP; + input CTL_RX_ENABLE_PPP; + input CTL_RX_FORCE_RESYNC; + input [8:0] CTL_RX_PAUSE_ACK; + input [8:0] CTL_RX_PAUSE_ENABLE; + input [79:0] CTL_RX_SYSTEMTIMERIN; + input CTL_RX_TEST_PATTERN; + input CTL_TX_ENABLE; + input CTL_TX_LANE0_VLM_BIP7_OVERRIDE; + input [7:0] CTL_TX_LANE0_VLM_BIP7_OVERRIDE_VALUE; + input [8:0] CTL_TX_PAUSE_ENABLE; + input [15:0] CTL_TX_PAUSE_QUANTA0; + input [15:0] CTL_TX_PAUSE_QUANTA1; + input [15:0] CTL_TX_PAUSE_QUANTA2; + input [15:0] CTL_TX_PAUSE_QUANTA3; + input [15:0] CTL_TX_PAUSE_QUANTA4; + input [15:0] CTL_TX_PAUSE_QUANTA5; + input [15:0] CTL_TX_PAUSE_QUANTA6; + input [15:0] CTL_TX_PAUSE_QUANTA7; + input [15:0] CTL_TX_PAUSE_QUANTA8; + input [15:0] CTL_TX_PAUSE_REFRESH_TIMER0; + input [15:0] CTL_TX_PAUSE_REFRESH_TIMER1; + input [15:0] CTL_TX_PAUSE_REFRESH_TIMER2; + input [15:0] CTL_TX_PAUSE_REFRESH_TIMER3; + input [15:0] CTL_TX_PAUSE_REFRESH_TIMER4; + input [15:0] CTL_TX_PAUSE_REFRESH_TIMER5; + input [15:0] CTL_TX_PAUSE_REFRESH_TIMER6; + input [15:0] CTL_TX_PAUSE_REFRESH_TIMER7; + input [15:0] CTL_TX_PAUSE_REFRESH_TIMER8; + input [8:0] CTL_TX_PAUSE_REQ; + input CTL_TX_PTP_VLANE_ADJUST_MODE; + input CTL_TX_RESEND_PAUSE; + input CTL_TX_SEND_IDLE; + input CTL_TX_SEND_RFI; + input [79:0] CTL_TX_SYSTEMTIMERIN; + input CTL_TX_TEST_PATTERN; + input [9:0] DRP_ADDR; + input DRP_CLK; + input [15:0] DRP_DI; + input DRP_EN; + input DRP_WE; + input RX_CLK; + input RX_RESET; + input [15:0] RX_SERDES_ALT_DATA0; + input [15:0] RX_SERDES_ALT_DATA1; + input [15:0] RX_SERDES_ALT_DATA2; + input [15:0] RX_SERDES_ALT_DATA3; + input [9:0] RX_SERDES_CLK; + input [63:0] RX_SERDES_DATA0; + input [63:0] RX_SERDES_DATA1; + input [63:0] RX_SERDES_DATA2; + input [63:0] RX_SERDES_DATA3; + input [31:0] RX_SERDES_DATA4; + input [31:0] RX_SERDES_DATA5; + input [31:0] RX_SERDES_DATA6; + input [31:0] RX_SERDES_DATA7; + input [31:0] RX_SERDES_DATA8; + input [31:0] RX_SERDES_DATA9; + input [9:0] RX_SERDES_RESET; + input TX_CLK; + input [127:0] TX_DATAIN0; + input [127:0] TX_DATAIN1; + input [127:0] TX_DATAIN2; + input [127:0] TX_DATAIN3; + input TX_ENAIN0; + input TX_ENAIN1; + input TX_ENAIN2; + input TX_ENAIN3; + input TX_EOPIN0; + input TX_EOPIN1; + input TX_EOPIN2; + input TX_EOPIN3; + input TX_ERRIN0; + input TX_ERRIN1; + input TX_ERRIN2; + input TX_ERRIN3; + input [3:0] TX_MTYIN0; + input [3:0] TX_MTYIN1; + input [3:0] TX_MTYIN2; + input [3:0] TX_MTYIN3; + input [1:0] TX_PTP_1588OP_IN; + input [15:0] TX_PTP_CHKSUM_OFFSET_IN; + input [63:0] TX_PTP_RXTSTAMP_IN; + input [15:0] TX_PTP_TAG_FIELD_IN; + input [15:0] TX_PTP_TSTAMP_OFFSET_IN; + input TX_PTP_UPD_CHKSUM_IN; + input TX_RESET; + input TX_SOPIN0; + input TX_SOPIN1; + input TX_SOPIN2; + input TX_SOPIN3; +endmodule + +module CMACE4 (...); + parameter CTL_PTP_TRANSPCLK_MODE = "FALSE"; + parameter CTL_RX_CHECK_ACK = "TRUE"; + parameter CTL_RX_CHECK_PREAMBLE = "FALSE"; + parameter CTL_RX_CHECK_SFD = "FALSE"; + parameter CTL_RX_DELETE_FCS = "TRUE"; + parameter [15:0] CTL_RX_ETYPE_GCP = 16'h8808; + parameter [15:0] CTL_RX_ETYPE_GPP = 16'h8808; + parameter [15:0] CTL_RX_ETYPE_PCP = 16'h8808; + parameter [15:0] CTL_RX_ETYPE_PPP = 16'h8808; + parameter CTL_RX_FORWARD_CONTROL = "FALSE"; + parameter CTL_RX_IGNORE_FCS = "FALSE"; + parameter [14:0] CTL_RX_MAX_PACKET_LEN = 15'h2580; + parameter [7:0] CTL_RX_MIN_PACKET_LEN = 8'h40; + parameter [15:0] CTL_RX_OPCODE_GPP = 16'h0001; + parameter [15:0] CTL_RX_OPCODE_MAX_GCP = 16'hFFFF; + parameter [15:0] CTL_RX_OPCODE_MAX_PCP = 16'hFFFF; + parameter [15:0] CTL_RX_OPCODE_MIN_GCP = 16'h0000; + parameter [15:0] CTL_RX_OPCODE_MIN_PCP = 16'h0000; + parameter [15:0] CTL_RX_OPCODE_PPP = 16'h0001; + parameter [47:0] CTL_RX_PAUSE_DA_MCAST = 48'h0180C2000001; + parameter [47:0] CTL_RX_PAUSE_DA_UCAST = 48'h000000000000; + parameter [47:0] CTL_RX_PAUSE_SA = 48'h000000000000; + parameter CTL_RX_PROCESS_LFI = "FALSE"; + parameter [8:0] CTL_RX_RSFEC_AM_THRESHOLD = 9'h046; + parameter [1:0] CTL_RX_RSFEC_FILL_ADJUST = 2'h0; + parameter [15:0] CTL_RX_VL_LENGTH_MINUS1 = 16'h3FFF; + parameter [63:0] CTL_RX_VL_MARKER_ID0 = 64'hC16821003E97DE00; + parameter [63:0] CTL_RX_VL_MARKER_ID1 = 64'h9D718E00628E7100; + parameter [63:0] CTL_RX_VL_MARKER_ID10 = 64'hFD6C990002936600; + parameter [63:0] CTL_RX_VL_MARKER_ID11 = 64'hB9915500466EAA00; + parameter [63:0] CTL_RX_VL_MARKER_ID12 = 64'h5CB9B200A3464D00; + parameter [63:0] CTL_RX_VL_MARKER_ID13 = 64'h1AF8BD00E5074200; + parameter [63:0] CTL_RX_VL_MARKER_ID14 = 64'h83C7CA007C383500; + parameter [63:0] CTL_RX_VL_MARKER_ID15 = 64'h3536CD00CAC93200; + parameter [63:0] CTL_RX_VL_MARKER_ID16 = 64'hC4314C003BCEB300; + parameter [63:0] CTL_RX_VL_MARKER_ID17 = 64'hADD6B70052294800; + parameter [63:0] CTL_RX_VL_MARKER_ID18 = 64'h5F662A00A099D500; + parameter [63:0] CTL_RX_VL_MARKER_ID19 = 64'hC0F0E5003F0F1A00; + parameter [63:0] CTL_RX_VL_MARKER_ID2 = 64'h594BE800A6B41700; + parameter [63:0] CTL_RX_VL_MARKER_ID3 = 64'h4D957B00B26A8400; + parameter [63:0] CTL_RX_VL_MARKER_ID4 = 64'hF50709000AF8F600; + parameter [63:0] CTL_RX_VL_MARKER_ID5 = 64'hDD14C20022EB3D00; + parameter [63:0] CTL_RX_VL_MARKER_ID6 = 64'h9A4A260065B5D900; + parameter [63:0] CTL_RX_VL_MARKER_ID7 = 64'h7B45660084BA9900; + parameter [63:0] CTL_RX_VL_MARKER_ID8 = 64'hA02476005FDB8900; + parameter [63:0] CTL_RX_VL_MARKER_ID9 = 64'h68C9FB0097360400; + parameter CTL_TEST_MODE_PIN_CHAR = "FALSE"; + parameter CTL_TX_CUSTOM_PREAMBLE_ENABLE = "FALSE"; + parameter [47:0] CTL_TX_DA_GPP = 48'h0180C2000001; + parameter [47:0] CTL_TX_DA_PPP = 48'h0180C2000001; + parameter [15:0] CTL_TX_ETHERTYPE_GPP = 16'h8808; + parameter [15:0] CTL_TX_ETHERTYPE_PPP = 16'h8808; + parameter CTL_TX_FCS_INS_ENABLE = "TRUE"; + parameter CTL_TX_IGNORE_FCS = "FALSE"; + parameter [3:0] CTL_TX_IPG_VALUE = 4'hC; + parameter [15:0] CTL_TX_OPCODE_GPP = 16'h0001; + parameter [15:0] CTL_TX_OPCODE_PPP = 16'h0001; + parameter CTL_TX_PTP_1STEP_ENABLE = "FALSE"; + parameter [10:0] CTL_TX_PTP_LATENCY_ADJUST = 11'h2C1; + parameter [47:0] CTL_TX_SA_GPP = 48'h000000000000; + parameter [47:0] CTL_TX_SA_PPP = 48'h000000000000; + parameter [15:0] CTL_TX_VL_LENGTH_MINUS1 = 16'h3FFF; + parameter [63:0] CTL_TX_VL_MARKER_ID0 = 64'hC16821003E97DE00; + parameter [63:0] CTL_TX_VL_MARKER_ID1 = 64'h9D718E00628E7100; + parameter [63:0] CTL_TX_VL_MARKER_ID10 = 64'hFD6C990002936600; + parameter [63:0] CTL_TX_VL_MARKER_ID11 = 64'hB9915500466EAA00; + parameter [63:0] CTL_TX_VL_MARKER_ID12 = 64'h5CB9B200A3464D00; + parameter [63:0] CTL_TX_VL_MARKER_ID13 = 64'h1AF8BD00E5074200; + parameter [63:0] CTL_TX_VL_MARKER_ID14 = 64'h83C7CA007C383500; + parameter [63:0] CTL_TX_VL_MARKER_ID15 = 64'h3536CD00CAC93200; + parameter [63:0] CTL_TX_VL_MARKER_ID16 = 64'hC4314C003BCEB300; + parameter [63:0] CTL_TX_VL_MARKER_ID17 = 64'hADD6B70052294800; + parameter [63:0] CTL_TX_VL_MARKER_ID18 = 64'h5F662A00A099D500; + parameter [63:0] CTL_TX_VL_MARKER_ID19 = 64'hC0F0E5003F0F1A00; + parameter [63:0] CTL_TX_VL_MARKER_ID2 = 64'h594BE800A6B41700; + parameter [63:0] CTL_TX_VL_MARKER_ID3 = 64'h4D957B00B26A8400; + parameter [63:0] CTL_TX_VL_MARKER_ID4 = 64'hF50709000AF8F600; + parameter [63:0] CTL_TX_VL_MARKER_ID5 = 64'hDD14C20022EB3D00; + parameter [63:0] CTL_TX_VL_MARKER_ID6 = 64'h9A4A260065B5D900; + parameter [63:0] CTL_TX_VL_MARKER_ID7 = 64'h7B45660084BA9900; + parameter [63:0] CTL_TX_VL_MARKER_ID8 = 64'hA02476005FDB8900; + parameter [63:0] CTL_TX_VL_MARKER_ID9 = 64'h68C9FB0097360400; + parameter SIM_DEVICE = "ULTRASCALE_PLUS"; + parameter TEST_MODE_PIN_CHAR = "FALSE"; + output [15:0] DRP_DO; + output DRP_RDY; + output [329:0] RSFEC_BYPASS_RX_DOUT; + output RSFEC_BYPASS_RX_DOUT_CW_START; + output RSFEC_BYPASS_RX_DOUT_VALID; + output [329:0] RSFEC_BYPASS_TX_DOUT; + output RSFEC_BYPASS_TX_DOUT_CW_START; + output RSFEC_BYPASS_TX_DOUT_VALID; + output [127:0] RX_DATAOUT0; + output [127:0] RX_DATAOUT1; + output [127:0] RX_DATAOUT2; + output [127:0] RX_DATAOUT3; + output RX_ENAOUT0; + output RX_ENAOUT1; + output RX_ENAOUT2; + output RX_ENAOUT3; + output RX_EOPOUT0; + output RX_EOPOUT1; + output RX_EOPOUT2; + output RX_EOPOUT3; + output RX_ERROUT0; + output RX_ERROUT1; + output RX_ERROUT2; + output RX_ERROUT3; + output [6:0] RX_LANE_ALIGNER_FILL_0; + output [6:0] RX_LANE_ALIGNER_FILL_1; + output [6:0] RX_LANE_ALIGNER_FILL_10; + output [6:0] RX_LANE_ALIGNER_FILL_11; + output [6:0] RX_LANE_ALIGNER_FILL_12; + output [6:0] RX_LANE_ALIGNER_FILL_13; + output [6:0] RX_LANE_ALIGNER_FILL_14; + output [6:0] RX_LANE_ALIGNER_FILL_15; + output [6:0] RX_LANE_ALIGNER_FILL_16; + output [6:0] RX_LANE_ALIGNER_FILL_17; + output [6:0] RX_LANE_ALIGNER_FILL_18; + output [6:0] RX_LANE_ALIGNER_FILL_19; + output [6:0] RX_LANE_ALIGNER_FILL_2; + output [6:0] RX_LANE_ALIGNER_FILL_3; + output [6:0] RX_LANE_ALIGNER_FILL_4; + output [6:0] RX_LANE_ALIGNER_FILL_5; + output [6:0] RX_LANE_ALIGNER_FILL_6; + output [6:0] RX_LANE_ALIGNER_FILL_7; + output [6:0] RX_LANE_ALIGNER_FILL_8; + output [6:0] RX_LANE_ALIGNER_FILL_9; + output [3:0] RX_MTYOUT0; + output [3:0] RX_MTYOUT1; + output [3:0] RX_MTYOUT2; + output [3:0] RX_MTYOUT3; + output [7:0] RX_OTN_BIP8_0; + output [7:0] RX_OTN_BIP8_1; + output [7:0] RX_OTN_BIP8_2; + output [7:0] RX_OTN_BIP8_3; + output [7:0] RX_OTN_BIP8_4; + output [65:0] RX_OTN_DATA_0; + output [65:0] RX_OTN_DATA_1; + output [65:0] RX_OTN_DATA_2; + output [65:0] RX_OTN_DATA_3; + output [65:0] RX_OTN_DATA_4; + output RX_OTN_ENA; + output RX_OTN_LANE0; + output RX_OTN_VLMARKER; + output [55:0] RX_PREOUT; + output [4:0] RX_PTP_PCSLANE_OUT; + output [79:0] RX_PTP_TSTAMP_OUT; + output RX_SOPOUT0; + output RX_SOPOUT1; + output RX_SOPOUT2; + output RX_SOPOUT3; + output STAT_RX_ALIGNED; + output STAT_RX_ALIGNED_ERR; + output [2:0] STAT_RX_BAD_CODE; + output [2:0] STAT_RX_BAD_FCS; + output STAT_RX_BAD_PREAMBLE; + output STAT_RX_BAD_SFD; + output STAT_RX_BIP_ERR_0; + output STAT_RX_BIP_ERR_1; + output STAT_RX_BIP_ERR_10; + output STAT_RX_BIP_ERR_11; + output STAT_RX_BIP_ERR_12; + output STAT_RX_BIP_ERR_13; + output STAT_RX_BIP_ERR_14; + output STAT_RX_BIP_ERR_15; + output STAT_RX_BIP_ERR_16; + output STAT_RX_BIP_ERR_17; + output STAT_RX_BIP_ERR_18; + output STAT_RX_BIP_ERR_19; + output STAT_RX_BIP_ERR_2; + output STAT_RX_BIP_ERR_3; + output STAT_RX_BIP_ERR_4; + output STAT_RX_BIP_ERR_5; + output STAT_RX_BIP_ERR_6; + output STAT_RX_BIP_ERR_7; + output STAT_RX_BIP_ERR_8; + output STAT_RX_BIP_ERR_9; + output [19:0] STAT_RX_BLOCK_LOCK; + output STAT_RX_BROADCAST; + output [2:0] STAT_RX_FRAGMENT; + output [1:0] STAT_RX_FRAMING_ERR_0; + output [1:0] STAT_RX_FRAMING_ERR_1; + output [1:0] STAT_RX_FRAMING_ERR_10; + output [1:0] STAT_RX_FRAMING_ERR_11; + output [1:0] STAT_RX_FRAMING_ERR_12; + output [1:0] STAT_RX_FRAMING_ERR_13; + output [1:0] STAT_RX_FRAMING_ERR_14; + output [1:0] STAT_RX_FRAMING_ERR_15; + output [1:0] STAT_RX_FRAMING_ERR_16; + output [1:0] STAT_RX_FRAMING_ERR_17; + output [1:0] STAT_RX_FRAMING_ERR_18; + output [1:0] STAT_RX_FRAMING_ERR_19; + output [1:0] STAT_RX_FRAMING_ERR_2; + output [1:0] STAT_RX_FRAMING_ERR_3; + output [1:0] STAT_RX_FRAMING_ERR_4; + output [1:0] STAT_RX_FRAMING_ERR_5; + output [1:0] STAT_RX_FRAMING_ERR_6; + output [1:0] STAT_RX_FRAMING_ERR_7; + output [1:0] STAT_RX_FRAMING_ERR_8; + output [1:0] STAT_RX_FRAMING_ERR_9; + output STAT_RX_FRAMING_ERR_VALID_0; + output STAT_RX_FRAMING_ERR_VALID_1; + output STAT_RX_FRAMING_ERR_VALID_10; + output STAT_RX_FRAMING_ERR_VALID_11; + output STAT_RX_FRAMING_ERR_VALID_12; + output STAT_RX_FRAMING_ERR_VALID_13; + output STAT_RX_FRAMING_ERR_VALID_14; + output STAT_RX_FRAMING_ERR_VALID_15; + output STAT_RX_FRAMING_ERR_VALID_16; + output STAT_RX_FRAMING_ERR_VALID_17; + output STAT_RX_FRAMING_ERR_VALID_18; + output STAT_RX_FRAMING_ERR_VALID_19; + output STAT_RX_FRAMING_ERR_VALID_2; + output STAT_RX_FRAMING_ERR_VALID_3; + output STAT_RX_FRAMING_ERR_VALID_4; + output STAT_RX_FRAMING_ERR_VALID_5; + output STAT_RX_FRAMING_ERR_VALID_6; + output STAT_RX_FRAMING_ERR_VALID_7; + output STAT_RX_FRAMING_ERR_VALID_8; + output STAT_RX_FRAMING_ERR_VALID_9; + output STAT_RX_GOT_SIGNAL_OS; + output STAT_RX_HI_BER; + output STAT_RX_INRANGEERR; + output STAT_RX_INTERNAL_LOCAL_FAULT; + output STAT_RX_JABBER; + output [7:0] STAT_RX_LANE0_VLM_BIP7; + output STAT_RX_LANE0_VLM_BIP7_VALID; + output STAT_RX_LOCAL_FAULT; + output [19:0] STAT_RX_MF_ERR; + output [19:0] STAT_RX_MF_LEN_ERR; + output [19:0] STAT_RX_MF_REPEAT_ERR; + output STAT_RX_MISALIGNED; + output STAT_RX_MULTICAST; + output STAT_RX_OVERSIZE; + output STAT_RX_PACKET_1024_1518_BYTES; + output STAT_RX_PACKET_128_255_BYTES; + output STAT_RX_PACKET_1519_1522_BYTES; + output STAT_RX_PACKET_1523_1548_BYTES; + output STAT_RX_PACKET_1549_2047_BYTES; + output STAT_RX_PACKET_2048_4095_BYTES; + output STAT_RX_PACKET_256_511_BYTES; + output STAT_RX_PACKET_4096_8191_BYTES; + output STAT_RX_PACKET_512_1023_BYTES; + output STAT_RX_PACKET_64_BYTES; + output STAT_RX_PACKET_65_127_BYTES; + output STAT_RX_PACKET_8192_9215_BYTES; + output STAT_RX_PACKET_BAD_FCS; + output STAT_RX_PACKET_LARGE; + output [2:0] STAT_RX_PACKET_SMALL; + output STAT_RX_PAUSE; + output [15:0] STAT_RX_PAUSE_QUANTA0; + output [15:0] STAT_RX_PAUSE_QUANTA1; + output [15:0] STAT_RX_PAUSE_QUANTA2; + output [15:0] STAT_RX_PAUSE_QUANTA3; + output [15:0] STAT_RX_PAUSE_QUANTA4; + output [15:0] STAT_RX_PAUSE_QUANTA5; + output [15:0] STAT_RX_PAUSE_QUANTA6; + output [15:0] STAT_RX_PAUSE_QUANTA7; + output [15:0] STAT_RX_PAUSE_QUANTA8; + output [8:0] STAT_RX_PAUSE_REQ; + output [8:0] STAT_RX_PAUSE_VALID; + output STAT_RX_RECEIVED_LOCAL_FAULT; + output STAT_RX_REMOTE_FAULT; + output STAT_RX_RSFEC_AM_LOCK0; + output STAT_RX_RSFEC_AM_LOCK1; + output STAT_RX_RSFEC_AM_LOCK2; + output STAT_RX_RSFEC_AM_LOCK3; + output STAT_RX_RSFEC_CORRECTED_CW_INC; + output STAT_RX_RSFEC_CW_INC; + output [2:0] STAT_RX_RSFEC_ERR_COUNT0_INC; + output [2:0] STAT_RX_RSFEC_ERR_COUNT1_INC; + output [2:0] STAT_RX_RSFEC_ERR_COUNT2_INC; + output [2:0] STAT_RX_RSFEC_ERR_COUNT3_INC; + output STAT_RX_RSFEC_HI_SER; + output STAT_RX_RSFEC_LANE_ALIGNMENT_STATUS; + output [13:0] STAT_RX_RSFEC_LANE_FILL_0; + output [13:0] STAT_RX_RSFEC_LANE_FILL_1; + output [13:0] STAT_RX_RSFEC_LANE_FILL_2; + output [13:0] STAT_RX_RSFEC_LANE_FILL_3; + output [7:0] STAT_RX_RSFEC_LANE_MAPPING; + output [31:0] STAT_RX_RSFEC_RSVD; + output STAT_RX_RSFEC_UNCORRECTED_CW_INC; + output STAT_RX_STATUS; + output [2:0] STAT_RX_STOMPED_FCS; + output [19:0] STAT_RX_SYNCED; + output [19:0] STAT_RX_SYNCED_ERR; + output [2:0] STAT_RX_TEST_PATTERN_MISMATCH; + output STAT_RX_TOOLONG; + output [6:0] STAT_RX_TOTAL_BYTES; + output [13:0] STAT_RX_TOTAL_GOOD_BYTES; + output STAT_RX_TOTAL_GOOD_PACKETS; + output [2:0] STAT_RX_TOTAL_PACKETS; + output STAT_RX_TRUNCATED; + output [2:0] STAT_RX_UNDERSIZE; + output STAT_RX_UNICAST; + output STAT_RX_USER_PAUSE; + output STAT_RX_VLAN; + output [19:0] STAT_RX_VL_DEMUXED; + output [4:0] STAT_RX_VL_NUMBER_0; + output [4:0] STAT_RX_VL_NUMBER_1; + output [4:0] STAT_RX_VL_NUMBER_10; + output [4:0] STAT_RX_VL_NUMBER_11; + output [4:0] STAT_RX_VL_NUMBER_12; + output [4:0] STAT_RX_VL_NUMBER_13; + output [4:0] STAT_RX_VL_NUMBER_14; + output [4:0] STAT_RX_VL_NUMBER_15; + output [4:0] STAT_RX_VL_NUMBER_16; + output [4:0] STAT_RX_VL_NUMBER_17; + output [4:0] STAT_RX_VL_NUMBER_18; + output [4:0] STAT_RX_VL_NUMBER_19; + output [4:0] STAT_RX_VL_NUMBER_2; + output [4:0] STAT_RX_VL_NUMBER_3; + output [4:0] STAT_RX_VL_NUMBER_4; + output [4:0] STAT_RX_VL_NUMBER_5; + output [4:0] STAT_RX_VL_NUMBER_6; + output [4:0] STAT_RX_VL_NUMBER_7; + output [4:0] STAT_RX_VL_NUMBER_8; + output [4:0] STAT_RX_VL_NUMBER_9; + output STAT_TX_BAD_FCS; + output STAT_TX_BROADCAST; + output STAT_TX_FRAME_ERROR; + output STAT_TX_LOCAL_FAULT; + output STAT_TX_MULTICAST; + output STAT_TX_PACKET_1024_1518_BYTES; + output STAT_TX_PACKET_128_255_BYTES; + output STAT_TX_PACKET_1519_1522_BYTES; + output STAT_TX_PACKET_1523_1548_BYTES; + output STAT_TX_PACKET_1549_2047_BYTES; + output STAT_TX_PACKET_2048_4095_BYTES; + output STAT_TX_PACKET_256_511_BYTES; + output STAT_TX_PACKET_4096_8191_BYTES; + output STAT_TX_PACKET_512_1023_BYTES; + output STAT_TX_PACKET_64_BYTES; + output STAT_TX_PACKET_65_127_BYTES; + output STAT_TX_PACKET_8192_9215_BYTES; + output STAT_TX_PACKET_LARGE; + output STAT_TX_PACKET_SMALL; + output STAT_TX_PAUSE; + output [8:0] STAT_TX_PAUSE_VALID; + output STAT_TX_PTP_FIFO_READ_ERROR; + output STAT_TX_PTP_FIFO_WRITE_ERROR; + output [5:0] STAT_TX_TOTAL_BYTES; + output [13:0] STAT_TX_TOTAL_GOOD_BYTES; + output STAT_TX_TOTAL_GOOD_PACKETS; + output STAT_TX_TOTAL_PACKETS; + output STAT_TX_UNICAST; + output STAT_TX_USER_PAUSE; + output STAT_TX_VLAN; + output TX_OVFOUT; + output [4:0] TX_PTP_PCSLANE_OUT; + output [79:0] TX_PTP_TSTAMP_OUT; + output [15:0] TX_PTP_TSTAMP_TAG_OUT; + output TX_PTP_TSTAMP_VALID_OUT; + output TX_RDYOUT; + output [15:0] TX_SERDES_ALT_DATA0; + output [15:0] TX_SERDES_ALT_DATA1; + output [15:0] TX_SERDES_ALT_DATA2; + output [15:0] TX_SERDES_ALT_DATA3; + output [63:0] TX_SERDES_DATA0; + output [63:0] TX_SERDES_DATA1; + output [63:0] TX_SERDES_DATA2; + output [63:0] TX_SERDES_DATA3; + output [31:0] TX_SERDES_DATA4; + output [31:0] TX_SERDES_DATA5; + output [31:0] TX_SERDES_DATA6; + output [31:0] TX_SERDES_DATA7; + output [31:0] TX_SERDES_DATA8; + output [31:0] TX_SERDES_DATA9; + output TX_UNFOUT; + input CTL_CAUI4_MODE; + input CTL_RSFEC_ENABLE_TRANSCODER_BYPASS_MODE; + input CTL_RSFEC_IEEE_ERROR_INDICATION_MODE; + input CTL_RX_CHECK_ETYPE_GCP; + input CTL_RX_CHECK_ETYPE_GPP; + input CTL_RX_CHECK_ETYPE_PCP; + input CTL_RX_CHECK_ETYPE_PPP; + input CTL_RX_CHECK_MCAST_GCP; + input CTL_RX_CHECK_MCAST_GPP; + input CTL_RX_CHECK_MCAST_PCP; + input CTL_RX_CHECK_MCAST_PPP; + input CTL_RX_CHECK_OPCODE_GCP; + input CTL_RX_CHECK_OPCODE_GPP; + input CTL_RX_CHECK_OPCODE_PCP; + input CTL_RX_CHECK_OPCODE_PPP; + input CTL_RX_CHECK_SA_GCP; + input CTL_RX_CHECK_SA_GPP; + input CTL_RX_CHECK_SA_PCP; + input CTL_RX_CHECK_SA_PPP; + input CTL_RX_CHECK_UCAST_GCP; + input CTL_RX_CHECK_UCAST_GPP; + input CTL_RX_CHECK_UCAST_PCP; + input CTL_RX_CHECK_UCAST_PPP; + input CTL_RX_ENABLE; + input CTL_RX_ENABLE_GCP; + input CTL_RX_ENABLE_GPP; + input CTL_RX_ENABLE_PCP; + input CTL_RX_ENABLE_PPP; + input CTL_RX_FORCE_RESYNC; + input [8:0] CTL_RX_PAUSE_ACK; + input [8:0] CTL_RX_PAUSE_ENABLE; + input CTL_RX_RSFEC_ENABLE; + input CTL_RX_RSFEC_ENABLE_CORRECTION; + input CTL_RX_RSFEC_ENABLE_INDICATION; + input [79:0] CTL_RX_SYSTEMTIMERIN; + input CTL_RX_TEST_PATTERN; + input CTL_TX_ENABLE; + input CTL_TX_LANE0_VLM_BIP7_OVERRIDE; + input [7:0] CTL_TX_LANE0_VLM_BIP7_OVERRIDE_VALUE; + input [8:0] CTL_TX_PAUSE_ENABLE; + input [15:0] CTL_TX_PAUSE_QUANTA0; + input [15:0] CTL_TX_PAUSE_QUANTA1; + input [15:0] CTL_TX_PAUSE_QUANTA2; + input [15:0] CTL_TX_PAUSE_QUANTA3; + input [15:0] CTL_TX_PAUSE_QUANTA4; + input [15:0] CTL_TX_PAUSE_QUANTA5; + input [15:0] CTL_TX_PAUSE_QUANTA6; + input [15:0] CTL_TX_PAUSE_QUANTA7; + input [15:0] CTL_TX_PAUSE_QUANTA8; + input [15:0] CTL_TX_PAUSE_REFRESH_TIMER0; + input [15:0] CTL_TX_PAUSE_REFRESH_TIMER1; + input [15:0] CTL_TX_PAUSE_REFRESH_TIMER2; + input [15:0] CTL_TX_PAUSE_REFRESH_TIMER3; + input [15:0] CTL_TX_PAUSE_REFRESH_TIMER4; + input [15:0] CTL_TX_PAUSE_REFRESH_TIMER5; + input [15:0] CTL_TX_PAUSE_REFRESH_TIMER6; + input [15:0] CTL_TX_PAUSE_REFRESH_TIMER7; + input [15:0] CTL_TX_PAUSE_REFRESH_TIMER8; + input [8:0] CTL_TX_PAUSE_REQ; + input CTL_TX_PTP_VLANE_ADJUST_MODE; + input CTL_TX_RESEND_PAUSE; + input CTL_TX_RSFEC_ENABLE; + input CTL_TX_SEND_IDLE; + input CTL_TX_SEND_LFI; + input CTL_TX_SEND_RFI; + input [79:0] CTL_TX_SYSTEMTIMERIN; + input CTL_TX_TEST_PATTERN; + input [9:0] DRP_ADDR; + input DRP_CLK; + input [15:0] DRP_DI; + input DRP_EN; + input DRP_WE; + input [329:0] RSFEC_BYPASS_RX_DIN; + input RSFEC_BYPASS_RX_DIN_CW_START; + input [329:0] RSFEC_BYPASS_TX_DIN; + input RSFEC_BYPASS_TX_DIN_CW_START; + input RX_CLK; + input RX_RESET; + input [15:0] RX_SERDES_ALT_DATA0; + input [15:0] RX_SERDES_ALT_DATA1; + input [15:0] RX_SERDES_ALT_DATA2; + input [15:0] RX_SERDES_ALT_DATA3; + input [9:0] RX_SERDES_CLK; + input [63:0] RX_SERDES_DATA0; + input [63:0] RX_SERDES_DATA1; + input [63:0] RX_SERDES_DATA2; + input [63:0] RX_SERDES_DATA3; + input [31:0] RX_SERDES_DATA4; + input [31:0] RX_SERDES_DATA5; + input [31:0] RX_SERDES_DATA6; + input [31:0] RX_SERDES_DATA7; + input [31:0] RX_SERDES_DATA8; + input [31:0] RX_SERDES_DATA9; + input [9:0] RX_SERDES_RESET; + input TX_CLK; + input [127:0] TX_DATAIN0; + input [127:0] TX_DATAIN1; + input [127:0] TX_DATAIN2; + input [127:0] TX_DATAIN3; + input TX_ENAIN0; + input TX_ENAIN1; + input TX_ENAIN2; + input TX_ENAIN3; + input TX_EOPIN0; + input TX_EOPIN1; + input TX_EOPIN2; + input TX_EOPIN3; + input TX_ERRIN0; + input TX_ERRIN1; + input TX_ERRIN2; + input TX_ERRIN3; + input [3:0] TX_MTYIN0; + input [3:0] TX_MTYIN1; + input [3:0] TX_MTYIN2; + input [3:0] TX_MTYIN3; + input [55:0] TX_PREIN; + input [1:0] TX_PTP_1588OP_IN; + input [15:0] TX_PTP_CHKSUM_OFFSET_IN; + input [63:0] TX_PTP_RXTSTAMP_IN; + input [15:0] TX_PTP_TAG_FIELD_IN; + input [15:0] TX_PTP_TSTAMP_OFFSET_IN; + input TX_PTP_UPD_CHKSUM_IN; + input TX_RESET; + input TX_SOPIN0; + input TX_SOPIN1; + input TX_SOPIN2; + input TX_SOPIN3; +endmodule + +module GTHE3_CHANNEL (...); + parameter [0:0] ACJTAG_DEBUG_MODE = 1'b0; + parameter [0:0] ACJTAG_MODE = 1'b0; + parameter [0:0] ACJTAG_RESET = 1'b0; + parameter [15:0] ADAPT_CFG0 = 16'hF800; + parameter [15:0] ADAPT_CFG1 = 16'h0000; + parameter ALIGN_COMMA_DOUBLE = "FALSE"; + parameter [9:0] ALIGN_COMMA_ENABLE = 10'b0001111111; + parameter integer ALIGN_COMMA_WORD = 1; + parameter ALIGN_MCOMMA_DET = "TRUE"; + parameter [9:0] ALIGN_MCOMMA_VALUE = 10'b1010000011; + parameter ALIGN_PCOMMA_DET = "TRUE"; + parameter [9:0] ALIGN_PCOMMA_VALUE = 10'b0101111100; + parameter [0:0] A_RXOSCALRESET = 1'b0; + parameter [0:0] A_RXPROGDIVRESET = 1'b0; + parameter [0:0] A_TXPROGDIVRESET = 1'b0; + parameter CBCC_DATA_SOURCE_SEL = "DECODED"; + parameter [0:0] CDR_SWAP_MODE_EN = 1'b0; + parameter CHAN_BOND_KEEP_ALIGN = "FALSE"; + parameter integer CHAN_BOND_MAX_SKEW = 7; + parameter [9:0] CHAN_BOND_SEQ_1_1 = 10'b0101111100; + parameter [9:0] CHAN_BOND_SEQ_1_2 = 10'b0000000000; + parameter [9:0] CHAN_BOND_SEQ_1_3 = 10'b0000000000; + parameter [9:0] CHAN_BOND_SEQ_1_4 = 10'b0000000000; + parameter [3:0] CHAN_BOND_SEQ_1_ENABLE = 4'b1111; + parameter [9:0] CHAN_BOND_SEQ_2_1 = 10'b0100000000; + parameter [9:0] CHAN_BOND_SEQ_2_2 = 10'b0100000000; + parameter [9:0] CHAN_BOND_SEQ_2_3 = 10'b0100000000; + parameter [9:0] CHAN_BOND_SEQ_2_4 = 10'b0100000000; + parameter [3:0] CHAN_BOND_SEQ_2_ENABLE = 4'b1111; + parameter CHAN_BOND_SEQ_2_USE = "FALSE"; + parameter integer CHAN_BOND_SEQ_LEN = 2; + parameter CLK_CORRECT_USE = "TRUE"; + parameter CLK_COR_KEEP_IDLE = "FALSE"; + parameter integer CLK_COR_MAX_LAT = 20; + parameter integer CLK_COR_MIN_LAT = 18; + parameter CLK_COR_PRECEDENCE = "TRUE"; + parameter integer CLK_COR_REPEAT_WAIT = 0; + parameter [9:0] CLK_COR_SEQ_1_1 = 10'b0100011100; + parameter [9:0] CLK_COR_SEQ_1_2 = 10'b0000000000; + parameter [9:0] CLK_COR_SEQ_1_3 = 10'b0000000000; + parameter [9:0] CLK_COR_SEQ_1_4 = 10'b0000000000; + parameter [3:0] CLK_COR_SEQ_1_ENABLE = 4'b1111; + parameter [9:0] CLK_COR_SEQ_2_1 = 10'b0100000000; + parameter [9:0] CLK_COR_SEQ_2_2 = 10'b0100000000; + parameter [9:0] CLK_COR_SEQ_2_3 = 10'b0100000000; + parameter [9:0] CLK_COR_SEQ_2_4 = 10'b0100000000; + parameter [3:0] CLK_COR_SEQ_2_ENABLE = 4'b1111; + parameter CLK_COR_SEQ_2_USE = "FALSE"; + parameter integer CLK_COR_SEQ_LEN = 2; + parameter [15:0] CPLL_CFG0 = 16'h20F8; + parameter [15:0] CPLL_CFG1 = 16'hA494; + parameter [15:0] CPLL_CFG2 = 16'hF001; + parameter [5:0] CPLL_CFG3 = 6'h00; + parameter integer CPLL_FBDIV = 4; + parameter integer CPLL_FBDIV_45 = 4; + parameter [15:0] CPLL_INIT_CFG0 = 16'h001E; + parameter [7:0] CPLL_INIT_CFG1 = 8'h00; + parameter [15:0] CPLL_LOCK_CFG = 16'h01E8; + parameter integer CPLL_REFCLK_DIV = 1; + parameter [1:0] DDI_CTRL = 2'b00; + parameter integer DDI_REALIGN_WAIT = 15; + parameter DEC_MCOMMA_DETECT = "TRUE"; + parameter DEC_PCOMMA_DETECT = "TRUE"; + parameter DEC_VALID_COMMA_ONLY = "TRUE"; + parameter [0:0] DFE_D_X_REL_POS = 1'b0; + parameter [0:0] DFE_VCM_COMP_EN = 1'b0; + parameter [9:0] DMONITOR_CFG0 = 10'h000; + parameter [7:0] DMONITOR_CFG1 = 8'h00; + parameter [0:0] ES_CLK_PHASE_SEL = 1'b0; + parameter [5:0] ES_CONTROL = 6'b000000; + parameter ES_ERRDET_EN = "FALSE"; + parameter ES_EYE_SCAN_EN = "FALSE"; + parameter [11:0] ES_HORZ_OFFSET = 12'h000; + parameter [9:0] ES_PMA_CFG = 10'b0000000000; + parameter [4:0] ES_PRESCALE = 5'b00000; + parameter [15:0] ES_QUALIFIER0 = 16'h0000; + parameter [15:0] ES_QUALIFIER1 = 16'h0000; + parameter [15:0] ES_QUALIFIER2 = 16'h0000; + parameter [15:0] ES_QUALIFIER3 = 16'h0000; + parameter [15:0] ES_QUALIFIER4 = 16'h0000; + parameter [15:0] ES_QUAL_MASK0 = 16'h0000; + parameter [15:0] ES_QUAL_MASK1 = 16'h0000; + parameter [15:0] ES_QUAL_MASK2 = 16'h0000; + parameter [15:0] ES_QUAL_MASK3 = 16'h0000; + parameter [15:0] ES_QUAL_MASK4 = 16'h0000; + parameter [15:0] ES_SDATA_MASK0 = 16'h0000; + parameter [15:0] ES_SDATA_MASK1 = 16'h0000; + parameter [15:0] ES_SDATA_MASK2 = 16'h0000; + parameter [15:0] ES_SDATA_MASK3 = 16'h0000; + parameter [15:0] ES_SDATA_MASK4 = 16'h0000; + parameter [10:0] EVODD_PHI_CFG = 11'b00000000000; + parameter [0:0] EYE_SCAN_SWAP_EN = 1'b0; + parameter [3:0] FTS_DESKEW_SEQ_ENABLE = 4'b1111; + parameter [3:0] FTS_LANE_DESKEW_CFG = 4'b1111; + parameter FTS_LANE_DESKEW_EN = "FALSE"; + parameter [4:0] GEARBOX_MODE = 5'b00000; + parameter [0:0] GM_BIAS_SELECT = 1'b0; + parameter [0:0] LOCAL_MASTER = 1'b0; + parameter [1:0] OOBDIVCTL = 2'b00; + parameter [0:0] OOB_PWRUP = 1'b0; + parameter PCI3_AUTO_REALIGN = "FRST_SMPL"; + parameter [0:0] PCI3_PIPE_RX_ELECIDLE = 1'b1; + parameter [1:0] PCI3_RX_ASYNC_EBUF_BYPASS = 2'b00; + parameter [0:0] PCI3_RX_ELECIDLE_EI2_ENABLE = 1'b0; + parameter [5:0] PCI3_RX_ELECIDLE_H2L_COUNT = 6'b000000; + parameter [2:0] PCI3_RX_ELECIDLE_H2L_DISABLE = 3'b000; + parameter [5:0] PCI3_RX_ELECIDLE_HI_COUNT = 6'b000000; + parameter [0:0] PCI3_RX_ELECIDLE_LP4_DISABLE = 1'b0; + parameter [0:0] PCI3_RX_FIFO_DISABLE = 1'b0; + parameter [15:0] PCIE_BUFG_DIV_CTRL = 16'h0000; + parameter [15:0] PCIE_RXPCS_CFG_GEN3 = 16'h0000; + parameter [15:0] PCIE_RXPMA_CFG = 16'h0000; + parameter [15:0] PCIE_TXPCS_CFG_GEN3 = 16'h0000; + parameter [15:0] PCIE_TXPMA_CFG = 16'h0000; + parameter PCS_PCIE_EN = "FALSE"; + parameter [15:0] PCS_RSVD0 = 16'b0000000000000000; + parameter [2:0] PCS_RSVD1 = 3'b000; + parameter [11:0] PD_TRANS_TIME_FROM_P2 = 12'h03C; + parameter [7:0] PD_TRANS_TIME_NONE_P2 = 8'h19; + parameter [7:0] PD_TRANS_TIME_TO_P2 = 8'h64; + parameter [1:0] PLL_SEL_MODE_GEN12 = 2'h0; + parameter [1:0] PLL_SEL_MODE_GEN3 = 2'h0; + parameter [15:0] PMA_RSV1 = 16'h0000; + parameter [2:0] PROCESS_PAR = 3'b010; + parameter [0:0] RATE_SW_USE_DRP = 1'b0; + parameter [0:0] RESET_POWERSAVE_DISABLE = 1'b0; + parameter [4:0] RXBUFRESET_TIME = 5'b00001; + parameter RXBUF_ADDR_MODE = "FULL"; + parameter [3:0] RXBUF_EIDLE_HI_CNT = 4'b1000; + parameter [3:0] RXBUF_EIDLE_LO_CNT = 4'b0000; + parameter RXBUF_EN = "TRUE"; + parameter RXBUF_RESET_ON_CB_CHANGE = "TRUE"; + parameter RXBUF_RESET_ON_COMMAALIGN = "FALSE"; + parameter RXBUF_RESET_ON_EIDLE = "FALSE"; + parameter RXBUF_RESET_ON_RATE_CHANGE = "TRUE"; + parameter integer RXBUF_THRESH_OVFLW = 0; + parameter RXBUF_THRESH_OVRD = "FALSE"; + parameter integer RXBUF_THRESH_UNDFLW = 4; + parameter [4:0] RXCDRFREQRESET_TIME = 5'b00001; + parameter [4:0] RXCDRPHRESET_TIME = 5'b00001; + parameter [15:0] RXCDR_CFG0 = 16'h0000; + parameter [15:0] RXCDR_CFG0_GEN3 = 16'h0000; + parameter [15:0] RXCDR_CFG1 = 16'h0080; + parameter [15:0] RXCDR_CFG1_GEN3 = 16'h0000; + parameter [15:0] RXCDR_CFG2 = 16'h07E6; + parameter [15:0] RXCDR_CFG2_GEN3 = 16'h0000; + parameter [15:0] RXCDR_CFG3 = 16'h0000; + parameter [15:0] RXCDR_CFG3_GEN3 = 16'h0000; + parameter [15:0] RXCDR_CFG4 = 16'h0000; + parameter [15:0] RXCDR_CFG4_GEN3 = 16'h0000; + parameter [15:0] RXCDR_CFG5 = 16'h0000; + parameter [15:0] RXCDR_CFG5_GEN3 = 16'h0000; + parameter [0:0] RXCDR_FR_RESET_ON_EIDLE = 1'b0; + parameter [0:0] RXCDR_HOLD_DURING_EIDLE = 1'b0; + parameter [15:0] RXCDR_LOCK_CFG0 = 16'h5080; + parameter [15:0] RXCDR_LOCK_CFG1 = 16'h07E0; + parameter [15:0] RXCDR_LOCK_CFG2 = 16'h7C42; + parameter [0:0] RXCDR_PH_RESET_ON_EIDLE = 1'b0; + parameter [15:0] RXCFOK_CFG0 = 16'h4000; + parameter [15:0] RXCFOK_CFG1 = 16'h0060; + parameter [15:0] RXCFOK_CFG2 = 16'h000E; + parameter [6:0] RXDFELPMRESET_TIME = 7'b0001111; + parameter [15:0] RXDFELPM_KL_CFG0 = 16'h0000; + parameter [15:0] RXDFELPM_KL_CFG1 = 16'h0032; + parameter [15:0] RXDFELPM_KL_CFG2 = 16'h0000; + parameter [15:0] RXDFE_CFG0 = 16'h0A00; + parameter [15:0] RXDFE_CFG1 = 16'h0000; + parameter [15:0] RXDFE_GC_CFG0 = 16'h0000; + parameter [15:0] RXDFE_GC_CFG1 = 16'h7840; + parameter [15:0] RXDFE_GC_CFG2 = 16'h0000; + parameter [15:0] RXDFE_H2_CFG0 = 16'h0000; + parameter [15:0] RXDFE_H2_CFG1 = 16'h0000; + parameter [15:0] RXDFE_H3_CFG0 = 16'h4000; + parameter [15:0] RXDFE_H3_CFG1 = 16'h0000; + parameter [15:0] RXDFE_H4_CFG0 = 16'h2000; + parameter [15:0] RXDFE_H4_CFG1 = 16'h0003; + parameter [15:0] RXDFE_H5_CFG0 = 16'h2000; + parameter [15:0] RXDFE_H5_CFG1 = 16'h0003; + parameter [15:0] RXDFE_H6_CFG0 = 16'h2000; + parameter [15:0] RXDFE_H6_CFG1 = 16'h0000; + parameter [15:0] RXDFE_H7_CFG0 = 16'h2000; + parameter [15:0] RXDFE_H7_CFG1 = 16'h0000; + parameter [15:0] RXDFE_H8_CFG0 = 16'h2000; + parameter [15:0] RXDFE_H8_CFG1 = 16'h0000; + parameter [15:0] RXDFE_H9_CFG0 = 16'h2000; + parameter [15:0] RXDFE_H9_CFG1 = 16'h0000; + parameter [15:0] RXDFE_HA_CFG0 = 16'h2000; + parameter [15:0] RXDFE_HA_CFG1 = 16'h0000; + parameter [15:0] RXDFE_HB_CFG0 = 16'h2000; + parameter [15:0] RXDFE_HB_CFG1 = 16'h0000; + parameter [15:0] RXDFE_HC_CFG0 = 16'h0000; + parameter [15:0] RXDFE_HC_CFG1 = 16'h0000; + parameter [15:0] RXDFE_HD_CFG0 = 16'h0000; + parameter [15:0] RXDFE_HD_CFG1 = 16'h0000; + parameter [15:0] RXDFE_HE_CFG0 = 16'h0000; + parameter [15:0] RXDFE_HE_CFG1 = 16'h0000; + parameter [15:0] RXDFE_HF_CFG0 = 16'h0000; + parameter [15:0] RXDFE_HF_CFG1 = 16'h0000; + parameter [15:0] RXDFE_OS_CFG0 = 16'h8000; + parameter [15:0] RXDFE_OS_CFG1 = 16'h0000; + parameter [15:0] RXDFE_UT_CFG0 = 16'h8000; + parameter [15:0] RXDFE_UT_CFG1 = 16'h0003; + parameter [15:0] RXDFE_VP_CFG0 = 16'hAA00; + parameter [15:0] RXDFE_VP_CFG1 = 16'h0033; + parameter [15:0] RXDLY_CFG = 16'h001F; + parameter [15:0] RXDLY_LCFG = 16'h0030; + parameter RXELECIDLE_CFG = "Sigcfg_4"; + parameter integer RXGBOX_FIFO_INIT_RD_ADDR = 4; + parameter RXGEARBOX_EN = "FALSE"; + parameter [4:0] RXISCANRESET_TIME = 5'b00001; + parameter [15:0] RXLPM_CFG = 16'h0000; + parameter [15:0] RXLPM_GC_CFG = 16'h0000; + parameter [15:0] RXLPM_KH_CFG0 = 16'h0000; + parameter [15:0] RXLPM_KH_CFG1 = 16'h0002; + parameter [15:0] RXLPM_OS_CFG0 = 16'h8000; + parameter [15:0] RXLPM_OS_CFG1 = 16'h0002; + parameter [8:0] RXOOB_CFG = 9'b000000110; + parameter RXOOB_CLK_CFG = "PMA"; + parameter [4:0] RXOSCALRESET_TIME = 5'b00011; + parameter integer RXOUT_DIV = 4; + parameter [4:0] RXPCSRESET_TIME = 5'b00001; + parameter [15:0] RXPHBEACON_CFG = 16'h0000; + parameter [15:0] RXPHDLY_CFG = 16'h2020; + parameter [15:0] RXPHSAMP_CFG = 16'h2100; + parameter [15:0] RXPHSLIP_CFG = 16'h6622; + parameter [4:0] RXPH_MONITOR_SEL = 5'b00000; + parameter [1:0] RXPI_CFG0 = 2'b00; + parameter [1:0] RXPI_CFG1 = 2'b00; + parameter [1:0] RXPI_CFG2 = 2'b00; + parameter [1:0] RXPI_CFG3 = 2'b00; + parameter [0:0] RXPI_CFG4 = 1'b0; + parameter [0:0] RXPI_CFG5 = 1'b1; + parameter [2:0] RXPI_CFG6 = 3'b000; + parameter [0:0] RXPI_LPM = 1'b0; + parameter [0:0] RXPI_VREFSEL = 1'b0; + parameter RXPMACLK_SEL = "DATA"; + parameter [4:0] RXPMARESET_TIME = 5'b00001; + parameter [0:0] RXPRBS_ERR_LOOPBACK = 1'b0; + parameter integer RXPRBS_LINKACQ_CNT = 15; + parameter integer RXSLIDE_AUTO_WAIT = 7; + parameter RXSLIDE_MODE = "OFF"; + parameter [0:0] RXSYNC_MULTILANE = 1'b0; + parameter [0:0] RXSYNC_OVRD = 1'b0; + parameter [0:0] RXSYNC_SKIP_DA = 1'b0; + parameter [0:0] RX_AFE_CM_EN = 1'b0; + parameter [15:0] RX_BIAS_CFG0 = 16'h0AD4; + parameter [5:0] RX_BUFFER_CFG = 6'b000000; + parameter [0:0] RX_CAPFF_SARC_ENB = 1'b0; + parameter integer RX_CLK25_DIV = 8; + parameter [0:0] RX_CLKMUX_EN = 1'b1; + parameter [4:0] RX_CLK_SLIP_OVRD = 5'b00000; + parameter [3:0] RX_CM_BUF_CFG = 4'b1010; + parameter [0:0] RX_CM_BUF_PD = 1'b0; + parameter [1:0] RX_CM_SEL = 2'b11; + parameter [3:0] RX_CM_TRIM = 4'b0100; + parameter [7:0] RX_CTLE3_LPF = 8'b00000000; + parameter integer RX_DATA_WIDTH = 20; + parameter [5:0] RX_DDI_SEL = 6'b000000; + parameter RX_DEFER_RESET_BUF_EN = "TRUE"; + parameter [3:0] RX_DFELPM_CFG0 = 4'b0110; + parameter [0:0] RX_DFELPM_CFG1 = 1'b0; + parameter [0:0] RX_DFELPM_KLKH_AGC_STUP_EN = 1'b1; + parameter [1:0] RX_DFE_AGC_CFG0 = 2'b00; + parameter [2:0] RX_DFE_AGC_CFG1 = 3'b100; + parameter [1:0] RX_DFE_KL_LPM_KH_CFG0 = 2'b01; + parameter [2:0] RX_DFE_KL_LPM_KH_CFG1 = 3'b010; + parameter [1:0] RX_DFE_KL_LPM_KL_CFG0 = 2'b01; + parameter [2:0] RX_DFE_KL_LPM_KL_CFG1 = 3'b010; + parameter [0:0] RX_DFE_LPM_HOLD_DURING_EIDLE = 1'b0; + parameter RX_DISPERR_SEQ_MATCH = "TRUE"; + parameter [4:0] RX_DIVRESET_TIME = 5'b00001; + parameter [0:0] RX_EN_HI_LR = 1'b0; + parameter [6:0] RX_EYESCAN_VS_CODE = 7'b0000000; + parameter [0:0] RX_EYESCAN_VS_NEG_DIR = 1'b0; + parameter [1:0] RX_EYESCAN_VS_RANGE = 2'b00; + parameter [0:0] RX_EYESCAN_VS_UT_SIGN = 1'b0; + parameter [0:0] RX_FABINT_USRCLK_FLOP = 1'b0; + parameter integer RX_INT_DATAWIDTH = 1; + parameter [0:0] RX_PMA_POWER_SAVE = 1'b0; + parameter real RX_PROGDIV_CFG = 4.0; + parameter [2:0] RX_SAMPLE_PERIOD = 3'b101; + parameter integer RX_SIG_VALID_DLY = 11; + parameter [0:0] RX_SUM_DFETAPREP_EN = 1'b0; + parameter [3:0] RX_SUM_IREF_TUNE = 4'b0000; + parameter [1:0] RX_SUM_RES_CTRL = 2'b00; + parameter [3:0] RX_SUM_VCMTUNE = 4'b0000; + parameter [0:0] RX_SUM_VCM_OVWR = 1'b0; + parameter [2:0] RX_SUM_VREF_TUNE = 3'b000; + parameter [1:0] RX_TUNE_AFE_OS = 2'b00; + parameter [0:0] RX_WIDEMODE_CDR = 1'b0; + parameter RX_XCLK_SEL = "RXDES"; + parameter integer SAS_MAX_COM = 64; + parameter integer SAS_MIN_COM = 36; + parameter [3:0] SATA_BURST_SEQ_LEN = 4'b1111; + parameter [2:0] SATA_BURST_VAL = 3'b100; + parameter SATA_CPLL_CFG = "VCO_3000MHZ"; + parameter [2:0] SATA_EIDLE_VAL = 3'b100; + parameter integer SATA_MAX_BURST = 8; + parameter integer SATA_MAX_INIT = 21; + parameter integer SATA_MAX_WAKE = 7; + parameter integer SATA_MIN_BURST = 4; + parameter integer SATA_MIN_INIT = 12; + parameter integer SATA_MIN_WAKE = 4; + parameter SHOW_REALIGN_COMMA = "TRUE"; + parameter SIM_MODE = "FAST"; + parameter SIM_RECEIVER_DETECT_PASS = "TRUE"; + parameter SIM_RESET_SPEEDUP = "TRUE"; + parameter [0:0] SIM_TX_EIDLE_DRIVE_LEVEL = 1'b0; + parameter integer SIM_VERSION = 2; + parameter [1:0] TAPDLY_SET_TX = 2'h0; + parameter [3:0] TEMPERATUR_PAR = 4'b0010; + parameter [14:0] TERM_RCAL_CFG = 15'b100001000010000; + parameter [2:0] TERM_RCAL_OVRD = 3'b000; + parameter [7:0] TRANS_TIME_RATE = 8'h0E; + parameter [7:0] TST_RSV0 = 8'h00; + parameter [7:0] TST_RSV1 = 8'h00; + parameter TXBUF_EN = "TRUE"; + parameter TXBUF_RESET_ON_RATE_CHANGE = "FALSE"; + parameter [15:0] TXDLY_CFG = 16'h001F; + parameter [15:0] TXDLY_LCFG = 16'h0030; + parameter [3:0] TXDRVBIAS_N = 4'b1010; + parameter [3:0] TXDRVBIAS_P = 4'b1100; + parameter TXFIFO_ADDR_CFG = "LOW"; + parameter integer TXGBOX_FIFO_INIT_RD_ADDR = 4; + parameter TXGEARBOX_EN = "FALSE"; + parameter integer TXOUT_DIV = 4; + parameter [4:0] TXPCSRESET_TIME = 5'b00001; + parameter [15:0] TXPHDLY_CFG0 = 16'h2020; + parameter [15:0] TXPHDLY_CFG1 = 16'h0001; + parameter [15:0] TXPH_CFG = 16'h0980; + parameter [4:0] TXPH_MONITOR_SEL = 5'b00000; + parameter [1:0] TXPI_CFG0 = 2'b00; + parameter [1:0] TXPI_CFG1 = 2'b00; + parameter [1:0] TXPI_CFG2 = 2'b00; + parameter [0:0] TXPI_CFG3 = 1'b0; + parameter [0:0] TXPI_CFG4 = 1'b1; + parameter [2:0] TXPI_CFG5 = 3'b000; + parameter [0:0] TXPI_GRAY_SEL = 1'b0; + parameter [0:0] TXPI_INVSTROBE_SEL = 1'b0; + parameter [0:0] TXPI_LPM = 1'b0; + parameter TXPI_PPMCLK_SEL = "TXUSRCLK2"; + parameter [7:0] TXPI_PPM_CFG = 8'b00000000; + parameter [2:0] TXPI_SYNFREQ_PPM = 3'b000; + parameter [0:0] TXPI_VREFSEL = 1'b0; + parameter [4:0] TXPMARESET_TIME = 5'b00001; + parameter [0:0] TXSYNC_MULTILANE = 1'b0; + parameter [0:0] TXSYNC_OVRD = 1'b0; + parameter [0:0] TXSYNC_SKIP_DA = 1'b0; + parameter integer TX_CLK25_DIV = 8; + parameter [0:0] TX_CLKMUX_EN = 1'b1; + parameter integer TX_DATA_WIDTH = 20; + parameter [5:0] TX_DCD_CFG = 6'b000010; + parameter [0:0] TX_DCD_EN = 1'b0; + parameter [5:0] TX_DEEMPH0 = 6'b000000; + parameter [5:0] TX_DEEMPH1 = 6'b000000; + parameter [4:0] TX_DIVRESET_TIME = 5'b00001; + parameter TX_DRIVE_MODE = "DIRECT"; + parameter [2:0] TX_EIDLE_ASSERT_DELAY = 3'b110; + parameter [2:0] TX_EIDLE_DEASSERT_DELAY = 3'b100; + parameter [0:0] TX_EML_PHI_TUNE = 1'b0; + parameter [0:0] TX_FABINT_USRCLK_FLOP = 1'b0; + parameter [0:0] TX_IDLE_DATA_ZERO = 1'b0; + parameter integer TX_INT_DATAWIDTH = 1; + parameter TX_LOOPBACK_DRIVE_HIZ = "FALSE"; + parameter [0:0] TX_MAINCURSOR_SEL = 1'b0; + parameter [6:0] TX_MARGIN_FULL_0 = 7'b1001110; + parameter [6:0] TX_MARGIN_FULL_1 = 7'b1001001; + parameter [6:0] TX_MARGIN_FULL_2 = 7'b1000101; + parameter [6:0] TX_MARGIN_FULL_3 = 7'b1000010; + parameter [6:0] TX_MARGIN_FULL_4 = 7'b1000000; + parameter [6:0] TX_MARGIN_LOW_0 = 7'b1000110; + parameter [6:0] TX_MARGIN_LOW_1 = 7'b1000100; + parameter [6:0] TX_MARGIN_LOW_2 = 7'b1000010; + parameter [6:0] TX_MARGIN_LOW_3 = 7'b1000000; + parameter [6:0] TX_MARGIN_LOW_4 = 7'b1000000; + parameter [2:0] TX_MODE_SEL = 3'b000; + parameter [0:0] TX_PMADATA_OPT = 1'b0; + parameter [0:0] TX_PMA_POWER_SAVE = 1'b0; + parameter TX_PROGCLK_SEL = "POSTPI"; + parameter real TX_PROGDIV_CFG = 4.0; + parameter [0:0] TX_QPI_STATUS_EN = 1'b0; + parameter [13:0] TX_RXDETECT_CFG = 14'h0032; + parameter [2:0] TX_RXDETECT_REF = 3'b100; + parameter [2:0] TX_SAMPLE_PERIOD = 3'b101; + parameter [0:0] TX_SARC_LPBK_ENB = 1'b0; + parameter TX_XCLK_SEL = "TXOUT"; + parameter [0:0] USE_PCS_CLK_PHASE_SEL = 1'b0; + parameter [1:0] WB_MODE = 2'b00; + output [2:0] BUFGTCE; + output [2:0] BUFGTCEMASK; + output [8:0] BUFGTDIV; + output [2:0] BUFGTRESET; + output [2:0] BUFGTRSTMASK; + output CPLLFBCLKLOST; + output CPLLLOCK; + output CPLLREFCLKLOST; + output [16:0] DMONITOROUT; + output [15:0] DRPDO; + output DRPRDY; + output EYESCANDATAERROR; + output GTHTXN; + output GTHTXP; + output GTPOWERGOOD; + output GTREFCLKMONITOR; + output PCIERATEGEN3; + output PCIERATEIDLE; + output [1:0] PCIERATEQPLLPD; + output [1:0] PCIERATEQPLLRESET; + output PCIESYNCTXSYNCDONE; + output PCIEUSERGEN3RDY; + output PCIEUSERPHYSTATUSRST; + output PCIEUSERRATESTART; + output [11:0] PCSRSVDOUT; + output PHYSTATUS; + output [7:0] PINRSRVDAS; + output RESETEXCEPTION; + output [2:0] RXBUFSTATUS; + output RXBYTEISALIGNED; + output RXBYTEREALIGN; + output RXCDRLOCK; + output RXCDRPHDONE; + output RXCHANBONDSEQ; + output RXCHANISALIGNED; + output RXCHANREALIGN; + output [4:0] RXCHBONDO; + output [1:0] RXCLKCORCNT; + output RXCOMINITDET; + output RXCOMMADET; + output RXCOMSASDET; + output RXCOMWAKEDET; + output [15:0] RXCTRL0; + output [15:0] RXCTRL1; + output [7:0] RXCTRL2; + output [7:0] RXCTRL3; + output [127:0] RXDATA; + output [7:0] RXDATAEXTENDRSVD; + output [1:0] RXDATAVALID; + output RXDLYSRESETDONE; + output RXELECIDLE; + output [5:0] RXHEADER; + output [1:0] RXHEADERVALID; + output [6:0] RXMONITOROUT; + output RXOSINTDONE; + output RXOSINTSTARTED; + output RXOSINTSTROBEDONE; + output RXOSINTSTROBESTARTED; + output RXOUTCLK; + output RXOUTCLKFABRIC; + output RXOUTCLKPCS; + output RXPHALIGNDONE; + output RXPHALIGNERR; + output RXPMARESETDONE; + output RXPRBSERR; + output RXPRBSLOCKED; + output RXPRGDIVRESETDONE; + output RXQPISENN; + output RXQPISENP; + output RXRATEDONE; + output RXRECCLKOUT; + output RXRESETDONE; + output RXSLIDERDY; + output RXSLIPDONE; + output RXSLIPOUTCLKRDY; + output RXSLIPPMARDY; + output [1:0] RXSTARTOFSEQ; + output [2:0] RXSTATUS; + output RXSYNCDONE; + output RXSYNCOUT; + output RXVALID; + output [1:0] TXBUFSTATUS; + output TXCOMFINISH; + output TXDLYSRESETDONE; + output TXOUTCLK; + output TXOUTCLKFABRIC; + output TXOUTCLKPCS; + output TXPHALIGNDONE; + output TXPHINITDONE; + output TXPMARESETDONE; + output TXPRGDIVRESETDONE; + output TXQPISENN; + output TXQPISENP; + output TXRATEDONE; + output TXRESETDONE; + output TXSYNCDONE; + output TXSYNCOUT; + input CFGRESET; + input CLKRSVD0; + input CLKRSVD1; + input CPLLLOCKDETCLK; + input CPLLLOCKEN; + input CPLLPD; + input [2:0] CPLLREFCLKSEL; + input CPLLRESET; + input DMONFIFORESET; + input DMONITORCLK; + input [8:0] DRPADDR; + input DRPCLK; + input [15:0] DRPDI; + input DRPEN; + input DRPWE; + input EVODDPHICALDONE; + input EVODDPHICALSTART; + input EVODDPHIDRDEN; + input EVODDPHIDWREN; + input EVODDPHIXRDEN; + input EVODDPHIXWREN; + input EYESCANMODE; + input EYESCANRESET; + input EYESCANTRIGGER; + input GTGREFCLK; + input GTHRXN; + input GTHRXP; + input GTNORTHREFCLK0; + input GTNORTHREFCLK1; + input GTREFCLK0; + input GTREFCLK1; + input GTRESETSEL; + input [15:0] GTRSVD; + input GTRXRESET; + input GTSOUTHREFCLK0; + input GTSOUTHREFCLK1; + input GTTXRESET; + input [2:0] LOOPBACK; + input LPBKRXTXSEREN; + input LPBKTXRXSEREN; + input PCIEEQRXEQADAPTDONE; + input PCIERSTIDLE; + input PCIERSTTXSYNCSTART; + input PCIEUSERRATEDONE; + input [15:0] PCSRSVDIN; + input [4:0] PCSRSVDIN2; + input [4:0] PMARSVDIN; + input QPLL0CLK; + input QPLL0REFCLK; + input QPLL1CLK; + input QPLL1REFCLK; + input RESETOVRD; + input RSTCLKENTX; + input RX8B10BEN; + input RXBUFRESET; + input RXCDRFREQRESET; + input RXCDRHOLD; + input RXCDROVRDEN; + input RXCDRRESET; + input RXCDRRESETRSV; + input RXCHBONDEN; + input [4:0] RXCHBONDI; + input [2:0] RXCHBONDLEVEL; + input RXCHBONDMASTER; + input RXCHBONDSLAVE; + input RXCOMMADETEN; + input [1:0] RXDFEAGCCTRL; + input RXDFEAGCHOLD; + input RXDFEAGCOVRDEN; + input RXDFELFHOLD; + input RXDFELFOVRDEN; + input RXDFELPMRESET; + input RXDFETAP10HOLD; + input RXDFETAP10OVRDEN; + input RXDFETAP11HOLD; + input RXDFETAP11OVRDEN; + input RXDFETAP12HOLD; + input RXDFETAP12OVRDEN; + input RXDFETAP13HOLD; + input RXDFETAP13OVRDEN; + input RXDFETAP14HOLD; + input RXDFETAP14OVRDEN; + input RXDFETAP15HOLD; + input RXDFETAP15OVRDEN; + input RXDFETAP2HOLD; + input RXDFETAP2OVRDEN; + input RXDFETAP3HOLD; + input RXDFETAP3OVRDEN; + input RXDFETAP4HOLD; + input RXDFETAP4OVRDEN; + input RXDFETAP5HOLD; + input RXDFETAP5OVRDEN; + input RXDFETAP6HOLD; + input RXDFETAP6OVRDEN; + input RXDFETAP7HOLD; + input RXDFETAP7OVRDEN; + input RXDFETAP8HOLD; + input RXDFETAP8OVRDEN; + input RXDFETAP9HOLD; + input RXDFETAP9OVRDEN; + input RXDFEUTHOLD; + input RXDFEUTOVRDEN; + input RXDFEVPHOLD; + input RXDFEVPOVRDEN; + input RXDFEVSEN; + input RXDFEXYDEN; + input RXDLYBYPASS; + input RXDLYEN; + input RXDLYOVRDEN; + input RXDLYSRESET; + input [1:0] RXELECIDLEMODE; + input RXGEARBOXSLIP; + input RXLATCLK; + input RXLPMEN; + input RXLPMGCHOLD; + input RXLPMGCOVRDEN; + input RXLPMHFHOLD; + input RXLPMHFOVRDEN; + input RXLPMLFHOLD; + input RXLPMLFKLOVRDEN; + input RXLPMOSHOLD; + input RXLPMOSOVRDEN; + input RXMCOMMAALIGNEN; + input [1:0] RXMONITORSEL; + input RXOOBRESET; + input RXOSCALRESET; + input RXOSHOLD; + input [3:0] RXOSINTCFG; + input RXOSINTEN; + input RXOSINTHOLD; + input RXOSINTOVRDEN; + input RXOSINTSTROBE; + input RXOSINTTESTOVRDEN; + input RXOSOVRDEN; + input [2:0] RXOUTCLKSEL; + input RXPCOMMAALIGNEN; + input RXPCSRESET; + input [1:0] RXPD; + input RXPHALIGN; + input RXPHALIGNEN; + input RXPHDLYPD; + input RXPHDLYRESET; + input RXPHOVRDEN; + input [1:0] RXPLLCLKSEL; + input RXPMARESET; + input RXPOLARITY; + input RXPRBSCNTRESET; + input [3:0] RXPRBSSEL; + input RXPROGDIVRESET; + input RXQPIEN; + input [2:0] RXRATE; + input RXRATEMODE; + input RXSLIDE; + input RXSLIPOUTCLK; + input RXSLIPPMA; + input RXSYNCALLIN; + input RXSYNCIN; + input RXSYNCMODE; + input [1:0] RXSYSCLKSEL; + input RXUSERRDY; + input RXUSRCLK; + input RXUSRCLK2; + input SIGVALIDCLK; + input [19:0] TSTIN; + input [7:0] TX8B10BBYPASS; + input TX8B10BEN; + input [2:0] TXBUFDIFFCTRL; + input TXCOMINIT; + input TXCOMSAS; + input TXCOMWAKE; + input [15:0] TXCTRL0; + input [15:0] TXCTRL1; + input [7:0] TXCTRL2; + input [127:0] TXDATA; + input [7:0] TXDATAEXTENDRSVD; + input TXDEEMPH; + input TXDETECTRX; + input [3:0] TXDIFFCTRL; + input TXDIFFPD; + input TXDLYBYPASS; + input TXDLYEN; + input TXDLYHOLD; + input TXDLYOVRDEN; + input TXDLYSRESET; + input TXDLYUPDOWN; + input TXELECIDLE; + input [5:0] TXHEADER; + input TXINHIBIT; + input TXLATCLK; + input [6:0] TXMAINCURSOR; + input [2:0] TXMARGIN; + input [2:0] TXOUTCLKSEL; + input TXPCSRESET; + input [1:0] TXPD; + input TXPDELECIDLEMODE; + input TXPHALIGN; + input TXPHALIGNEN; + input TXPHDLYPD; + input TXPHDLYRESET; + input TXPHDLYTSTCLK; + input TXPHINIT; + input TXPHOVRDEN; + input TXPIPPMEN; + input TXPIPPMOVRDEN; + input TXPIPPMPD; + input TXPIPPMSEL; + input [4:0] TXPIPPMSTEPSIZE; + input TXPISOPD; + input [1:0] TXPLLCLKSEL; + input TXPMARESET; + input TXPOLARITY; + input [4:0] TXPOSTCURSOR; + input TXPOSTCURSORINV; + input TXPRBSFORCEERR; + input [3:0] TXPRBSSEL; + input [4:0] TXPRECURSOR; + input TXPRECURSORINV; + input TXPROGDIVRESET; + input TXQPIBIASEN; + input TXQPISTRONGPDOWN; + input TXQPIWEAKPUP; + input [2:0] TXRATE; + input TXRATEMODE; + input [6:0] TXSEQUENCE; + input TXSWING; + input TXSYNCALLIN; + input TXSYNCIN; + input TXSYNCMODE; + input [1:0] TXSYSCLKSEL; + input TXUSERRDY; + input TXUSRCLK; + input TXUSRCLK2; +endmodule + +module GTHE3_COMMON (...); + parameter [15:0] BIAS_CFG0 = 16'h0000; + parameter [15:0] BIAS_CFG1 = 16'h0000; + parameter [15:0] BIAS_CFG2 = 16'h0000; + parameter [15:0] BIAS_CFG3 = 16'h0000; + parameter [15:0] BIAS_CFG4 = 16'h0000; + parameter [9:0] BIAS_CFG_RSVD = 10'b0000000000; + parameter [15:0] COMMON_CFG0 = 16'h0000; + parameter [15:0] COMMON_CFG1 = 16'h0000; + parameter [15:0] POR_CFG = 16'h0004; + parameter [15:0] QPLL0_CFG0 = 16'h3018; + parameter [15:0] QPLL0_CFG1 = 16'h0000; + parameter [15:0] QPLL0_CFG1_G3 = 16'h0020; + parameter [15:0] QPLL0_CFG2 = 16'h0000; + parameter [15:0] QPLL0_CFG2_G3 = 16'h0000; + parameter [15:0] QPLL0_CFG3 = 16'h0120; + parameter [15:0] QPLL0_CFG4 = 16'h0009; + parameter [9:0] QPLL0_CP = 10'b0000011111; + parameter [9:0] QPLL0_CP_G3 = 10'b0000011111; + parameter integer QPLL0_FBDIV = 66; + parameter integer QPLL0_FBDIV_G3 = 80; + parameter [15:0] QPLL0_INIT_CFG0 = 16'h0000; + parameter [7:0] QPLL0_INIT_CFG1 = 8'h00; + parameter [15:0] QPLL0_LOCK_CFG = 16'h01E8; + parameter [15:0] QPLL0_LOCK_CFG_G3 = 16'h01E8; + parameter [9:0] QPLL0_LPF = 10'b1111111111; + parameter [9:0] QPLL0_LPF_G3 = 10'b1111111111; + parameter integer QPLL0_REFCLK_DIV = 2; + parameter [15:0] QPLL0_SDM_CFG0 = 16'b0000000000000000; + parameter [15:0] QPLL0_SDM_CFG1 = 16'b0000000000000000; + parameter [15:0] QPLL0_SDM_CFG2 = 16'b0000000000000000; + parameter [15:0] QPLL1_CFG0 = 16'h3018; + parameter [15:0] QPLL1_CFG1 = 16'h0000; + parameter [15:0] QPLL1_CFG1_G3 = 16'h0020; + parameter [15:0] QPLL1_CFG2 = 16'h0000; + parameter [15:0] QPLL1_CFG2_G3 = 16'h0000; + parameter [15:0] QPLL1_CFG3 = 16'h0120; + parameter [15:0] QPLL1_CFG4 = 16'h0009; + parameter [9:0] QPLL1_CP = 10'b0000011111; + parameter [9:0] QPLL1_CP_G3 = 10'b0000011111; + parameter integer QPLL1_FBDIV = 66; + parameter integer QPLL1_FBDIV_G3 = 80; + parameter [15:0] QPLL1_INIT_CFG0 = 16'h0000; + parameter [7:0] QPLL1_INIT_CFG1 = 8'h00; + parameter [15:0] QPLL1_LOCK_CFG = 16'h01E8; + parameter [15:0] QPLL1_LOCK_CFG_G3 = 16'h21E8; + parameter [9:0] QPLL1_LPF = 10'b1111111111; + parameter [9:0] QPLL1_LPF_G3 = 10'b1111111111; + parameter integer QPLL1_REFCLK_DIV = 2; + parameter [15:0] QPLL1_SDM_CFG0 = 16'b0000000000000000; + parameter [15:0] QPLL1_SDM_CFG1 = 16'b0000000000000000; + parameter [15:0] QPLL1_SDM_CFG2 = 16'b0000000000000000; + parameter [15:0] RSVD_ATTR0 = 16'h0000; + parameter [15:0] RSVD_ATTR1 = 16'h0000; + parameter [15:0] RSVD_ATTR2 = 16'h0000; + parameter [15:0] RSVD_ATTR3 = 16'h0000; + parameter [1:0] RXRECCLKOUT0_SEL = 2'b00; + parameter [1:0] RXRECCLKOUT1_SEL = 2'b00; + parameter [0:0] SARC_EN = 1'b1; + parameter [0:0] SARC_SEL = 1'b0; + parameter [15:0] SDM0DATA1_0 = 16'b0000000000000000; + parameter [8:0] SDM0DATA1_1 = 9'b000000000; + parameter [15:0] SDM0INITSEED0_0 = 16'b0000000000000000; + parameter [8:0] SDM0INITSEED0_1 = 9'b000000000; + parameter [0:0] SDM0_DATA_PIN_SEL = 1'b0; + parameter [0:0] SDM0_WIDTH_PIN_SEL = 1'b0; + parameter [15:0] SDM1DATA1_0 = 16'b0000000000000000; + parameter [8:0] SDM1DATA1_1 = 9'b000000000; + parameter [15:0] SDM1INITSEED0_0 = 16'b0000000000000000; + parameter [8:0] SDM1INITSEED0_1 = 9'b000000000; + parameter [0:0] SDM1_DATA_PIN_SEL = 1'b0; + parameter [0:0] SDM1_WIDTH_PIN_SEL = 1'b0; + parameter SIM_MODE = "FAST"; + parameter SIM_RESET_SPEEDUP = "TRUE"; + parameter integer SIM_VERSION = 2; + output [15:0] DRPDO; + output DRPRDY; + output [7:0] PMARSVDOUT0; + output [7:0] PMARSVDOUT1; + output QPLL0FBCLKLOST; + output QPLL0LOCK; + output QPLL0OUTCLK; + output QPLL0OUTREFCLK; + output QPLL0REFCLKLOST; + output QPLL1FBCLKLOST; + output QPLL1LOCK; + output QPLL1OUTCLK; + output QPLL1OUTREFCLK; + output QPLL1REFCLKLOST; + output [7:0] QPLLDMONITOR0; + output [7:0] QPLLDMONITOR1; + output REFCLKOUTMONITOR0; + output REFCLKOUTMONITOR1; + output [1:0] RXRECCLK0_SEL; + output [1:0] RXRECCLK1_SEL; + input BGBYPASSB; + input BGMONITORENB; + input BGPDB; + input [4:0] BGRCALOVRD; + input BGRCALOVRDENB; + input [8:0] DRPADDR; + input DRPCLK; + input [15:0] DRPDI; + input DRPEN; + input DRPWE; + input GTGREFCLK0; + input GTGREFCLK1; + input GTNORTHREFCLK00; + input GTNORTHREFCLK01; + input GTNORTHREFCLK10; + input GTNORTHREFCLK11; + input GTREFCLK00; + input GTREFCLK01; + input GTREFCLK10; + input GTREFCLK11; + input GTSOUTHREFCLK00; + input GTSOUTHREFCLK01; + input GTSOUTHREFCLK10; + input GTSOUTHREFCLK11; + input [7:0] PMARSVD0; + input [7:0] PMARSVD1; + input QPLL0CLKRSVD0; + input QPLL0CLKRSVD1; + input QPLL0LOCKDETCLK; + input QPLL0LOCKEN; + input QPLL0PD; + input [2:0] QPLL0REFCLKSEL; + input QPLL0RESET; + input QPLL1CLKRSVD0; + input QPLL1CLKRSVD1; + input QPLL1LOCKDETCLK; + input QPLL1LOCKEN; + input QPLL1PD; + input [2:0] QPLL1REFCLKSEL; + input QPLL1RESET; + input [7:0] QPLLRSVD1; + input [4:0] QPLLRSVD2; + input [4:0] QPLLRSVD3; + input [7:0] QPLLRSVD4; + input RCALENB; +endmodule + +module GTHE4_CHANNEL (...); + parameter [0:0] ACJTAG_DEBUG_MODE = 1'b0; + parameter [0:0] ACJTAG_MODE = 1'b0; + parameter [0:0] ACJTAG_RESET = 1'b0; + parameter [15:0] ADAPT_CFG0 = 16'h9200; + parameter [15:0] ADAPT_CFG1 = 16'h801C; + parameter [15:0] ADAPT_CFG2 = 16'h0000; + parameter ALIGN_COMMA_DOUBLE = "FALSE"; + parameter [9:0] ALIGN_COMMA_ENABLE = 10'b0001111111; + parameter integer ALIGN_COMMA_WORD = 1; + parameter ALIGN_MCOMMA_DET = "TRUE"; + parameter [9:0] ALIGN_MCOMMA_VALUE = 10'b1010000011; + parameter ALIGN_PCOMMA_DET = "TRUE"; + parameter [9:0] ALIGN_PCOMMA_VALUE = 10'b0101111100; + parameter [0:0] A_RXOSCALRESET = 1'b0; + parameter [0:0] A_RXPROGDIVRESET = 1'b0; + parameter [0:0] A_RXTERMINATION = 1'b1; + parameter [4:0] A_TXDIFFCTRL = 5'b01100; + parameter [0:0] A_TXPROGDIVRESET = 1'b0; + parameter [0:0] CAPBYPASS_FORCE = 1'b0; + parameter CBCC_DATA_SOURCE_SEL = "DECODED"; + parameter [0:0] CDR_SWAP_MODE_EN = 1'b0; + parameter [0:0] CFOK_PWRSVE_EN = 1'b1; + parameter CHAN_BOND_KEEP_ALIGN = "FALSE"; + parameter integer CHAN_BOND_MAX_SKEW = 7; + parameter [9:0] CHAN_BOND_SEQ_1_1 = 10'b0101111100; + parameter [9:0] CHAN_BOND_SEQ_1_2 = 10'b0000000000; + parameter [9:0] CHAN_BOND_SEQ_1_3 = 10'b0000000000; + parameter [9:0] CHAN_BOND_SEQ_1_4 = 10'b0000000000; + parameter [3:0] CHAN_BOND_SEQ_1_ENABLE = 4'b1111; + parameter [9:0] CHAN_BOND_SEQ_2_1 = 10'b0100000000; + parameter [9:0] CHAN_BOND_SEQ_2_2 = 10'b0100000000; + parameter [9:0] CHAN_BOND_SEQ_2_3 = 10'b0100000000; + parameter [9:0] CHAN_BOND_SEQ_2_4 = 10'b0100000000; + parameter [3:0] CHAN_BOND_SEQ_2_ENABLE = 4'b1111; + parameter CHAN_BOND_SEQ_2_USE = "FALSE"; + parameter integer CHAN_BOND_SEQ_LEN = 2; + parameter [15:0] CH_HSPMUX = 16'h2424; + parameter [15:0] CKCAL1_CFG_0 = 16'b0000000000000000; + parameter [15:0] CKCAL1_CFG_1 = 16'b0000000000000000; + parameter [15:0] CKCAL1_CFG_2 = 16'b0000000000000000; + parameter [15:0] CKCAL1_CFG_3 = 16'b0000000000000000; + parameter [15:0] CKCAL2_CFG_0 = 16'b0000000000000000; + parameter [15:0] CKCAL2_CFG_1 = 16'b0000000000000000; + parameter [15:0] CKCAL2_CFG_2 = 16'b0000000000000000; + parameter [15:0] CKCAL2_CFG_3 = 16'b0000000000000000; + parameter [15:0] CKCAL2_CFG_4 = 16'b0000000000000000; + parameter [15:0] CKCAL_RSVD0 = 16'h4000; + parameter [15:0] CKCAL_RSVD1 = 16'h0000; + parameter CLK_CORRECT_USE = "TRUE"; + parameter CLK_COR_KEEP_IDLE = "FALSE"; + parameter integer CLK_COR_MAX_LAT = 20; + parameter integer CLK_COR_MIN_LAT = 18; + parameter CLK_COR_PRECEDENCE = "TRUE"; + parameter integer CLK_COR_REPEAT_WAIT = 0; + parameter [9:0] CLK_COR_SEQ_1_1 = 10'b0100011100; + parameter [9:0] CLK_COR_SEQ_1_2 = 10'b0000000000; + parameter [9:0] CLK_COR_SEQ_1_3 = 10'b0000000000; + parameter [9:0] CLK_COR_SEQ_1_4 = 10'b0000000000; + parameter [3:0] CLK_COR_SEQ_1_ENABLE = 4'b1111; + parameter [9:0] CLK_COR_SEQ_2_1 = 10'b0100000000; + parameter [9:0] CLK_COR_SEQ_2_2 = 10'b0100000000; + parameter [9:0] CLK_COR_SEQ_2_3 = 10'b0100000000; + parameter [9:0] CLK_COR_SEQ_2_4 = 10'b0100000000; + parameter [3:0] CLK_COR_SEQ_2_ENABLE = 4'b1111; + parameter CLK_COR_SEQ_2_USE = "FALSE"; + parameter integer CLK_COR_SEQ_LEN = 2; + parameter [15:0] CPLL_CFG0 = 16'h01FA; + parameter [15:0] CPLL_CFG1 = 16'h24A9; + parameter [15:0] CPLL_CFG2 = 16'h6807; + parameter [15:0] CPLL_CFG3 = 16'h0000; + parameter integer CPLL_FBDIV = 4; + parameter integer CPLL_FBDIV_45 = 4; + parameter [15:0] CPLL_INIT_CFG0 = 16'h001E; + parameter [15:0] CPLL_LOCK_CFG = 16'h01E8; + parameter integer CPLL_REFCLK_DIV = 1; + parameter [2:0] CTLE3_OCAP_EXT_CTRL = 3'b000; + parameter [0:0] CTLE3_OCAP_EXT_EN = 1'b0; + parameter [1:0] DDI_CTRL = 2'b00; + parameter integer DDI_REALIGN_WAIT = 15; + parameter DEC_MCOMMA_DETECT = "TRUE"; + parameter DEC_PCOMMA_DETECT = "TRUE"; + parameter DEC_VALID_COMMA_ONLY = "TRUE"; + parameter [0:0] DELAY_ELEC = 1'b0; + parameter [9:0] DMONITOR_CFG0 = 10'h000; + parameter [7:0] DMONITOR_CFG1 = 8'h00; + parameter [0:0] ES_CLK_PHASE_SEL = 1'b0; + parameter [5:0] ES_CONTROL = 6'b000000; + parameter ES_ERRDET_EN = "FALSE"; + parameter ES_EYE_SCAN_EN = "FALSE"; + parameter [11:0] ES_HORZ_OFFSET = 12'h800; + parameter [4:0] ES_PRESCALE = 5'b00000; + parameter [15:0] ES_QUALIFIER0 = 16'h0000; + parameter [15:0] ES_QUALIFIER1 = 16'h0000; + parameter [15:0] ES_QUALIFIER2 = 16'h0000; + parameter [15:0] ES_QUALIFIER3 = 16'h0000; + parameter [15:0] ES_QUALIFIER4 = 16'h0000; + parameter [15:0] ES_QUALIFIER5 = 16'h0000; + parameter [15:0] ES_QUALIFIER6 = 16'h0000; + parameter [15:0] ES_QUALIFIER7 = 16'h0000; + parameter [15:0] ES_QUALIFIER8 = 16'h0000; + parameter [15:0] ES_QUALIFIER9 = 16'h0000; + parameter [15:0] ES_QUAL_MASK0 = 16'h0000; + parameter [15:0] ES_QUAL_MASK1 = 16'h0000; + parameter [15:0] ES_QUAL_MASK2 = 16'h0000; + parameter [15:0] ES_QUAL_MASK3 = 16'h0000; + parameter [15:0] ES_QUAL_MASK4 = 16'h0000; + parameter [15:0] ES_QUAL_MASK5 = 16'h0000; + parameter [15:0] ES_QUAL_MASK6 = 16'h0000; + parameter [15:0] ES_QUAL_MASK7 = 16'h0000; + parameter [15:0] ES_QUAL_MASK8 = 16'h0000; + parameter [15:0] ES_QUAL_MASK9 = 16'h0000; + parameter [15:0] ES_SDATA_MASK0 = 16'h0000; + parameter [15:0] ES_SDATA_MASK1 = 16'h0000; + parameter [15:0] ES_SDATA_MASK2 = 16'h0000; + parameter [15:0] ES_SDATA_MASK3 = 16'h0000; + parameter [15:0] ES_SDATA_MASK4 = 16'h0000; + parameter [15:0] ES_SDATA_MASK5 = 16'h0000; + parameter [15:0] ES_SDATA_MASK6 = 16'h0000; + parameter [15:0] ES_SDATA_MASK7 = 16'h0000; + parameter [15:0] ES_SDATA_MASK8 = 16'h0000; + parameter [15:0] ES_SDATA_MASK9 = 16'h0000; + parameter [0:0] EYE_SCAN_SWAP_EN = 1'b0; + parameter [3:0] FTS_DESKEW_SEQ_ENABLE = 4'b1111; + parameter [3:0] FTS_LANE_DESKEW_CFG = 4'b1111; + parameter FTS_LANE_DESKEW_EN = "FALSE"; + parameter [4:0] GEARBOX_MODE = 5'b00000; + parameter [0:0] ISCAN_CK_PH_SEL2 = 1'b0; + parameter [0:0] LOCAL_MASTER = 1'b0; + parameter [2:0] LPBK_BIAS_CTRL = 3'b000; + parameter [0:0] LPBK_EN_RCAL_B = 1'b0; + parameter [3:0] LPBK_EXT_RCAL = 4'b0000; + parameter [2:0] LPBK_IND_CTRL0 = 3'b000; + parameter [2:0] LPBK_IND_CTRL1 = 3'b000; + parameter [2:0] LPBK_IND_CTRL2 = 3'b000; + parameter [3:0] LPBK_RG_CTRL = 4'b0000; + parameter [1:0] OOBDIVCTL = 2'b00; + parameter [0:0] OOB_PWRUP = 1'b0; + parameter PCI3_AUTO_REALIGN = "FRST_SMPL"; + parameter [0:0] PCI3_PIPE_RX_ELECIDLE = 1'b1; + parameter [1:0] PCI3_RX_ASYNC_EBUF_BYPASS = 2'b00; + parameter [0:0] PCI3_RX_ELECIDLE_EI2_ENABLE = 1'b0; + parameter [5:0] PCI3_RX_ELECIDLE_H2L_COUNT = 6'b000000; + parameter [2:0] PCI3_RX_ELECIDLE_H2L_DISABLE = 3'b000; + parameter [5:0] PCI3_RX_ELECIDLE_HI_COUNT = 6'b000000; + parameter [0:0] PCI3_RX_ELECIDLE_LP4_DISABLE = 1'b0; + parameter [0:0] PCI3_RX_FIFO_DISABLE = 1'b0; + parameter [4:0] PCIE3_CLK_COR_EMPTY_THRSH = 5'b00000; + parameter [5:0] PCIE3_CLK_COR_FULL_THRSH = 6'b010000; + parameter [4:0] PCIE3_CLK_COR_MAX_LAT = 5'b01000; + parameter [4:0] PCIE3_CLK_COR_MIN_LAT = 5'b00100; + parameter [5:0] PCIE3_CLK_COR_THRSH_TIMER = 6'b001000; + parameter [15:0] PCIE_BUFG_DIV_CTRL = 16'h0000; + parameter [1:0] PCIE_PLL_SEL_MODE_GEN12 = 2'h0; + parameter [1:0] PCIE_PLL_SEL_MODE_GEN3 = 2'h0; + parameter [1:0] PCIE_PLL_SEL_MODE_GEN4 = 2'h0; + parameter [15:0] PCIE_RXPCS_CFG_GEN3 = 16'h0000; + parameter [15:0] PCIE_RXPMA_CFG = 16'h0000; + parameter [15:0] PCIE_TXPCS_CFG_GEN3 = 16'h0000; + parameter [15:0] PCIE_TXPMA_CFG = 16'h0000; + parameter PCS_PCIE_EN = "FALSE"; + parameter [15:0] PCS_RSVD0 = 16'b0000000000000000; + parameter [11:0] PD_TRANS_TIME_FROM_P2 = 12'h03C; + parameter [7:0] PD_TRANS_TIME_NONE_P2 = 8'h19; + parameter [7:0] PD_TRANS_TIME_TO_P2 = 8'h64; + parameter integer PREIQ_FREQ_BST = 0; + parameter [2:0] PROCESS_PAR = 3'b010; + parameter [0:0] RATE_SW_USE_DRP = 1'b0; + parameter [0:0] RCLK_SIPO_DLY_ENB = 1'b0; + parameter [0:0] RCLK_SIPO_INV_EN = 1'b0; + parameter [0:0] RESET_POWERSAVE_DISABLE = 1'b0; + parameter [2:0] RTX_BUF_CML_CTRL = 3'b010; + parameter [1:0] RTX_BUF_TERM_CTRL = 2'b00; + parameter [4:0] RXBUFRESET_TIME = 5'b00001; + parameter RXBUF_ADDR_MODE = "FULL"; + parameter [3:0] RXBUF_EIDLE_HI_CNT = 4'b1000; + parameter [3:0] RXBUF_EIDLE_LO_CNT = 4'b0000; + parameter RXBUF_EN = "TRUE"; + parameter RXBUF_RESET_ON_CB_CHANGE = "TRUE"; + parameter RXBUF_RESET_ON_COMMAALIGN = "FALSE"; + parameter RXBUF_RESET_ON_EIDLE = "FALSE"; + parameter RXBUF_RESET_ON_RATE_CHANGE = "TRUE"; + parameter integer RXBUF_THRESH_OVFLW = 0; + parameter RXBUF_THRESH_OVRD = "FALSE"; + parameter integer RXBUF_THRESH_UNDFLW = 4; + parameter [4:0] RXCDRFREQRESET_TIME = 5'b00001; + parameter [4:0] RXCDRPHRESET_TIME = 5'b00001; + parameter [15:0] RXCDR_CFG0 = 16'h0003; + parameter [15:0] RXCDR_CFG0_GEN3 = 16'h0003; + parameter [15:0] RXCDR_CFG1 = 16'h0000; + parameter [15:0] RXCDR_CFG1_GEN3 = 16'h0000; + parameter [15:0] RXCDR_CFG2 = 16'h0164; + parameter [9:0] RXCDR_CFG2_GEN2 = 10'h164; + parameter [15:0] RXCDR_CFG2_GEN3 = 16'h0034; + parameter [15:0] RXCDR_CFG2_GEN4 = 16'h0034; + parameter [15:0] RXCDR_CFG3 = 16'h0024; + parameter [5:0] RXCDR_CFG3_GEN2 = 6'h24; + parameter [15:0] RXCDR_CFG3_GEN3 = 16'h0024; + parameter [15:0] RXCDR_CFG3_GEN4 = 16'h0024; + parameter [15:0] RXCDR_CFG4 = 16'h5CF6; + parameter [15:0] RXCDR_CFG4_GEN3 = 16'h5CF6; + parameter [15:0] RXCDR_CFG5 = 16'hB46B; + parameter [15:0] RXCDR_CFG5_GEN3 = 16'h146B; + parameter [0:0] RXCDR_FR_RESET_ON_EIDLE = 1'b0; + parameter [0:0] RXCDR_HOLD_DURING_EIDLE = 1'b0; + parameter [15:0] RXCDR_LOCK_CFG0 = 16'h0040; + parameter [15:0] RXCDR_LOCK_CFG1 = 16'h8000; + parameter [15:0] RXCDR_LOCK_CFG2 = 16'h0000; + parameter [15:0] RXCDR_LOCK_CFG3 = 16'h0000; + parameter [15:0] RXCDR_LOCK_CFG4 = 16'h0000; + parameter [0:0] RXCDR_PH_RESET_ON_EIDLE = 1'b0; + parameter [15:0] RXCFOK_CFG0 = 16'h0000; + parameter [15:0] RXCFOK_CFG1 = 16'h0002; + parameter [15:0] RXCFOK_CFG2 = 16'h002D; + parameter [15:0] RXCKCAL1_IQ_LOOP_RST_CFG = 16'h0000; + parameter [15:0] RXCKCAL1_I_LOOP_RST_CFG = 16'h0000; + parameter [15:0] RXCKCAL1_Q_LOOP_RST_CFG = 16'h0000; + parameter [15:0] RXCKCAL2_DX_LOOP_RST_CFG = 16'h0000; + parameter [15:0] RXCKCAL2_D_LOOP_RST_CFG = 16'h0000; + parameter [15:0] RXCKCAL2_S_LOOP_RST_CFG = 16'h0000; + parameter [15:0] RXCKCAL2_X_LOOP_RST_CFG = 16'h0000; + parameter [6:0] RXDFELPMRESET_TIME = 7'b0001111; + parameter [15:0] RXDFELPM_KL_CFG0 = 16'h0000; + parameter [15:0] RXDFELPM_KL_CFG1 = 16'h0022; + parameter [15:0] RXDFELPM_KL_CFG2 = 16'h0100; + parameter [15:0] RXDFE_CFG0 = 16'h4000; + parameter [15:0] RXDFE_CFG1 = 16'h0000; + parameter [15:0] RXDFE_GC_CFG0 = 16'h0000; + parameter [15:0] RXDFE_GC_CFG1 = 16'h0000; + parameter [15:0] RXDFE_GC_CFG2 = 16'h0000; + parameter [15:0] RXDFE_H2_CFG0 = 16'h0000; + parameter [15:0] RXDFE_H2_CFG1 = 16'h0002; + parameter [15:0] RXDFE_H3_CFG0 = 16'h0000; + parameter [15:0] RXDFE_H3_CFG1 = 16'h0002; + parameter [15:0] RXDFE_H4_CFG0 = 16'h0000; + parameter [15:0] RXDFE_H4_CFG1 = 16'h0003; + parameter [15:0] RXDFE_H5_CFG0 = 16'h0000; + parameter [15:0] RXDFE_H5_CFG1 = 16'h0002; + parameter [15:0] RXDFE_H6_CFG0 = 16'h0000; + parameter [15:0] RXDFE_H6_CFG1 = 16'h0002; + parameter [15:0] RXDFE_H7_CFG0 = 16'h0000; + parameter [15:0] RXDFE_H7_CFG1 = 16'h0002; + parameter [15:0] RXDFE_H8_CFG0 = 16'h0000; + parameter [15:0] RXDFE_H8_CFG1 = 16'h0002; + parameter [15:0] RXDFE_H9_CFG0 = 16'h0000; + parameter [15:0] RXDFE_H9_CFG1 = 16'h0002; + parameter [15:0] RXDFE_HA_CFG0 = 16'h0000; + parameter [15:0] RXDFE_HA_CFG1 = 16'h0002; + parameter [15:0] RXDFE_HB_CFG0 = 16'h0000; + parameter [15:0] RXDFE_HB_CFG1 = 16'h0002; + parameter [15:0] RXDFE_HC_CFG0 = 16'h0000; + parameter [15:0] RXDFE_HC_CFG1 = 16'h0002; + parameter [15:0] RXDFE_HD_CFG0 = 16'h0000; + parameter [15:0] RXDFE_HD_CFG1 = 16'h0002; + parameter [15:0] RXDFE_HE_CFG0 = 16'h0000; + parameter [15:0] RXDFE_HE_CFG1 = 16'h0002; + parameter [15:0] RXDFE_HF_CFG0 = 16'h0000; + parameter [15:0] RXDFE_HF_CFG1 = 16'h0002; + parameter [15:0] RXDFE_KH_CFG0 = 16'h0000; + parameter [15:0] RXDFE_KH_CFG1 = 16'h0000; + parameter [15:0] RXDFE_KH_CFG2 = 16'h0000; + parameter [15:0] RXDFE_KH_CFG3 = 16'h0000; + parameter [15:0] RXDFE_OS_CFG0 = 16'h0000; + parameter [15:0] RXDFE_OS_CFG1 = 16'h0002; + parameter [0:0] RXDFE_PWR_SAVING = 1'b0; + parameter [15:0] RXDFE_UT_CFG0 = 16'h0000; + parameter [15:0] RXDFE_UT_CFG1 = 16'h0002; + parameter [15:0] RXDFE_UT_CFG2 = 16'h0000; + parameter [15:0] RXDFE_VP_CFG0 = 16'h0000; + parameter [15:0] RXDFE_VP_CFG1 = 16'h0022; + parameter [15:0] RXDLY_CFG = 16'h0010; + parameter [15:0] RXDLY_LCFG = 16'h0030; + parameter RXELECIDLE_CFG = "SIGCFG_4"; + parameter integer RXGBOX_FIFO_INIT_RD_ADDR = 4; + parameter RXGEARBOX_EN = "FALSE"; + parameter [4:0] RXISCANRESET_TIME = 5'b00001; + parameter [15:0] RXLPM_CFG = 16'h0000; + parameter [15:0] RXLPM_GC_CFG = 16'h1000; + parameter [15:0] RXLPM_KH_CFG0 = 16'h0000; + parameter [15:0] RXLPM_KH_CFG1 = 16'h0002; + parameter [15:0] RXLPM_OS_CFG0 = 16'h0000; + parameter [15:0] RXLPM_OS_CFG1 = 16'h0000; + parameter [8:0] RXOOB_CFG = 9'b000110000; + parameter RXOOB_CLK_CFG = "PMA"; + parameter [4:0] RXOSCALRESET_TIME = 5'b00011; + parameter integer RXOUT_DIV = 4; + parameter [4:0] RXPCSRESET_TIME = 5'b00001; + parameter [15:0] RXPHBEACON_CFG = 16'h0000; + parameter [15:0] RXPHDLY_CFG = 16'h2020; + parameter [15:0] RXPHSAMP_CFG = 16'h2100; + parameter [15:0] RXPHSLIP_CFG = 16'h9933; + parameter [4:0] RXPH_MONITOR_SEL = 5'b00000; + parameter [0:0] RXPI_AUTO_BW_SEL_BYPASS = 1'b0; + parameter [15:0] RXPI_CFG0 = 16'h0002; + parameter [15:0] RXPI_CFG1 = 16'b0000000000000000; + parameter [0:0] RXPI_LPM = 1'b0; + parameter [1:0] RXPI_SEL_LC = 2'b00; + parameter [1:0] RXPI_STARTCODE = 2'b00; + parameter [0:0] RXPI_VREFSEL = 1'b0; + parameter RXPMACLK_SEL = "DATA"; + parameter [4:0] RXPMARESET_TIME = 5'b00001; + parameter [0:0] RXPRBS_ERR_LOOPBACK = 1'b0; + parameter integer RXPRBS_LINKACQ_CNT = 15; + parameter [0:0] RXREFCLKDIV2_SEL = 1'b0; + parameter integer RXSLIDE_AUTO_WAIT = 7; + parameter RXSLIDE_MODE = "OFF"; + parameter [0:0] RXSYNC_MULTILANE = 1'b0; + parameter [0:0] RXSYNC_OVRD = 1'b0; + parameter [0:0] RXSYNC_SKIP_DA = 1'b0; + parameter [0:0] RX_AFE_CM_EN = 1'b0; + parameter [15:0] RX_BIAS_CFG0 = 16'h12B0; + parameter [5:0] RX_BUFFER_CFG = 6'b000000; + parameter [0:0] RX_CAPFF_SARC_ENB = 1'b0; + parameter integer RX_CLK25_DIV = 8; + parameter [0:0] RX_CLKMUX_EN = 1'b1; + parameter [4:0] RX_CLK_SLIP_OVRD = 5'b00000; + parameter [3:0] RX_CM_BUF_CFG = 4'b1010; + parameter [0:0] RX_CM_BUF_PD = 1'b0; + parameter integer RX_CM_SEL = 3; + parameter integer RX_CM_TRIM = 12; + parameter [7:0] RX_CTLE3_LPF = 8'b00000000; + parameter integer RX_DATA_WIDTH = 20; + parameter [5:0] RX_DDI_SEL = 6'b000000; + parameter RX_DEFER_RESET_BUF_EN = "TRUE"; + parameter [2:0] RX_DEGEN_CTRL = 3'b011; + parameter integer RX_DFELPM_CFG0 = 0; + parameter [0:0] RX_DFELPM_CFG1 = 1'b1; + parameter [0:0] RX_DFELPM_KLKH_AGC_STUP_EN = 1'b1; + parameter [1:0] RX_DFE_AGC_CFG0 = 2'b00; + parameter integer RX_DFE_AGC_CFG1 = 4; + parameter integer RX_DFE_KL_LPM_KH_CFG0 = 1; + parameter integer RX_DFE_KL_LPM_KH_CFG1 = 4; + parameter [1:0] RX_DFE_KL_LPM_KL_CFG0 = 2'b01; + parameter integer RX_DFE_KL_LPM_KL_CFG1 = 4; + parameter [0:0] RX_DFE_LPM_HOLD_DURING_EIDLE = 1'b0; + parameter RX_DISPERR_SEQ_MATCH = "TRUE"; + parameter [0:0] RX_DIV2_MODE_B = 1'b0; + parameter [4:0] RX_DIVRESET_TIME = 5'b00001; + parameter [0:0] RX_EN_CTLE_RCAL_B = 1'b0; + parameter [0:0] RX_EN_HI_LR = 1'b1; + parameter [8:0] RX_EXT_RL_CTRL = 9'b000000000; + parameter [6:0] RX_EYESCAN_VS_CODE = 7'b0000000; + parameter [0:0] RX_EYESCAN_VS_NEG_DIR = 1'b0; + parameter [1:0] RX_EYESCAN_VS_RANGE = 2'b00; + parameter [0:0] RX_EYESCAN_VS_UT_SIGN = 1'b0; + parameter [0:0] RX_FABINT_USRCLK_FLOP = 1'b0; + parameter integer RX_INT_DATAWIDTH = 1; + parameter [0:0] RX_PMA_POWER_SAVE = 1'b0; + parameter [15:0] RX_PMA_RSV0 = 16'h0000; + parameter real RX_PROGDIV_CFG = 0.0; + parameter [15:0] RX_PROGDIV_RATE = 16'h0001; + parameter [3:0] RX_RESLOAD_CTRL = 4'b0000; + parameter [0:0] RX_RESLOAD_OVRD = 1'b0; + parameter [2:0] RX_SAMPLE_PERIOD = 3'b101; + parameter integer RX_SIG_VALID_DLY = 11; + parameter [0:0] RX_SUM_DFETAPREP_EN = 1'b0; + parameter [3:0] RX_SUM_IREF_TUNE = 4'b1001; + parameter [3:0] RX_SUM_RESLOAD_CTRL = 4'b0000; + parameter [3:0] RX_SUM_VCMTUNE = 4'b1010; + parameter [0:0] RX_SUM_VCM_OVWR = 1'b0; + parameter [2:0] RX_SUM_VREF_TUNE = 3'b100; + parameter [1:0] RX_TUNE_AFE_OS = 2'b00; + parameter [2:0] RX_VREG_CTRL = 3'b101; + parameter [0:0] RX_VREG_PDB = 1'b1; + parameter [1:0] RX_WIDEMODE_CDR = 2'b01; + parameter [1:0] RX_WIDEMODE_CDR_GEN3 = 2'b01; + parameter [1:0] RX_WIDEMODE_CDR_GEN4 = 2'b01; + parameter RX_XCLK_SEL = "RXDES"; + parameter [0:0] RX_XMODE_SEL = 1'b0; + parameter [0:0] SAMPLE_CLK_PHASE = 1'b0; + parameter [0:0] SAS_12G_MODE = 1'b0; + parameter [3:0] SATA_BURST_SEQ_LEN = 4'b1111; + parameter [2:0] SATA_BURST_VAL = 3'b100; + parameter SATA_CPLL_CFG = "VCO_3000MHZ"; + parameter [2:0] SATA_EIDLE_VAL = 3'b100; + parameter SHOW_REALIGN_COMMA = "TRUE"; + parameter SIM_DEVICE = "ULTRASCALE_PLUS"; + parameter SIM_MODE = "FAST"; + parameter SIM_RECEIVER_DETECT_PASS = "TRUE"; + parameter SIM_RESET_SPEEDUP = "TRUE"; + parameter SIM_TX_EIDLE_DRIVE_LEVEL = "Z"; + parameter [0:0] SRSTMODE = 1'b0; + parameter [1:0] TAPDLY_SET_TX = 2'h0; + parameter [3:0] TEMPERATURE_PAR = 4'b0010; + parameter [14:0] TERM_RCAL_CFG = 15'b100001000010000; + parameter [2:0] TERM_RCAL_OVRD = 3'b000; + parameter [7:0] TRANS_TIME_RATE = 8'h0E; + parameter [7:0] TST_RSV0 = 8'h00; + parameter [7:0] TST_RSV1 = 8'h00; + parameter TXBUF_EN = "TRUE"; + parameter TXBUF_RESET_ON_RATE_CHANGE = "FALSE"; + parameter [15:0] TXDLY_CFG = 16'h0010; + parameter [15:0] TXDLY_LCFG = 16'h0030; + parameter [3:0] TXDRVBIAS_N = 4'b1010; + parameter TXFIFO_ADDR_CFG = "LOW"; + parameter integer TXGBOX_FIFO_INIT_RD_ADDR = 4; + parameter TXGEARBOX_EN = "FALSE"; + parameter integer TXOUT_DIV = 4; + parameter [4:0] TXPCSRESET_TIME = 5'b00001; + parameter [15:0] TXPHDLY_CFG0 = 16'h6020; + parameter [15:0] TXPHDLY_CFG1 = 16'h0002; + parameter [15:0] TXPH_CFG = 16'h0123; + parameter [15:0] TXPH_CFG2 = 16'h0000; + parameter [4:0] TXPH_MONITOR_SEL = 5'b00000; + parameter [15:0] TXPI_CFG = 16'h0000; + parameter [1:0] TXPI_CFG0 = 2'b00; + parameter [1:0] TXPI_CFG1 = 2'b00; + parameter [1:0] TXPI_CFG2 = 2'b00; + parameter [0:0] TXPI_CFG3 = 1'b0; + parameter [0:0] TXPI_CFG4 = 1'b1; + parameter [2:0] TXPI_CFG5 = 3'b000; + parameter [0:0] TXPI_GRAY_SEL = 1'b0; + parameter [0:0] TXPI_INVSTROBE_SEL = 1'b0; + parameter [0:0] TXPI_LPM = 1'b0; + parameter [0:0] TXPI_PPM = 1'b0; + parameter TXPI_PPMCLK_SEL = "TXUSRCLK2"; + parameter [7:0] TXPI_PPM_CFG = 8'b00000000; + parameter [2:0] TXPI_SYNFREQ_PPM = 3'b000; + parameter [0:0] TXPI_VREFSEL = 1'b0; + parameter [4:0] TXPMARESET_TIME = 5'b00001; + parameter [0:0] TXREFCLKDIV2_SEL = 1'b0; + parameter [0:0] TXSYNC_MULTILANE = 1'b0; + parameter [0:0] TXSYNC_OVRD = 1'b0; + parameter [0:0] TXSYNC_SKIP_DA = 1'b0; + parameter integer TX_CLK25_DIV = 8; + parameter [0:0] TX_CLKMUX_EN = 1'b1; + parameter integer TX_DATA_WIDTH = 20; + parameter [15:0] TX_DCC_LOOP_RST_CFG = 16'h0000; + parameter [5:0] TX_DEEMPH0 = 6'b000000; + parameter [5:0] TX_DEEMPH1 = 6'b000000; + parameter [5:0] TX_DEEMPH2 = 6'b000000; + parameter [5:0] TX_DEEMPH3 = 6'b000000; + parameter [4:0] TX_DIVRESET_TIME = 5'b00001; + parameter TX_DRIVE_MODE = "DIRECT"; + parameter integer TX_DRVMUX_CTRL = 2; + parameter [2:0] TX_EIDLE_ASSERT_DELAY = 3'b110; + parameter [2:0] TX_EIDLE_DEASSERT_DELAY = 3'b100; + parameter [0:0] TX_FABINT_USRCLK_FLOP = 1'b0; + parameter [0:0] TX_FIFO_BYP_EN = 1'b0; + parameter [0:0] TX_IDLE_DATA_ZERO = 1'b0; + parameter integer TX_INT_DATAWIDTH = 1; + parameter TX_LOOPBACK_DRIVE_HIZ = "FALSE"; + parameter [0:0] TX_MAINCURSOR_SEL = 1'b0; + parameter [6:0] TX_MARGIN_FULL_0 = 7'b1001110; + parameter [6:0] TX_MARGIN_FULL_1 = 7'b1001001; + parameter [6:0] TX_MARGIN_FULL_2 = 7'b1000101; + parameter [6:0] TX_MARGIN_FULL_3 = 7'b1000010; + parameter [6:0] TX_MARGIN_FULL_4 = 7'b1000000; + parameter [6:0] TX_MARGIN_LOW_0 = 7'b1000110; + parameter [6:0] TX_MARGIN_LOW_1 = 7'b1000100; + parameter [6:0] TX_MARGIN_LOW_2 = 7'b1000010; + parameter [6:0] TX_MARGIN_LOW_3 = 7'b1000000; + parameter [6:0] TX_MARGIN_LOW_4 = 7'b1000000; + parameter [15:0] TX_PHICAL_CFG0 = 16'h0000; + parameter [15:0] TX_PHICAL_CFG1 = 16'h003F; + parameter [15:0] TX_PHICAL_CFG2 = 16'h0000; + parameter integer TX_PI_BIASSET = 0; + parameter [1:0] TX_PI_IBIAS_MID = 2'b00; + parameter [0:0] TX_PMADATA_OPT = 1'b0; + parameter [0:0] TX_PMA_POWER_SAVE = 1'b0; + parameter [15:0] TX_PMA_RSV0 = 16'h0008; + parameter integer TX_PREDRV_CTRL = 2; + parameter TX_PROGCLK_SEL = "POSTPI"; + parameter real TX_PROGDIV_CFG = 0.0; + parameter [15:0] TX_PROGDIV_RATE = 16'h0001; + parameter [0:0] TX_QPI_STATUS_EN = 1'b0; + parameter [13:0] TX_RXDETECT_CFG = 14'h0032; + parameter integer TX_RXDETECT_REF = 3; + parameter [2:0] TX_SAMPLE_PERIOD = 3'b101; + parameter [0:0] TX_SARC_LPBK_ENB = 1'b0; + parameter [1:0] TX_SW_MEAS = 2'b00; + parameter [2:0] TX_VREG_CTRL = 3'b000; + parameter [0:0] TX_VREG_PDB = 1'b0; + parameter [1:0] TX_VREG_VREFSEL = 2'b00; + parameter TX_XCLK_SEL = "TXOUT"; + parameter [0:0] USB_BOTH_BURST_IDLE = 1'b0; + parameter [6:0] USB_BURSTMAX_U3WAKE = 7'b1111111; + parameter [6:0] USB_BURSTMIN_U3WAKE = 7'b1100011; + parameter [0:0] USB_CLK_COR_EQ_EN = 1'b0; + parameter [0:0] USB_EXT_CNTL = 1'b1; + parameter [9:0] USB_IDLEMAX_POLLING = 10'b1010111011; + parameter [9:0] USB_IDLEMIN_POLLING = 10'b0100101011; + parameter [8:0] USB_LFPSPING_BURST = 9'b000000101; + parameter [8:0] USB_LFPSPOLLING_BURST = 9'b000110001; + parameter [8:0] USB_LFPSPOLLING_IDLE_MS = 9'b000000100; + parameter [8:0] USB_LFPSU1EXIT_BURST = 9'b000011101; + parameter [8:0] USB_LFPSU2LPEXIT_BURST_MS = 9'b001100011; + parameter [8:0] USB_LFPSU3WAKE_BURST_MS = 9'b111110011; + parameter [3:0] USB_LFPS_TPERIOD = 4'b0011; + parameter [0:0] USB_LFPS_TPERIOD_ACCURATE = 1'b1; + parameter [0:0] USB_MODE = 1'b0; + parameter [0:0] USB_PCIE_ERR_REP_DIS = 1'b0; + parameter integer USB_PING_SATA_MAX_INIT = 21; + parameter integer USB_PING_SATA_MIN_INIT = 12; + parameter integer USB_POLL_SATA_MAX_BURST = 8; + parameter integer USB_POLL_SATA_MIN_BURST = 4; + parameter [0:0] USB_RAW_ELEC = 1'b0; + parameter [0:0] USB_RXIDLE_P0_CTRL = 1'b1; + parameter [0:0] USB_TXIDLE_TUNE_ENABLE = 1'b1; + parameter integer USB_U1_SATA_MAX_WAKE = 7; + parameter integer USB_U1_SATA_MIN_WAKE = 4; + parameter integer USB_U2_SAS_MAX_COM = 64; + parameter integer USB_U2_SAS_MIN_COM = 36; + parameter [0:0] USE_PCS_CLK_PHASE_SEL = 1'b0; + parameter [0:0] Y_ALL_MODE = 1'b0; + output BUFGTCE; + output [2:0] BUFGTCEMASK; + output [8:0] BUFGTDIV; + output BUFGTRESET; + output [2:0] BUFGTRSTMASK; + output CPLLFBCLKLOST; + output CPLLLOCK; + output CPLLREFCLKLOST; + output [15:0] DMONITOROUT; + output DMONITOROUTCLK; + output [15:0] DRPDO; + output DRPRDY; + output EYESCANDATAERROR; + output GTHTXN; + output GTHTXP; + output GTPOWERGOOD; + output GTREFCLKMONITOR; + output PCIERATEGEN3; + output PCIERATEIDLE; + output [1:0] PCIERATEQPLLPD; + output [1:0] PCIERATEQPLLRESET; + output PCIESYNCTXSYNCDONE; + output PCIEUSERGEN3RDY; + output PCIEUSERPHYSTATUSRST; + output PCIEUSERRATESTART; + output [15:0] PCSRSVDOUT; + output PHYSTATUS; + output [15:0] PINRSRVDAS; + output POWERPRESENT; + output RESETEXCEPTION; + output [2:0] RXBUFSTATUS; + output RXBYTEISALIGNED; + output RXBYTEREALIGN; + output RXCDRLOCK; + output RXCDRPHDONE; + output RXCHANBONDSEQ; + output RXCHANISALIGNED; + output RXCHANREALIGN; + output [4:0] RXCHBONDO; + output RXCKCALDONE; + output [1:0] RXCLKCORCNT; + output RXCOMINITDET; + output RXCOMMADET; + output RXCOMSASDET; + output RXCOMWAKEDET; + output [15:0] RXCTRL0; + output [15:0] RXCTRL1; + output [7:0] RXCTRL2; + output [7:0] RXCTRL3; + output [127:0] RXDATA; + output [7:0] RXDATAEXTENDRSVD; + output [1:0] RXDATAVALID; + output RXDLYSRESETDONE; + output RXELECIDLE; + output [5:0] RXHEADER; + output [1:0] RXHEADERVALID; + output RXLFPSTRESETDET; + output RXLFPSU2LPEXITDET; + output RXLFPSU3WAKEDET; + output [7:0] RXMONITOROUT; + output RXOSINTDONE; + output RXOSINTSTARTED; + output RXOSINTSTROBEDONE; + output RXOSINTSTROBESTARTED; + output RXOUTCLK; + output RXOUTCLKFABRIC; + output RXOUTCLKPCS; + output RXPHALIGNDONE; + output RXPHALIGNERR; + output RXPMARESETDONE; + output RXPRBSERR; + output RXPRBSLOCKED; + output RXPRGDIVRESETDONE; + output RXQPISENN; + output RXQPISENP; + output RXRATEDONE; + output RXRECCLKOUT; + output RXRESETDONE; + output RXSLIDERDY; + output RXSLIPDONE; + output RXSLIPOUTCLKRDY; + output RXSLIPPMARDY; + output [1:0] RXSTARTOFSEQ; + output [2:0] RXSTATUS; + output RXSYNCDONE; + output RXSYNCOUT; + output RXVALID; + output [1:0] TXBUFSTATUS; + output TXCOMFINISH; + output TXDCCDONE; + output TXDLYSRESETDONE; + output TXOUTCLK; + output TXOUTCLKFABRIC; + output TXOUTCLKPCS; + output TXPHALIGNDONE; + output TXPHINITDONE; + output TXPMARESETDONE; + output TXPRGDIVRESETDONE; + output TXQPISENN; + output TXQPISENP; + output TXRATEDONE; + output TXRESETDONE; + output TXSYNCDONE; + output TXSYNCOUT; + input CDRSTEPDIR; + input CDRSTEPSQ; + input CDRSTEPSX; + input CFGRESET; + input CLKRSVD0; + input CLKRSVD1; + input CPLLFREQLOCK; + input CPLLLOCKDETCLK; + input CPLLLOCKEN; + input CPLLPD; + input [2:0] CPLLREFCLKSEL; + input CPLLRESET; + input DMONFIFORESET; + input DMONITORCLK; + input [9:0] DRPADDR; + input DRPCLK; + input [15:0] DRPDI; + input DRPEN; + input DRPRST; + input DRPWE; + input EYESCANRESET; + input EYESCANTRIGGER; + input FREQOS; + input GTGREFCLK; + input GTHRXN; + input GTHRXP; + input GTNORTHREFCLK0; + input GTNORTHREFCLK1; + input GTREFCLK0; + input GTREFCLK1; + input [15:0] GTRSVD; + input GTRXRESET; + input GTRXRESETSEL; + input GTSOUTHREFCLK0; + input GTSOUTHREFCLK1; + input GTTXRESET; + input GTTXRESETSEL; + input INCPCTRL; + input [2:0] LOOPBACK; + input PCIEEQRXEQADAPTDONE; + input PCIERSTIDLE; + input PCIERSTTXSYNCSTART; + input PCIEUSERRATEDONE; + input [15:0] PCSRSVDIN; + input QPLL0CLK; + input QPLL0FREQLOCK; + input QPLL0REFCLK; + input QPLL1CLK; + input QPLL1FREQLOCK; + input QPLL1REFCLK; + input RESETOVRD; + input RX8B10BEN; + input RXAFECFOKEN; + input RXBUFRESET; + input RXCDRFREQRESET; + input RXCDRHOLD; + input RXCDROVRDEN; + input RXCDRRESET; + input RXCHBONDEN; + input [4:0] RXCHBONDI; + input [2:0] RXCHBONDLEVEL; + input RXCHBONDMASTER; + input RXCHBONDSLAVE; + input RXCKCALRESET; + input [6:0] RXCKCALSTART; + input RXCOMMADETEN; + input [1:0] RXDFEAGCCTRL; + input RXDFEAGCHOLD; + input RXDFEAGCOVRDEN; + input [3:0] RXDFECFOKFCNUM; + input RXDFECFOKFEN; + input RXDFECFOKFPULSE; + input RXDFECFOKHOLD; + input RXDFECFOKOVREN; + input RXDFEKHHOLD; + input RXDFEKHOVRDEN; + input RXDFELFHOLD; + input RXDFELFOVRDEN; + input RXDFELPMRESET; + input RXDFETAP10HOLD; + input RXDFETAP10OVRDEN; + input RXDFETAP11HOLD; + input RXDFETAP11OVRDEN; + input RXDFETAP12HOLD; + input RXDFETAP12OVRDEN; + input RXDFETAP13HOLD; + input RXDFETAP13OVRDEN; + input RXDFETAP14HOLD; + input RXDFETAP14OVRDEN; + input RXDFETAP15HOLD; + input RXDFETAP15OVRDEN; + input RXDFETAP2HOLD; + input RXDFETAP2OVRDEN; + input RXDFETAP3HOLD; + input RXDFETAP3OVRDEN; + input RXDFETAP4HOLD; + input RXDFETAP4OVRDEN; + input RXDFETAP5HOLD; + input RXDFETAP5OVRDEN; + input RXDFETAP6HOLD; + input RXDFETAP6OVRDEN; + input RXDFETAP7HOLD; + input RXDFETAP7OVRDEN; + input RXDFETAP8HOLD; + input RXDFETAP8OVRDEN; + input RXDFETAP9HOLD; + input RXDFETAP9OVRDEN; + input RXDFEUTHOLD; + input RXDFEUTOVRDEN; + input RXDFEVPHOLD; + input RXDFEVPOVRDEN; + input RXDFEXYDEN; + input RXDLYBYPASS; + input RXDLYEN; + input RXDLYOVRDEN; + input RXDLYSRESET; + input [1:0] RXELECIDLEMODE; + input RXEQTRAINING; + input RXGEARBOXSLIP; + input RXLATCLK; + input RXLPMEN; + input RXLPMGCHOLD; + input RXLPMGCOVRDEN; + input RXLPMHFHOLD; + input RXLPMHFOVRDEN; + input RXLPMLFHOLD; + input RXLPMLFKLOVRDEN; + input RXLPMOSHOLD; + input RXLPMOSOVRDEN; + input RXMCOMMAALIGNEN; + input [1:0] RXMONITORSEL; + input RXOOBRESET; + input RXOSCALRESET; + input RXOSHOLD; + input RXOSOVRDEN; + input [2:0] RXOUTCLKSEL; + input RXPCOMMAALIGNEN; + input RXPCSRESET; + input [1:0] RXPD; + input RXPHALIGN; + input RXPHALIGNEN; + input RXPHDLYPD; + input RXPHDLYRESET; + input RXPHOVRDEN; + input [1:0] RXPLLCLKSEL; + input RXPMARESET; + input RXPOLARITY; + input RXPRBSCNTRESET; + input [3:0] RXPRBSSEL; + input RXPROGDIVRESET; + input RXQPIEN; + input [2:0] RXRATE; + input RXRATEMODE; + input RXSLIDE; + input RXSLIPOUTCLK; + input RXSLIPPMA; + input RXSYNCALLIN; + input RXSYNCIN; + input RXSYNCMODE; + input [1:0] RXSYSCLKSEL; + input RXTERMINATION; + input RXUSERRDY; + input RXUSRCLK; + input RXUSRCLK2; + input SIGVALIDCLK; + input [19:0] TSTIN; + input [7:0] TX8B10BBYPASS; + input TX8B10BEN; + input TXCOMINIT; + input TXCOMSAS; + input TXCOMWAKE; + input [15:0] TXCTRL0; + input [15:0] TXCTRL1; + input [7:0] TXCTRL2; + input [127:0] TXDATA; + input [7:0] TXDATAEXTENDRSVD; + input TXDCCFORCESTART; + input TXDCCRESET; + input [1:0] TXDEEMPH; + input TXDETECTRX; + input [4:0] TXDIFFCTRL; + input TXDLYBYPASS; + input TXDLYEN; + input TXDLYHOLD; + input TXDLYOVRDEN; + input TXDLYSRESET; + input TXDLYUPDOWN; + input TXELECIDLE; + input [5:0] TXHEADER; + input TXINHIBIT; + input TXLATCLK; + input TXLFPSTRESET; + input TXLFPSU2LPEXIT; + input TXLFPSU3WAKE; + input [6:0] TXMAINCURSOR; + input [2:0] TXMARGIN; + input TXMUXDCDEXHOLD; + input TXMUXDCDORWREN; + input TXONESZEROS; + input [2:0] TXOUTCLKSEL; + input TXPCSRESET; + input [1:0] TXPD; + input TXPDELECIDLEMODE; + input TXPHALIGN; + input TXPHALIGNEN; + input TXPHDLYPD; + input TXPHDLYRESET; + input TXPHDLYTSTCLK; + input TXPHINIT; + input TXPHOVRDEN; + input TXPIPPMEN; + input TXPIPPMOVRDEN; + input TXPIPPMPD; + input TXPIPPMSEL; + input [4:0] TXPIPPMSTEPSIZE; + input TXPISOPD; + input [1:0] TXPLLCLKSEL; + input TXPMARESET; + input TXPOLARITY; + input [4:0] TXPOSTCURSOR; + input TXPRBSFORCEERR; + input [3:0] TXPRBSSEL; + input [4:0] TXPRECURSOR; + input TXPROGDIVRESET; + input TXQPIBIASEN; + input TXQPIWEAKPUP; + input [2:0] TXRATE; + input TXRATEMODE; + input [6:0] TXSEQUENCE; + input TXSWING; + input TXSYNCALLIN; + input TXSYNCIN; + input TXSYNCMODE; + input [1:0] TXSYSCLKSEL; + input TXUSERRDY; + input TXUSRCLK; + input TXUSRCLK2; +endmodule + +module GTHE4_COMMON (...); + parameter [0:0] AEN_QPLL0_FBDIV = 1'b1; + parameter [0:0] AEN_QPLL1_FBDIV = 1'b1; + parameter [0:0] AEN_SDM0TOGGLE = 1'b0; + parameter [0:0] AEN_SDM1TOGGLE = 1'b0; + parameter [0:0] A_SDM0TOGGLE = 1'b0; + parameter [8:0] A_SDM1DATA_HIGH = 9'b000000000; + parameter [15:0] A_SDM1DATA_LOW = 16'b0000000000000000; + parameter [0:0] A_SDM1TOGGLE = 1'b0; + parameter [15:0] BIAS_CFG0 = 16'h0000; + parameter [15:0] BIAS_CFG1 = 16'h0000; + parameter [15:0] BIAS_CFG2 = 16'h0000; + parameter [15:0] BIAS_CFG3 = 16'h0000; + parameter [15:0] BIAS_CFG4 = 16'h0000; + parameter [15:0] BIAS_CFG_RSVD = 16'h0000; + parameter [15:0] COMMON_CFG0 = 16'h0000; + parameter [15:0] COMMON_CFG1 = 16'h0000; + parameter [15:0] POR_CFG = 16'h0000; + parameter [15:0] PPF0_CFG = 16'h0F00; + parameter [15:0] PPF1_CFG = 16'h0F00; + parameter QPLL0CLKOUT_RATE = "FULL"; + parameter [15:0] QPLL0_CFG0 = 16'h391C; + parameter [15:0] QPLL0_CFG1 = 16'h0000; + parameter [15:0] QPLL0_CFG1_G3 = 16'h0020; + parameter [15:0] QPLL0_CFG2 = 16'h0F80; + parameter [15:0] QPLL0_CFG2_G3 = 16'h0F80; + parameter [15:0] QPLL0_CFG3 = 16'h0120; + parameter [15:0] QPLL0_CFG4 = 16'h0002; + parameter [9:0] QPLL0_CP = 10'b0000011111; + parameter [9:0] QPLL0_CP_G3 = 10'b0000011111; + parameter integer QPLL0_FBDIV = 66; + parameter integer QPLL0_FBDIV_G3 = 80; + parameter [15:0] QPLL0_INIT_CFG0 = 16'h0000; + parameter [7:0] QPLL0_INIT_CFG1 = 8'h00; + parameter [15:0] QPLL0_LOCK_CFG = 16'h01E8; + parameter [15:0] QPLL0_LOCK_CFG_G3 = 16'h21E8; + parameter [9:0] QPLL0_LPF = 10'b1011111111; + parameter [9:0] QPLL0_LPF_G3 = 10'b1111111111; + parameter [0:0] QPLL0_PCI_EN = 1'b0; + parameter [0:0] QPLL0_RATE_SW_USE_DRP = 1'b0; + parameter integer QPLL0_REFCLK_DIV = 1; + parameter [15:0] QPLL0_SDM_CFG0 = 16'h0040; + parameter [15:0] QPLL0_SDM_CFG1 = 16'h0000; + parameter [15:0] QPLL0_SDM_CFG2 = 16'h0000; + parameter QPLL1CLKOUT_RATE = "FULL"; + parameter [15:0] QPLL1_CFG0 = 16'h691C; + parameter [15:0] QPLL1_CFG1 = 16'h0020; + parameter [15:0] QPLL1_CFG1_G3 = 16'h0020; + parameter [15:0] QPLL1_CFG2 = 16'h0F80; + parameter [15:0] QPLL1_CFG2_G3 = 16'h0F80; + parameter [15:0] QPLL1_CFG3 = 16'h0120; + parameter [15:0] QPLL1_CFG4 = 16'h0002; + parameter [9:0] QPLL1_CP = 10'b0000011111; + parameter [9:0] QPLL1_CP_G3 = 10'b0000011111; + parameter integer QPLL1_FBDIV = 66; + parameter integer QPLL1_FBDIV_G3 = 80; + parameter [15:0] QPLL1_INIT_CFG0 = 16'h0000; + parameter [7:0] QPLL1_INIT_CFG1 = 8'h00; + parameter [15:0] QPLL1_LOCK_CFG = 16'h01E8; + parameter [15:0] QPLL1_LOCK_CFG_G3 = 16'h21E8; + parameter [9:0] QPLL1_LPF = 10'b1011111111; + parameter [9:0] QPLL1_LPF_G3 = 10'b1111111111; + parameter [0:0] QPLL1_PCI_EN = 1'b0; + parameter [0:0] QPLL1_RATE_SW_USE_DRP = 1'b0; + parameter integer QPLL1_REFCLK_DIV = 1; + parameter [15:0] QPLL1_SDM_CFG0 = 16'h0000; + parameter [15:0] QPLL1_SDM_CFG1 = 16'h0000; + parameter [15:0] QPLL1_SDM_CFG2 = 16'h0000; + parameter [15:0] RSVD_ATTR0 = 16'h0000; + parameter [15:0] RSVD_ATTR1 = 16'h0000; + parameter [15:0] RSVD_ATTR2 = 16'h0000; + parameter [15:0] RSVD_ATTR3 = 16'h0000; + parameter [1:0] RXRECCLKOUT0_SEL = 2'b00; + parameter [1:0] RXRECCLKOUT1_SEL = 2'b00; + parameter [0:0] SARC_ENB = 1'b0; + parameter [0:0] SARC_SEL = 1'b0; + parameter [15:0] SDM0INITSEED0_0 = 16'b0000000000000000; + parameter [8:0] SDM0INITSEED0_1 = 9'b000000000; + parameter [15:0] SDM1INITSEED0_0 = 16'b0000000000000000; + parameter [8:0] SDM1INITSEED0_1 = 9'b000000000; + parameter SIM_DEVICE = "ULTRASCALE_PLUS"; + parameter SIM_MODE = "FAST"; + parameter SIM_RESET_SPEEDUP = "TRUE"; + output [15:0] DRPDO; + output DRPRDY; + output [7:0] PMARSVDOUT0; + output [7:0] PMARSVDOUT1; + output QPLL0FBCLKLOST; + output QPLL0LOCK; + output QPLL0OUTCLK; + output QPLL0OUTREFCLK; + output QPLL0REFCLKLOST; + output QPLL1FBCLKLOST; + output QPLL1LOCK; + output QPLL1OUTCLK; + output QPLL1OUTREFCLK; + output QPLL1REFCLKLOST; + output [7:0] QPLLDMONITOR0; + output [7:0] QPLLDMONITOR1; + output REFCLKOUTMONITOR0; + output REFCLKOUTMONITOR1; + output [1:0] RXRECCLK0SEL; + output [1:0] RXRECCLK1SEL; + output [3:0] SDM0FINALOUT; + output [14:0] SDM0TESTDATA; + output [3:0] SDM1FINALOUT; + output [14:0] SDM1TESTDATA; + output [9:0] TCONGPO; + output TCONRSVDOUT0; + input BGBYPASSB; + input BGMONITORENB; + input BGPDB; + input [4:0] BGRCALOVRD; + input BGRCALOVRDENB; + input [15:0] DRPADDR; + input DRPCLK; + input [15:0] DRPDI; + input DRPEN; + input DRPWE; + input GTGREFCLK0; + input GTGREFCLK1; + input GTNORTHREFCLK00; + input GTNORTHREFCLK01; + input GTNORTHREFCLK10; + input GTNORTHREFCLK11; + input GTREFCLK00; + input GTREFCLK01; + input GTREFCLK10; + input GTREFCLK11; + input GTSOUTHREFCLK00; + input GTSOUTHREFCLK01; + input GTSOUTHREFCLK10; + input GTSOUTHREFCLK11; + input [2:0] PCIERATEQPLL0; + input [2:0] PCIERATEQPLL1; + input [7:0] PMARSVD0; + input [7:0] PMARSVD1; + input QPLL0CLKRSVD0; + input QPLL0CLKRSVD1; + input [7:0] QPLL0FBDIV; + input QPLL0LOCKDETCLK; + input QPLL0LOCKEN; + input QPLL0PD; + input [2:0] QPLL0REFCLKSEL; + input QPLL0RESET; + input QPLL1CLKRSVD0; + input QPLL1CLKRSVD1; + input [7:0] QPLL1FBDIV; + input QPLL1LOCKDETCLK; + input QPLL1LOCKEN; + input QPLL1PD; + input [2:0] QPLL1REFCLKSEL; + input QPLL1RESET; + input [7:0] QPLLRSVD1; + input [4:0] QPLLRSVD2; + input [4:0] QPLLRSVD3; + input [7:0] QPLLRSVD4; + input RCALENB; + input [24:0] SDM0DATA; + input SDM0RESET; + input SDM0TOGGLE; + input [1:0] SDM0WIDTH; + input [24:0] SDM1DATA; + input SDM1RESET; + input SDM1TOGGLE; + input [1:0] SDM1WIDTH; + input [9:0] TCONGPI; + input TCONPOWERUP; + input [1:0] TCONRESET; + input [1:0] TCONRSVDIN1; +endmodule + +module GTYE3_CHANNEL (...); + parameter [0:0] ACJTAG_DEBUG_MODE = 1'b0; + parameter [0:0] ACJTAG_MODE = 1'b0; + parameter [0:0] ACJTAG_RESET = 1'b0; + parameter [15:0] ADAPT_CFG0 = 16'h9200; + parameter [15:0] ADAPT_CFG1 = 16'h801C; + parameter [15:0] ADAPT_CFG2 = 16'b0000000000000000; + parameter ALIGN_COMMA_DOUBLE = "FALSE"; + parameter [9:0] ALIGN_COMMA_ENABLE = 10'b0001111111; + parameter integer ALIGN_COMMA_WORD = 1; + parameter ALIGN_MCOMMA_DET = "TRUE"; + parameter [9:0] ALIGN_MCOMMA_VALUE = 10'b1010000011; + parameter ALIGN_PCOMMA_DET = "TRUE"; + parameter [9:0] ALIGN_PCOMMA_VALUE = 10'b0101111100; + parameter [0:0] AUTO_BW_SEL_BYPASS = 1'b0; + parameter [0:0] A_RXOSCALRESET = 1'b0; + parameter [0:0] A_RXPROGDIVRESET = 1'b0; + parameter [4:0] A_TXDIFFCTRL = 5'b01100; + parameter [0:0] A_TXPROGDIVRESET = 1'b0; + parameter [0:0] CAPBYPASS_FORCE = 1'b0; + parameter CBCC_DATA_SOURCE_SEL = "DECODED"; + parameter [0:0] CDR_SWAP_MODE_EN = 1'b0; + parameter CHAN_BOND_KEEP_ALIGN = "FALSE"; + parameter integer CHAN_BOND_MAX_SKEW = 7; + parameter [9:0] CHAN_BOND_SEQ_1_1 = 10'b0101111100; + parameter [9:0] CHAN_BOND_SEQ_1_2 = 10'b0000000000; + parameter [9:0] CHAN_BOND_SEQ_1_3 = 10'b0000000000; + parameter [9:0] CHAN_BOND_SEQ_1_4 = 10'b0000000000; + parameter [3:0] CHAN_BOND_SEQ_1_ENABLE = 4'b1111; + parameter [9:0] CHAN_BOND_SEQ_2_1 = 10'b0100000000; + parameter [9:0] CHAN_BOND_SEQ_2_2 = 10'b0100000000; + parameter [9:0] CHAN_BOND_SEQ_2_3 = 10'b0100000000; + parameter [9:0] CHAN_BOND_SEQ_2_4 = 10'b0100000000; + parameter [3:0] CHAN_BOND_SEQ_2_ENABLE = 4'b1111; + parameter CHAN_BOND_SEQ_2_USE = "FALSE"; + parameter integer CHAN_BOND_SEQ_LEN = 2; + parameter [15:0] CH_HSPMUX = 16'h0000; + parameter [15:0] CKCAL1_CFG_0 = 16'b0000000000000000; + parameter [15:0] CKCAL1_CFG_1 = 16'b0000000000000000; + parameter [15:0] CKCAL1_CFG_2 = 16'b0000000000000000; + parameter [15:0] CKCAL1_CFG_3 = 16'b0000000000000000; + parameter [15:0] CKCAL2_CFG_0 = 16'b0000000000000000; + parameter [15:0] CKCAL2_CFG_1 = 16'b0000000000000000; + parameter [15:0] CKCAL2_CFG_2 = 16'b0000000000000000; + parameter [15:0] CKCAL2_CFG_3 = 16'b0000000000000000; + parameter [15:0] CKCAL2_CFG_4 = 16'b0000000000000000; + parameter [15:0] CKCAL_RSVD0 = 16'h0000; + parameter [15:0] CKCAL_RSVD1 = 16'h0000; + parameter CLK_CORRECT_USE = "TRUE"; + parameter CLK_COR_KEEP_IDLE = "FALSE"; + parameter integer CLK_COR_MAX_LAT = 20; + parameter integer CLK_COR_MIN_LAT = 18; + parameter CLK_COR_PRECEDENCE = "TRUE"; + parameter integer CLK_COR_REPEAT_WAIT = 0; + parameter [9:0] CLK_COR_SEQ_1_1 = 10'b0100011100; + parameter [9:0] CLK_COR_SEQ_1_2 = 10'b0000000000; + parameter [9:0] CLK_COR_SEQ_1_3 = 10'b0000000000; + parameter [9:0] CLK_COR_SEQ_1_4 = 10'b0000000000; + parameter [3:0] CLK_COR_SEQ_1_ENABLE = 4'b1111; + parameter [9:0] CLK_COR_SEQ_2_1 = 10'b0100000000; + parameter [9:0] CLK_COR_SEQ_2_2 = 10'b0100000000; + parameter [9:0] CLK_COR_SEQ_2_3 = 10'b0100000000; + parameter [9:0] CLK_COR_SEQ_2_4 = 10'b0100000000; + parameter [3:0] CLK_COR_SEQ_2_ENABLE = 4'b1111; + parameter CLK_COR_SEQ_2_USE = "FALSE"; + parameter integer CLK_COR_SEQ_LEN = 2; + parameter [15:0] CPLL_CFG0 = 16'h20F8; + parameter [15:0] CPLL_CFG1 = 16'hA494; + parameter [15:0] CPLL_CFG2 = 16'hF001; + parameter [5:0] CPLL_CFG3 = 6'h00; + parameter integer CPLL_FBDIV = 4; + parameter integer CPLL_FBDIV_45 = 4; + parameter [15:0] CPLL_INIT_CFG0 = 16'h001E; + parameter [7:0] CPLL_INIT_CFG1 = 8'h00; + parameter [15:0] CPLL_LOCK_CFG = 16'h01E8; + parameter integer CPLL_REFCLK_DIV = 1; + parameter [2:0] CTLE3_OCAP_EXT_CTRL = 3'b000; + parameter [0:0] CTLE3_OCAP_EXT_EN = 1'b0; + parameter [1:0] DDI_CTRL = 2'b00; + parameter integer DDI_REALIGN_WAIT = 15; + parameter DEC_MCOMMA_DETECT = "TRUE"; + parameter DEC_PCOMMA_DETECT = "TRUE"; + parameter DEC_VALID_COMMA_ONLY = "TRUE"; + parameter [0:0] DFE_D_X_REL_POS = 1'b0; + parameter [0:0] DFE_VCM_COMP_EN = 1'b0; + parameter [9:0] DMONITOR_CFG0 = 10'h000; + parameter [7:0] DMONITOR_CFG1 = 8'h00; + parameter [0:0] ES_CLK_PHASE_SEL = 1'b0; + parameter [5:0] ES_CONTROL = 6'b000000; + parameter ES_ERRDET_EN = "FALSE"; + parameter ES_EYE_SCAN_EN = "FALSE"; + parameter [11:0] ES_HORZ_OFFSET = 12'h000; + parameter [9:0] ES_PMA_CFG = 10'b0000000000; + parameter [4:0] ES_PRESCALE = 5'b00000; + parameter [15:0] ES_QUALIFIER0 = 16'h0000; + parameter [15:0] ES_QUALIFIER1 = 16'h0000; + parameter [15:0] ES_QUALIFIER2 = 16'h0000; + parameter [15:0] ES_QUALIFIER3 = 16'h0000; + parameter [15:0] ES_QUALIFIER4 = 16'h0000; + parameter [15:0] ES_QUALIFIER5 = 16'h0000; + parameter [15:0] ES_QUALIFIER6 = 16'h0000; + parameter [15:0] ES_QUALIFIER7 = 16'h0000; + parameter [15:0] ES_QUALIFIER8 = 16'h0000; + parameter [15:0] ES_QUALIFIER9 = 16'h0000; + parameter [15:0] ES_QUAL_MASK0 = 16'h0000; + parameter [15:0] ES_QUAL_MASK1 = 16'h0000; + parameter [15:0] ES_QUAL_MASK2 = 16'h0000; + parameter [15:0] ES_QUAL_MASK3 = 16'h0000; + parameter [15:0] ES_QUAL_MASK4 = 16'h0000; + parameter [15:0] ES_QUAL_MASK5 = 16'h0000; + parameter [15:0] ES_QUAL_MASK6 = 16'h0000; + parameter [15:0] ES_QUAL_MASK7 = 16'h0000; + parameter [15:0] ES_QUAL_MASK8 = 16'h0000; + parameter [15:0] ES_QUAL_MASK9 = 16'h0000; + parameter [15:0] ES_SDATA_MASK0 = 16'h0000; + parameter [15:0] ES_SDATA_MASK1 = 16'h0000; + parameter [15:0] ES_SDATA_MASK2 = 16'h0000; + parameter [15:0] ES_SDATA_MASK3 = 16'h0000; + parameter [15:0] ES_SDATA_MASK4 = 16'h0000; + parameter [15:0] ES_SDATA_MASK5 = 16'h0000; + parameter [15:0] ES_SDATA_MASK6 = 16'h0000; + parameter [15:0] ES_SDATA_MASK7 = 16'h0000; + parameter [15:0] ES_SDATA_MASK8 = 16'h0000; + parameter [15:0] ES_SDATA_MASK9 = 16'h0000; + parameter [10:0] EVODD_PHI_CFG = 11'b00000000000; + parameter [0:0] EYE_SCAN_SWAP_EN = 1'b0; + parameter [3:0] FTS_DESKEW_SEQ_ENABLE = 4'b1111; + parameter [3:0] FTS_LANE_DESKEW_CFG = 4'b1111; + parameter FTS_LANE_DESKEW_EN = "FALSE"; + parameter [4:0] GEARBOX_MODE = 5'b00000; + parameter [0:0] GM_BIAS_SELECT = 1'b0; + parameter [0:0] ISCAN_CK_PH_SEL2 = 1'b0; + parameter [0:0] LOCAL_MASTER = 1'b0; + parameter [15:0] LOOP0_CFG = 16'h0000; + parameter [15:0] LOOP10_CFG = 16'h0000; + parameter [15:0] LOOP11_CFG = 16'h0000; + parameter [15:0] LOOP12_CFG = 16'h0000; + parameter [15:0] LOOP13_CFG = 16'h0000; + parameter [15:0] LOOP1_CFG = 16'h0000; + parameter [15:0] LOOP2_CFG = 16'h0000; + parameter [15:0] LOOP3_CFG = 16'h0000; + parameter [15:0] LOOP4_CFG = 16'h0000; + parameter [15:0] LOOP5_CFG = 16'h0000; + parameter [15:0] LOOP6_CFG = 16'h0000; + parameter [15:0] LOOP7_CFG = 16'h0000; + parameter [15:0] LOOP8_CFG = 16'h0000; + parameter [15:0] LOOP9_CFG = 16'h0000; + parameter [2:0] LPBK_BIAS_CTRL = 3'b000; + parameter [0:0] LPBK_EN_RCAL_B = 1'b0; + parameter [3:0] LPBK_EXT_RCAL = 4'b0000; + parameter [3:0] LPBK_RG_CTRL = 4'b0000; + parameter [1:0] OOBDIVCTL = 2'b00; + parameter [0:0] OOB_PWRUP = 1'b0; + parameter PCI3_AUTO_REALIGN = "FRST_SMPL"; + parameter [0:0] PCI3_PIPE_RX_ELECIDLE = 1'b1; + parameter [1:0] PCI3_RX_ASYNC_EBUF_BYPASS = 2'b00; + parameter [0:0] PCI3_RX_ELECIDLE_EI2_ENABLE = 1'b0; + parameter [5:0] PCI3_RX_ELECIDLE_H2L_COUNT = 6'b000000; + parameter [2:0] PCI3_RX_ELECIDLE_H2L_DISABLE = 3'b000; + parameter [5:0] PCI3_RX_ELECIDLE_HI_COUNT = 6'b000000; + parameter [0:0] PCI3_RX_ELECIDLE_LP4_DISABLE = 1'b0; + parameter [0:0] PCI3_RX_FIFO_DISABLE = 1'b0; + parameter [15:0] PCIE_BUFG_DIV_CTRL = 16'h0000; + parameter [15:0] PCIE_RXPCS_CFG_GEN3 = 16'h0000; + parameter [15:0] PCIE_RXPMA_CFG = 16'h0000; + parameter [15:0] PCIE_TXPCS_CFG_GEN3 = 16'h0000; + parameter [15:0] PCIE_TXPMA_CFG = 16'h0000; + parameter PCS_PCIE_EN = "FALSE"; + parameter [15:0] PCS_RSVD0 = 16'b0000000000000000; + parameter [2:0] PCS_RSVD1 = 3'b000; + parameter [11:0] PD_TRANS_TIME_FROM_P2 = 12'h03C; + parameter [7:0] PD_TRANS_TIME_NONE_P2 = 8'h19; + parameter [7:0] PD_TRANS_TIME_TO_P2 = 8'h64; + parameter [1:0] PLL_SEL_MODE_GEN12 = 2'h0; + parameter [1:0] PLL_SEL_MODE_GEN3 = 2'h0; + parameter [15:0] PMA_RSV0 = 16'h0000; + parameter [15:0] PMA_RSV1 = 16'h0000; + parameter integer PREIQ_FREQ_BST = 0; + parameter [2:0] PROCESS_PAR = 3'b010; + parameter [0:0] RATE_SW_USE_DRP = 1'b0; + parameter [0:0] RESET_POWERSAVE_DISABLE = 1'b0; + parameter [4:0] RXBUFRESET_TIME = 5'b00001; + parameter RXBUF_ADDR_MODE = "FULL"; + parameter [3:0] RXBUF_EIDLE_HI_CNT = 4'b1000; + parameter [3:0] RXBUF_EIDLE_LO_CNT = 4'b0000; + parameter RXBUF_EN = "TRUE"; + parameter RXBUF_RESET_ON_CB_CHANGE = "TRUE"; + parameter RXBUF_RESET_ON_COMMAALIGN = "FALSE"; + parameter RXBUF_RESET_ON_EIDLE = "FALSE"; + parameter RXBUF_RESET_ON_RATE_CHANGE = "TRUE"; + parameter integer RXBUF_THRESH_OVFLW = 0; + parameter RXBUF_THRESH_OVRD = "FALSE"; + parameter integer RXBUF_THRESH_UNDFLW = 4; + parameter [4:0] RXCDRFREQRESET_TIME = 5'b00001; + parameter [4:0] RXCDRPHRESET_TIME = 5'b00001; + parameter [15:0] RXCDR_CFG0 = 16'h0000; + parameter [15:0] RXCDR_CFG0_GEN3 = 16'h0000; + parameter [15:0] RXCDR_CFG1 = 16'h0300; + parameter [15:0] RXCDR_CFG1_GEN3 = 16'h0300; + parameter [15:0] RXCDR_CFG2 = 16'h0060; + parameter [15:0] RXCDR_CFG2_GEN3 = 16'h0060; + parameter [15:0] RXCDR_CFG3 = 16'h0000; + parameter [15:0] RXCDR_CFG3_GEN3 = 16'h0000; + parameter [15:0] RXCDR_CFG4 = 16'h0002; + parameter [15:0] RXCDR_CFG4_GEN3 = 16'h0002; + parameter [15:0] RXCDR_CFG5 = 16'h0000; + parameter [15:0] RXCDR_CFG5_GEN3 = 16'h0000; + parameter [0:0] RXCDR_FR_RESET_ON_EIDLE = 1'b0; + parameter [0:0] RXCDR_HOLD_DURING_EIDLE = 1'b0; + parameter [15:0] RXCDR_LOCK_CFG0 = 16'h0001; + parameter [15:0] RXCDR_LOCK_CFG1 = 16'h0000; + parameter [15:0] RXCDR_LOCK_CFG2 = 16'h0000; + parameter [15:0] RXCDR_LOCK_CFG3 = 16'h0000; + parameter [0:0] RXCDR_PH_RESET_ON_EIDLE = 1'b0; + parameter [1:0] RXCFOKDONE_SRC = 2'b00; + parameter [15:0] RXCFOK_CFG0 = 16'h3E00; + parameter [15:0] RXCFOK_CFG1 = 16'h0042; + parameter [15:0] RXCFOK_CFG2 = 16'h002D; + parameter [6:0] RXDFELPMRESET_TIME = 7'b0001111; + parameter [15:0] RXDFELPM_KL_CFG0 = 16'h0000; + parameter [15:0] RXDFELPM_KL_CFG1 = 16'h0022; + parameter [15:0] RXDFELPM_KL_CFG2 = 16'h0100; + parameter [15:0] RXDFE_CFG0 = 16'h4C00; + parameter [15:0] RXDFE_CFG1 = 16'h0000; + parameter [15:0] RXDFE_GC_CFG0 = 16'h1E00; + parameter [15:0] RXDFE_GC_CFG1 = 16'h1900; + parameter [15:0] RXDFE_GC_CFG2 = 16'h0000; + parameter [15:0] RXDFE_H2_CFG0 = 16'h0000; + parameter [15:0] RXDFE_H2_CFG1 = 16'h0002; + parameter [15:0] RXDFE_H3_CFG0 = 16'h0000; + parameter [15:0] RXDFE_H3_CFG1 = 16'h0002; + parameter [15:0] RXDFE_H4_CFG0 = 16'h0000; + parameter [15:0] RXDFE_H4_CFG1 = 16'h0003; + parameter [15:0] RXDFE_H5_CFG0 = 16'h0000; + parameter [15:0] RXDFE_H5_CFG1 = 16'h0002; + parameter [15:0] RXDFE_H6_CFG0 = 16'h0000; + parameter [15:0] RXDFE_H6_CFG1 = 16'h0002; + parameter [15:0] RXDFE_H7_CFG0 = 16'h0000; + parameter [15:0] RXDFE_H7_CFG1 = 16'h0002; + parameter [15:0] RXDFE_H8_CFG0 = 16'h0000; + parameter [15:0] RXDFE_H8_CFG1 = 16'h0002; + parameter [15:0] RXDFE_H9_CFG0 = 16'h0000; + parameter [15:0] RXDFE_H9_CFG1 = 16'h0002; + parameter [15:0] RXDFE_HA_CFG0 = 16'h0000; + parameter [15:0] RXDFE_HA_CFG1 = 16'h0002; + parameter [15:0] RXDFE_HB_CFG0 = 16'h0000; + parameter [15:0] RXDFE_HB_CFG1 = 16'h0002; + parameter [15:0] RXDFE_HC_CFG0 = 16'h0000; + parameter [15:0] RXDFE_HC_CFG1 = 16'h0002; + parameter [15:0] RXDFE_HD_CFG0 = 16'h0000; + parameter [15:0] RXDFE_HD_CFG1 = 16'h0002; + parameter [15:0] RXDFE_HE_CFG0 = 16'h0000; + parameter [15:0] RXDFE_HE_CFG1 = 16'h0002; + parameter [15:0] RXDFE_HF_CFG0 = 16'h0000; + parameter [15:0] RXDFE_HF_CFG1 = 16'h0002; + parameter [15:0] RXDFE_OS_CFG0 = 16'h0000; + parameter [15:0] RXDFE_OS_CFG1 = 16'h0200; + parameter [0:0] RXDFE_PWR_SAVING = 1'b0; + parameter [15:0] RXDFE_UT_CFG0 = 16'h0000; + parameter [15:0] RXDFE_UT_CFG1 = 16'h0002; + parameter [15:0] RXDFE_VP_CFG0 = 16'h0000; + parameter [15:0] RXDFE_VP_CFG1 = 16'h0022; + parameter [15:0] RXDLY_CFG = 16'h001F; + parameter [15:0] RXDLY_LCFG = 16'h0030; + parameter RXELECIDLE_CFG = "SIGCFG_4"; + parameter integer RXGBOX_FIFO_INIT_RD_ADDR = 4; + parameter RXGEARBOX_EN = "FALSE"; + parameter [4:0] RXISCANRESET_TIME = 5'b00001; + parameter [15:0] RXLPM_CFG = 16'h0000; + parameter [15:0] RXLPM_GC_CFG = 16'h0200; + parameter [15:0] RXLPM_KH_CFG0 = 16'h0000; + parameter [15:0] RXLPM_KH_CFG1 = 16'h0002; + parameter [15:0] RXLPM_OS_CFG0 = 16'h0400; + parameter [15:0] RXLPM_OS_CFG1 = 16'h0000; + parameter [8:0] RXOOB_CFG = 9'b000000110; + parameter RXOOB_CLK_CFG = "PMA"; + parameter [4:0] RXOSCALRESET_TIME = 5'b00011; + parameter integer RXOUT_DIV = 4; + parameter [4:0] RXPCSRESET_TIME = 5'b00001; + parameter [15:0] RXPHBEACON_CFG = 16'h0000; + parameter [15:0] RXPHDLY_CFG = 16'h2020; + parameter [15:0] RXPHSAMP_CFG = 16'h2100; + parameter [15:0] RXPHSLIP_CFG = 16'h9933; + parameter [4:0] RXPH_MONITOR_SEL = 5'b00000; + parameter [0:0] RXPI_AUTO_BW_SEL_BYPASS = 1'b0; + parameter [15:0] RXPI_CFG = 16'h0100; + parameter [0:0] RXPI_LPM = 1'b0; + parameter [15:0] RXPI_RSV0 = 16'h0000; + parameter [1:0] RXPI_SEL_LC = 2'b00; + parameter [1:0] RXPI_STARTCODE = 2'b00; + parameter [0:0] RXPI_VREFSEL = 1'b0; + parameter RXPMACLK_SEL = "DATA"; + parameter [4:0] RXPMARESET_TIME = 5'b00001; + parameter [0:0] RXPRBS_ERR_LOOPBACK = 1'b0; + parameter integer RXPRBS_LINKACQ_CNT = 15; + parameter integer RXSLIDE_AUTO_WAIT = 7; + parameter RXSLIDE_MODE = "OFF"; + parameter [0:0] RXSYNC_MULTILANE = 1'b0; + parameter [0:0] RXSYNC_OVRD = 1'b0; + parameter [0:0] RXSYNC_SKIP_DA = 1'b0; + parameter [0:0] RX_AFE_CM_EN = 1'b0; + parameter [15:0] RX_BIAS_CFG0 = 16'h1534; + parameter [5:0] RX_BUFFER_CFG = 6'b000000; + parameter [0:0] RX_CAPFF_SARC_ENB = 1'b0; + parameter integer RX_CLK25_DIV = 8; + parameter [0:0] RX_CLKMUX_EN = 1'b1; + parameter [4:0] RX_CLK_SLIP_OVRD = 5'b00000; + parameter [3:0] RX_CM_BUF_CFG = 4'b1010; + parameter [0:0] RX_CM_BUF_PD = 1'b0; + parameter integer RX_CM_SEL = 3; + parameter integer RX_CM_TRIM = 10; + parameter [0:0] RX_CTLE1_KHKL = 1'b0; + parameter [0:0] RX_CTLE2_KHKL = 1'b0; + parameter [0:0] RX_CTLE3_AGC = 1'b0; + parameter integer RX_DATA_WIDTH = 20; + parameter [5:0] RX_DDI_SEL = 6'b000000; + parameter RX_DEFER_RESET_BUF_EN = "TRUE"; + parameter [2:0] RX_DEGEN_CTRL = 3'b010; + parameter integer RX_DFELPM_CFG0 = 6; + parameter [0:0] RX_DFELPM_CFG1 = 1'b0; + parameter [0:0] RX_DFELPM_KLKH_AGC_STUP_EN = 1'b1; + parameter [1:0] RX_DFE_AGC_CFG0 = 2'b00; + parameter integer RX_DFE_AGC_CFG1 = 4; + parameter integer RX_DFE_KL_LPM_KH_CFG0 = 1; + parameter integer RX_DFE_KL_LPM_KH_CFG1 = 2; + parameter [1:0] RX_DFE_KL_LPM_KL_CFG0 = 2'b01; + parameter [2:0] RX_DFE_KL_LPM_KL_CFG1 = 3'b010; + parameter [0:0] RX_DFE_LPM_HOLD_DURING_EIDLE = 1'b0; + parameter RX_DISPERR_SEQ_MATCH = "TRUE"; + parameter [0:0] RX_DIV2_MODE_B = 1'b0; + parameter [4:0] RX_DIVRESET_TIME = 5'b00001; + parameter [0:0] RX_EN_CTLE_RCAL_B = 1'b0; + parameter [0:0] RX_EN_HI_LR = 1'b0; + parameter [8:0] RX_EXT_RL_CTRL = 9'b000000000; + parameter [6:0] RX_EYESCAN_VS_CODE = 7'b0000000; + parameter [0:0] RX_EYESCAN_VS_NEG_DIR = 1'b0; + parameter [1:0] RX_EYESCAN_VS_RANGE = 2'b00; + parameter [0:0] RX_EYESCAN_VS_UT_SIGN = 1'b0; + parameter [0:0] RX_FABINT_USRCLK_FLOP = 1'b0; + parameter integer RX_INT_DATAWIDTH = 1; + parameter [0:0] RX_PMA_POWER_SAVE = 1'b0; + parameter real RX_PROGDIV_CFG = 0.0; + parameter [15:0] RX_PROGDIV_RATE = 16'h0001; + parameter [3:0] RX_RESLOAD_CTRL = 4'b0000; + parameter [0:0] RX_RESLOAD_OVRD = 1'b0; + parameter [2:0] RX_SAMPLE_PERIOD = 3'b101; + parameter integer RX_SIG_VALID_DLY = 11; + parameter [0:0] RX_SUM_DFETAPREP_EN = 1'b0; + parameter [3:0] RX_SUM_IREF_TUNE = 4'b0000; + parameter [3:0] RX_SUM_VCMTUNE = 4'b1000; + parameter [0:0] RX_SUM_VCM_OVWR = 1'b0; + parameter [2:0] RX_SUM_VREF_TUNE = 3'b100; + parameter [1:0] RX_TUNE_AFE_OS = 2'b00; + parameter [2:0] RX_VREG_CTRL = 3'b101; + parameter [0:0] RX_VREG_PDB = 1'b1; + parameter [1:0] RX_WIDEMODE_CDR = 2'b01; + parameter RX_XCLK_SEL = "RXDES"; + parameter [0:0] RX_XMODE_SEL = 1'b0; + parameter integer SAS_MAX_COM = 64; + parameter integer SAS_MIN_COM = 36; + parameter [3:0] SATA_BURST_SEQ_LEN = 4'b1111; + parameter [2:0] SATA_BURST_VAL = 3'b100; + parameter SATA_CPLL_CFG = "VCO_3000MHZ"; + parameter [2:0] SATA_EIDLE_VAL = 3'b100; + parameter integer SATA_MAX_BURST = 8; + parameter integer SATA_MAX_INIT = 21; + parameter integer SATA_MAX_WAKE = 7; + parameter integer SATA_MIN_BURST = 4; + parameter integer SATA_MIN_INIT = 12; + parameter integer SATA_MIN_WAKE = 4; + parameter SHOW_REALIGN_COMMA = "TRUE"; + parameter SIM_MODE = "FAST"; + parameter SIM_RECEIVER_DETECT_PASS = "TRUE"; + parameter SIM_RESET_SPEEDUP = "TRUE"; + parameter [0:0] SIM_TX_EIDLE_DRIVE_LEVEL = 1'b0; + parameter integer SIM_VERSION = 2; + parameter [1:0] TAPDLY_SET_TX = 2'h0; + parameter [3:0] TEMPERATURE_PAR = 4'b0010; + parameter [14:0] TERM_RCAL_CFG = 15'b100001000010000; + parameter [2:0] TERM_RCAL_OVRD = 3'b000; + parameter [7:0] TRANS_TIME_RATE = 8'h0E; + parameter [7:0] TST_RSV0 = 8'h00; + parameter [7:0] TST_RSV1 = 8'h00; + parameter TXBUF_EN = "TRUE"; + parameter TXBUF_RESET_ON_RATE_CHANGE = "FALSE"; + parameter [15:0] TXDLY_CFG = 16'h001F; + parameter [15:0] TXDLY_LCFG = 16'h0030; + parameter TXFIFO_ADDR_CFG = "LOW"; + parameter integer TXGBOX_FIFO_INIT_RD_ADDR = 4; + parameter TXGEARBOX_EN = "FALSE"; + parameter integer TXOUT_DIV = 4; + parameter [4:0] TXPCSRESET_TIME = 5'b00001; + parameter [15:0] TXPHDLY_CFG0 = 16'h2020; + parameter [15:0] TXPHDLY_CFG1 = 16'h0001; + parameter [15:0] TXPH_CFG = 16'h0123; + parameter [15:0] TXPH_CFG2 = 16'h0000; + parameter [4:0] TXPH_MONITOR_SEL = 5'b00000; + parameter [1:0] TXPI_CFG0 = 2'b00; + parameter [1:0] TXPI_CFG1 = 2'b00; + parameter [1:0] TXPI_CFG2 = 2'b00; + parameter [0:0] TXPI_CFG3 = 1'b0; + parameter [0:0] TXPI_CFG4 = 1'b1; + parameter [2:0] TXPI_CFG5 = 3'b000; + parameter [0:0] TXPI_GRAY_SEL = 1'b0; + parameter [0:0] TXPI_INVSTROBE_SEL = 1'b0; + parameter [0:0] TXPI_LPM = 1'b0; + parameter TXPI_PPMCLK_SEL = "TXUSRCLK2"; + parameter [7:0] TXPI_PPM_CFG = 8'b00000000; + parameter [15:0] TXPI_RSV0 = 16'h0000; + parameter [2:0] TXPI_SYNFREQ_PPM = 3'b000; + parameter [0:0] TXPI_VREFSEL = 1'b0; + parameter [4:0] TXPMARESET_TIME = 5'b00001; + parameter [0:0] TXSYNC_MULTILANE = 1'b0; + parameter [0:0] TXSYNC_OVRD = 1'b0; + parameter [0:0] TXSYNC_SKIP_DA = 1'b0; + parameter integer TX_CLK25_DIV = 8; + parameter [0:0] TX_CLKMUX_EN = 1'b1; + parameter [0:0] TX_CLKREG_PDB = 1'b0; + parameter [2:0] TX_CLKREG_SET = 3'b000; + parameter integer TX_DATA_WIDTH = 20; + parameter [5:0] TX_DCD_CFG = 6'b000010; + parameter [0:0] TX_DCD_EN = 1'b0; + parameter [5:0] TX_DEEMPH0 = 6'b000000; + parameter [5:0] TX_DEEMPH1 = 6'b000000; + parameter [4:0] TX_DIVRESET_TIME = 5'b00001; + parameter TX_DRIVE_MODE = "DIRECT"; + parameter integer TX_DRVMUX_CTRL = 2; + parameter [2:0] TX_EIDLE_ASSERT_DELAY = 3'b110; + parameter [2:0] TX_EIDLE_DEASSERT_DELAY = 3'b100; + parameter [0:0] TX_EML_PHI_TUNE = 1'b0; + parameter [0:0] TX_FABINT_USRCLK_FLOP = 1'b0; + parameter [0:0] TX_FIFO_BYP_EN = 1'b0; + parameter [0:0] TX_IDLE_DATA_ZERO = 1'b0; + parameter integer TX_INT_DATAWIDTH = 1; + parameter TX_LOOPBACK_DRIVE_HIZ = "FALSE"; + parameter [0:0] TX_MAINCURSOR_SEL = 1'b0; + parameter [6:0] TX_MARGIN_FULL_0 = 7'b1001110; + parameter [6:0] TX_MARGIN_FULL_1 = 7'b1001001; + parameter [6:0] TX_MARGIN_FULL_2 = 7'b1000101; + parameter [6:0] TX_MARGIN_FULL_3 = 7'b1000010; + parameter [6:0] TX_MARGIN_FULL_4 = 7'b1000000; + parameter [6:0] TX_MARGIN_LOW_0 = 7'b1000110; + parameter [6:0] TX_MARGIN_LOW_1 = 7'b1000100; + parameter [6:0] TX_MARGIN_LOW_2 = 7'b1000010; + parameter [6:0] TX_MARGIN_LOW_3 = 7'b1000000; + parameter [6:0] TX_MARGIN_LOW_4 = 7'b1000000; + parameter [2:0] TX_MODE_SEL = 3'b000; + parameter [15:0] TX_PHICAL_CFG0 = 16'h0000; + parameter [15:0] TX_PHICAL_CFG1 = 16'h7E00; + parameter [15:0] TX_PHICAL_CFG2 = 16'h0000; + parameter integer TX_PI_BIASSET = 0; + parameter [15:0] TX_PI_CFG0 = 16'h0000; + parameter [15:0] TX_PI_CFG1 = 16'h0000; + parameter [0:0] TX_PI_DIV2_MODE_B = 1'b0; + parameter [0:0] TX_PI_SEL_QPLL0 = 1'b0; + parameter [0:0] TX_PI_SEL_QPLL1 = 1'b0; + parameter [0:0] TX_PMADATA_OPT = 1'b0; + parameter [0:0] TX_PMA_POWER_SAVE = 1'b0; + parameter integer TX_PREDRV_CTRL = 2; + parameter TX_PROGCLK_SEL = "POSTPI"; + parameter real TX_PROGDIV_CFG = 0.0; + parameter [15:0] TX_PROGDIV_RATE = 16'h0001; + parameter [13:0] TX_RXDETECT_CFG = 14'h0032; + parameter integer TX_RXDETECT_REF = 4; + parameter [2:0] TX_SAMPLE_PERIOD = 3'b101; + parameter [0:0] TX_SARC_LPBK_ENB = 1'b0; + parameter TX_XCLK_SEL = "TXOUT"; + parameter [0:0] USE_PCS_CLK_PHASE_SEL = 1'b0; + output [2:0] BUFGTCE; + output [2:0] BUFGTCEMASK; + output [8:0] BUFGTDIV; + output [2:0] BUFGTRESET; + output [2:0] BUFGTRSTMASK; + output CPLLFBCLKLOST; + output CPLLLOCK; + output CPLLREFCLKLOST; + output [16:0] DMONITOROUT; + output [15:0] DRPDO; + output DRPRDY; + output EYESCANDATAERROR; + output GTPOWERGOOD; + output GTREFCLKMONITOR; + output GTYTXN; + output GTYTXP; + output PCIERATEGEN3; + output PCIERATEIDLE; + output [1:0] PCIERATEQPLLPD; + output [1:0] PCIERATEQPLLRESET; + output PCIESYNCTXSYNCDONE; + output PCIEUSERGEN3RDY; + output PCIEUSERPHYSTATUSRST; + output PCIEUSERRATESTART; + output [15:0] PCSRSVDOUT; + output PHYSTATUS; + output [7:0] PINRSRVDAS; + output RESETEXCEPTION; + output [2:0] RXBUFSTATUS; + output RXBYTEISALIGNED; + output RXBYTEREALIGN; + output RXCDRLOCK; + output RXCDRPHDONE; + output RXCHANBONDSEQ; + output RXCHANISALIGNED; + output RXCHANREALIGN; + output [4:0] RXCHBONDO; + output RXCKCALDONE; + output [1:0] RXCLKCORCNT; + output RXCOMINITDET; + output RXCOMMADET; + output RXCOMSASDET; + output RXCOMWAKEDET; + output [15:0] RXCTRL0; + output [15:0] RXCTRL1; + output [7:0] RXCTRL2; + output [7:0] RXCTRL3; + output [127:0] RXDATA; + output [7:0] RXDATAEXTENDRSVD; + output [1:0] RXDATAVALID; + output RXDLYSRESETDONE; + output RXELECIDLE; + output [5:0] RXHEADER; + output [1:0] RXHEADERVALID; + output [6:0] RXMONITOROUT; + output RXOSINTDONE; + output RXOSINTSTARTED; + output RXOSINTSTROBEDONE; + output RXOSINTSTROBESTARTED; + output RXOUTCLK; + output RXOUTCLKFABRIC; + output RXOUTCLKPCS; + output RXPHALIGNDONE; + output RXPHALIGNERR; + output RXPMARESETDONE; + output RXPRBSERR; + output RXPRBSLOCKED; + output RXPRGDIVRESETDONE; + output RXRATEDONE; + output RXRECCLKOUT; + output RXRESETDONE; + output RXSLIDERDY; + output RXSLIPDONE; + output RXSLIPOUTCLKRDY; + output RXSLIPPMARDY; + output [1:0] RXSTARTOFSEQ; + output [2:0] RXSTATUS; + output RXSYNCDONE; + output RXSYNCOUT; + output RXVALID; + output [1:0] TXBUFSTATUS; + output TXCOMFINISH; + output TXDCCDONE; + output TXDLYSRESETDONE; + output TXOUTCLK; + output TXOUTCLKFABRIC; + output TXOUTCLKPCS; + output TXPHALIGNDONE; + output TXPHINITDONE; + output TXPMARESETDONE; + output TXPRGDIVRESETDONE; + output TXRATEDONE; + output TXRESETDONE; + output TXSYNCDONE; + output TXSYNCOUT; + input CDRSTEPDIR; + input CDRSTEPSQ; + input CDRSTEPSX; + input CFGRESET; + input CLKRSVD0; + input CLKRSVD1; + input CPLLLOCKDETCLK; + input CPLLLOCKEN; + input CPLLPD; + input [2:0] CPLLREFCLKSEL; + input CPLLRESET; + input DMONFIFORESET; + input DMONITORCLK; + input [9:0] DRPADDR; + input DRPCLK; + input [15:0] DRPDI; + input DRPEN; + input DRPWE; + input ELPCALDVORWREN; + input ELPCALPAORWREN; + input EVODDPHICALDONE; + input EVODDPHICALSTART; + input EVODDPHIDRDEN; + input EVODDPHIDWREN; + input EVODDPHIXRDEN; + input EVODDPHIXWREN; + input EYESCANMODE; + input EYESCANRESET; + input EYESCANTRIGGER; + input GTGREFCLK; + input GTNORTHREFCLK0; + input GTNORTHREFCLK1; + input GTREFCLK0; + input GTREFCLK1; + input GTRESETSEL; + input [15:0] GTRSVD; + input GTRXRESET; + input GTSOUTHREFCLK0; + input GTSOUTHREFCLK1; + input GTTXRESET; + input GTYRXN; + input GTYRXP; + input [2:0] LOOPBACK; + input [15:0] LOOPRSVD; + input LPBKRXTXSEREN; + input LPBKTXRXSEREN; + input PCIEEQRXEQADAPTDONE; + input PCIERSTIDLE; + input PCIERSTTXSYNCSTART; + input PCIEUSERRATEDONE; + input [15:0] PCSRSVDIN; + input [4:0] PCSRSVDIN2; + input [4:0] PMARSVDIN; + input QPLL0CLK; + input QPLL0REFCLK; + input QPLL1CLK; + input QPLL1REFCLK; + input RESETOVRD; + input RSTCLKENTX; + input RX8B10BEN; + input RXBUFRESET; + input RXCDRFREQRESET; + input RXCDRHOLD; + input RXCDROVRDEN; + input RXCDRRESET; + input RXCDRRESETRSV; + input RXCHBONDEN; + input [4:0] RXCHBONDI; + input [2:0] RXCHBONDLEVEL; + input RXCHBONDMASTER; + input RXCHBONDSLAVE; + input RXCKCALRESET; + input RXCOMMADETEN; + input RXDCCFORCESTART; + input RXDFEAGCHOLD; + input RXDFEAGCOVRDEN; + input RXDFELFHOLD; + input RXDFELFOVRDEN; + input RXDFELPMRESET; + input RXDFETAP10HOLD; + input RXDFETAP10OVRDEN; + input RXDFETAP11HOLD; + input RXDFETAP11OVRDEN; + input RXDFETAP12HOLD; + input RXDFETAP12OVRDEN; + input RXDFETAP13HOLD; + input RXDFETAP13OVRDEN; + input RXDFETAP14HOLD; + input RXDFETAP14OVRDEN; + input RXDFETAP15HOLD; + input RXDFETAP15OVRDEN; + input RXDFETAP2HOLD; + input RXDFETAP2OVRDEN; + input RXDFETAP3HOLD; + input RXDFETAP3OVRDEN; + input RXDFETAP4HOLD; + input RXDFETAP4OVRDEN; + input RXDFETAP5HOLD; + input RXDFETAP5OVRDEN; + input RXDFETAP6HOLD; + input RXDFETAP6OVRDEN; + input RXDFETAP7HOLD; + input RXDFETAP7OVRDEN; + input RXDFETAP8HOLD; + input RXDFETAP8OVRDEN; + input RXDFETAP9HOLD; + input RXDFETAP9OVRDEN; + input RXDFEUTHOLD; + input RXDFEUTOVRDEN; + input RXDFEVPHOLD; + input RXDFEVPOVRDEN; + input RXDFEVSEN; + input RXDFEXYDEN; + input RXDLYBYPASS; + input RXDLYEN; + input RXDLYOVRDEN; + input RXDLYSRESET; + input [1:0] RXELECIDLEMODE; + input RXGEARBOXSLIP; + input RXLATCLK; + input RXLPMEN; + input RXLPMGCHOLD; + input RXLPMGCOVRDEN; + input RXLPMHFHOLD; + input RXLPMHFOVRDEN; + input RXLPMLFHOLD; + input RXLPMLFKLOVRDEN; + input RXLPMOSHOLD; + input RXLPMOSOVRDEN; + input RXMCOMMAALIGNEN; + input [1:0] RXMONITORSEL; + input RXOOBRESET; + input RXOSCALRESET; + input RXOSHOLD; + input [3:0] RXOSINTCFG; + input RXOSINTEN; + input RXOSINTHOLD; + input RXOSINTOVRDEN; + input RXOSINTSTROBE; + input RXOSINTTESTOVRDEN; + input RXOSOVRDEN; + input [2:0] RXOUTCLKSEL; + input RXPCOMMAALIGNEN; + input RXPCSRESET; + input [1:0] RXPD; + input RXPHALIGN; + input RXPHALIGNEN; + input RXPHDLYPD; + input RXPHDLYRESET; + input RXPHOVRDEN; + input [1:0] RXPLLCLKSEL; + input RXPMARESET; + input RXPOLARITY; + input RXPRBSCNTRESET; + input [3:0] RXPRBSSEL; + input RXPROGDIVRESET; + input [2:0] RXRATE; + input RXRATEMODE; + input RXSLIDE; + input RXSLIPOUTCLK; + input RXSLIPPMA; + input RXSYNCALLIN; + input RXSYNCIN; + input RXSYNCMODE; + input [1:0] RXSYSCLKSEL; + input RXUSERRDY; + input RXUSRCLK; + input RXUSRCLK2; + input SIGVALIDCLK; + input [19:0] TSTIN; + input [7:0] TX8B10BBYPASS; + input TX8B10BEN; + input [2:0] TXBUFDIFFCTRL; + input TXCOMINIT; + input TXCOMSAS; + input TXCOMWAKE; + input [15:0] TXCTRL0; + input [15:0] TXCTRL1; + input [7:0] TXCTRL2; + input [127:0] TXDATA; + input [7:0] TXDATAEXTENDRSVD; + input TXDCCFORCESTART; + input TXDCCRESET; + input TXDEEMPH; + input TXDETECTRX; + input [4:0] TXDIFFCTRL; + input TXDIFFPD; + input TXDLYBYPASS; + input TXDLYEN; + input TXDLYHOLD; + input TXDLYOVRDEN; + input TXDLYSRESET; + input TXDLYUPDOWN; + input TXELECIDLE; + input TXELFORCESTART; + input [5:0] TXHEADER; + input TXINHIBIT; + input TXLATCLK; + input [6:0] TXMAINCURSOR; + input [2:0] TXMARGIN; + input [2:0] TXOUTCLKSEL; + input TXPCSRESET; + input [1:0] TXPD; + input TXPDELECIDLEMODE; + input TXPHALIGN; + input TXPHALIGNEN; + input TXPHDLYPD; + input TXPHDLYRESET; + input TXPHDLYTSTCLK; + input TXPHINIT; + input TXPHOVRDEN; + input TXPIPPMEN; + input TXPIPPMOVRDEN; + input TXPIPPMPD; + input TXPIPPMSEL; + input [4:0] TXPIPPMSTEPSIZE; + input TXPISOPD; + input [1:0] TXPLLCLKSEL; + input TXPMARESET; + input TXPOLARITY; + input [4:0] TXPOSTCURSOR; + input TXPRBSFORCEERR; + input [3:0] TXPRBSSEL; + input [4:0] TXPRECURSOR; + input TXPROGDIVRESET; + input [2:0] TXRATE; + input TXRATEMODE; + input [6:0] TXSEQUENCE; + input TXSWING; + input TXSYNCALLIN; + input TXSYNCIN; + input TXSYNCMODE; + input [1:0] TXSYSCLKSEL; + input TXUSERRDY; + input TXUSRCLK; + input TXUSRCLK2; +endmodule + +module GTYE3_COMMON (...); + parameter [15:0] A_SDM1DATA1_0 = 16'b0000000000000000; + parameter [8:0] A_SDM1DATA1_1 = 9'b000000000; + parameter [15:0] BIAS_CFG0 = 16'h0000; + parameter [15:0] BIAS_CFG1 = 16'h0000; + parameter [15:0] BIAS_CFG2 = 16'h0000; + parameter [15:0] BIAS_CFG3 = 16'h0000; + parameter [15:0] BIAS_CFG4 = 16'h0000; + parameter [9:0] BIAS_CFG_RSVD = 10'b0000000000; + parameter [15:0] COMMON_CFG0 = 16'h0000; + parameter [15:0] COMMON_CFG1 = 16'h0000; + parameter [15:0] POR_CFG = 16'h0004; + parameter [15:0] PPF0_CFG = 16'h0FFF; + parameter [15:0] PPF1_CFG = 16'h0FFF; + parameter QPLL0CLKOUT_RATE = "FULL"; + parameter [15:0] QPLL0_CFG0 = 16'h301C; + parameter [15:0] QPLL0_CFG1 = 16'h0000; + parameter [15:0] QPLL0_CFG1_G3 = 16'h0020; + parameter [15:0] QPLL0_CFG2 = 16'h0780; + parameter [15:0] QPLL0_CFG2_G3 = 16'h0780; + parameter [15:0] QPLL0_CFG3 = 16'h0120; + parameter [15:0] QPLL0_CFG4 = 16'h0021; + parameter [9:0] QPLL0_CP = 10'b0000011111; + parameter [9:0] QPLL0_CP_G3 = 10'b0000011111; + parameter integer QPLL0_FBDIV = 66; + parameter integer QPLL0_FBDIV_G3 = 80; + parameter [15:0] QPLL0_INIT_CFG0 = 16'h0000; + parameter [7:0] QPLL0_INIT_CFG1 = 8'h00; + parameter [15:0] QPLL0_LOCK_CFG = 16'h01E8; + parameter [15:0] QPLL0_LOCK_CFG_G3 = 16'h21E8; + parameter [9:0] QPLL0_LPF = 10'b1111111111; + parameter [9:0] QPLL0_LPF_G3 = 10'b1111111111; + parameter integer QPLL0_REFCLK_DIV = 2; + parameter [15:0] QPLL0_SDM_CFG0 = 16'h0040; + parameter [15:0] QPLL0_SDM_CFG1 = 16'h0000; + parameter [15:0] QPLL0_SDM_CFG2 = 16'h0000; + parameter QPLL1CLKOUT_RATE = "FULL"; + parameter [15:0] QPLL1_CFG0 = 16'h301C; + parameter [15:0] QPLL1_CFG1 = 16'h0000; + parameter [15:0] QPLL1_CFG1_G3 = 16'h0020; + parameter [15:0] QPLL1_CFG2 = 16'h0780; + parameter [15:0] QPLL1_CFG2_G3 = 16'h0780; + parameter [15:0] QPLL1_CFG3 = 16'h0120; + parameter [15:0] QPLL1_CFG4 = 16'h0021; + parameter [9:0] QPLL1_CP = 10'b0000011111; + parameter [9:0] QPLL1_CP_G3 = 10'b0000011111; + parameter integer QPLL1_FBDIV = 66; + parameter integer QPLL1_FBDIV_G3 = 80; + parameter [15:0] QPLL1_INIT_CFG0 = 16'h0000; + parameter [7:0] QPLL1_INIT_CFG1 = 8'h00; + parameter [15:0] QPLL1_LOCK_CFG = 16'h01E8; + parameter [15:0] QPLL1_LOCK_CFG_G3 = 16'h21E8; + parameter [9:0] QPLL1_LPF = 10'b1111111111; + parameter [9:0] QPLL1_LPF_G3 = 10'b1111111111; + parameter integer QPLL1_REFCLK_DIV = 2; + parameter [15:0] QPLL1_SDM_CFG0 = 16'h0040; + parameter [15:0] QPLL1_SDM_CFG1 = 16'h0000; + parameter [15:0] QPLL1_SDM_CFG2 = 16'h0000; + parameter [15:0] RSVD_ATTR0 = 16'h0000; + parameter [15:0] RSVD_ATTR1 = 16'h0000; + parameter [15:0] RSVD_ATTR2 = 16'h0000; + parameter [15:0] RSVD_ATTR3 = 16'h0000; + parameter [1:0] RXRECCLKOUT0_SEL = 2'b00; + parameter [1:0] RXRECCLKOUT1_SEL = 2'b00; + parameter [0:0] SARC_EN = 1'b1; + parameter [0:0] SARC_SEL = 1'b0; + parameter [15:0] SDM0INITSEED0_0 = 16'b0000000000000000; + parameter [8:0] SDM0INITSEED0_1 = 9'b000000000; + parameter [15:0] SDM1INITSEED0_0 = 16'b0000000000000000; + parameter [8:0] SDM1INITSEED0_1 = 9'b000000000; + parameter SIM_MODE = "FAST"; + parameter SIM_RESET_SPEEDUP = "TRUE"; + parameter integer SIM_VERSION = 2; + output [15:0] DRPDO; + output DRPRDY; + output [7:0] PMARSVDOUT0; + output [7:0] PMARSVDOUT1; + output QPLL0FBCLKLOST; + output QPLL0LOCK; + output QPLL0OUTCLK; + output QPLL0OUTREFCLK; + output QPLL0REFCLKLOST; + output QPLL1FBCLKLOST; + output QPLL1LOCK; + output QPLL1OUTCLK; + output QPLL1OUTREFCLK; + output QPLL1REFCLKLOST; + output [7:0] QPLLDMONITOR0; + output [7:0] QPLLDMONITOR1; + output REFCLKOUTMONITOR0; + output REFCLKOUTMONITOR1; + output [1:0] RXRECCLK0_SEL; + output [1:0] RXRECCLK1_SEL; + output [3:0] SDM0FINALOUT; + output [14:0] SDM0TESTDATA; + output [3:0] SDM1FINALOUT; + output [14:0] SDM1TESTDATA; + input BGBYPASSB; + input BGMONITORENB; + input BGPDB; + input [4:0] BGRCALOVRD; + input BGRCALOVRDENB; + input [9:0] DRPADDR; + input DRPCLK; + input [15:0] DRPDI; + input DRPEN; + input DRPWE; + input GTGREFCLK0; + input GTGREFCLK1; + input GTNORTHREFCLK00; + input GTNORTHREFCLK01; + input GTNORTHREFCLK10; + input GTNORTHREFCLK11; + input GTREFCLK00; + input GTREFCLK01; + input GTREFCLK10; + input GTREFCLK11; + input GTSOUTHREFCLK00; + input GTSOUTHREFCLK01; + input GTSOUTHREFCLK10; + input GTSOUTHREFCLK11; + input [7:0] PMARSVD0; + input [7:0] PMARSVD1; + input QPLL0CLKRSVD0; + input QPLL0LOCKDETCLK; + input QPLL0LOCKEN; + input QPLL0PD; + input [2:0] QPLL0REFCLKSEL; + input QPLL0RESET; + input QPLL1CLKRSVD0; + input QPLL1LOCKDETCLK; + input QPLL1LOCKEN; + input QPLL1PD; + input [2:0] QPLL1REFCLKSEL; + input QPLL1RESET; + input [7:0] QPLLRSVD1; + input [4:0] QPLLRSVD2; + input [4:0] QPLLRSVD3; + input [7:0] QPLLRSVD4; + input RCALENB; + input [24:0] SDM0DATA; + input SDM0RESET; + input [1:0] SDM0WIDTH; + input [24:0] SDM1DATA; + input SDM1RESET; + input [1:0] SDM1WIDTH; +endmodule + +module GTYE4_CHANNEL (...); + parameter [0:0] ACJTAG_DEBUG_MODE = 1'b0; + parameter [0:0] ACJTAG_MODE = 1'b0; + parameter [0:0] ACJTAG_RESET = 1'b0; + parameter [15:0] ADAPT_CFG0 = 16'h9200; + parameter [15:0] ADAPT_CFG1 = 16'h801C; + parameter [15:0] ADAPT_CFG2 = 16'h0000; + parameter ALIGN_COMMA_DOUBLE = "FALSE"; + parameter [9:0] ALIGN_COMMA_ENABLE = 10'b0001111111; + parameter integer ALIGN_COMMA_WORD = 1; + parameter ALIGN_MCOMMA_DET = "TRUE"; + parameter [9:0] ALIGN_MCOMMA_VALUE = 10'b1010000011; + parameter ALIGN_PCOMMA_DET = "TRUE"; + parameter [9:0] ALIGN_PCOMMA_VALUE = 10'b0101111100; + parameter [0:0] A_RXOSCALRESET = 1'b0; + parameter [0:0] A_RXPROGDIVRESET = 1'b0; + parameter [0:0] A_RXTERMINATION = 1'b1; + parameter [4:0] A_TXDIFFCTRL = 5'b01100; + parameter [0:0] A_TXPROGDIVRESET = 1'b0; + parameter CBCC_DATA_SOURCE_SEL = "DECODED"; + parameter [0:0] CDR_SWAP_MODE_EN = 1'b0; + parameter [0:0] CFOK_PWRSVE_EN = 1'b1; + parameter CHAN_BOND_KEEP_ALIGN = "FALSE"; + parameter integer CHAN_BOND_MAX_SKEW = 7; + parameter [9:0] CHAN_BOND_SEQ_1_1 = 10'b0101111100; + parameter [9:0] CHAN_BOND_SEQ_1_2 = 10'b0000000000; + parameter [9:0] CHAN_BOND_SEQ_1_3 = 10'b0000000000; + parameter [9:0] CHAN_BOND_SEQ_1_4 = 10'b0000000000; + parameter [3:0] CHAN_BOND_SEQ_1_ENABLE = 4'b1111; + parameter [9:0] CHAN_BOND_SEQ_2_1 = 10'b0100000000; + parameter [9:0] CHAN_BOND_SEQ_2_2 = 10'b0100000000; + parameter [9:0] CHAN_BOND_SEQ_2_3 = 10'b0100000000; + parameter [9:0] CHAN_BOND_SEQ_2_4 = 10'b0100000000; + parameter [3:0] CHAN_BOND_SEQ_2_ENABLE = 4'b1111; + parameter CHAN_BOND_SEQ_2_USE = "FALSE"; + parameter integer CHAN_BOND_SEQ_LEN = 2; + parameter [15:0] CH_HSPMUX = 16'h2424; + parameter [15:0] CKCAL1_CFG_0 = 16'b1100000011000000; + parameter [15:0] CKCAL1_CFG_1 = 16'b0101000011000000; + parameter [15:0] CKCAL1_CFG_2 = 16'b0000000000000000; + parameter [15:0] CKCAL1_CFG_3 = 16'b0000000000000000; + parameter [15:0] CKCAL2_CFG_0 = 16'b1100000011000000; + parameter [15:0] CKCAL2_CFG_1 = 16'b1000000011000000; + parameter [15:0] CKCAL2_CFG_2 = 16'b0000000000000000; + parameter [15:0] CKCAL2_CFG_3 = 16'b0000000000000000; + parameter [15:0] CKCAL2_CFG_4 = 16'b0000000000000000; + parameter CLK_CORRECT_USE = "TRUE"; + parameter CLK_COR_KEEP_IDLE = "FALSE"; + parameter integer CLK_COR_MAX_LAT = 20; + parameter integer CLK_COR_MIN_LAT = 18; + parameter CLK_COR_PRECEDENCE = "TRUE"; + parameter integer CLK_COR_REPEAT_WAIT = 0; + parameter [9:0] CLK_COR_SEQ_1_1 = 10'b0100011100; + parameter [9:0] CLK_COR_SEQ_1_2 = 10'b0000000000; + parameter [9:0] CLK_COR_SEQ_1_3 = 10'b0000000000; + parameter [9:0] CLK_COR_SEQ_1_4 = 10'b0000000000; + parameter [3:0] CLK_COR_SEQ_1_ENABLE = 4'b1111; + parameter [9:0] CLK_COR_SEQ_2_1 = 10'b0100000000; + parameter [9:0] CLK_COR_SEQ_2_2 = 10'b0100000000; + parameter [9:0] CLK_COR_SEQ_2_3 = 10'b0100000000; + parameter [9:0] CLK_COR_SEQ_2_4 = 10'b0100000000; + parameter [3:0] CLK_COR_SEQ_2_ENABLE = 4'b1111; + parameter CLK_COR_SEQ_2_USE = "FALSE"; + parameter integer CLK_COR_SEQ_LEN = 2; + parameter [15:0] CPLL_CFG0 = 16'h01FA; + parameter [15:0] CPLL_CFG1 = 16'h24A9; + parameter [15:0] CPLL_CFG2 = 16'h6807; + parameter [15:0] CPLL_CFG3 = 16'h0000; + parameter integer CPLL_FBDIV = 4; + parameter integer CPLL_FBDIV_45 = 4; + parameter [15:0] CPLL_INIT_CFG0 = 16'h001E; + parameter [15:0] CPLL_LOCK_CFG = 16'h01E8; + parameter integer CPLL_REFCLK_DIV = 1; + parameter [2:0] CTLE3_OCAP_EXT_CTRL = 3'b000; + parameter [0:0] CTLE3_OCAP_EXT_EN = 1'b0; + parameter [1:0] DDI_CTRL = 2'b00; + parameter integer DDI_REALIGN_WAIT = 15; + parameter DEC_MCOMMA_DETECT = "TRUE"; + parameter DEC_PCOMMA_DETECT = "TRUE"; + parameter DEC_VALID_COMMA_ONLY = "TRUE"; + parameter [0:0] DELAY_ELEC = 1'b0; + parameter [9:0] DMONITOR_CFG0 = 10'h000; + parameter [7:0] DMONITOR_CFG1 = 8'h00; + parameter [0:0] ES_CLK_PHASE_SEL = 1'b0; + parameter [5:0] ES_CONTROL = 6'b000000; + parameter ES_ERRDET_EN = "FALSE"; + parameter ES_EYE_SCAN_EN = "FALSE"; + parameter [11:0] ES_HORZ_OFFSET = 12'h800; + parameter [4:0] ES_PRESCALE = 5'b00000; + parameter [15:0] ES_QUALIFIER0 = 16'h0000; + parameter [15:0] ES_QUALIFIER1 = 16'h0000; + parameter [15:0] ES_QUALIFIER2 = 16'h0000; + parameter [15:0] ES_QUALIFIER3 = 16'h0000; + parameter [15:0] ES_QUALIFIER4 = 16'h0000; + parameter [15:0] ES_QUALIFIER5 = 16'h0000; + parameter [15:0] ES_QUALIFIER6 = 16'h0000; + parameter [15:0] ES_QUALIFIER7 = 16'h0000; + parameter [15:0] ES_QUALIFIER8 = 16'h0000; + parameter [15:0] ES_QUALIFIER9 = 16'h0000; + parameter [15:0] ES_QUAL_MASK0 = 16'h0000; + parameter [15:0] ES_QUAL_MASK1 = 16'h0000; + parameter [15:0] ES_QUAL_MASK2 = 16'h0000; + parameter [15:0] ES_QUAL_MASK3 = 16'h0000; + parameter [15:0] ES_QUAL_MASK4 = 16'h0000; + parameter [15:0] ES_QUAL_MASK5 = 16'h0000; + parameter [15:0] ES_QUAL_MASK6 = 16'h0000; + parameter [15:0] ES_QUAL_MASK7 = 16'h0000; + parameter [15:0] ES_QUAL_MASK8 = 16'h0000; + parameter [15:0] ES_QUAL_MASK9 = 16'h0000; + parameter [15:0] ES_SDATA_MASK0 = 16'h0000; + parameter [15:0] ES_SDATA_MASK1 = 16'h0000; + parameter [15:0] ES_SDATA_MASK2 = 16'h0000; + parameter [15:0] ES_SDATA_MASK3 = 16'h0000; + parameter [15:0] ES_SDATA_MASK4 = 16'h0000; + parameter [15:0] ES_SDATA_MASK5 = 16'h0000; + parameter [15:0] ES_SDATA_MASK6 = 16'h0000; + parameter [15:0] ES_SDATA_MASK7 = 16'h0000; + parameter [15:0] ES_SDATA_MASK8 = 16'h0000; + parameter [15:0] ES_SDATA_MASK9 = 16'h0000; + parameter integer EYESCAN_VP_RANGE = 0; + parameter [0:0] EYE_SCAN_SWAP_EN = 1'b0; + parameter [3:0] FTS_DESKEW_SEQ_ENABLE = 4'b1111; + parameter [3:0] FTS_LANE_DESKEW_CFG = 4'b1111; + parameter FTS_LANE_DESKEW_EN = "FALSE"; + parameter [4:0] GEARBOX_MODE = 5'b00000; + parameter [0:0] ISCAN_CK_PH_SEL2 = 1'b0; + parameter [0:0] LOCAL_MASTER = 1'b0; + parameter integer LPBK_BIAS_CTRL = 4; + parameter [0:0] LPBK_EN_RCAL_B = 1'b0; + parameter [3:0] LPBK_EXT_RCAL = 4'b0000; + parameter integer LPBK_IND_CTRL0 = 5; + parameter integer LPBK_IND_CTRL1 = 5; + parameter integer LPBK_IND_CTRL2 = 5; + parameter integer LPBK_RG_CTRL = 2; + parameter [1:0] OOBDIVCTL = 2'b00; + parameter [0:0] OOB_PWRUP = 1'b0; + parameter PCI3_AUTO_REALIGN = "FRST_SMPL"; + parameter [0:0] PCI3_PIPE_RX_ELECIDLE = 1'b1; + parameter [1:0] PCI3_RX_ASYNC_EBUF_BYPASS = 2'b00; + parameter [0:0] PCI3_RX_ELECIDLE_EI2_ENABLE = 1'b0; + parameter [5:0] PCI3_RX_ELECIDLE_H2L_COUNT = 6'b000000; + parameter [2:0] PCI3_RX_ELECIDLE_H2L_DISABLE = 3'b000; + parameter [5:0] PCI3_RX_ELECIDLE_HI_COUNT = 6'b000000; + parameter [0:0] PCI3_RX_ELECIDLE_LP4_DISABLE = 1'b0; + parameter [0:0] PCI3_RX_FIFO_DISABLE = 1'b0; + parameter [4:0] PCIE3_CLK_COR_EMPTY_THRSH = 5'b00000; + parameter [5:0] PCIE3_CLK_COR_FULL_THRSH = 6'b010000; + parameter [4:0] PCIE3_CLK_COR_MAX_LAT = 5'b01000; + parameter [4:0] PCIE3_CLK_COR_MIN_LAT = 5'b00100; + parameter [5:0] PCIE3_CLK_COR_THRSH_TIMER = 6'b001000; + parameter PCIE_64B_DYN_CLKSW_DIS = "FALSE"; + parameter [15:0] PCIE_BUFG_DIV_CTRL = 16'h0000; + parameter PCIE_GEN4_64BIT_INT_EN = "FALSE"; + parameter [1:0] PCIE_PLL_SEL_MODE_GEN12 = 2'h0; + parameter [1:0] PCIE_PLL_SEL_MODE_GEN3 = 2'h0; + parameter [1:0] PCIE_PLL_SEL_MODE_GEN4 = 2'h0; + parameter [15:0] PCIE_RXPCS_CFG_GEN3 = 16'h0000; + parameter [15:0] PCIE_RXPMA_CFG = 16'h0000; + parameter [15:0] PCIE_TXPCS_CFG_GEN3 = 16'h0000; + parameter [15:0] PCIE_TXPMA_CFG = 16'h0000; + parameter PCS_PCIE_EN = "FALSE"; + parameter [15:0] PCS_RSVD0 = 16'h0000; + parameter [11:0] PD_TRANS_TIME_FROM_P2 = 12'h03C; + parameter [7:0] PD_TRANS_TIME_NONE_P2 = 8'h19; + parameter [7:0] PD_TRANS_TIME_TO_P2 = 8'h64; + parameter integer PREIQ_FREQ_BST = 0; + parameter [0:0] RATE_SW_USE_DRP = 1'b0; + parameter [0:0] RCLK_SIPO_DLY_ENB = 1'b0; + parameter [0:0] RCLK_SIPO_INV_EN = 1'b0; + parameter [2:0] RTX_BUF_CML_CTRL = 3'b010; + parameter [1:0] RTX_BUF_TERM_CTRL = 2'b00; + parameter [4:0] RXBUFRESET_TIME = 5'b00001; + parameter RXBUF_ADDR_MODE = "FULL"; + parameter [3:0] RXBUF_EIDLE_HI_CNT = 4'b1000; + parameter [3:0] RXBUF_EIDLE_LO_CNT = 4'b0000; + parameter RXBUF_EN = "TRUE"; + parameter RXBUF_RESET_ON_CB_CHANGE = "TRUE"; + parameter RXBUF_RESET_ON_COMMAALIGN = "FALSE"; + parameter RXBUF_RESET_ON_EIDLE = "FALSE"; + parameter RXBUF_RESET_ON_RATE_CHANGE = "TRUE"; + parameter integer RXBUF_THRESH_OVFLW = 0; + parameter RXBUF_THRESH_OVRD = "FALSE"; + parameter integer RXBUF_THRESH_UNDFLW = 4; + parameter [4:0] RXCDRFREQRESET_TIME = 5'b10000; + parameter [4:0] RXCDRPHRESET_TIME = 5'b00001; + parameter [15:0] RXCDR_CFG0 = 16'h0003; + parameter [15:0] RXCDR_CFG0_GEN3 = 16'h0003; + parameter [15:0] RXCDR_CFG1 = 16'h0000; + parameter [15:0] RXCDR_CFG1_GEN3 = 16'h0000; + parameter [15:0] RXCDR_CFG2 = 16'h0164; + parameter [9:0] RXCDR_CFG2_GEN2 = 10'h164; + parameter [15:0] RXCDR_CFG2_GEN3 = 16'h0034; + parameter [15:0] RXCDR_CFG2_GEN4 = 16'h0034; + parameter [15:0] RXCDR_CFG3 = 16'h0024; + parameter [5:0] RXCDR_CFG3_GEN2 = 6'h24; + parameter [15:0] RXCDR_CFG3_GEN3 = 16'h0024; + parameter [15:0] RXCDR_CFG3_GEN4 = 16'h0024; + parameter [15:0] RXCDR_CFG4 = 16'h5CF6; + parameter [15:0] RXCDR_CFG4_GEN3 = 16'h5CF6; + parameter [15:0] RXCDR_CFG5 = 16'hB46B; + parameter [15:0] RXCDR_CFG5_GEN3 = 16'h146B; + parameter [0:0] RXCDR_FR_RESET_ON_EIDLE = 1'b0; + parameter [0:0] RXCDR_HOLD_DURING_EIDLE = 1'b0; + parameter [15:0] RXCDR_LOCK_CFG0 = 16'h0040; + parameter [15:0] RXCDR_LOCK_CFG1 = 16'h8000; + parameter [15:0] RXCDR_LOCK_CFG2 = 16'h0000; + parameter [15:0] RXCDR_LOCK_CFG3 = 16'h0000; + parameter [15:0] RXCDR_LOCK_CFG4 = 16'h0000; + parameter [0:0] RXCDR_PH_RESET_ON_EIDLE = 1'b0; + parameter [15:0] RXCFOK_CFG0 = 16'h0000; + parameter [15:0] RXCFOK_CFG1 = 16'h0002; + parameter [15:0] RXCFOK_CFG2 = 16'h002D; + parameter [15:0] RXCKCAL1_IQ_LOOP_RST_CFG = 16'h0000; + parameter [15:0] RXCKCAL1_I_LOOP_RST_CFG = 16'h0000; + parameter [15:0] RXCKCAL1_Q_LOOP_RST_CFG = 16'h0000; + parameter [15:0] RXCKCAL2_DX_LOOP_RST_CFG = 16'h0000; + parameter [15:0] RXCKCAL2_D_LOOP_RST_CFG = 16'h0000; + parameter [15:0] RXCKCAL2_S_LOOP_RST_CFG = 16'h0000; + parameter [15:0] RXCKCAL2_X_LOOP_RST_CFG = 16'h0000; + parameter [6:0] RXDFELPMRESET_TIME = 7'b0001111; + parameter [15:0] RXDFELPM_KL_CFG0 = 16'h0000; + parameter [15:0] RXDFELPM_KL_CFG1 = 16'h0022; + parameter [15:0] RXDFELPM_KL_CFG2 = 16'h0100; + parameter [15:0] RXDFE_CFG0 = 16'h4000; + parameter [15:0] RXDFE_CFG1 = 16'h0000; + parameter [15:0] RXDFE_GC_CFG0 = 16'h0000; + parameter [15:0] RXDFE_GC_CFG1 = 16'h0000; + parameter [15:0] RXDFE_GC_CFG2 = 16'h0000; + parameter [15:0] RXDFE_H2_CFG0 = 16'h0000; + parameter [15:0] RXDFE_H2_CFG1 = 16'h0002; + parameter [15:0] RXDFE_H3_CFG0 = 16'h0000; + parameter [15:0] RXDFE_H3_CFG1 = 16'h0002; + parameter [15:0] RXDFE_H4_CFG0 = 16'h0000; + parameter [15:0] RXDFE_H4_CFG1 = 16'h0003; + parameter [15:0] RXDFE_H5_CFG0 = 16'h0000; + parameter [15:0] RXDFE_H5_CFG1 = 16'h0002; + parameter [15:0] RXDFE_H6_CFG0 = 16'h0000; + parameter [15:0] RXDFE_H6_CFG1 = 16'h0002; + parameter [15:0] RXDFE_H7_CFG0 = 16'h0000; + parameter [15:0] RXDFE_H7_CFG1 = 16'h0002; + parameter [15:0] RXDFE_H8_CFG0 = 16'h0000; + parameter [15:0] RXDFE_H8_CFG1 = 16'h0002; + parameter [15:0] RXDFE_H9_CFG0 = 16'h0000; + parameter [15:0] RXDFE_H9_CFG1 = 16'h0002; + parameter [15:0] RXDFE_HA_CFG0 = 16'h0000; + parameter [15:0] RXDFE_HA_CFG1 = 16'h0002; + parameter [15:0] RXDFE_HB_CFG0 = 16'h0000; + parameter [15:0] RXDFE_HB_CFG1 = 16'h0002; + parameter [15:0] RXDFE_HC_CFG0 = 16'h0000; + parameter [15:0] RXDFE_HC_CFG1 = 16'h0002; + parameter [15:0] RXDFE_HD_CFG0 = 16'h0000; + parameter [15:0] RXDFE_HD_CFG1 = 16'h0002; + parameter [15:0] RXDFE_HE_CFG0 = 16'h0000; + parameter [15:0] RXDFE_HE_CFG1 = 16'h0002; + parameter [15:0] RXDFE_HF_CFG0 = 16'h0000; + parameter [15:0] RXDFE_HF_CFG1 = 16'h0002; + parameter [15:0] RXDFE_KH_CFG0 = 16'h0000; + parameter [15:0] RXDFE_KH_CFG1 = 16'h0000; + parameter [15:0] RXDFE_KH_CFG2 = 16'h0000; + parameter [15:0] RXDFE_KH_CFG3 = 16'h0000; + parameter [15:0] RXDFE_OS_CFG0 = 16'h0000; + parameter [15:0] RXDFE_OS_CFG1 = 16'h0000; + parameter [15:0] RXDFE_UT_CFG0 = 16'h0000; + parameter [15:0] RXDFE_UT_CFG1 = 16'h0002; + parameter [15:0] RXDFE_UT_CFG2 = 16'h0000; + parameter [15:0] RXDFE_VP_CFG0 = 16'h0000; + parameter [15:0] RXDFE_VP_CFG1 = 16'h0022; + parameter [15:0] RXDLY_CFG = 16'h0010; + parameter [15:0] RXDLY_LCFG = 16'h0030; + parameter RXELECIDLE_CFG = "SIGCFG_4"; + parameter integer RXGBOX_FIFO_INIT_RD_ADDR = 4; + parameter RXGEARBOX_EN = "FALSE"; + parameter [4:0] RXISCANRESET_TIME = 5'b00001; + parameter [15:0] RXLPM_CFG = 16'h0000; + parameter [15:0] RXLPM_GC_CFG = 16'h1000; + parameter [15:0] RXLPM_KH_CFG0 = 16'h0000; + parameter [15:0] RXLPM_KH_CFG1 = 16'h0002; + parameter [15:0] RXLPM_OS_CFG0 = 16'h0000; + parameter [15:0] RXLPM_OS_CFG1 = 16'h0000; + parameter [8:0] RXOOB_CFG = 9'b000110000; + parameter RXOOB_CLK_CFG = "PMA"; + parameter [4:0] RXOSCALRESET_TIME = 5'b00011; + parameter integer RXOUT_DIV = 4; + parameter [4:0] RXPCSRESET_TIME = 5'b00001; + parameter [15:0] RXPHBEACON_CFG = 16'h0000; + parameter [15:0] RXPHDLY_CFG = 16'h2020; + parameter [15:0] RXPHSAMP_CFG = 16'h2100; + parameter [15:0] RXPHSLIP_CFG = 16'h9933; + parameter [4:0] RXPH_MONITOR_SEL = 5'b00000; + parameter [15:0] RXPI_CFG0 = 16'h0102; + parameter [15:0] RXPI_CFG1 = 16'b0000000001010100; + parameter RXPMACLK_SEL = "DATA"; + parameter [4:0] RXPMARESET_TIME = 5'b00001; + parameter [0:0] RXPRBS_ERR_LOOPBACK = 1'b0; + parameter integer RXPRBS_LINKACQ_CNT = 15; + parameter [0:0] RXREFCLKDIV2_SEL = 1'b0; + parameter integer RXSLIDE_AUTO_WAIT = 7; + parameter RXSLIDE_MODE = "OFF"; + parameter [0:0] RXSYNC_MULTILANE = 1'b0; + parameter [0:0] RXSYNC_OVRD = 1'b0; + parameter [0:0] RXSYNC_SKIP_DA = 1'b0; + parameter [0:0] RX_AFE_CM_EN = 1'b0; + parameter [15:0] RX_BIAS_CFG0 = 16'h12B0; + parameter [5:0] RX_BUFFER_CFG = 6'b000000; + parameter [0:0] RX_CAPFF_SARC_ENB = 1'b0; + parameter integer RX_CLK25_DIV = 8; + parameter [0:0] RX_CLKMUX_EN = 1'b1; + parameter [4:0] RX_CLK_SLIP_OVRD = 5'b00000; + parameter [3:0] RX_CM_BUF_CFG = 4'b1010; + parameter [0:0] RX_CM_BUF_PD = 1'b0; + parameter integer RX_CM_SEL = 3; + parameter integer RX_CM_TRIM = 12; + parameter [0:0] RX_CTLE_PWR_SAVING = 1'b0; + parameter [3:0] RX_CTLE_RES_CTRL = 4'b0000; + parameter integer RX_DATA_WIDTH = 20; + parameter [5:0] RX_DDI_SEL = 6'b000000; + parameter RX_DEFER_RESET_BUF_EN = "TRUE"; + parameter [2:0] RX_DEGEN_CTRL = 3'b100; + parameter integer RX_DFELPM_CFG0 = 0; + parameter [0:0] RX_DFELPM_CFG1 = 1'b1; + parameter [0:0] RX_DFELPM_KLKH_AGC_STUP_EN = 1'b1; + parameter integer RX_DFE_AGC_CFG1 = 4; + parameter integer RX_DFE_KL_LPM_KH_CFG0 = 1; + parameter integer RX_DFE_KL_LPM_KH_CFG1 = 4; + parameter [1:0] RX_DFE_KL_LPM_KL_CFG0 = 2'b01; + parameter integer RX_DFE_KL_LPM_KL_CFG1 = 4; + parameter [0:0] RX_DFE_LPM_HOLD_DURING_EIDLE = 1'b0; + parameter RX_DISPERR_SEQ_MATCH = "TRUE"; + parameter [4:0] RX_DIVRESET_TIME = 5'b00001; + parameter [0:0] RX_EN_CTLE_RCAL_B = 1'b0; + parameter integer RX_EN_SUM_RCAL_B = 0; + parameter [6:0] RX_EYESCAN_VS_CODE = 7'b0000000; + parameter [0:0] RX_EYESCAN_VS_NEG_DIR = 1'b0; + parameter [1:0] RX_EYESCAN_VS_RANGE = 2'b10; + parameter [0:0] RX_EYESCAN_VS_UT_SIGN = 1'b0; + parameter [0:0] RX_FABINT_USRCLK_FLOP = 1'b0; + parameter [0:0] RX_I2V_FILTER_EN = 1'b1; + parameter integer RX_INT_DATAWIDTH = 1; + parameter [0:0] RX_PMA_POWER_SAVE = 1'b0; + parameter [15:0] RX_PMA_RSV0 = 16'h000F; + parameter real RX_PROGDIV_CFG = 0.0; + parameter [15:0] RX_PROGDIV_RATE = 16'h0001; + parameter [3:0] RX_RESLOAD_CTRL = 4'b0000; + parameter [0:0] RX_RESLOAD_OVRD = 1'b0; + parameter [2:0] RX_SAMPLE_PERIOD = 3'b101; + parameter integer RX_SIG_VALID_DLY = 11; + parameter integer RX_SUM_DEGEN_AVTT_OVERITE = 0; + parameter [0:0] RX_SUM_DFETAPREP_EN = 1'b0; + parameter [3:0] RX_SUM_IREF_TUNE = 4'b0000; + parameter integer RX_SUM_PWR_SAVING = 0; + parameter [3:0] RX_SUM_RES_CTRL = 4'b0000; + parameter [3:0] RX_SUM_VCMTUNE = 4'b0011; + parameter [0:0] RX_SUM_VCM_BIAS_TUNE_EN = 1'b1; + parameter [0:0] RX_SUM_VCM_OVWR = 1'b0; + parameter [2:0] RX_SUM_VREF_TUNE = 3'b100; + parameter [1:0] RX_TUNE_AFE_OS = 2'b00; + parameter [2:0] RX_VREG_CTRL = 3'b010; + parameter [0:0] RX_VREG_PDB = 1'b1; + parameter [1:0] RX_WIDEMODE_CDR = 2'b01; + parameter [1:0] RX_WIDEMODE_CDR_GEN3 = 2'b01; + parameter [1:0] RX_WIDEMODE_CDR_GEN4 = 2'b01; + parameter RX_XCLK_SEL = "RXDES"; + parameter [0:0] RX_XMODE_SEL = 1'b0; + parameter [0:0] SAMPLE_CLK_PHASE = 1'b0; + parameter [0:0] SAS_12G_MODE = 1'b0; + parameter [3:0] SATA_BURST_SEQ_LEN = 4'b1111; + parameter [2:0] SATA_BURST_VAL = 3'b100; + parameter SATA_CPLL_CFG = "VCO_3000MHZ"; + parameter [2:0] SATA_EIDLE_VAL = 3'b100; + parameter SHOW_REALIGN_COMMA = "TRUE"; + parameter SIM_MODE = "FAST"; + parameter SIM_RECEIVER_DETECT_PASS = "TRUE"; + parameter SIM_RESET_SPEEDUP = "TRUE"; + parameter SIM_TX_EIDLE_DRIVE_LEVEL = "Z"; + parameter SIM_DEVICE = "ULTRASCALE_PLUS"; + parameter [0:0] SRSTMODE = 1'b0; + parameter [1:0] TAPDLY_SET_TX = 2'h0; + parameter [14:0] TERM_RCAL_CFG = 15'b100001000010000; + parameter [2:0] TERM_RCAL_OVRD = 3'b000; + parameter [7:0] TRANS_TIME_RATE = 8'h0E; + parameter [7:0] TST_RSV0 = 8'h00; + parameter [7:0] TST_RSV1 = 8'h00; + parameter TXBUF_EN = "TRUE"; + parameter TXBUF_RESET_ON_RATE_CHANGE = "FALSE"; + parameter [15:0] TXDLY_CFG = 16'h0010; + parameter [15:0] TXDLY_LCFG = 16'h0030; + parameter integer TXDRV_FREQBAND = 0; + parameter [15:0] TXFE_CFG0 = 16'b0000000000000000; + parameter [15:0] TXFE_CFG1 = 16'b0000000000000000; + parameter [15:0] TXFE_CFG2 = 16'b0000000000000000; + parameter [15:0] TXFE_CFG3 = 16'b0000000000000000; + parameter TXFIFO_ADDR_CFG = "LOW"; + parameter integer TXGBOX_FIFO_INIT_RD_ADDR = 4; + parameter TXGEARBOX_EN = "FALSE"; + parameter integer TXOUT_DIV = 4; + parameter [4:0] TXPCSRESET_TIME = 5'b00001; + parameter [15:0] TXPHDLY_CFG0 = 16'h6020; + parameter [15:0] TXPHDLY_CFG1 = 16'h0002; + parameter [15:0] TXPH_CFG = 16'h0123; + parameter [15:0] TXPH_CFG2 = 16'h0000; + parameter [4:0] TXPH_MONITOR_SEL = 5'b00000; + parameter [15:0] TXPI_CFG0 = 16'b0000000100000000; + parameter [15:0] TXPI_CFG1 = 16'b0000000000000000; + parameter [0:0] TXPI_GRAY_SEL = 1'b0; + parameter [0:0] TXPI_INVSTROBE_SEL = 1'b0; + parameter [0:0] TXPI_PPM = 1'b0; + parameter [7:0] TXPI_PPM_CFG = 8'b00000000; + parameter [2:0] TXPI_SYNFREQ_PPM = 3'b000; + parameter [4:0] TXPMARESET_TIME = 5'b00001; + parameter [0:0] TXREFCLKDIV2_SEL = 1'b0; + parameter integer TXSWBST_BST = 1; + parameter integer TXSWBST_EN = 0; + parameter integer TXSWBST_MAG = 6; + parameter [0:0] TXSYNC_MULTILANE = 1'b0; + parameter [0:0] TXSYNC_OVRD = 1'b0; + parameter [0:0] TXSYNC_SKIP_DA = 1'b0; + parameter integer TX_CLK25_DIV = 8; + parameter [0:0] TX_CLKMUX_EN = 1'b1; + parameter integer TX_DATA_WIDTH = 20; + parameter [15:0] TX_DCC_LOOP_RST_CFG = 16'h0000; + parameter [5:0] TX_DEEMPH0 = 6'b000000; + parameter [5:0] TX_DEEMPH1 = 6'b000000; + parameter [5:0] TX_DEEMPH2 = 6'b000000; + parameter [5:0] TX_DEEMPH3 = 6'b000000; + parameter [4:0] TX_DIVRESET_TIME = 5'b00001; + parameter TX_DRIVE_MODE = "DIRECT"; + parameter [2:0] TX_EIDLE_ASSERT_DELAY = 3'b110; + parameter [2:0] TX_EIDLE_DEASSERT_DELAY = 3'b100; + parameter [0:0] TX_FABINT_USRCLK_FLOP = 1'b0; + parameter [0:0] TX_FIFO_BYP_EN = 1'b0; + parameter [0:0] TX_IDLE_DATA_ZERO = 1'b0; + parameter integer TX_INT_DATAWIDTH = 1; + parameter TX_LOOPBACK_DRIVE_HIZ = "FALSE"; + parameter [0:0] TX_MAINCURSOR_SEL = 1'b0; + parameter [6:0] TX_MARGIN_FULL_0 = 7'b1001110; + parameter [6:0] TX_MARGIN_FULL_1 = 7'b1001001; + parameter [6:0] TX_MARGIN_FULL_2 = 7'b1000101; + parameter [6:0] TX_MARGIN_FULL_3 = 7'b1000010; + parameter [6:0] TX_MARGIN_FULL_4 = 7'b1000000; + parameter [6:0] TX_MARGIN_LOW_0 = 7'b1000110; + parameter [6:0] TX_MARGIN_LOW_1 = 7'b1000100; + parameter [6:0] TX_MARGIN_LOW_2 = 7'b1000010; + parameter [6:0] TX_MARGIN_LOW_3 = 7'b1000000; + parameter [6:0] TX_MARGIN_LOW_4 = 7'b1000000; + parameter [15:0] TX_PHICAL_CFG0 = 16'h0000; + parameter [15:0] TX_PHICAL_CFG1 = 16'h003F; + parameter integer TX_PI_BIASSET = 0; + parameter [0:0] TX_PMADATA_OPT = 1'b0; + parameter [0:0] TX_PMA_POWER_SAVE = 1'b0; + parameter [15:0] TX_PMA_RSV0 = 16'h0000; + parameter [15:0] TX_PMA_RSV1 = 16'h0000; + parameter TX_PROGCLK_SEL = "POSTPI"; + parameter real TX_PROGDIV_CFG = 0.0; + parameter [15:0] TX_PROGDIV_RATE = 16'h0001; + parameter [13:0] TX_RXDETECT_CFG = 14'h0032; + parameter integer TX_RXDETECT_REF = 3; + parameter [2:0] TX_SAMPLE_PERIOD = 3'b101; + parameter [1:0] TX_SW_MEAS = 2'b00; + parameter [2:0] TX_VREG_CTRL = 3'b000; + parameter [0:0] TX_VREG_PDB = 1'b0; + parameter [1:0] TX_VREG_VREFSEL = 2'b00; + parameter TX_XCLK_SEL = "TXOUT"; + parameter [0:0] USB_BOTH_BURST_IDLE = 1'b0; + parameter [6:0] USB_BURSTMAX_U3WAKE = 7'b1111111; + parameter [6:0] USB_BURSTMIN_U3WAKE = 7'b1100011; + parameter [0:0] USB_CLK_COR_EQ_EN = 1'b0; + parameter [0:0] USB_EXT_CNTL = 1'b1; + parameter [9:0] USB_IDLEMAX_POLLING = 10'b1010111011; + parameter [9:0] USB_IDLEMIN_POLLING = 10'b0100101011; + parameter [8:0] USB_LFPSPING_BURST = 9'b000000101; + parameter [8:0] USB_LFPSPOLLING_BURST = 9'b000110001; + parameter [8:0] USB_LFPSPOLLING_IDLE_MS = 9'b000000100; + parameter [8:0] USB_LFPSU1EXIT_BURST = 9'b000011101; + parameter [8:0] USB_LFPSU2LPEXIT_BURST_MS = 9'b001100011; + parameter [8:0] USB_LFPSU3WAKE_BURST_MS = 9'b111110011; + parameter [3:0] USB_LFPS_TPERIOD = 4'b0011; + parameter [0:0] USB_LFPS_TPERIOD_ACCURATE = 1'b1; + parameter [0:0] USB_MODE = 1'b0; + parameter [0:0] USB_PCIE_ERR_REP_DIS = 1'b0; + parameter integer USB_PING_SATA_MAX_INIT = 21; + parameter integer USB_PING_SATA_MIN_INIT = 12; + parameter integer USB_POLL_SATA_MAX_BURST = 8; + parameter integer USB_POLL_SATA_MIN_BURST = 4; + parameter [0:0] USB_RAW_ELEC = 1'b0; + parameter [0:0] USB_RXIDLE_P0_CTRL = 1'b1; + parameter [0:0] USB_TXIDLE_TUNE_ENABLE = 1'b1; + parameter integer USB_U1_SATA_MAX_WAKE = 7; + parameter integer USB_U1_SATA_MIN_WAKE = 4; + parameter integer USB_U2_SAS_MAX_COM = 64; + parameter integer USB_U2_SAS_MIN_COM = 36; + parameter [0:0] USE_PCS_CLK_PHASE_SEL = 1'b0; + parameter [0:0] Y_ALL_MODE = 1'b0; + output BUFGTCE; + output [2:0] BUFGTCEMASK; + output [8:0] BUFGTDIV; + output BUFGTRESET; + output [2:0] BUFGTRSTMASK; + output CPLLFBCLKLOST; + output CPLLLOCK; + output CPLLREFCLKLOST; + output [15:0] DMONITOROUT; + output DMONITOROUTCLK; + output [15:0] DRPDO; + output DRPRDY; + output EYESCANDATAERROR; + output GTPOWERGOOD; + output GTREFCLKMONITOR; + output GTYTXN; + output GTYTXP; + output PCIERATEGEN3; + output PCIERATEIDLE; + output [1:0] PCIERATEQPLLPD; + output [1:0] PCIERATEQPLLRESET; + output PCIESYNCTXSYNCDONE; + output PCIEUSERGEN3RDY; + output PCIEUSERPHYSTATUSRST; + output PCIEUSERRATESTART; + output [15:0] PCSRSVDOUT; + output PHYSTATUS; + output [15:0] PINRSRVDAS; + output POWERPRESENT; + output RESETEXCEPTION; + output [2:0] RXBUFSTATUS; + output RXBYTEISALIGNED; + output RXBYTEREALIGN; + output RXCDRLOCK; + output RXCDRPHDONE; + output RXCHANBONDSEQ; + output RXCHANISALIGNED; + output RXCHANREALIGN; + output [4:0] RXCHBONDO; + output RXCKCALDONE; + output [1:0] RXCLKCORCNT; + output RXCOMINITDET; + output RXCOMMADET; + output RXCOMSASDET; + output RXCOMWAKEDET; + output [15:0] RXCTRL0; + output [15:0] RXCTRL1; + output [7:0] RXCTRL2; + output [7:0] RXCTRL3; + output [127:0] RXDATA; + output [7:0] RXDATAEXTENDRSVD; + output [1:0] RXDATAVALID; + output RXDLYSRESETDONE; + output RXELECIDLE; + output [5:0] RXHEADER; + output [1:0] RXHEADERVALID; + output RXLFPSTRESETDET; + output RXLFPSU2LPEXITDET; + output RXLFPSU3WAKEDET; + output [7:0] RXMONITOROUT; + output RXOSINTDONE; + output RXOSINTSTARTED; + output RXOSINTSTROBEDONE; + output RXOSINTSTROBESTARTED; + output RXOUTCLK; + output RXOUTCLKFABRIC; + output RXOUTCLKPCS; + output RXPHALIGNDONE; + output RXPHALIGNERR; + output RXPMARESETDONE; + output RXPRBSERR; + output RXPRBSLOCKED; + output RXPRGDIVRESETDONE; + output RXRATEDONE; + output RXRECCLKOUT; + output RXRESETDONE; + output RXSLIDERDY; + output RXSLIPDONE; + output RXSLIPOUTCLKRDY; + output RXSLIPPMARDY; + output [1:0] RXSTARTOFSEQ; + output [2:0] RXSTATUS; + output RXSYNCDONE; + output RXSYNCOUT; + output RXVALID; + output [1:0] TXBUFSTATUS; + output TXCOMFINISH; + output TXDCCDONE; + output TXDLYSRESETDONE; + output TXOUTCLK; + output TXOUTCLKFABRIC; + output TXOUTCLKPCS; + output TXPHALIGNDONE; + output TXPHINITDONE; + output TXPMARESETDONE; + output TXPRGDIVRESETDONE; + output TXRATEDONE; + output TXRESETDONE; + output TXSYNCDONE; + output TXSYNCOUT; + input CDRSTEPDIR; + input CDRSTEPSQ; + input CDRSTEPSX; + input CFGRESET; + input CLKRSVD0; + input CLKRSVD1; + input CPLLFREQLOCK; + input CPLLLOCKDETCLK; + input CPLLLOCKEN; + input CPLLPD; + input [2:0] CPLLREFCLKSEL; + input CPLLRESET; + input DMONFIFORESET; + input DMONITORCLK; + input [9:0] DRPADDR; + input DRPCLK; + input [15:0] DRPDI; + input DRPEN; + input DRPRST; + input DRPWE; + input EYESCANRESET; + input EYESCANTRIGGER; + input FREQOS; + input GTGREFCLK; + input GTNORTHREFCLK0; + input GTNORTHREFCLK1; + input GTREFCLK0; + input GTREFCLK1; + input [15:0] GTRSVD; + input GTRXRESET; + input GTRXRESETSEL; + input GTSOUTHREFCLK0; + input GTSOUTHREFCLK1; + input GTTXRESET; + input GTTXRESETSEL; + input GTYRXN; + input GTYRXP; + input INCPCTRL; + input [2:0] LOOPBACK; + input PCIEEQRXEQADAPTDONE; + input PCIERSTIDLE; + input PCIERSTTXSYNCSTART; + input PCIEUSERRATEDONE; + input [15:0] PCSRSVDIN; + input QPLL0CLK; + input QPLL0FREQLOCK; + input QPLL0REFCLK; + input QPLL1CLK; + input QPLL1FREQLOCK; + input QPLL1REFCLK; + input RESETOVRD; + input RX8B10BEN; + input RXAFECFOKEN; + input RXBUFRESET; + input RXCDRFREQRESET; + input RXCDRHOLD; + input RXCDROVRDEN; + input RXCDRRESET; + input RXCHBONDEN; + input [4:0] RXCHBONDI; + input [2:0] RXCHBONDLEVEL; + input RXCHBONDMASTER; + input RXCHBONDSLAVE; + input RXCKCALRESET; + input [6:0] RXCKCALSTART; + input RXCOMMADETEN; + input RXDFEAGCHOLD; + input RXDFEAGCOVRDEN; + input [3:0] RXDFECFOKFCNUM; + input RXDFECFOKFEN; + input RXDFECFOKFPULSE; + input RXDFECFOKHOLD; + input RXDFECFOKOVREN; + input RXDFEKHHOLD; + input RXDFEKHOVRDEN; + input RXDFELFHOLD; + input RXDFELFOVRDEN; + input RXDFELPMRESET; + input RXDFETAP10HOLD; + input RXDFETAP10OVRDEN; + input RXDFETAP11HOLD; + input RXDFETAP11OVRDEN; + input RXDFETAP12HOLD; + input RXDFETAP12OVRDEN; + input RXDFETAP13HOLD; + input RXDFETAP13OVRDEN; + input RXDFETAP14HOLD; + input RXDFETAP14OVRDEN; + input RXDFETAP15HOLD; + input RXDFETAP15OVRDEN; + input RXDFETAP2HOLD; + input RXDFETAP2OVRDEN; + input RXDFETAP3HOLD; + input RXDFETAP3OVRDEN; + input RXDFETAP4HOLD; + input RXDFETAP4OVRDEN; + input RXDFETAP5HOLD; + input RXDFETAP5OVRDEN; + input RXDFETAP6HOLD; + input RXDFETAP6OVRDEN; + input RXDFETAP7HOLD; + input RXDFETAP7OVRDEN; + input RXDFETAP8HOLD; + input RXDFETAP8OVRDEN; + input RXDFETAP9HOLD; + input RXDFETAP9OVRDEN; + input RXDFEUTHOLD; + input RXDFEUTOVRDEN; + input RXDFEVPHOLD; + input RXDFEVPOVRDEN; + input RXDFEXYDEN; + input RXDLYBYPASS; + input RXDLYEN; + input RXDLYOVRDEN; + input RXDLYSRESET; + input [1:0] RXELECIDLEMODE; + input RXEQTRAINING; + input RXGEARBOXSLIP; + input RXLATCLK; + input RXLPMEN; + input RXLPMGCHOLD; + input RXLPMGCOVRDEN; + input RXLPMHFHOLD; + input RXLPMHFOVRDEN; + input RXLPMLFHOLD; + input RXLPMLFKLOVRDEN; + input RXLPMOSHOLD; + input RXLPMOSOVRDEN; + input RXMCOMMAALIGNEN; + input [1:0] RXMONITORSEL; + input RXOOBRESET; + input RXOSCALRESET; + input RXOSHOLD; + input RXOSOVRDEN; + input [2:0] RXOUTCLKSEL; + input RXPCOMMAALIGNEN; + input RXPCSRESET; + input [1:0] RXPD; + input RXPHALIGN; + input RXPHALIGNEN; + input RXPHDLYPD; + input RXPHDLYRESET; + input [1:0] RXPLLCLKSEL; + input RXPMARESET; + input RXPOLARITY; + input RXPRBSCNTRESET; + input [3:0] RXPRBSSEL; + input RXPROGDIVRESET; + input [2:0] RXRATE; + input RXRATEMODE; + input RXSLIDE; + input RXSLIPOUTCLK; + input RXSLIPPMA; + input RXSYNCALLIN; + input RXSYNCIN; + input RXSYNCMODE; + input [1:0] RXSYSCLKSEL; + input RXTERMINATION; + input RXUSERRDY; + input RXUSRCLK; + input RXUSRCLK2; + input SIGVALIDCLK; + input [19:0] TSTIN; + input [7:0] TX8B10BBYPASS; + input TX8B10BEN; + input TXCOMINIT; + input TXCOMSAS; + input TXCOMWAKE; + input [15:0] TXCTRL0; + input [15:0] TXCTRL1; + input [7:0] TXCTRL2; + input [127:0] TXDATA; + input [7:0] TXDATAEXTENDRSVD; + input TXDCCFORCESTART; + input TXDCCRESET; + input [1:0] TXDEEMPH; + input TXDETECTRX; + input [4:0] TXDIFFCTRL; + input TXDLYBYPASS; + input TXDLYEN; + input TXDLYHOLD; + input TXDLYOVRDEN; + input TXDLYSRESET; + input TXDLYUPDOWN; + input TXELECIDLE; + input [5:0] TXHEADER; + input TXINHIBIT; + input TXLATCLK; + input TXLFPSTRESET; + input TXLFPSU2LPEXIT; + input TXLFPSU3WAKE; + input [6:0] TXMAINCURSOR; + input [2:0] TXMARGIN; + input TXMUXDCDEXHOLD; + input TXMUXDCDORWREN; + input TXONESZEROS; + input [2:0] TXOUTCLKSEL; + input TXPCSRESET; + input [1:0] TXPD; + input TXPDELECIDLEMODE; + input TXPHALIGN; + input TXPHALIGNEN; + input TXPHDLYPD; + input TXPHDLYRESET; + input TXPHDLYTSTCLK; + input TXPHINIT; + input TXPHOVRDEN; + input TXPIPPMEN; + input TXPIPPMOVRDEN; + input TXPIPPMPD; + input TXPIPPMSEL; + input [4:0] TXPIPPMSTEPSIZE; + input TXPISOPD; + input [1:0] TXPLLCLKSEL; + input TXPMARESET; + input TXPOLARITY; + input [4:0] TXPOSTCURSOR; + input TXPRBSFORCEERR; + input [3:0] TXPRBSSEL; + input [4:0] TXPRECURSOR; + input TXPROGDIVRESET; + input [2:0] TXRATE; + input TXRATEMODE; + input [6:0] TXSEQUENCE; + input TXSWING; + input TXSYNCALLIN; + input TXSYNCIN; + input TXSYNCMODE; + input [1:0] TXSYSCLKSEL; + input TXUSERRDY; + input TXUSRCLK; + input TXUSRCLK2; +endmodule + +module GTYE4_COMMON (...); + parameter [0:0] AEN_QPLL0_FBDIV = 1'b1; + parameter [0:0] AEN_QPLL1_FBDIV = 1'b1; + parameter [0:0] AEN_SDM0TOGGLE = 1'b0; + parameter [0:0] AEN_SDM1TOGGLE = 1'b0; + parameter [0:0] A_SDM0TOGGLE = 1'b0; + parameter [8:0] A_SDM1DATA_HIGH = 9'b000000000; + parameter [15:0] A_SDM1DATA_LOW = 16'b0000000000000000; + parameter [0:0] A_SDM1TOGGLE = 1'b0; + parameter [15:0] BIAS_CFG0 = 16'h0000; + parameter [15:0] BIAS_CFG1 = 16'h0000; + parameter [15:0] BIAS_CFG2 = 16'h0000; + parameter [15:0] BIAS_CFG3 = 16'h0000; + parameter [15:0] BIAS_CFG4 = 16'h0000; + parameter [15:0] BIAS_CFG_RSVD = 16'h0000; + parameter [15:0] COMMON_CFG0 = 16'h0000; + parameter [15:0] COMMON_CFG1 = 16'h0000; + parameter [15:0] POR_CFG = 16'h0000; + parameter [15:0] PPF0_CFG = 16'h0F00; + parameter [15:0] PPF1_CFG = 16'h0F00; + parameter QPLL0CLKOUT_RATE = "FULL"; + parameter [15:0] QPLL0_CFG0 = 16'h391C; + parameter [15:0] QPLL0_CFG1 = 16'h0000; + parameter [15:0] QPLL0_CFG1_G3 = 16'h0020; + parameter [15:0] QPLL0_CFG2 = 16'h0F80; + parameter [15:0] QPLL0_CFG2_G3 = 16'h0F80; + parameter [15:0] QPLL0_CFG3 = 16'h0120; + parameter [15:0] QPLL0_CFG4 = 16'h0002; + parameter [9:0] QPLL0_CP = 10'b0000011111; + parameter [9:0] QPLL0_CP_G3 = 10'b0000011111; + parameter integer QPLL0_FBDIV = 66; + parameter integer QPLL0_FBDIV_G3 = 80; + parameter [15:0] QPLL0_INIT_CFG0 = 16'h0000; + parameter [7:0] QPLL0_INIT_CFG1 = 8'h00; + parameter [15:0] QPLL0_LOCK_CFG = 16'h01E8; + parameter [15:0] QPLL0_LOCK_CFG_G3 = 16'h21E8; + parameter [9:0] QPLL0_LPF = 10'b1011111111; + parameter [9:0] QPLL0_LPF_G3 = 10'b1111111111; + parameter [0:0] QPLL0_PCI_EN = 1'b0; + parameter [0:0] QPLL0_RATE_SW_USE_DRP = 1'b0; + parameter integer QPLL0_REFCLK_DIV = 1; + parameter [15:0] QPLL0_SDM_CFG0 = 16'h0040; + parameter [15:0] QPLL0_SDM_CFG1 = 16'h0000; + parameter [15:0] QPLL0_SDM_CFG2 = 16'h0000; + parameter QPLL1CLKOUT_RATE = "FULL"; + parameter [15:0] QPLL1_CFG0 = 16'h691C; + parameter [15:0] QPLL1_CFG1 = 16'h0020; + parameter [15:0] QPLL1_CFG1_G3 = 16'h0020; + parameter [15:0] QPLL1_CFG2 = 16'h0F80; + parameter [15:0] QPLL1_CFG2_G3 = 16'h0F80; + parameter [15:0] QPLL1_CFG3 = 16'h0120; + parameter [15:0] QPLL1_CFG4 = 16'h0002; + parameter [9:0] QPLL1_CP = 10'b0000011111; + parameter [9:0] QPLL1_CP_G3 = 10'b0000011111; + parameter integer QPLL1_FBDIV = 66; + parameter integer QPLL1_FBDIV_G3 = 80; + parameter [15:0] QPLL1_INIT_CFG0 = 16'h0000; + parameter [7:0] QPLL1_INIT_CFG1 = 8'h00; + parameter [15:0] QPLL1_LOCK_CFG = 16'h01E8; + parameter [15:0] QPLL1_LOCK_CFG_G3 = 16'h21E8; + parameter [9:0] QPLL1_LPF = 10'b1011111111; + parameter [9:0] QPLL1_LPF_G3 = 10'b1111111111; + parameter [0:0] QPLL1_PCI_EN = 1'b0; + parameter [0:0] QPLL1_RATE_SW_USE_DRP = 1'b0; + parameter integer QPLL1_REFCLK_DIV = 1; + parameter [15:0] QPLL1_SDM_CFG0 = 16'h0000; + parameter [15:0] QPLL1_SDM_CFG1 = 16'h0000; + parameter [15:0] QPLL1_SDM_CFG2 = 16'h0000; + parameter [15:0] RSVD_ATTR0 = 16'h0000; + parameter [15:0] RSVD_ATTR1 = 16'h0000; + parameter [15:0] RSVD_ATTR2 = 16'h0000; + parameter [15:0] RSVD_ATTR3 = 16'h0000; + parameter [1:0] RXRECCLKOUT0_SEL = 2'b00; + parameter [1:0] RXRECCLKOUT1_SEL = 2'b00; + parameter [0:0] SARC_ENB = 1'b0; + parameter [0:0] SARC_SEL = 1'b0; + parameter [15:0] SDM0INITSEED0_0 = 16'b0000000000000000; + parameter [8:0] SDM0INITSEED0_1 = 9'b000000000; + parameter [15:0] SDM1INITSEED0_0 = 16'b0000000000000000; + parameter [8:0] SDM1INITSEED0_1 = 9'b000000000; + parameter SIM_MODE = "FAST"; + parameter SIM_RESET_SPEEDUP = "TRUE"; + parameter SIM_DEVICE = "ULTRASCALE_PLUS"; + parameter [15:0] UB_CFG0 = 16'h0000; + parameter [15:0] UB_CFG1 = 16'h0000; + parameter [15:0] UB_CFG2 = 16'h0000; + parameter [15:0] UB_CFG3 = 16'h0000; + parameter [15:0] UB_CFG4 = 16'h0000; + parameter [15:0] UB_CFG5 = 16'h0400; + parameter [15:0] UB_CFG6 = 16'h0000; + output [15:0] DRPDO; + output DRPRDY; + output [7:0] PMARSVDOUT0; + output [7:0] PMARSVDOUT1; + output QPLL0FBCLKLOST; + output QPLL0LOCK; + output QPLL0OUTCLK; + output QPLL0OUTREFCLK; + output QPLL0REFCLKLOST; + output QPLL1FBCLKLOST; + output QPLL1LOCK; + output QPLL1OUTCLK; + output QPLL1OUTREFCLK; + output QPLL1REFCLKLOST; + output [7:0] QPLLDMONITOR0; + output [7:0] QPLLDMONITOR1; + output REFCLKOUTMONITOR0; + output REFCLKOUTMONITOR1; + output [1:0] RXRECCLK0SEL; + output [1:0] RXRECCLK1SEL; + output [3:0] SDM0FINALOUT; + output [14:0] SDM0TESTDATA; + output [3:0] SDM1FINALOUT; + output [14:0] SDM1TESTDATA; + output [15:0] UBDADDR; + output UBDEN; + output [15:0] UBDI; + output UBDWE; + output UBMDMTDO; + output UBRSVDOUT; + output UBTXUART; + input BGBYPASSB; + input BGMONITORENB; + input BGPDB; + input [4:0] BGRCALOVRD; + input BGRCALOVRDENB; + input [15:0] DRPADDR; + input DRPCLK; + input [15:0] DRPDI; + input DRPEN; + input DRPWE; + input GTGREFCLK0; + input GTGREFCLK1; + input GTNORTHREFCLK00; + input GTNORTHREFCLK01; + input GTNORTHREFCLK10; + input GTNORTHREFCLK11; + input GTREFCLK00; + input GTREFCLK01; + input GTREFCLK10; + input GTREFCLK11; + input GTSOUTHREFCLK00; + input GTSOUTHREFCLK01; + input GTSOUTHREFCLK10; + input GTSOUTHREFCLK11; + input [2:0] PCIERATEQPLL0; + input [2:0] PCIERATEQPLL1; + input [7:0] PMARSVD0; + input [7:0] PMARSVD1; + input QPLL0CLKRSVD0; + input QPLL0CLKRSVD1; + input [7:0] QPLL0FBDIV; + input QPLL0LOCKDETCLK; + input QPLL0LOCKEN; + input QPLL0PD; + input [2:0] QPLL0REFCLKSEL; + input QPLL0RESET; + input QPLL1CLKRSVD0; + input QPLL1CLKRSVD1; + input [7:0] QPLL1FBDIV; + input QPLL1LOCKDETCLK; + input QPLL1LOCKEN; + input QPLL1PD; + input [2:0] QPLL1REFCLKSEL; + input QPLL1RESET; + input [7:0] QPLLRSVD1; + input [4:0] QPLLRSVD2; + input [4:0] QPLLRSVD3; + input [7:0] QPLLRSVD4; + input RCALENB; + input [24:0] SDM0DATA; + input SDM0RESET; + input SDM0TOGGLE; + input [1:0] SDM0WIDTH; + input [24:0] SDM1DATA; + input SDM1RESET; + input SDM1TOGGLE; + input [1:0] SDM1WIDTH; + input UBCFGSTREAMEN; + input [15:0] UBDO; + input UBDRDY; + input UBENABLE; + input [1:0] UBGPI; + input [1:0] UBINTR; + input UBIOLMBRST; + input UBMBRST; + input UBMDMCAPTURE; + input UBMDMDBGRST; + input UBMDMDBGUPDATE; + input [3:0] UBMDMREGEN; + input UBMDMSHIFT; + input UBMDMSYSRST; + input UBMDMTCK; + input UBMDMTDI; +endmodule + +module IBUFDS_GTE3 (...); + parameter [0:0] REFCLK_EN_TX_PATH = 1'b0; + parameter [1:0] REFCLK_HROW_CK_SEL = 2'b00; + parameter [1:0] REFCLK_ICNTL_RX = 2'b00; + output O; + output ODIV2; + input CEB; + (* iopad_external_pin *) + input I; + (* iopad_external_pin *) + input IB; +endmodule + +module IBUFDS_GTE4 (...); + parameter [0:0] REFCLK_EN_TX_PATH = 1'b0; + parameter [1:0] REFCLK_HROW_CK_SEL = 2'b00; + parameter [1:0] REFCLK_ICNTL_RX = 2'b00; + output O; + output ODIV2; + input CEB; + (* iopad_external_pin *) + input I; + (* iopad_external_pin *) + input IB; +endmodule + +module ILKN (...); + parameter BYPASS = "FALSE"; + parameter [1:0] CTL_RX_BURSTMAX = 2'h3; + parameter [1:0] CTL_RX_CHAN_EXT = 2'h0; + parameter [3:0] CTL_RX_LAST_LANE = 4'hB; + parameter [15:0] CTL_RX_MFRAMELEN_MINUS1 = 16'h07FF; + parameter CTL_RX_PACKET_MODE = "TRUE"; + parameter [2:0] CTL_RX_RETRANS_MULT = 3'h0; + parameter [3:0] CTL_RX_RETRANS_RETRY = 4'h2; + parameter [15:0] CTL_RX_RETRANS_TIMER1 = 16'h0000; + parameter [15:0] CTL_RX_RETRANS_TIMER2 = 16'h0008; + parameter [11:0] CTL_RX_RETRANS_WDOG = 12'h000; + parameter [7:0] CTL_RX_RETRANS_WRAP_TIMER = 8'h00; + parameter CTL_TEST_MODE_PIN_CHAR = "FALSE"; + parameter [1:0] CTL_TX_BURSTMAX = 2'h3; + parameter [2:0] CTL_TX_BURSTSHORT = 3'h1; + parameter [1:0] CTL_TX_CHAN_EXT = 2'h0; + parameter CTL_TX_DISABLE_SKIPWORD = "TRUE"; + parameter [6:0] CTL_TX_FC_CALLEN = 7'h00; + parameter [3:0] CTL_TX_LAST_LANE = 4'hB; + parameter [15:0] CTL_TX_MFRAMELEN_MINUS1 = 16'h07FF; + parameter [13:0] CTL_TX_RETRANS_DEPTH = 14'h0800; + parameter [2:0] CTL_TX_RETRANS_MULT = 3'h0; + parameter [1:0] CTL_TX_RETRANS_RAM_BANKS = 2'h3; + parameter MODE = "TRUE"; + parameter SIM_VERSION = "2.0"; + parameter TEST_MODE_PIN_CHAR = "FALSE"; + output [15:0] DRP_DO; + output DRP_RDY; + output [65:0] RX_BYPASS_DATAOUT00; + output [65:0] RX_BYPASS_DATAOUT01; + output [65:0] RX_BYPASS_DATAOUT02; + output [65:0] RX_BYPASS_DATAOUT03; + output [65:0] RX_BYPASS_DATAOUT04; + output [65:0] RX_BYPASS_DATAOUT05; + output [65:0] RX_BYPASS_DATAOUT06; + output [65:0] RX_BYPASS_DATAOUT07; + output [65:0] RX_BYPASS_DATAOUT08; + output [65:0] RX_BYPASS_DATAOUT09; + output [65:0] RX_BYPASS_DATAOUT10; + output [65:0] RX_BYPASS_DATAOUT11; + output [11:0] RX_BYPASS_ENAOUT; + output [11:0] RX_BYPASS_IS_AVAILOUT; + output [11:0] RX_BYPASS_IS_BADLYFRAMEDOUT; + output [11:0] RX_BYPASS_IS_OVERFLOWOUT; + output [11:0] RX_BYPASS_IS_SYNCEDOUT; + output [11:0] RX_BYPASS_IS_SYNCWORDOUT; + output [10:0] RX_CHANOUT0; + output [10:0] RX_CHANOUT1; + output [10:0] RX_CHANOUT2; + output [10:0] RX_CHANOUT3; + output [127:0] RX_DATAOUT0; + output [127:0] RX_DATAOUT1; + output [127:0] RX_DATAOUT2; + output [127:0] RX_DATAOUT3; + output RX_ENAOUT0; + output RX_ENAOUT1; + output RX_ENAOUT2; + output RX_ENAOUT3; + output RX_EOPOUT0; + output RX_EOPOUT1; + output RX_EOPOUT2; + output RX_EOPOUT3; + output RX_ERROUT0; + output RX_ERROUT1; + output RX_ERROUT2; + output RX_ERROUT3; + output [3:0] RX_MTYOUT0; + output [3:0] RX_MTYOUT1; + output [3:0] RX_MTYOUT2; + output [3:0] RX_MTYOUT3; + output RX_OVFOUT; + output RX_SOPOUT0; + output RX_SOPOUT1; + output RX_SOPOUT2; + output RX_SOPOUT3; + output STAT_RX_ALIGNED; + output STAT_RX_ALIGNED_ERR; + output [11:0] STAT_RX_BAD_TYPE_ERR; + output STAT_RX_BURSTMAX_ERR; + output STAT_RX_BURST_ERR; + output STAT_RX_CRC24_ERR; + output [11:0] STAT_RX_CRC32_ERR; + output [11:0] STAT_RX_CRC32_VALID; + output [11:0] STAT_RX_DESCRAM_ERR; + output [11:0] STAT_RX_DIAGWORD_INTFSTAT; + output [11:0] STAT_RX_DIAGWORD_LANESTAT; + output [255:0] STAT_RX_FC_STAT; + output [11:0] STAT_RX_FRAMING_ERR; + output STAT_RX_MEOP_ERR; + output [11:0] STAT_RX_MF_ERR; + output [11:0] STAT_RX_MF_LEN_ERR; + output [11:0] STAT_RX_MF_REPEAT_ERR; + output STAT_RX_MISALIGNED; + output STAT_RX_MSOP_ERR; + output [7:0] STAT_RX_MUBITS; + output STAT_RX_MUBITS_UPDATED; + output STAT_RX_OVERFLOW_ERR; + output STAT_RX_RETRANS_CRC24_ERR; + output STAT_RX_RETRANS_DISC; + output [15:0] STAT_RX_RETRANS_LATENCY; + output STAT_RX_RETRANS_REQ; + output STAT_RX_RETRANS_RETRY_ERR; + output [7:0] STAT_RX_RETRANS_SEQ; + output STAT_RX_RETRANS_SEQ_UPDATED; + output [2:0] STAT_RX_RETRANS_STATE; + output [4:0] STAT_RX_RETRANS_SUBSEQ; + output STAT_RX_RETRANS_WDOG_ERR; + output STAT_RX_RETRANS_WRAP_ERR; + output [11:0] STAT_RX_SYNCED; + output [11:0] STAT_RX_SYNCED_ERR; + output [11:0] STAT_RX_WORD_SYNC; + output STAT_TX_BURST_ERR; + output STAT_TX_ERRINJ_BITERR_DONE; + output STAT_TX_OVERFLOW_ERR; + output STAT_TX_RETRANS_BURST_ERR; + output STAT_TX_RETRANS_BUSY; + output STAT_TX_RETRANS_RAM_PERROUT; + output [8:0] STAT_TX_RETRANS_RAM_RADDR; + output STAT_TX_RETRANS_RAM_RD_B0; + output STAT_TX_RETRANS_RAM_RD_B1; + output STAT_TX_RETRANS_RAM_RD_B2; + output STAT_TX_RETRANS_RAM_RD_B3; + output [1:0] STAT_TX_RETRANS_RAM_RSEL; + output [8:0] STAT_TX_RETRANS_RAM_WADDR; + output [643:0] STAT_TX_RETRANS_RAM_WDATA; + output STAT_TX_RETRANS_RAM_WE_B0; + output STAT_TX_RETRANS_RAM_WE_B1; + output STAT_TX_RETRANS_RAM_WE_B2; + output STAT_TX_RETRANS_RAM_WE_B3; + output STAT_TX_UNDERFLOW_ERR; + output TX_OVFOUT; + output TX_RDYOUT; + output [63:0] TX_SERDES_DATA00; + output [63:0] TX_SERDES_DATA01; + output [63:0] TX_SERDES_DATA02; + output [63:0] TX_SERDES_DATA03; + output [63:0] TX_SERDES_DATA04; + output [63:0] TX_SERDES_DATA05; + output [63:0] TX_SERDES_DATA06; + output [63:0] TX_SERDES_DATA07; + output [63:0] TX_SERDES_DATA08; + output [63:0] TX_SERDES_DATA09; + output [63:0] TX_SERDES_DATA10; + output [63:0] TX_SERDES_DATA11; + input CORE_CLK; + input CTL_RX_FORCE_RESYNC; + input CTL_RX_RETRANS_ACK; + input CTL_RX_RETRANS_ENABLE; + input CTL_RX_RETRANS_ERRIN; + input CTL_RX_RETRANS_FORCE_REQ; + input CTL_RX_RETRANS_RESET; + input CTL_RX_RETRANS_RESET_MODE; + input CTL_TX_DIAGWORD_INTFSTAT; + input [11:0] CTL_TX_DIAGWORD_LANESTAT; + input CTL_TX_ENABLE; + input CTL_TX_ERRINJ_BITERR_GO; + input [3:0] CTL_TX_ERRINJ_BITERR_LANE; + input [255:0] CTL_TX_FC_STAT; + input [7:0] CTL_TX_MUBITS; + input CTL_TX_RETRANS_ENABLE; + input CTL_TX_RETRANS_RAM_PERRIN; + input [643:0] CTL_TX_RETRANS_RAM_RDATA; + input CTL_TX_RETRANS_REQ; + input CTL_TX_RETRANS_REQ_VALID; + input [11:0] CTL_TX_RLIM_DELTA; + input CTL_TX_RLIM_ENABLE; + input [7:0] CTL_TX_RLIM_INTV; + input [11:0] CTL_TX_RLIM_MAX; + input [9:0] DRP_ADDR; + input DRP_CLK; + input [15:0] DRP_DI; + input DRP_EN; + input DRP_WE; + input LBUS_CLK; + input RX_BYPASS_FORCE_REALIGNIN; + input RX_BYPASS_RDIN; + input RX_RESET; + input [11:0] RX_SERDES_CLK; + input [63:0] RX_SERDES_DATA00; + input [63:0] RX_SERDES_DATA01; + input [63:0] RX_SERDES_DATA02; + input [63:0] RX_SERDES_DATA03; + input [63:0] RX_SERDES_DATA04; + input [63:0] RX_SERDES_DATA05; + input [63:0] RX_SERDES_DATA06; + input [63:0] RX_SERDES_DATA07; + input [63:0] RX_SERDES_DATA08; + input [63:0] RX_SERDES_DATA09; + input [63:0] RX_SERDES_DATA10; + input [63:0] RX_SERDES_DATA11; + input [11:0] RX_SERDES_RESET; + input TX_BCTLIN0; + input TX_BCTLIN1; + input TX_BCTLIN2; + input TX_BCTLIN3; + input [11:0] TX_BYPASS_CTRLIN; + input [63:0] TX_BYPASS_DATAIN00; + input [63:0] TX_BYPASS_DATAIN01; + input [63:0] TX_BYPASS_DATAIN02; + input [63:0] TX_BYPASS_DATAIN03; + input [63:0] TX_BYPASS_DATAIN04; + input [63:0] TX_BYPASS_DATAIN05; + input [63:0] TX_BYPASS_DATAIN06; + input [63:0] TX_BYPASS_DATAIN07; + input [63:0] TX_BYPASS_DATAIN08; + input [63:0] TX_BYPASS_DATAIN09; + input [63:0] TX_BYPASS_DATAIN10; + input [63:0] TX_BYPASS_DATAIN11; + input TX_BYPASS_ENAIN; + input [7:0] TX_BYPASS_GEARBOX_SEQIN; + input [3:0] TX_BYPASS_MFRAMER_STATEIN; + input [10:0] TX_CHANIN0; + input [10:0] TX_CHANIN1; + input [10:0] TX_CHANIN2; + input [10:0] TX_CHANIN3; + input [127:0] TX_DATAIN0; + input [127:0] TX_DATAIN1; + input [127:0] TX_DATAIN2; + input [127:0] TX_DATAIN3; + input TX_ENAIN0; + input TX_ENAIN1; + input TX_ENAIN2; + input TX_ENAIN3; + input TX_EOPIN0; + input TX_EOPIN1; + input TX_EOPIN2; + input TX_EOPIN3; + input TX_ERRIN0; + input TX_ERRIN1; + input TX_ERRIN2; + input TX_ERRIN3; + input [3:0] TX_MTYIN0; + input [3:0] TX_MTYIN1; + input [3:0] TX_MTYIN2; + input [3:0] TX_MTYIN3; + input TX_RESET; + input TX_SERDES_REFCLK; + input TX_SERDES_REFCLK_RESET; + input TX_SOPIN0; + input TX_SOPIN1; + input TX_SOPIN2; + input TX_SOPIN3; +endmodule + +module ILKNE4 (...); + parameter BYPASS = "FALSE"; + parameter [1:0] CTL_RX_BURSTMAX = 2'h3; + parameter [1:0] CTL_RX_CHAN_EXT = 2'h0; + parameter [3:0] CTL_RX_LAST_LANE = 4'hB; + parameter [15:0] CTL_RX_MFRAMELEN_MINUS1 = 16'h07FF; + parameter CTL_RX_PACKET_MODE = "FALSE"; + parameter [2:0] CTL_RX_RETRANS_MULT = 3'h0; + parameter [3:0] CTL_RX_RETRANS_RETRY = 4'h2; + parameter [15:0] CTL_RX_RETRANS_TIMER1 = 16'h0009; + parameter [15:0] CTL_RX_RETRANS_TIMER2 = 16'h0000; + parameter [11:0] CTL_RX_RETRANS_WDOG = 12'h000; + parameter [7:0] CTL_RX_RETRANS_WRAP_TIMER = 8'h00; + parameter CTL_TEST_MODE_PIN_CHAR = "FALSE"; + parameter [1:0] CTL_TX_BURSTMAX = 2'h3; + parameter [2:0] CTL_TX_BURSTSHORT = 3'h1; + parameter [1:0] CTL_TX_CHAN_EXT = 2'h0; + parameter CTL_TX_DISABLE_SKIPWORD = "FALSE"; + parameter [3:0] CTL_TX_FC_CALLEN = 4'hF; + parameter [3:0] CTL_TX_LAST_LANE = 4'hB; + parameter [15:0] CTL_TX_MFRAMELEN_MINUS1 = 16'h07FF; + parameter [13:0] CTL_TX_RETRANS_DEPTH = 14'h0800; + parameter [2:0] CTL_TX_RETRANS_MULT = 3'h0; + parameter [1:0] CTL_TX_RETRANS_RAM_BANKS = 2'h3; + parameter MODE = "TRUE"; + parameter SIM_DEVICE = "ULTRASCALE_PLUS"; + parameter TEST_MODE_PIN_CHAR = "FALSE"; + output [15:0] DRP_DO; + output DRP_RDY; + output [65:0] RX_BYPASS_DATAOUT00; + output [65:0] RX_BYPASS_DATAOUT01; + output [65:0] RX_BYPASS_DATAOUT02; + output [65:0] RX_BYPASS_DATAOUT03; + output [65:0] RX_BYPASS_DATAOUT04; + output [65:0] RX_BYPASS_DATAOUT05; + output [65:0] RX_BYPASS_DATAOUT06; + output [65:0] RX_BYPASS_DATAOUT07; + output [65:0] RX_BYPASS_DATAOUT08; + output [65:0] RX_BYPASS_DATAOUT09; + output [65:0] RX_BYPASS_DATAOUT10; + output [65:0] RX_BYPASS_DATAOUT11; + output [11:0] RX_BYPASS_ENAOUT; + output [11:0] RX_BYPASS_IS_AVAILOUT; + output [11:0] RX_BYPASS_IS_BADLYFRAMEDOUT; + output [11:0] RX_BYPASS_IS_OVERFLOWOUT; + output [11:0] RX_BYPASS_IS_SYNCEDOUT; + output [11:0] RX_BYPASS_IS_SYNCWORDOUT; + output [10:0] RX_CHANOUT0; + output [10:0] RX_CHANOUT1; + output [10:0] RX_CHANOUT2; + output [10:0] RX_CHANOUT3; + output [127:0] RX_DATAOUT0; + output [127:0] RX_DATAOUT1; + output [127:0] RX_DATAOUT2; + output [127:0] RX_DATAOUT3; + output RX_ENAOUT0; + output RX_ENAOUT1; + output RX_ENAOUT2; + output RX_ENAOUT3; + output RX_EOPOUT0; + output RX_EOPOUT1; + output RX_EOPOUT2; + output RX_EOPOUT3; + output RX_ERROUT0; + output RX_ERROUT1; + output RX_ERROUT2; + output RX_ERROUT3; + output [3:0] RX_MTYOUT0; + output [3:0] RX_MTYOUT1; + output [3:0] RX_MTYOUT2; + output [3:0] RX_MTYOUT3; + output RX_OVFOUT; + output RX_SOPOUT0; + output RX_SOPOUT1; + output RX_SOPOUT2; + output RX_SOPOUT3; + output STAT_RX_ALIGNED; + output STAT_RX_ALIGNED_ERR; + output [11:0] STAT_RX_BAD_TYPE_ERR; + output STAT_RX_BURSTMAX_ERR; + output STAT_RX_BURST_ERR; + output STAT_RX_CRC24_ERR; + output [11:0] STAT_RX_CRC32_ERR; + output [11:0] STAT_RX_CRC32_VALID; + output [11:0] STAT_RX_DESCRAM_ERR; + output [11:0] STAT_RX_DIAGWORD_INTFSTAT; + output [11:0] STAT_RX_DIAGWORD_LANESTAT; + output [255:0] STAT_RX_FC_STAT; + output [11:0] STAT_RX_FRAMING_ERR; + output STAT_RX_MEOP_ERR; + output [11:0] STAT_RX_MF_ERR; + output [11:0] STAT_RX_MF_LEN_ERR; + output [11:0] STAT_RX_MF_REPEAT_ERR; + output STAT_RX_MISALIGNED; + output STAT_RX_MSOP_ERR; + output [7:0] STAT_RX_MUBITS; + output STAT_RX_MUBITS_UPDATED; + output STAT_RX_OVERFLOW_ERR; + output STAT_RX_RETRANS_CRC24_ERR; + output STAT_RX_RETRANS_DISC; + output [15:0] STAT_RX_RETRANS_LATENCY; + output STAT_RX_RETRANS_REQ; + output STAT_RX_RETRANS_RETRY_ERR; + output [7:0] STAT_RX_RETRANS_SEQ; + output STAT_RX_RETRANS_SEQ_UPDATED; + output [2:0] STAT_RX_RETRANS_STATE; + output [4:0] STAT_RX_RETRANS_SUBSEQ; + output STAT_RX_RETRANS_WDOG_ERR; + output STAT_RX_RETRANS_WRAP_ERR; + output [11:0] STAT_RX_SYNCED; + output [11:0] STAT_RX_SYNCED_ERR; + output [11:0] STAT_RX_WORD_SYNC; + output STAT_TX_BURST_ERR; + output STAT_TX_ERRINJ_BITERR_DONE; + output STAT_TX_OVERFLOW_ERR; + output STAT_TX_RETRANS_BURST_ERR; + output STAT_TX_RETRANS_BUSY; + output STAT_TX_RETRANS_RAM_PERROUT; + output [8:0] STAT_TX_RETRANS_RAM_RADDR; + output STAT_TX_RETRANS_RAM_RD_B0; + output STAT_TX_RETRANS_RAM_RD_B1; + output STAT_TX_RETRANS_RAM_RD_B2; + output STAT_TX_RETRANS_RAM_RD_B3; + output [1:0] STAT_TX_RETRANS_RAM_RSEL; + output [8:0] STAT_TX_RETRANS_RAM_WADDR; + output [643:0] STAT_TX_RETRANS_RAM_WDATA; + output STAT_TX_RETRANS_RAM_WE_B0; + output STAT_TX_RETRANS_RAM_WE_B1; + output STAT_TX_RETRANS_RAM_WE_B2; + output STAT_TX_RETRANS_RAM_WE_B3; + output STAT_TX_UNDERFLOW_ERR; + output TX_OVFOUT; + output TX_RDYOUT; + output [63:0] TX_SERDES_DATA00; + output [63:0] TX_SERDES_DATA01; + output [63:0] TX_SERDES_DATA02; + output [63:0] TX_SERDES_DATA03; + output [63:0] TX_SERDES_DATA04; + output [63:0] TX_SERDES_DATA05; + output [63:0] TX_SERDES_DATA06; + output [63:0] TX_SERDES_DATA07; + output [63:0] TX_SERDES_DATA08; + output [63:0] TX_SERDES_DATA09; + output [63:0] TX_SERDES_DATA10; + output [63:0] TX_SERDES_DATA11; + input CORE_CLK; + input CTL_RX_FORCE_RESYNC; + input CTL_RX_RETRANS_ACK; + input CTL_RX_RETRANS_ENABLE; + input CTL_RX_RETRANS_ERRIN; + input CTL_RX_RETRANS_FORCE_REQ; + input CTL_RX_RETRANS_RESET; + input CTL_RX_RETRANS_RESET_MODE; + input CTL_TX_DIAGWORD_INTFSTAT; + input [11:0] CTL_TX_DIAGWORD_LANESTAT; + input CTL_TX_ENABLE; + input CTL_TX_ERRINJ_BITERR_GO; + input [3:0] CTL_TX_ERRINJ_BITERR_LANE; + input [255:0] CTL_TX_FC_STAT; + input [7:0] CTL_TX_MUBITS; + input CTL_TX_RETRANS_ENABLE; + input CTL_TX_RETRANS_RAM_PERRIN; + input [643:0] CTL_TX_RETRANS_RAM_RDATA; + input CTL_TX_RETRANS_REQ; + input CTL_TX_RETRANS_REQ_VALID; + input [11:0] CTL_TX_RLIM_DELTA; + input CTL_TX_RLIM_ENABLE; + input [7:0] CTL_TX_RLIM_INTV; + input [11:0] CTL_TX_RLIM_MAX; + input [9:0] DRP_ADDR; + input DRP_CLK; + input [15:0] DRP_DI; + input DRP_EN; + input DRP_WE; + input LBUS_CLK; + input RX_BYPASS_FORCE_REALIGNIN; + input RX_BYPASS_RDIN; + input RX_RESET; + input [11:0] RX_SERDES_CLK; + input [63:0] RX_SERDES_DATA00; + input [63:0] RX_SERDES_DATA01; + input [63:0] RX_SERDES_DATA02; + input [63:0] RX_SERDES_DATA03; + input [63:0] RX_SERDES_DATA04; + input [63:0] RX_SERDES_DATA05; + input [63:0] RX_SERDES_DATA06; + input [63:0] RX_SERDES_DATA07; + input [63:0] RX_SERDES_DATA08; + input [63:0] RX_SERDES_DATA09; + input [63:0] RX_SERDES_DATA10; + input [63:0] RX_SERDES_DATA11; + input [11:0] RX_SERDES_RESET; + input TX_BCTLIN0; + input TX_BCTLIN1; + input TX_BCTLIN2; + input TX_BCTLIN3; + input [11:0] TX_BYPASS_CTRLIN; + input [63:0] TX_BYPASS_DATAIN00; + input [63:0] TX_BYPASS_DATAIN01; + input [63:0] TX_BYPASS_DATAIN02; + input [63:0] TX_BYPASS_DATAIN03; + input [63:0] TX_BYPASS_DATAIN04; + input [63:0] TX_BYPASS_DATAIN05; + input [63:0] TX_BYPASS_DATAIN06; + input [63:0] TX_BYPASS_DATAIN07; + input [63:0] TX_BYPASS_DATAIN08; + input [63:0] TX_BYPASS_DATAIN09; + input [63:0] TX_BYPASS_DATAIN10; + input [63:0] TX_BYPASS_DATAIN11; + input TX_BYPASS_ENAIN; + input [7:0] TX_BYPASS_GEARBOX_SEQIN; + input [3:0] TX_BYPASS_MFRAMER_STATEIN; + input [10:0] TX_CHANIN0; + input [10:0] TX_CHANIN1; + input [10:0] TX_CHANIN2; + input [10:0] TX_CHANIN3; + input [127:0] TX_DATAIN0; + input [127:0] TX_DATAIN1; + input [127:0] TX_DATAIN2; + input [127:0] TX_DATAIN3; + input TX_ENAIN0; + input TX_ENAIN1; + input TX_ENAIN2; + input TX_ENAIN3; + input TX_EOPIN0; + input TX_EOPIN1; + input TX_EOPIN2; + input TX_EOPIN3; + input TX_ERRIN0; + input TX_ERRIN1; + input TX_ERRIN2; + input TX_ERRIN3; + input [3:0] TX_MTYIN0; + input [3:0] TX_MTYIN1; + input [3:0] TX_MTYIN2; + input [3:0] TX_MTYIN3; + input TX_RESET; + input TX_SERDES_REFCLK; + input TX_SERDES_REFCLK_RESET; + input TX_SOPIN0; + input TX_SOPIN1; + input TX_SOPIN2; + input TX_SOPIN3; +endmodule + +module OBUFDS_GTE3 (...); + parameter [0:0] REFCLK_EN_TX_PATH = 1'b0; + parameter [4:0] REFCLK_ICNTL_TX = 5'b00000; + (* iopad_external_pin *) + output O; + (* iopad_external_pin *) + output OB; + input CEB; + input I; +endmodule + +module OBUFDS_GTE3_ADV (...); + parameter [0:0] REFCLK_EN_TX_PATH = 1'b0; + parameter [4:0] REFCLK_ICNTL_TX = 5'b00000; + (* iopad_external_pin *) + output O; + (* iopad_external_pin *) + output OB; + input CEB; + input [3:0] I; + input [1:0] RXRECCLK_SEL; +endmodule + +module OBUFDS_GTE4 (...); + parameter [0:0] REFCLK_EN_TX_PATH = 1'b0; + parameter [4:0] REFCLK_ICNTL_TX = 5'b00000; + (* iopad_external_pin *) + output O; + (* iopad_external_pin *) + output OB; + input CEB; + input I; +endmodule + +module OBUFDS_GTE4_ADV (...); + parameter [0:0] REFCLK_EN_TX_PATH = 1'b0; + parameter [4:0] REFCLK_ICNTL_TX = 5'b00000; + (* iopad_external_pin *) + output O; + (* iopad_external_pin *) + output OB; + input CEB; + input [3:0] I; + input [1:0] RXRECCLK_SEL; +endmodule + +module PCIE40E4 (...); + parameter ARI_CAP_ENABLE = "FALSE"; + parameter AUTO_FLR_RESPONSE = "FALSE"; + parameter [1:0] AXISTEN_IF_CC_ALIGNMENT_MODE = 2'h0; + parameter [23:0] AXISTEN_IF_COMPL_TIMEOUT_REG0 = 24'hBEBC20; + parameter [27:0] AXISTEN_IF_COMPL_TIMEOUT_REG1 = 28'h2FAF080; + parameter [1:0] AXISTEN_IF_CQ_ALIGNMENT_MODE = 2'h0; + parameter AXISTEN_IF_CQ_EN_POISONED_MEM_WR = "FALSE"; + parameter AXISTEN_IF_ENABLE_256_TAGS = "FALSE"; + parameter AXISTEN_IF_ENABLE_CLIENT_TAG = "FALSE"; + parameter AXISTEN_IF_ENABLE_INTERNAL_MSIX_TABLE = "FALSE"; + parameter AXISTEN_IF_ENABLE_MESSAGE_RID_CHECK = "TRUE"; + parameter [17:0] AXISTEN_IF_ENABLE_MSG_ROUTE = 18'h00000; + parameter AXISTEN_IF_ENABLE_RX_MSG_INTFC = "FALSE"; + parameter AXISTEN_IF_EXT_512 = "FALSE"; + parameter AXISTEN_IF_EXT_512_CC_STRADDLE = "FALSE"; + parameter AXISTEN_IF_EXT_512_CQ_STRADDLE = "FALSE"; + parameter AXISTEN_IF_EXT_512_RC_STRADDLE = "FALSE"; + parameter AXISTEN_IF_EXT_512_RQ_STRADDLE = "FALSE"; + parameter AXISTEN_IF_LEGACY_MODE_ENABLE = "FALSE"; + parameter AXISTEN_IF_MSIX_FROM_RAM_PIPELINE = "FALSE"; + parameter AXISTEN_IF_MSIX_RX_PARITY_EN = "TRUE"; + parameter AXISTEN_IF_MSIX_TO_RAM_PIPELINE = "FALSE"; + parameter [1:0] AXISTEN_IF_RC_ALIGNMENT_MODE = 2'h0; + parameter AXISTEN_IF_RC_STRADDLE = "FALSE"; + parameter [1:0] AXISTEN_IF_RQ_ALIGNMENT_MODE = 2'h0; + parameter AXISTEN_IF_RX_PARITY_EN = "TRUE"; + parameter AXISTEN_IF_SIM_SHORT_CPL_TIMEOUT = "FALSE"; + parameter AXISTEN_IF_TX_PARITY_EN = "TRUE"; + parameter [1:0] AXISTEN_IF_WIDTH = 2'h2; + parameter CFG_BYPASS_MODE_ENABLE = "FALSE"; + parameter CRM_CORE_CLK_FREQ_500 = "TRUE"; + parameter [1:0] CRM_USER_CLK_FREQ = 2'h2; + parameter [15:0] DEBUG_AXI4ST_SPARE = 16'h0000; + parameter [7:0] DEBUG_AXIST_DISABLE_FEATURE_BIT = 8'h00; + parameter [3:0] DEBUG_CAR_SPARE = 4'h0; + parameter [15:0] DEBUG_CFG_SPARE = 16'h0000; + parameter [15:0] DEBUG_LL_SPARE = 16'h0000; + parameter DEBUG_PL_DISABLE_LES_UPDATE_ON_DEFRAMER_ERROR = "FALSE"; + parameter DEBUG_PL_DISABLE_LES_UPDATE_ON_SKP_ERROR = "FALSE"; + parameter DEBUG_PL_DISABLE_LES_UPDATE_ON_SKP_PARITY_ERROR = "FALSE"; + parameter DEBUG_PL_DISABLE_REC_ENTRY_ON_DYNAMIC_DSKEW_FAIL = "FALSE"; + parameter DEBUG_PL_DISABLE_REC_ENTRY_ON_RX_BUFFER_UNDER_OVER_FLOW = "FALSE"; + parameter DEBUG_PL_DISABLE_SCRAMBLING = "FALSE"; + parameter DEBUG_PL_SIM_RESET_LFSR = "FALSE"; + parameter [15:0] DEBUG_PL_SPARE = 16'h0000; + parameter DEBUG_TL_DISABLE_FC_TIMEOUT = "FALSE"; + parameter DEBUG_TL_DISABLE_RX_TLP_ORDER_CHECKS = "FALSE"; + parameter [15:0] DEBUG_TL_SPARE = 16'h0000; + parameter [7:0] DNSTREAM_LINK_NUM = 8'h00; + parameter DSN_CAP_ENABLE = "FALSE"; + parameter EXTENDED_CFG_EXTEND_INTERFACE_ENABLE = "FALSE"; + parameter HEADER_TYPE_OVERRIDE = "FALSE"; + parameter IS_SWITCH_PORT = "FALSE"; + parameter LEGACY_CFG_EXTEND_INTERFACE_ENABLE = "FALSE"; + parameter [8:0] LL_ACK_TIMEOUT = 9'h000; + parameter LL_ACK_TIMEOUT_EN = "FALSE"; + parameter integer LL_ACK_TIMEOUT_FUNC = 0; + parameter LL_DISABLE_SCHED_TX_NAK = "FALSE"; + parameter LL_REPLAY_FROM_RAM_PIPELINE = "FALSE"; + parameter [8:0] LL_REPLAY_TIMEOUT = 9'h000; + parameter LL_REPLAY_TIMEOUT_EN = "FALSE"; + parameter integer LL_REPLAY_TIMEOUT_FUNC = 0; + parameter LL_REPLAY_TO_RAM_PIPELINE = "FALSE"; + parameter LL_RX_TLP_PARITY_GEN = "TRUE"; + parameter LL_TX_TLP_PARITY_CHK = "TRUE"; + parameter [15:0] LL_USER_SPARE = 16'h0000; + parameter [9:0] LTR_TX_MESSAGE_MINIMUM_INTERVAL = 10'h250; + parameter LTR_TX_MESSAGE_ON_FUNC_POWER_STATE_CHANGE = "FALSE"; + parameter LTR_TX_MESSAGE_ON_LTR_ENABLE = "FALSE"; + parameter [11:0] MCAP_CAP_NEXTPTR = 12'h000; + parameter MCAP_CONFIGURE_OVERRIDE = "FALSE"; + parameter MCAP_ENABLE = "FALSE"; + parameter MCAP_EOS_DESIGN_SWITCH = "FALSE"; + parameter [31:0] MCAP_FPGA_BITSTREAM_VERSION = 32'h00000000; + parameter MCAP_GATE_IO_ENABLE_DESIGN_SWITCH = "FALSE"; + parameter MCAP_GATE_MEM_ENABLE_DESIGN_SWITCH = "FALSE"; + parameter MCAP_INPUT_GATE_DESIGN_SWITCH = "FALSE"; + parameter MCAP_INTERRUPT_ON_MCAP_EOS = "FALSE"; + parameter MCAP_INTERRUPT_ON_MCAP_ERROR = "FALSE"; + parameter [15:0] MCAP_VSEC_ID = 16'h0000; + parameter [11:0] MCAP_VSEC_LEN = 12'h02C; + parameter [3:0] MCAP_VSEC_REV = 4'h0; + parameter PF0_AER_CAP_ECRC_GEN_AND_CHECK_CAPABLE = "FALSE"; + parameter [11:0] PF0_AER_CAP_NEXTPTR = 12'h000; + parameter [11:0] PF0_ARI_CAP_NEXTPTR = 12'h000; + parameter [7:0] PF0_ARI_CAP_NEXT_FUNC = 8'h00; + parameter [3:0] PF0_ARI_CAP_VER = 4'h1; + parameter [5:0] PF0_BAR0_APERTURE_SIZE = 6'h03; + parameter [2:0] PF0_BAR0_CONTROL = 3'h4; + parameter [4:0] PF0_BAR1_APERTURE_SIZE = 5'h00; + parameter [2:0] PF0_BAR1_CONTROL = 3'h0; + parameter [5:0] PF0_BAR2_APERTURE_SIZE = 6'h03; + parameter [2:0] PF0_BAR2_CONTROL = 3'h4; + parameter [4:0] PF0_BAR3_APERTURE_SIZE = 5'h03; + parameter [2:0] PF0_BAR3_CONTROL = 3'h0; + parameter [5:0] PF0_BAR4_APERTURE_SIZE = 6'h03; + parameter [2:0] PF0_BAR4_CONTROL = 3'h4; + parameter [4:0] PF0_BAR5_APERTURE_SIZE = 5'h03; + parameter [2:0] PF0_BAR5_CONTROL = 3'h0; + parameter [7:0] PF0_CAPABILITY_POINTER = 8'h80; + parameter [23:0] PF0_CLASS_CODE = 24'h000000; + parameter PF0_DEV_CAP2_128B_CAS_ATOMIC_COMPLETER_SUPPORT = "TRUE"; + parameter PF0_DEV_CAP2_32B_ATOMIC_COMPLETER_SUPPORT = "TRUE"; + parameter PF0_DEV_CAP2_64B_ATOMIC_COMPLETER_SUPPORT = "TRUE"; + parameter PF0_DEV_CAP2_ARI_FORWARD_ENABLE = "FALSE"; + parameter PF0_DEV_CAP2_CPL_TIMEOUT_DISABLE = "TRUE"; + parameter PF0_DEV_CAP2_LTR_SUPPORT = "TRUE"; + parameter [1:0] PF0_DEV_CAP2_OBFF_SUPPORT = 2'h0; + parameter PF0_DEV_CAP2_TPH_COMPLETER_SUPPORT = "FALSE"; + parameter integer PF0_DEV_CAP_ENDPOINT_L0S_LATENCY = 0; + parameter integer PF0_DEV_CAP_ENDPOINT_L1_LATENCY = 0; + parameter PF0_DEV_CAP_EXT_TAG_SUPPORTED = "TRUE"; + parameter PF0_DEV_CAP_FUNCTION_LEVEL_RESET_CAPABLE = "TRUE"; + parameter [2:0] PF0_DEV_CAP_MAX_PAYLOAD_SIZE = 3'h3; + parameter [11:0] PF0_DSN_CAP_NEXTPTR = 12'h10C; + parameter [4:0] PF0_EXPANSION_ROM_APERTURE_SIZE = 5'h03; + parameter PF0_EXPANSION_ROM_ENABLE = "FALSE"; + parameter [2:0] PF0_INTERRUPT_PIN = 3'h1; + parameter integer PF0_LINK_CAP_ASPM_SUPPORT = 0; + parameter integer PF0_LINK_CAP_L0S_EXIT_LATENCY_COMCLK_GEN1 = 7; + parameter integer PF0_LINK_CAP_L0S_EXIT_LATENCY_COMCLK_GEN2 = 7; + parameter integer PF0_LINK_CAP_L0S_EXIT_LATENCY_COMCLK_GEN3 = 7; + parameter integer PF0_LINK_CAP_L0S_EXIT_LATENCY_COMCLK_GEN4 = 7; + parameter integer PF0_LINK_CAP_L0S_EXIT_LATENCY_GEN1 = 7; + parameter integer PF0_LINK_CAP_L0S_EXIT_LATENCY_GEN2 = 7; + parameter integer PF0_LINK_CAP_L0S_EXIT_LATENCY_GEN3 = 7; + parameter integer PF0_LINK_CAP_L0S_EXIT_LATENCY_GEN4 = 7; + parameter integer PF0_LINK_CAP_L1_EXIT_LATENCY_COMCLK_GEN1 = 7; + parameter integer PF0_LINK_CAP_L1_EXIT_LATENCY_COMCLK_GEN2 = 7; + parameter integer PF0_LINK_CAP_L1_EXIT_LATENCY_COMCLK_GEN3 = 7; + parameter integer PF0_LINK_CAP_L1_EXIT_LATENCY_COMCLK_GEN4 = 7; + parameter integer PF0_LINK_CAP_L1_EXIT_LATENCY_GEN1 = 7; + parameter integer PF0_LINK_CAP_L1_EXIT_LATENCY_GEN2 = 7; + parameter integer PF0_LINK_CAP_L1_EXIT_LATENCY_GEN3 = 7; + parameter integer PF0_LINK_CAP_L1_EXIT_LATENCY_GEN4 = 7; + parameter [0:0] PF0_LINK_CONTROL_RCB = 1'h0; + parameter PF0_LINK_STATUS_SLOT_CLOCK_CONFIG = "TRUE"; + parameter [9:0] PF0_LTR_CAP_MAX_NOSNOOP_LAT = 10'h000; + parameter [9:0] PF0_LTR_CAP_MAX_SNOOP_LAT = 10'h000; + parameter [11:0] PF0_LTR_CAP_NEXTPTR = 12'h000; + parameter [3:0] PF0_LTR_CAP_VER = 4'h1; + parameter [7:0] PF0_MSIX_CAP_NEXTPTR = 8'h00; + parameter integer PF0_MSIX_CAP_PBA_BIR = 0; + parameter [28:0] PF0_MSIX_CAP_PBA_OFFSET = 29'h00000050; + parameter integer PF0_MSIX_CAP_TABLE_BIR = 0; + parameter [28:0] PF0_MSIX_CAP_TABLE_OFFSET = 29'h00000040; + parameter [10:0] PF0_MSIX_CAP_TABLE_SIZE = 11'h000; + parameter [5:0] PF0_MSIX_VECTOR_COUNT = 6'h04; + parameter integer PF0_MSI_CAP_MULTIMSGCAP = 0; + parameter [7:0] PF0_MSI_CAP_NEXTPTR = 8'h00; + parameter PF0_MSI_CAP_PERVECMASKCAP = "FALSE"; + parameter [7:0] PF0_PCIE_CAP_NEXTPTR = 8'h00; + parameter [7:0] PF0_PM_CAP_ID = 8'h01; + parameter [7:0] PF0_PM_CAP_NEXTPTR = 8'h00; + parameter PF0_PM_CAP_PMESUPPORT_D0 = "TRUE"; + parameter PF0_PM_CAP_PMESUPPORT_D1 = "TRUE"; + parameter PF0_PM_CAP_PMESUPPORT_D3HOT = "TRUE"; + parameter PF0_PM_CAP_SUPP_D1_STATE = "TRUE"; + parameter [2:0] PF0_PM_CAP_VER_ID = 3'h3; + parameter PF0_PM_CSR_NOSOFTRESET = "TRUE"; + parameter [11:0] PF0_SECONDARY_PCIE_CAP_NEXTPTR = 12'h000; + parameter PF0_SRIOV_ARI_CAPBL_HIER_PRESERVED = "FALSE"; + parameter [5:0] PF0_SRIOV_BAR0_APERTURE_SIZE = 6'h03; + parameter [2:0] PF0_SRIOV_BAR0_CONTROL = 3'h4; + parameter [4:0] PF0_SRIOV_BAR1_APERTURE_SIZE = 5'h00; + parameter [2:0] PF0_SRIOV_BAR1_CONTROL = 3'h0; + parameter [5:0] PF0_SRIOV_BAR2_APERTURE_SIZE = 6'h03; + parameter [2:0] PF0_SRIOV_BAR2_CONTROL = 3'h4; + parameter [4:0] PF0_SRIOV_BAR3_APERTURE_SIZE = 5'h03; + parameter [2:0] PF0_SRIOV_BAR3_CONTROL = 3'h0; + parameter [5:0] PF0_SRIOV_BAR4_APERTURE_SIZE = 6'h03; + parameter [2:0] PF0_SRIOV_BAR4_CONTROL = 3'h4; + parameter [4:0] PF0_SRIOV_BAR5_APERTURE_SIZE = 5'h03; + parameter [2:0] PF0_SRIOV_BAR5_CONTROL = 3'h0; + parameter [15:0] PF0_SRIOV_CAP_INITIAL_VF = 16'h0000; + parameter [11:0] PF0_SRIOV_CAP_NEXTPTR = 12'h000; + parameter [15:0] PF0_SRIOV_CAP_TOTAL_VF = 16'h0000; + parameter [3:0] PF0_SRIOV_CAP_VER = 4'h1; + parameter [15:0] PF0_SRIOV_FIRST_VF_OFFSET = 16'h0000; + parameter [15:0] PF0_SRIOV_FUNC_DEP_LINK = 16'h0000; + parameter [31:0] PF0_SRIOV_SUPPORTED_PAGE_SIZE = 32'h00000000; + parameter [15:0] PF0_SRIOV_VF_DEVICE_ID = 16'h0000; + parameter PF0_TPHR_CAP_DEV_SPECIFIC_MODE = "TRUE"; + parameter PF0_TPHR_CAP_ENABLE = "FALSE"; + parameter PF0_TPHR_CAP_INT_VEC_MODE = "TRUE"; + parameter [11:0] PF0_TPHR_CAP_NEXTPTR = 12'h000; + parameter [2:0] PF0_TPHR_CAP_ST_MODE_SEL = 3'h0; + parameter [1:0] PF0_TPHR_CAP_ST_TABLE_LOC = 2'h0; + parameter [10:0] PF0_TPHR_CAP_ST_TABLE_SIZE = 11'h000; + parameter [3:0] PF0_TPHR_CAP_VER = 4'h1; + parameter PF0_VC_CAP_ENABLE = "FALSE"; + parameter [11:0] PF0_VC_CAP_NEXTPTR = 12'h000; + parameter [3:0] PF0_VC_CAP_VER = 4'h1; + parameter [11:0] PF1_AER_CAP_NEXTPTR = 12'h000; + parameter [11:0] PF1_ARI_CAP_NEXTPTR = 12'h000; + parameter [7:0] PF1_ARI_CAP_NEXT_FUNC = 8'h00; + parameter [5:0] PF1_BAR0_APERTURE_SIZE = 6'h03; + parameter [2:0] PF1_BAR0_CONTROL = 3'h4; + parameter [4:0] PF1_BAR1_APERTURE_SIZE = 5'h00; + parameter [2:0] PF1_BAR1_CONTROL = 3'h0; + parameter [5:0] PF1_BAR2_APERTURE_SIZE = 6'h03; + parameter [2:0] PF1_BAR2_CONTROL = 3'h4; + parameter [4:0] PF1_BAR3_APERTURE_SIZE = 5'h03; + parameter [2:0] PF1_BAR3_CONTROL = 3'h0; + parameter [5:0] PF1_BAR4_APERTURE_SIZE = 6'h03; + parameter [2:0] PF1_BAR4_CONTROL = 3'h4; + parameter [4:0] PF1_BAR5_APERTURE_SIZE = 5'h03; + parameter [2:0] PF1_BAR5_CONTROL = 3'h0; + parameter [7:0] PF1_CAPABILITY_POINTER = 8'h80; + parameter [23:0] PF1_CLASS_CODE = 24'h000000; + parameter [2:0] PF1_DEV_CAP_MAX_PAYLOAD_SIZE = 3'h3; + parameter [11:0] PF1_DSN_CAP_NEXTPTR = 12'h10C; + parameter [4:0] PF1_EXPANSION_ROM_APERTURE_SIZE = 5'h03; + parameter PF1_EXPANSION_ROM_ENABLE = "FALSE"; + parameter [2:0] PF1_INTERRUPT_PIN = 3'h1; + parameter [7:0] PF1_MSIX_CAP_NEXTPTR = 8'h00; + parameter integer PF1_MSIX_CAP_PBA_BIR = 0; + parameter [28:0] PF1_MSIX_CAP_PBA_OFFSET = 29'h00000050; + parameter integer PF1_MSIX_CAP_TABLE_BIR = 0; + parameter [28:0] PF1_MSIX_CAP_TABLE_OFFSET = 29'h00000040; + parameter [10:0] PF1_MSIX_CAP_TABLE_SIZE = 11'h000; + parameter integer PF1_MSI_CAP_MULTIMSGCAP = 0; + parameter [7:0] PF1_MSI_CAP_NEXTPTR = 8'h00; + parameter PF1_MSI_CAP_PERVECMASKCAP = "FALSE"; + parameter [7:0] PF1_PCIE_CAP_NEXTPTR = 8'h00; + parameter [7:0] PF1_PM_CAP_NEXTPTR = 8'h00; + parameter PF1_SRIOV_ARI_CAPBL_HIER_PRESERVED = "FALSE"; + parameter [5:0] PF1_SRIOV_BAR0_APERTURE_SIZE = 6'h03; + parameter [2:0] PF1_SRIOV_BAR0_CONTROL = 3'h4; + parameter [4:0] PF1_SRIOV_BAR1_APERTURE_SIZE = 5'h00; + parameter [2:0] PF1_SRIOV_BAR1_CONTROL = 3'h0; + parameter [5:0] PF1_SRIOV_BAR2_APERTURE_SIZE = 6'h03; + parameter [2:0] PF1_SRIOV_BAR2_CONTROL = 3'h4; + parameter [4:0] PF1_SRIOV_BAR3_APERTURE_SIZE = 5'h03; + parameter [2:0] PF1_SRIOV_BAR3_CONTROL = 3'h0; + parameter [5:0] PF1_SRIOV_BAR4_APERTURE_SIZE = 6'h03; + parameter [2:0] PF1_SRIOV_BAR4_CONTROL = 3'h4; + parameter [4:0] PF1_SRIOV_BAR5_APERTURE_SIZE = 5'h03; + parameter [2:0] PF1_SRIOV_BAR5_CONTROL = 3'h0; + parameter [15:0] PF1_SRIOV_CAP_INITIAL_VF = 16'h0000; + parameter [11:0] PF1_SRIOV_CAP_NEXTPTR = 12'h000; + parameter [15:0] PF1_SRIOV_CAP_TOTAL_VF = 16'h0000; + parameter [3:0] PF1_SRIOV_CAP_VER = 4'h1; + parameter [15:0] PF1_SRIOV_FIRST_VF_OFFSET = 16'h0000; + parameter [15:0] PF1_SRIOV_FUNC_DEP_LINK = 16'h0000; + parameter [31:0] PF1_SRIOV_SUPPORTED_PAGE_SIZE = 32'h00000000; + parameter [15:0] PF1_SRIOV_VF_DEVICE_ID = 16'h0000; + parameter [11:0] PF1_TPHR_CAP_NEXTPTR = 12'h000; + parameter [2:0] PF1_TPHR_CAP_ST_MODE_SEL = 3'h0; + parameter [11:0] PF2_AER_CAP_NEXTPTR = 12'h000; + parameter [11:0] PF2_ARI_CAP_NEXTPTR = 12'h000; + parameter [7:0] PF2_ARI_CAP_NEXT_FUNC = 8'h00; + parameter [5:0] PF2_BAR0_APERTURE_SIZE = 6'h03; + parameter [2:0] PF2_BAR0_CONTROL = 3'h4; + parameter [4:0] PF2_BAR1_APERTURE_SIZE = 5'h00; + parameter [2:0] PF2_BAR1_CONTROL = 3'h0; + parameter [5:0] PF2_BAR2_APERTURE_SIZE = 6'h03; + parameter [2:0] PF2_BAR2_CONTROL = 3'h4; + parameter [4:0] PF2_BAR3_APERTURE_SIZE = 5'h03; + parameter [2:0] PF2_BAR3_CONTROL = 3'h0; + parameter [5:0] PF2_BAR4_APERTURE_SIZE = 6'h03; + parameter [2:0] PF2_BAR4_CONTROL = 3'h4; + parameter [4:0] PF2_BAR5_APERTURE_SIZE = 5'h03; + parameter [2:0] PF2_BAR5_CONTROL = 3'h0; + parameter [7:0] PF2_CAPABILITY_POINTER = 8'h80; + parameter [23:0] PF2_CLASS_CODE = 24'h000000; + parameter [2:0] PF2_DEV_CAP_MAX_PAYLOAD_SIZE = 3'h3; + parameter [11:0] PF2_DSN_CAP_NEXTPTR = 12'h10C; + parameter [4:0] PF2_EXPANSION_ROM_APERTURE_SIZE = 5'h03; + parameter PF2_EXPANSION_ROM_ENABLE = "FALSE"; + parameter [2:0] PF2_INTERRUPT_PIN = 3'h1; + parameter [7:0] PF2_MSIX_CAP_NEXTPTR = 8'h00; + parameter integer PF2_MSIX_CAP_PBA_BIR = 0; + parameter [28:0] PF2_MSIX_CAP_PBA_OFFSET = 29'h00000050; + parameter integer PF2_MSIX_CAP_TABLE_BIR = 0; + parameter [28:0] PF2_MSIX_CAP_TABLE_OFFSET = 29'h00000040; + parameter [10:0] PF2_MSIX_CAP_TABLE_SIZE = 11'h000; + parameter integer PF2_MSI_CAP_MULTIMSGCAP = 0; + parameter [7:0] PF2_MSI_CAP_NEXTPTR = 8'h00; + parameter PF2_MSI_CAP_PERVECMASKCAP = "FALSE"; + parameter [7:0] PF2_PCIE_CAP_NEXTPTR = 8'h00; + parameter [7:0] PF2_PM_CAP_NEXTPTR = 8'h00; + parameter PF2_SRIOV_ARI_CAPBL_HIER_PRESERVED = "FALSE"; + parameter [5:0] PF2_SRIOV_BAR0_APERTURE_SIZE = 6'h03; + parameter [2:0] PF2_SRIOV_BAR0_CONTROL = 3'h4; + parameter [4:0] PF2_SRIOV_BAR1_APERTURE_SIZE = 5'h00; + parameter [2:0] PF2_SRIOV_BAR1_CONTROL = 3'h0; + parameter [5:0] PF2_SRIOV_BAR2_APERTURE_SIZE = 6'h03; + parameter [2:0] PF2_SRIOV_BAR2_CONTROL = 3'h4; + parameter [4:0] PF2_SRIOV_BAR3_APERTURE_SIZE = 5'h03; + parameter [2:0] PF2_SRIOV_BAR3_CONTROL = 3'h0; + parameter [5:0] PF2_SRIOV_BAR4_APERTURE_SIZE = 6'h03; + parameter [2:0] PF2_SRIOV_BAR4_CONTROL = 3'h4; + parameter [4:0] PF2_SRIOV_BAR5_APERTURE_SIZE = 5'h03; + parameter [2:0] PF2_SRIOV_BAR5_CONTROL = 3'h0; + parameter [15:0] PF2_SRIOV_CAP_INITIAL_VF = 16'h0000; + parameter [11:0] PF2_SRIOV_CAP_NEXTPTR = 12'h000; + parameter [15:0] PF2_SRIOV_CAP_TOTAL_VF = 16'h0000; + parameter [3:0] PF2_SRIOV_CAP_VER = 4'h1; + parameter [15:0] PF2_SRIOV_FIRST_VF_OFFSET = 16'h0000; + parameter [15:0] PF2_SRIOV_FUNC_DEP_LINK = 16'h0000; + parameter [31:0] PF2_SRIOV_SUPPORTED_PAGE_SIZE = 32'h00000000; + parameter [15:0] PF2_SRIOV_VF_DEVICE_ID = 16'h0000; + parameter [11:0] PF2_TPHR_CAP_NEXTPTR = 12'h000; + parameter [2:0] PF2_TPHR_CAP_ST_MODE_SEL = 3'h0; + parameter [11:0] PF3_AER_CAP_NEXTPTR = 12'h000; + parameter [11:0] PF3_ARI_CAP_NEXTPTR = 12'h000; + parameter [7:0] PF3_ARI_CAP_NEXT_FUNC = 8'h00; + parameter [5:0] PF3_BAR0_APERTURE_SIZE = 6'h03; + parameter [2:0] PF3_BAR0_CONTROL = 3'h4; + parameter [4:0] PF3_BAR1_APERTURE_SIZE = 5'h00; + parameter [2:0] PF3_BAR1_CONTROL = 3'h0; + parameter [5:0] PF3_BAR2_APERTURE_SIZE = 6'h03; + parameter [2:0] PF3_BAR2_CONTROL = 3'h4; + parameter [4:0] PF3_BAR3_APERTURE_SIZE = 5'h03; + parameter [2:0] PF3_BAR3_CONTROL = 3'h0; + parameter [5:0] PF3_BAR4_APERTURE_SIZE = 6'h03; + parameter [2:0] PF3_BAR4_CONTROL = 3'h4; + parameter [4:0] PF3_BAR5_APERTURE_SIZE = 5'h03; + parameter [2:0] PF3_BAR5_CONTROL = 3'h0; + parameter [7:0] PF3_CAPABILITY_POINTER = 8'h80; + parameter [23:0] PF3_CLASS_CODE = 24'h000000; + parameter [2:0] PF3_DEV_CAP_MAX_PAYLOAD_SIZE = 3'h3; + parameter [11:0] PF3_DSN_CAP_NEXTPTR = 12'h10C; + parameter [4:0] PF3_EXPANSION_ROM_APERTURE_SIZE = 5'h03; + parameter PF3_EXPANSION_ROM_ENABLE = "FALSE"; + parameter [2:0] PF3_INTERRUPT_PIN = 3'h1; + parameter [7:0] PF3_MSIX_CAP_NEXTPTR = 8'h00; + parameter integer PF3_MSIX_CAP_PBA_BIR = 0; + parameter [28:0] PF3_MSIX_CAP_PBA_OFFSET = 29'h00000050; + parameter integer PF3_MSIX_CAP_TABLE_BIR = 0; + parameter [28:0] PF3_MSIX_CAP_TABLE_OFFSET = 29'h00000040; + parameter [10:0] PF3_MSIX_CAP_TABLE_SIZE = 11'h000; + parameter integer PF3_MSI_CAP_MULTIMSGCAP = 0; + parameter [7:0] PF3_MSI_CAP_NEXTPTR = 8'h00; + parameter PF3_MSI_CAP_PERVECMASKCAP = "FALSE"; + parameter [7:0] PF3_PCIE_CAP_NEXTPTR = 8'h00; + parameter [7:0] PF3_PM_CAP_NEXTPTR = 8'h00; + parameter PF3_SRIOV_ARI_CAPBL_HIER_PRESERVED = "FALSE"; + parameter [5:0] PF3_SRIOV_BAR0_APERTURE_SIZE = 6'h03; + parameter [2:0] PF3_SRIOV_BAR0_CONTROL = 3'h4; + parameter [4:0] PF3_SRIOV_BAR1_APERTURE_SIZE = 5'h00; + parameter [2:0] PF3_SRIOV_BAR1_CONTROL = 3'h0; + parameter [5:0] PF3_SRIOV_BAR2_APERTURE_SIZE = 6'h03; + parameter [2:0] PF3_SRIOV_BAR2_CONTROL = 3'h4; + parameter [4:0] PF3_SRIOV_BAR3_APERTURE_SIZE = 5'h03; + parameter [2:0] PF3_SRIOV_BAR3_CONTROL = 3'h0; + parameter [5:0] PF3_SRIOV_BAR4_APERTURE_SIZE = 6'h03; + parameter [2:0] PF3_SRIOV_BAR4_CONTROL = 3'h4; + parameter [4:0] PF3_SRIOV_BAR5_APERTURE_SIZE = 5'h03; + parameter [2:0] PF3_SRIOV_BAR5_CONTROL = 3'h0; + parameter [15:0] PF3_SRIOV_CAP_INITIAL_VF = 16'h0000; + parameter [11:0] PF3_SRIOV_CAP_NEXTPTR = 12'h000; + parameter [15:0] PF3_SRIOV_CAP_TOTAL_VF = 16'h0000; + parameter [3:0] PF3_SRIOV_CAP_VER = 4'h1; + parameter [15:0] PF3_SRIOV_FIRST_VF_OFFSET = 16'h0000; + parameter [15:0] PF3_SRIOV_FUNC_DEP_LINK = 16'h0000; + parameter [31:0] PF3_SRIOV_SUPPORTED_PAGE_SIZE = 32'h00000000; + parameter [15:0] PF3_SRIOV_VF_DEVICE_ID = 16'h0000; + parameter [11:0] PF3_TPHR_CAP_NEXTPTR = 12'h000; + parameter [2:0] PF3_TPHR_CAP_ST_MODE_SEL = 3'h0; + parameter PL_CFG_STATE_ROBUSTNESS_ENABLE = "TRUE"; + parameter PL_DEEMPH_SOURCE_SELECT = "TRUE"; + parameter PL_DESKEW_ON_SKIP_IN_GEN12 = "FALSE"; + parameter PL_DISABLE_AUTO_EQ_SPEED_CHANGE_TO_GEN3 = "FALSE"; + parameter PL_DISABLE_AUTO_EQ_SPEED_CHANGE_TO_GEN4 = "FALSE"; + parameter PL_DISABLE_AUTO_SPEED_CHANGE_TO_GEN2 = "FALSE"; + parameter PL_DISABLE_DC_BALANCE = "FALSE"; + parameter PL_DISABLE_EI_INFER_IN_L0 = "FALSE"; + parameter PL_DISABLE_LANE_REVERSAL = "FALSE"; + parameter [1:0] PL_DISABLE_LFSR_UPDATE_ON_SKP = 2'h0; + parameter PL_DISABLE_RETRAIN_ON_EB_ERROR = "FALSE"; + parameter PL_DISABLE_RETRAIN_ON_FRAMING_ERROR = "FALSE"; + parameter [15:0] PL_DISABLE_RETRAIN_ON_SPECIFIC_FRAMING_ERROR = 16'h0000; + parameter PL_DISABLE_UPCONFIG_CAPABLE = "FALSE"; + parameter [1:0] PL_EQ_ADAPT_DISABLE_COEFF_CHECK = 2'h0; + parameter [1:0] PL_EQ_ADAPT_DISABLE_PRESET_CHECK = 2'h0; + parameter [4:0] PL_EQ_ADAPT_ITER_COUNT = 5'h02; + parameter [1:0] PL_EQ_ADAPT_REJECT_RETRY_COUNT = 2'h1; + parameter [1:0] PL_EQ_BYPASS_PHASE23 = 2'h0; + parameter [5:0] PL_EQ_DEFAULT_RX_PRESET_HINT = 6'h33; + parameter [7:0] PL_EQ_DEFAULT_TX_PRESET = 8'h44; + parameter PL_EQ_DISABLE_MISMATCH_CHECK = "TRUE"; + parameter [1:0] PL_EQ_RX_ADAPT_EQ_PHASE0 = 2'h0; + parameter [1:0] PL_EQ_RX_ADAPT_EQ_PHASE1 = 2'h0; + parameter PL_EQ_SHORT_ADAPT_PHASE = "FALSE"; + parameter PL_EQ_TX_8G_EQ_TS2_ENABLE = "FALSE"; + parameter PL_EXIT_LOOPBACK_ON_EI_ENTRY = "TRUE"; + parameter PL_INFER_EI_DISABLE_LPBK_ACTIVE = "TRUE"; + parameter PL_INFER_EI_DISABLE_REC_RC = "FALSE"; + parameter PL_INFER_EI_DISABLE_REC_SPD = "FALSE"; + parameter [31:0] PL_LANE0_EQ_CONTROL = 32'h00003F00; + parameter [31:0] PL_LANE10_EQ_CONTROL = 32'h00003F00; + parameter [31:0] PL_LANE11_EQ_CONTROL = 32'h00003F00; + parameter [31:0] PL_LANE12_EQ_CONTROL = 32'h00003F00; + parameter [31:0] PL_LANE13_EQ_CONTROL = 32'h00003F00; + parameter [31:0] PL_LANE14_EQ_CONTROL = 32'h00003F00; + parameter [31:0] PL_LANE15_EQ_CONTROL = 32'h00003F00; + parameter [31:0] PL_LANE1_EQ_CONTROL = 32'h00003F00; + parameter [31:0] PL_LANE2_EQ_CONTROL = 32'h00003F00; + parameter [31:0] PL_LANE3_EQ_CONTROL = 32'h00003F00; + parameter [31:0] PL_LANE4_EQ_CONTROL = 32'h00003F00; + parameter [31:0] PL_LANE5_EQ_CONTROL = 32'h00003F00; + parameter [31:0] PL_LANE6_EQ_CONTROL = 32'h00003F00; + parameter [31:0] PL_LANE7_EQ_CONTROL = 32'h00003F00; + parameter [31:0] PL_LANE8_EQ_CONTROL = 32'h00003F00; + parameter [31:0] PL_LANE9_EQ_CONTROL = 32'h00003F00; + parameter [3:0] PL_LINK_CAP_MAX_LINK_SPEED = 4'h4; + parameter [4:0] PL_LINK_CAP_MAX_LINK_WIDTH = 5'h08; + parameter integer PL_N_FTS = 255; + parameter PL_QUIESCE_GUARANTEE_DISABLE = "FALSE"; + parameter PL_REDO_EQ_SOURCE_SELECT = "TRUE"; + parameter [7:0] PL_REPORT_ALL_PHY_ERRORS = 8'h00; + parameter [1:0] PL_RX_ADAPT_TIMER_CLWS_CLOBBER_TX_TS = 2'h0; + parameter [3:0] PL_RX_ADAPT_TIMER_CLWS_GEN3 = 4'h0; + parameter [3:0] PL_RX_ADAPT_TIMER_CLWS_GEN4 = 4'h0; + parameter [1:0] PL_RX_ADAPT_TIMER_RRL_CLOBBER_TX_TS = 2'h0; + parameter [3:0] PL_RX_ADAPT_TIMER_RRL_GEN3 = 4'h0; + parameter [3:0] PL_RX_ADAPT_TIMER_RRL_GEN4 = 4'h0; + parameter [1:0] PL_RX_L0S_EXIT_TO_RECOVERY = 2'h0; + parameter [1:0] PL_SIM_FAST_LINK_TRAINING = 2'h0; + parameter PL_SRIS_ENABLE = "FALSE"; + parameter [6:0] PL_SRIS_SKPOS_GEN_SPD_VEC = 7'h00; + parameter [6:0] PL_SRIS_SKPOS_REC_SPD_VEC = 7'h00; + parameter PL_UPSTREAM_FACING = "TRUE"; + parameter [15:0] PL_USER_SPARE = 16'h0000; + parameter [15:0] PM_ASPML0S_TIMEOUT = 16'h1500; + parameter [19:0] PM_ASPML1_ENTRY_DELAY = 20'h003E8; + parameter PM_ENABLE_L23_ENTRY = "FALSE"; + parameter PM_ENABLE_SLOT_POWER_CAPTURE = "TRUE"; + parameter [31:0] PM_L1_REENTRY_DELAY = 32'h00000100; + parameter [19:0] PM_PME_SERVICE_TIMEOUT_DELAY = 20'h00000; + parameter [15:0] PM_PME_TURNOFF_ACK_DELAY = 16'h0100; + parameter SIM_DEVICE = "ULTRASCALE_PLUS"; + parameter [31:0] SIM_JTAG_IDCODE = 32'h00000000; + parameter SIM_VERSION = "1.0"; + parameter SPARE_BIT0 = "FALSE"; + parameter integer SPARE_BIT1 = 0; + parameter integer SPARE_BIT2 = 0; + parameter SPARE_BIT3 = "FALSE"; + parameter integer SPARE_BIT4 = 0; + parameter integer SPARE_BIT5 = 0; + parameter integer SPARE_BIT6 = 0; + parameter integer SPARE_BIT7 = 0; + parameter integer SPARE_BIT8 = 0; + parameter [7:0] SPARE_BYTE0 = 8'h00; + parameter [7:0] SPARE_BYTE1 = 8'h00; + parameter [7:0] SPARE_BYTE2 = 8'h00; + parameter [7:0] SPARE_BYTE3 = 8'h00; + parameter [31:0] SPARE_WORD0 = 32'h00000000; + parameter [31:0] SPARE_WORD1 = 32'h00000000; + parameter [31:0] SPARE_WORD2 = 32'h00000000; + parameter [31:0] SPARE_WORD3 = 32'h00000000; + parameter [3:0] SRIOV_CAP_ENABLE = 4'h0; + parameter TL2CFG_IF_PARITY_CHK = "TRUE"; + parameter [1:0] TL_COMPLETION_RAM_NUM_TLPS = 2'h0; + parameter [1:0] TL_COMPLETION_RAM_SIZE = 2'h1; + parameter [11:0] TL_CREDITS_CD = 12'h000; + parameter [7:0] TL_CREDITS_CH = 8'h00; + parameter [11:0] TL_CREDITS_NPD = 12'h004; + parameter [7:0] TL_CREDITS_NPH = 8'h20; + parameter [11:0] TL_CREDITS_PD = 12'h0E0; + parameter [7:0] TL_CREDITS_PH = 8'h20; + parameter [4:0] TL_FC_UPDATE_MIN_INTERVAL_TIME = 5'h02; + parameter [4:0] TL_FC_UPDATE_MIN_INTERVAL_TLP_COUNT = 5'h08; + parameter [1:0] TL_PF_ENABLE_REG = 2'h0; + parameter [0:0] TL_POSTED_RAM_SIZE = 1'h0; + parameter TL_RX_COMPLETION_FROM_RAM_READ_PIPELINE = "FALSE"; + parameter TL_RX_COMPLETION_TO_RAM_READ_PIPELINE = "FALSE"; + parameter TL_RX_COMPLETION_TO_RAM_WRITE_PIPELINE = "FALSE"; + parameter TL_RX_POSTED_FROM_RAM_READ_PIPELINE = "FALSE"; + parameter TL_RX_POSTED_TO_RAM_READ_PIPELINE = "FALSE"; + parameter TL_RX_POSTED_TO_RAM_WRITE_PIPELINE = "FALSE"; + parameter TL_TX_MUX_STRICT_PRIORITY = "TRUE"; + parameter TL_TX_TLP_STRADDLE_ENABLE = "FALSE"; + parameter TL_TX_TLP_TERMINATE_PARITY = "FALSE"; + parameter [15:0] TL_USER_SPARE = 16'h0000; + parameter TPH_FROM_RAM_PIPELINE = "FALSE"; + parameter TPH_TO_RAM_PIPELINE = "FALSE"; + parameter [7:0] VF0_CAPABILITY_POINTER = 8'h80; + parameter [11:0] VFG0_ARI_CAP_NEXTPTR = 12'h000; + parameter [7:0] VFG0_MSIX_CAP_NEXTPTR = 8'h00; + parameter integer VFG0_MSIX_CAP_PBA_BIR = 0; + parameter [28:0] VFG0_MSIX_CAP_PBA_OFFSET = 29'h00000050; + parameter integer VFG0_MSIX_CAP_TABLE_BIR = 0; + parameter [28:0] VFG0_MSIX_CAP_TABLE_OFFSET = 29'h00000040; + parameter [10:0] VFG0_MSIX_CAP_TABLE_SIZE = 11'h000; + parameter [7:0] VFG0_PCIE_CAP_NEXTPTR = 8'h00; + parameter [11:0] VFG0_TPHR_CAP_NEXTPTR = 12'h000; + parameter [2:0] VFG0_TPHR_CAP_ST_MODE_SEL = 3'h0; + parameter [11:0] VFG1_ARI_CAP_NEXTPTR = 12'h000; + parameter [7:0] VFG1_MSIX_CAP_NEXTPTR = 8'h00; + parameter integer VFG1_MSIX_CAP_PBA_BIR = 0; + parameter [28:0] VFG1_MSIX_CAP_PBA_OFFSET = 29'h00000050; + parameter integer VFG1_MSIX_CAP_TABLE_BIR = 0; + parameter [28:0] VFG1_MSIX_CAP_TABLE_OFFSET = 29'h00000040; + parameter [10:0] VFG1_MSIX_CAP_TABLE_SIZE = 11'h000; + parameter [7:0] VFG1_PCIE_CAP_NEXTPTR = 8'h00; + parameter [11:0] VFG1_TPHR_CAP_NEXTPTR = 12'h000; + parameter [2:0] VFG1_TPHR_CAP_ST_MODE_SEL = 3'h0; + parameter [11:0] VFG2_ARI_CAP_NEXTPTR = 12'h000; + parameter [7:0] VFG2_MSIX_CAP_NEXTPTR = 8'h00; + parameter integer VFG2_MSIX_CAP_PBA_BIR = 0; + parameter [28:0] VFG2_MSIX_CAP_PBA_OFFSET = 29'h00000050; + parameter integer VFG2_MSIX_CAP_TABLE_BIR = 0; + parameter [28:0] VFG2_MSIX_CAP_TABLE_OFFSET = 29'h00000040; + parameter [10:0] VFG2_MSIX_CAP_TABLE_SIZE = 11'h000; + parameter [7:0] VFG2_PCIE_CAP_NEXTPTR = 8'h00; + parameter [11:0] VFG2_TPHR_CAP_NEXTPTR = 12'h000; + parameter [2:0] VFG2_TPHR_CAP_ST_MODE_SEL = 3'h0; + parameter [11:0] VFG3_ARI_CAP_NEXTPTR = 12'h000; + parameter [7:0] VFG3_MSIX_CAP_NEXTPTR = 8'h00; + parameter integer VFG3_MSIX_CAP_PBA_BIR = 0; + parameter [28:0] VFG3_MSIX_CAP_PBA_OFFSET = 29'h00000050; + parameter integer VFG3_MSIX_CAP_TABLE_BIR = 0; + parameter [28:0] VFG3_MSIX_CAP_TABLE_OFFSET = 29'h00000040; + parameter [10:0] VFG3_MSIX_CAP_TABLE_SIZE = 11'h000; + parameter [7:0] VFG3_PCIE_CAP_NEXTPTR = 8'h00; + parameter [11:0] VFG3_TPHR_CAP_NEXTPTR = 12'h000; + parameter [2:0] VFG3_TPHR_CAP_ST_MODE_SEL = 3'h0; + output [7:0] AXIUSEROUT; + output [7:0] CFGBUSNUMBER; + output [1:0] CFGCURRENTSPEED; + output CFGERRCOROUT; + output CFGERRFATALOUT; + output CFGERRNONFATALOUT; + output [7:0] CFGEXTFUNCTIONNUMBER; + output CFGEXTREADRECEIVED; + output [9:0] CFGEXTREGISTERNUMBER; + output [3:0] CFGEXTWRITEBYTEENABLE; + output [31:0] CFGEXTWRITEDATA; + output CFGEXTWRITERECEIVED; + output [11:0] CFGFCCPLD; + output [7:0] CFGFCCPLH; + output [11:0] CFGFCNPD; + output [7:0] CFGFCNPH; + output [11:0] CFGFCPD; + output [7:0] CFGFCPH; + output [3:0] CFGFLRINPROCESS; + output [11:0] CFGFUNCTIONPOWERSTATE; + output [15:0] CFGFUNCTIONSTATUS; + output CFGHOTRESETOUT; + output [31:0] CFGINTERRUPTMSIDATA; + output [3:0] CFGINTERRUPTMSIENABLE; + output CFGINTERRUPTMSIFAIL; + output CFGINTERRUPTMSIMASKUPDATE; + output [11:0] CFGINTERRUPTMSIMMENABLE; + output CFGINTERRUPTMSISENT; + output [3:0] CFGINTERRUPTMSIXENABLE; + output [3:0] CFGINTERRUPTMSIXMASK; + output CFGINTERRUPTMSIXVECPENDINGSTATUS; + output CFGINTERRUPTSENT; + output [1:0] CFGLINKPOWERSTATE; + output [4:0] CFGLOCALERROROUT; + output CFGLOCALERRORVALID; + output CFGLTRENABLE; + output [5:0] CFGLTSSMSTATE; + output [1:0] CFGMAXPAYLOAD; + output [2:0] CFGMAXREADREQ; + output [31:0] CFGMGMTREADDATA; + output CFGMGMTREADWRITEDONE; + output CFGMSGRECEIVED; + output [7:0] CFGMSGRECEIVEDDATA; + output [4:0] CFGMSGRECEIVEDTYPE; + output CFGMSGTRANSMITDONE; + output [12:0] CFGMSIXRAMADDRESS; + output CFGMSIXRAMREADENABLE; + output [3:0] CFGMSIXRAMWRITEBYTEENABLE; + output [35:0] CFGMSIXRAMWRITEDATA; + output [2:0] CFGNEGOTIATEDWIDTH; + output [1:0] CFGOBFFENABLE; + output CFGPHYLINKDOWN; + output [1:0] CFGPHYLINKSTATUS; + output CFGPLSTATUSCHANGE; + output CFGPOWERSTATECHANGEINTERRUPT; + output [3:0] CFGRCBSTATUS; + output [1:0] CFGRXPMSTATE; + output [11:0] CFGTPHRAMADDRESS; + output CFGTPHRAMREADENABLE; + output [3:0] CFGTPHRAMWRITEBYTEENABLE; + output [35:0] CFGTPHRAMWRITEDATA; + output [3:0] CFGTPHREQUESTERENABLE; + output [11:0] CFGTPHSTMODE; + output [1:0] CFGTXPMSTATE; + output CONFMCAPDESIGNSWITCH; + output CONFMCAPEOS; + output CONFMCAPINUSEBYPCIE; + output CONFREQREADY; + output [31:0] CONFRESPRDATA; + output CONFRESPVALID; + output [31:0] DBGCTRL0OUT; + output [31:0] DBGCTRL1OUT; + output [255:0] DBGDATA0OUT; + output [255:0] DBGDATA1OUT; + output [15:0] DRPDO; + output DRPRDY; + output [255:0] MAXISCQTDATA; + output [7:0] MAXISCQTKEEP; + output MAXISCQTLAST; + output [87:0] MAXISCQTUSER; + output MAXISCQTVALID; + output [255:0] MAXISRCTDATA; + output [7:0] MAXISRCTKEEP; + output MAXISRCTLAST; + output [74:0] MAXISRCTUSER; + output MAXISRCTVALID; + output [8:0] MIREPLAYRAMADDRESS0; + output [8:0] MIREPLAYRAMADDRESS1; + output MIREPLAYRAMREADENABLE0; + output MIREPLAYRAMREADENABLE1; + output [127:0] MIREPLAYRAMWRITEDATA0; + output [127:0] MIREPLAYRAMWRITEDATA1; + output MIREPLAYRAMWRITEENABLE0; + output MIREPLAYRAMWRITEENABLE1; + output [8:0] MIRXCOMPLETIONRAMREADADDRESS0; + output [8:0] MIRXCOMPLETIONRAMREADADDRESS1; + output [1:0] MIRXCOMPLETIONRAMREADENABLE0; + output [1:0] MIRXCOMPLETIONRAMREADENABLE1; + output [8:0] MIRXCOMPLETIONRAMWRITEADDRESS0; + output [8:0] MIRXCOMPLETIONRAMWRITEADDRESS1; + output [143:0] MIRXCOMPLETIONRAMWRITEDATA0; + output [143:0] MIRXCOMPLETIONRAMWRITEDATA1; + output [1:0] MIRXCOMPLETIONRAMWRITEENABLE0; + output [1:0] MIRXCOMPLETIONRAMWRITEENABLE1; + output [8:0] MIRXPOSTEDREQUESTRAMREADADDRESS0; + output [8:0] MIRXPOSTEDREQUESTRAMREADADDRESS1; + output MIRXPOSTEDREQUESTRAMREADENABLE0; + output MIRXPOSTEDREQUESTRAMREADENABLE1; + output [8:0] MIRXPOSTEDREQUESTRAMWRITEADDRESS0; + output [8:0] MIRXPOSTEDREQUESTRAMWRITEADDRESS1; + output [143:0] MIRXPOSTEDREQUESTRAMWRITEDATA0; + output [143:0] MIRXPOSTEDREQUESTRAMWRITEDATA1; + output MIRXPOSTEDREQUESTRAMWRITEENABLE0; + output MIRXPOSTEDREQUESTRAMWRITEENABLE1; + output [5:0] PCIECQNPREQCOUNT; + output PCIEPERST0B; + output PCIEPERST1B; + output [5:0] PCIERQSEQNUM0; + output [5:0] PCIERQSEQNUM1; + output PCIERQSEQNUMVLD0; + output PCIERQSEQNUMVLD1; + output [7:0] PCIERQTAG0; + output [7:0] PCIERQTAG1; + output [3:0] PCIERQTAGAV; + output PCIERQTAGVLD0; + output PCIERQTAGVLD1; + output [3:0] PCIETFCNPDAV; + output [3:0] PCIETFCNPHAV; + output [1:0] PIPERX00EQCONTROL; + output PIPERX00POLARITY; + output [1:0] PIPERX01EQCONTROL; + output PIPERX01POLARITY; + output [1:0] PIPERX02EQCONTROL; + output PIPERX02POLARITY; + output [1:0] PIPERX03EQCONTROL; + output PIPERX03POLARITY; + output [1:0] PIPERX04EQCONTROL; + output PIPERX04POLARITY; + output [1:0] PIPERX05EQCONTROL; + output PIPERX05POLARITY; + output [1:0] PIPERX06EQCONTROL; + output PIPERX06POLARITY; + output [1:0] PIPERX07EQCONTROL; + output PIPERX07POLARITY; + output [1:0] PIPERX08EQCONTROL; + output PIPERX08POLARITY; + output [1:0] PIPERX09EQCONTROL; + output PIPERX09POLARITY; + output [1:0] PIPERX10EQCONTROL; + output PIPERX10POLARITY; + output [1:0] PIPERX11EQCONTROL; + output PIPERX11POLARITY; + output [1:0] PIPERX12EQCONTROL; + output PIPERX12POLARITY; + output [1:0] PIPERX13EQCONTROL; + output PIPERX13POLARITY; + output [1:0] PIPERX14EQCONTROL; + output PIPERX14POLARITY; + output [1:0] PIPERX15EQCONTROL; + output PIPERX15POLARITY; + output [5:0] PIPERXEQLPLFFS; + output [3:0] PIPERXEQLPTXPRESET; + output [1:0] PIPETX00CHARISK; + output PIPETX00COMPLIANCE; + output [31:0] PIPETX00DATA; + output PIPETX00DATAVALID; + output PIPETX00ELECIDLE; + output [1:0] PIPETX00EQCONTROL; + output [5:0] PIPETX00EQDEEMPH; + output [1:0] PIPETX00POWERDOWN; + output PIPETX00STARTBLOCK; + output [1:0] PIPETX00SYNCHEADER; + output [1:0] PIPETX01CHARISK; + output PIPETX01COMPLIANCE; + output [31:0] PIPETX01DATA; + output PIPETX01DATAVALID; + output PIPETX01ELECIDLE; + output [1:0] PIPETX01EQCONTROL; + output [5:0] PIPETX01EQDEEMPH; + output [1:0] PIPETX01POWERDOWN; + output PIPETX01STARTBLOCK; + output [1:0] PIPETX01SYNCHEADER; + output [1:0] PIPETX02CHARISK; + output PIPETX02COMPLIANCE; + output [31:0] PIPETX02DATA; + output PIPETX02DATAVALID; + output PIPETX02ELECIDLE; + output [1:0] PIPETX02EQCONTROL; + output [5:0] PIPETX02EQDEEMPH; + output [1:0] PIPETX02POWERDOWN; + output PIPETX02STARTBLOCK; + output [1:0] PIPETX02SYNCHEADER; + output [1:0] PIPETX03CHARISK; + output PIPETX03COMPLIANCE; + output [31:0] PIPETX03DATA; + output PIPETX03DATAVALID; + output PIPETX03ELECIDLE; + output [1:0] PIPETX03EQCONTROL; + output [5:0] PIPETX03EQDEEMPH; + output [1:0] PIPETX03POWERDOWN; + output PIPETX03STARTBLOCK; + output [1:0] PIPETX03SYNCHEADER; + output [1:0] PIPETX04CHARISK; + output PIPETX04COMPLIANCE; + output [31:0] PIPETX04DATA; + output PIPETX04DATAVALID; + output PIPETX04ELECIDLE; + output [1:0] PIPETX04EQCONTROL; + output [5:0] PIPETX04EQDEEMPH; + output [1:0] PIPETX04POWERDOWN; + output PIPETX04STARTBLOCK; + output [1:0] PIPETX04SYNCHEADER; + output [1:0] PIPETX05CHARISK; + output PIPETX05COMPLIANCE; + output [31:0] PIPETX05DATA; + output PIPETX05DATAVALID; + output PIPETX05ELECIDLE; + output [1:0] PIPETX05EQCONTROL; + output [5:0] PIPETX05EQDEEMPH; + output [1:0] PIPETX05POWERDOWN; + output PIPETX05STARTBLOCK; + output [1:0] PIPETX05SYNCHEADER; + output [1:0] PIPETX06CHARISK; + output PIPETX06COMPLIANCE; + output [31:0] PIPETX06DATA; + output PIPETX06DATAVALID; + output PIPETX06ELECIDLE; + output [1:0] PIPETX06EQCONTROL; + output [5:0] PIPETX06EQDEEMPH; + output [1:0] PIPETX06POWERDOWN; + output PIPETX06STARTBLOCK; + output [1:0] PIPETX06SYNCHEADER; + output [1:0] PIPETX07CHARISK; + output PIPETX07COMPLIANCE; + output [31:0] PIPETX07DATA; + output PIPETX07DATAVALID; + output PIPETX07ELECIDLE; + output [1:0] PIPETX07EQCONTROL; + output [5:0] PIPETX07EQDEEMPH; + output [1:0] PIPETX07POWERDOWN; + output PIPETX07STARTBLOCK; + output [1:0] PIPETX07SYNCHEADER; + output [1:0] PIPETX08CHARISK; + output PIPETX08COMPLIANCE; + output [31:0] PIPETX08DATA; + output PIPETX08DATAVALID; + output PIPETX08ELECIDLE; + output [1:0] PIPETX08EQCONTROL; + output [5:0] PIPETX08EQDEEMPH; + output [1:0] PIPETX08POWERDOWN; + output PIPETX08STARTBLOCK; + output [1:0] PIPETX08SYNCHEADER; + output [1:0] PIPETX09CHARISK; + output PIPETX09COMPLIANCE; + output [31:0] PIPETX09DATA; + output PIPETX09DATAVALID; + output PIPETX09ELECIDLE; + output [1:0] PIPETX09EQCONTROL; + output [5:0] PIPETX09EQDEEMPH; + output [1:0] PIPETX09POWERDOWN; + output PIPETX09STARTBLOCK; + output [1:0] PIPETX09SYNCHEADER; + output [1:0] PIPETX10CHARISK; + output PIPETX10COMPLIANCE; + output [31:0] PIPETX10DATA; + output PIPETX10DATAVALID; + output PIPETX10ELECIDLE; + output [1:0] PIPETX10EQCONTROL; + output [5:0] PIPETX10EQDEEMPH; + output [1:0] PIPETX10POWERDOWN; + output PIPETX10STARTBLOCK; + output [1:0] PIPETX10SYNCHEADER; + output [1:0] PIPETX11CHARISK; + output PIPETX11COMPLIANCE; + output [31:0] PIPETX11DATA; + output PIPETX11DATAVALID; + output PIPETX11ELECIDLE; + output [1:0] PIPETX11EQCONTROL; + output [5:0] PIPETX11EQDEEMPH; + output [1:0] PIPETX11POWERDOWN; + output PIPETX11STARTBLOCK; + output [1:0] PIPETX11SYNCHEADER; + output [1:0] PIPETX12CHARISK; + output PIPETX12COMPLIANCE; + output [31:0] PIPETX12DATA; + output PIPETX12DATAVALID; + output PIPETX12ELECIDLE; + output [1:0] PIPETX12EQCONTROL; + output [5:0] PIPETX12EQDEEMPH; + output [1:0] PIPETX12POWERDOWN; + output PIPETX12STARTBLOCK; + output [1:0] PIPETX12SYNCHEADER; + output [1:0] PIPETX13CHARISK; + output PIPETX13COMPLIANCE; + output [31:0] PIPETX13DATA; + output PIPETX13DATAVALID; + output PIPETX13ELECIDLE; + output [1:0] PIPETX13EQCONTROL; + output [5:0] PIPETX13EQDEEMPH; + output [1:0] PIPETX13POWERDOWN; + output PIPETX13STARTBLOCK; + output [1:0] PIPETX13SYNCHEADER; + output [1:0] PIPETX14CHARISK; + output PIPETX14COMPLIANCE; + output [31:0] PIPETX14DATA; + output PIPETX14DATAVALID; + output PIPETX14ELECIDLE; + output [1:0] PIPETX14EQCONTROL; + output [5:0] PIPETX14EQDEEMPH; + output [1:0] PIPETX14POWERDOWN; + output PIPETX14STARTBLOCK; + output [1:0] PIPETX14SYNCHEADER; + output [1:0] PIPETX15CHARISK; + output PIPETX15COMPLIANCE; + output [31:0] PIPETX15DATA; + output PIPETX15DATAVALID; + output PIPETX15ELECIDLE; + output [1:0] PIPETX15EQCONTROL; + output [5:0] PIPETX15EQDEEMPH; + output [1:0] PIPETX15POWERDOWN; + output PIPETX15STARTBLOCK; + output [1:0] PIPETX15SYNCHEADER; + output PIPETXDEEMPH; + output [2:0] PIPETXMARGIN; + output [1:0] PIPETXRATE; + output PIPETXRCVRDET; + output PIPETXRESET; + output PIPETXSWING; + output PLEQINPROGRESS; + output [1:0] PLEQPHASE; + output PLGEN34EQMISMATCH; + output [3:0] SAXISCCTREADY; + output [3:0] SAXISRQTREADY; + output [31:0] USERSPAREOUT; + input [7:0] AXIUSERIN; + input CFGCONFIGSPACEENABLE; + input [15:0] CFGDEVIDPF0; + input [15:0] CFGDEVIDPF1; + input [15:0] CFGDEVIDPF2; + input [15:0] CFGDEVIDPF3; + input [7:0] CFGDSBUSNUMBER; + input [4:0] CFGDSDEVICENUMBER; + input [2:0] CFGDSFUNCTIONNUMBER; + input [63:0] CFGDSN; + input [7:0] CFGDSPORTNUMBER; + input CFGERRCORIN; + input CFGERRUNCORIN; + input [31:0] CFGEXTREADDATA; + input CFGEXTREADDATAVALID; + input [2:0] CFGFCSEL; + input [3:0] CFGFLRDONE; + input CFGHOTRESETIN; + input [3:0] CFGINTERRUPTINT; + input [2:0] CFGINTERRUPTMSIATTR; + input [7:0] CFGINTERRUPTMSIFUNCTIONNUMBER; + input [31:0] CFGINTERRUPTMSIINT; + input [31:0] CFGINTERRUPTMSIPENDINGSTATUS; + input CFGINTERRUPTMSIPENDINGSTATUSDATAENABLE; + input [1:0] CFGINTERRUPTMSIPENDINGSTATUSFUNCTIONNUM; + input [1:0] CFGINTERRUPTMSISELECT; + input CFGINTERRUPTMSITPHPRESENT; + input [7:0] CFGINTERRUPTMSITPHSTTAG; + input [1:0] CFGINTERRUPTMSITPHTYPE; + input [63:0] CFGINTERRUPTMSIXADDRESS; + input [31:0] CFGINTERRUPTMSIXDATA; + input CFGINTERRUPTMSIXINT; + input [1:0] CFGINTERRUPTMSIXVECPENDING; + input [3:0] CFGINTERRUPTPENDING; + input CFGLINKTRAININGENABLE; + input [9:0] CFGMGMTADDR; + input [3:0] CFGMGMTBYTEENABLE; + input CFGMGMTDEBUGACCESS; + input [7:0] CFGMGMTFUNCTIONNUMBER; + input CFGMGMTREAD; + input CFGMGMTWRITE; + input [31:0] CFGMGMTWRITEDATA; + input CFGMSGTRANSMIT; + input [31:0] CFGMSGTRANSMITDATA; + input [2:0] CFGMSGTRANSMITTYPE; + input [35:0] CFGMSIXRAMREADDATA; + input CFGPMASPML1ENTRYREJECT; + input CFGPMASPMTXL0SENTRYDISABLE; + input CFGPOWERSTATECHANGEACK; + input CFGREQPMTRANSITIONL23READY; + input [7:0] CFGREVIDPF0; + input [7:0] CFGREVIDPF1; + input [7:0] CFGREVIDPF2; + input [7:0] CFGREVIDPF3; + input [15:0] CFGSUBSYSIDPF0; + input [15:0] CFGSUBSYSIDPF1; + input [15:0] CFGSUBSYSIDPF2; + input [15:0] CFGSUBSYSIDPF3; + input [15:0] CFGSUBSYSVENDID; + input [35:0] CFGTPHRAMREADDATA; + input [15:0] CFGVENDID; + input CFGVFFLRDONE; + input [7:0] CFGVFFLRFUNCNUM; + input CONFMCAPREQUESTBYCONF; + input [31:0] CONFREQDATA; + input [3:0] CONFREQREGNUM; + input [1:0] CONFREQTYPE; + input CONFREQVALID; + input CORECLK; + input CORECLKMIREPLAYRAM0; + input CORECLKMIREPLAYRAM1; + input CORECLKMIRXCOMPLETIONRAM0; + input CORECLKMIRXCOMPLETIONRAM1; + input CORECLKMIRXPOSTEDREQUESTRAM0; + input CORECLKMIRXPOSTEDREQUESTRAM1; + input [5:0] DBGSEL0; + input [5:0] DBGSEL1; + input [9:0] DRPADDR; + input DRPCLK; + input [15:0] DRPDI; + input DRPEN; + input DRPWE; + input [21:0] MAXISCQTREADY; + input [21:0] MAXISRCTREADY; + input MCAPCLK; + input MCAPPERST0B; + input MCAPPERST1B; + input MGMTRESETN; + input MGMTSTICKYRESETN; + input [5:0] MIREPLAYRAMERRCOR; + input [5:0] MIREPLAYRAMERRUNCOR; + input [127:0] MIREPLAYRAMREADDATA0; + input [127:0] MIREPLAYRAMREADDATA1; + input [11:0] MIRXCOMPLETIONRAMERRCOR; + input [11:0] MIRXCOMPLETIONRAMERRUNCOR; + input [143:0] MIRXCOMPLETIONRAMREADDATA0; + input [143:0] MIRXCOMPLETIONRAMREADDATA1; + input [5:0] MIRXPOSTEDREQUESTRAMERRCOR; + input [5:0] MIRXPOSTEDREQUESTRAMERRUNCOR; + input [143:0] MIRXPOSTEDREQUESTRAMREADDATA0; + input [143:0] MIRXPOSTEDREQUESTRAMREADDATA1; + input [1:0] PCIECOMPLDELIVERED; + input [7:0] PCIECOMPLDELIVEREDTAG0; + input [7:0] PCIECOMPLDELIVEREDTAG1; + input [1:0] PCIECQNPREQ; + input PCIECQNPUSERCREDITRCVD; + input PCIECQPIPELINEEMPTY; + input PCIEPOSTEDREQDELIVERED; + input PIPECLK; + input PIPECLKEN; + input [5:0] PIPEEQFS; + input [5:0] PIPEEQLF; + input PIPERESETN; + input [1:0] PIPERX00CHARISK; + input [31:0] PIPERX00DATA; + input PIPERX00DATAVALID; + input PIPERX00ELECIDLE; + input PIPERX00EQDONE; + input PIPERX00EQLPADAPTDONE; + input PIPERX00EQLPLFFSSEL; + input [17:0] PIPERX00EQLPNEWTXCOEFFORPRESET; + input PIPERX00PHYSTATUS; + input [1:0] PIPERX00STARTBLOCK; + input [2:0] PIPERX00STATUS; + input [1:0] PIPERX00SYNCHEADER; + input PIPERX00VALID; + input [1:0] PIPERX01CHARISK; + input [31:0] PIPERX01DATA; + input PIPERX01DATAVALID; + input PIPERX01ELECIDLE; + input PIPERX01EQDONE; + input PIPERX01EQLPADAPTDONE; + input PIPERX01EQLPLFFSSEL; + input [17:0] PIPERX01EQLPNEWTXCOEFFORPRESET; + input PIPERX01PHYSTATUS; + input [1:0] PIPERX01STARTBLOCK; + input [2:0] PIPERX01STATUS; + input [1:0] PIPERX01SYNCHEADER; + input PIPERX01VALID; + input [1:0] PIPERX02CHARISK; + input [31:0] PIPERX02DATA; + input PIPERX02DATAVALID; + input PIPERX02ELECIDLE; + input PIPERX02EQDONE; + input PIPERX02EQLPADAPTDONE; + input PIPERX02EQLPLFFSSEL; + input [17:0] PIPERX02EQLPNEWTXCOEFFORPRESET; + input PIPERX02PHYSTATUS; + input [1:0] PIPERX02STARTBLOCK; + input [2:0] PIPERX02STATUS; + input [1:0] PIPERX02SYNCHEADER; + input PIPERX02VALID; + input [1:0] PIPERX03CHARISK; + input [31:0] PIPERX03DATA; + input PIPERX03DATAVALID; + input PIPERX03ELECIDLE; + input PIPERX03EQDONE; + input PIPERX03EQLPADAPTDONE; + input PIPERX03EQLPLFFSSEL; + input [17:0] PIPERX03EQLPNEWTXCOEFFORPRESET; + input PIPERX03PHYSTATUS; + input [1:0] PIPERX03STARTBLOCK; + input [2:0] PIPERX03STATUS; + input [1:0] PIPERX03SYNCHEADER; + input PIPERX03VALID; + input [1:0] PIPERX04CHARISK; + input [31:0] PIPERX04DATA; + input PIPERX04DATAVALID; + input PIPERX04ELECIDLE; + input PIPERX04EQDONE; + input PIPERX04EQLPADAPTDONE; + input PIPERX04EQLPLFFSSEL; + input [17:0] PIPERX04EQLPNEWTXCOEFFORPRESET; + input PIPERX04PHYSTATUS; + input [1:0] PIPERX04STARTBLOCK; + input [2:0] PIPERX04STATUS; + input [1:0] PIPERX04SYNCHEADER; + input PIPERX04VALID; + input [1:0] PIPERX05CHARISK; + input [31:0] PIPERX05DATA; + input PIPERX05DATAVALID; + input PIPERX05ELECIDLE; + input PIPERX05EQDONE; + input PIPERX05EQLPADAPTDONE; + input PIPERX05EQLPLFFSSEL; + input [17:0] PIPERX05EQLPNEWTXCOEFFORPRESET; + input PIPERX05PHYSTATUS; + input [1:0] PIPERX05STARTBLOCK; + input [2:0] PIPERX05STATUS; + input [1:0] PIPERX05SYNCHEADER; + input PIPERX05VALID; + input [1:0] PIPERX06CHARISK; + input [31:0] PIPERX06DATA; + input PIPERX06DATAVALID; + input PIPERX06ELECIDLE; + input PIPERX06EQDONE; + input PIPERX06EQLPADAPTDONE; + input PIPERX06EQLPLFFSSEL; + input [17:0] PIPERX06EQLPNEWTXCOEFFORPRESET; + input PIPERX06PHYSTATUS; + input [1:0] PIPERX06STARTBLOCK; + input [2:0] PIPERX06STATUS; + input [1:0] PIPERX06SYNCHEADER; + input PIPERX06VALID; + input [1:0] PIPERX07CHARISK; + input [31:0] PIPERX07DATA; + input PIPERX07DATAVALID; + input PIPERX07ELECIDLE; + input PIPERX07EQDONE; + input PIPERX07EQLPADAPTDONE; + input PIPERX07EQLPLFFSSEL; + input [17:0] PIPERX07EQLPNEWTXCOEFFORPRESET; + input PIPERX07PHYSTATUS; + input [1:0] PIPERX07STARTBLOCK; + input [2:0] PIPERX07STATUS; + input [1:0] PIPERX07SYNCHEADER; + input PIPERX07VALID; + input [1:0] PIPERX08CHARISK; + input [31:0] PIPERX08DATA; + input PIPERX08DATAVALID; + input PIPERX08ELECIDLE; + input PIPERX08EQDONE; + input PIPERX08EQLPADAPTDONE; + input PIPERX08EQLPLFFSSEL; + input [17:0] PIPERX08EQLPNEWTXCOEFFORPRESET; + input PIPERX08PHYSTATUS; + input [1:0] PIPERX08STARTBLOCK; + input [2:0] PIPERX08STATUS; + input [1:0] PIPERX08SYNCHEADER; + input PIPERX08VALID; + input [1:0] PIPERX09CHARISK; + input [31:0] PIPERX09DATA; + input PIPERX09DATAVALID; + input PIPERX09ELECIDLE; + input PIPERX09EQDONE; + input PIPERX09EQLPADAPTDONE; + input PIPERX09EQLPLFFSSEL; + input [17:0] PIPERX09EQLPNEWTXCOEFFORPRESET; + input PIPERX09PHYSTATUS; + input [1:0] PIPERX09STARTBLOCK; + input [2:0] PIPERX09STATUS; + input [1:0] PIPERX09SYNCHEADER; + input PIPERX09VALID; + input [1:0] PIPERX10CHARISK; + input [31:0] PIPERX10DATA; + input PIPERX10DATAVALID; + input PIPERX10ELECIDLE; + input PIPERX10EQDONE; + input PIPERX10EQLPADAPTDONE; + input PIPERX10EQLPLFFSSEL; + input [17:0] PIPERX10EQLPNEWTXCOEFFORPRESET; + input PIPERX10PHYSTATUS; + input [1:0] PIPERX10STARTBLOCK; + input [2:0] PIPERX10STATUS; + input [1:0] PIPERX10SYNCHEADER; + input PIPERX10VALID; + input [1:0] PIPERX11CHARISK; + input [31:0] PIPERX11DATA; + input PIPERX11DATAVALID; + input PIPERX11ELECIDLE; + input PIPERX11EQDONE; + input PIPERX11EQLPADAPTDONE; + input PIPERX11EQLPLFFSSEL; + input [17:0] PIPERX11EQLPNEWTXCOEFFORPRESET; + input PIPERX11PHYSTATUS; + input [1:0] PIPERX11STARTBLOCK; + input [2:0] PIPERX11STATUS; + input [1:0] PIPERX11SYNCHEADER; + input PIPERX11VALID; + input [1:0] PIPERX12CHARISK; + input [31:0] PIPERX12DATA; + input PIPERX12DATAVALID; + input PIPERX12ELECIDLE; + input PIPERX12EQDONE; + input PIPERX12EQLPADAPTDONE; + input PIPERX12EQLPLFFSSEL; + input [17:0] PIPERX12EQLPNEWTXCOEFFORPRESET; + input PIPERX12PHYSTATUS; + input [1:0] PIPERX12STARTBLOCK; + input [2:0] PIPERX12STATUS; + input [1:0] PIPERX12SYNCHEADER; + input PIPERX12VALID; + input [1:0] PIPERX13CHARISK; + input [31:0] PIPERX13DATA; + input PIPERX13DATAVALID; + input PIPERX13ELECIDLE; + input PIPERX13EQDONE; + input PIPERX13EQLPADAPTDONE; + input PIPERX13EQLPLFFSSEL; + input [17:0] PIPERX13EQLPNEWTXCOEFFORPRESET; + input PIPERX13PHYSTATUS; + input [1:0] PIPERX13STARTBLOCK; + input [2:0] PIPERX13STATUS; + input [1:0] PIPERX13SYNCHEADER; + input PIPERX13VALID; + input [1:0] PIPERX14CHARISK; + input [31:0] PIPERX14DATA; + input PIPERX14DATAVALID; + input PIPERX14ELECIDLE; + input PIPERX14EQDONE; + input PIPERX14EQLPADAPTDONE; + input PIPERX14EQLPLFFSSEL; + input [17:0] PIPERX14EQLPNEWTXCOEFFORPRESET; + input PIPERX14PHYSTATUS; + input [1:0] PIPERX14STARTBLOCK; + input [2:0] PIPERX14STATUS; + input [1:0] PIPERX14SYNCHEADER; + input PIPERX14VALID; + input [1:0] PIPERX15CHARISK; + input [31:0] PIPERX15DATA; + input PIPERX15DATAVALID; + input PIPERX15ELECIDLE; + input PIPERX15EQDONE; + input PIPERX15EQLPADAPTDONE; + input PIPERX15EQLPLFFSSEL; + input [17:0] PIPERX15EQLPNEWTXCOEFFORPRESET; + input PIPERX15PHYSTATUS; + input [1:0] PIPERX15STARTBLOCK; + input [2:0] PIPERX15STATUS; + input [1:0] PIPERX15SYNCHEADER; + input PIPERX15VALID; + input [17:0] PIPETX00EQCOEFF; + input PIPETX00EQDONE; + input [17:0] PIPETX01EQCOEFF; + input PIPETX01EQDONE; + input [17:0] PIPETX02EQCOEFF; + input PIPETX02EQDONE; + input [17:0] PIPETX03EQCOEFF; + input PIPETX03EQDONE; + input [17:0] PIPETX04EQCOEFF; + input PIPETX04EQDONE; + input [17:0] PIPETX05EQCOEFF; + input PIPETX05EQDONE; + input [17:0] PIPETX06EQCOEFF; + input PIPETX06EQDONE; + input [17:0] PIPETX07EQCOEFF; + input PIPETX07EQDONE; + input [17:0] PIPETX08EQCOEFF; + input PIPETX08EQDONE; + input [17:0] PIPETX09EQCOEFF; + input PIPETX09EQDONE; + input [17:0] PIPETX10EQCOEFF; + input PIPETX10EQDONE; + input [17:0] PIPETX11EQCOEFF; + input PIPETX11EQDONE; + input [17:0] PIPETX12EQCOEFF; + input PIPETX12EQDONE; + input [17:0] PIPETX13EQCOEFF; + input PIPETX13EQDONE; + input [17:0] PIPETX14EQCOEFF; + input PIPETX14EQDONE; + input [17:0] PIPETX15EQCOEFF; + input PIPETX15EQDONE; + input PLEQRESETEIEOSCOUNT; + input PLGEN2UPSTREAMPREFERDEEMPH; + input PLGEN34REDOEQSPEED; + input PLGEN34REDOEQUALIZATION; + input RESETN; + input [255:0] SAXISCCTDATA; + input [7:0] SAXISCCTKEEP; + input SAXISCCTLAST; + input [32:0] SAXISCCTUSER; + input SAXISCCTVALID; + input [255:0] SAXISRQTDATA; + input [7:0] SAXISRQTKEEP; + input SAXISRQTLAST; + input [61:0] SAXISRQTUSER; + input SAXISRQTVALID; + input USERCLK; + input USERCLK2; + input USERCLKEN; + input [31:0] USERSPAREIN; +endmodule + +module PCIE_3_1 (...); + parameter ARI_CAP_ENABLE = "FALSE"; + parameter AXISTEN_IF_CC_ALIGNMENT_MODE = "FALSE"; + parameter AXISTEN_IF_CC_PARITY_CHK = "TRUE"; + parameter AXISTEN_IF_CQ_ALIGNMENT_MODE = "FALSE"; + parameter AXISTEN_IF_ENABLE_CLIENT_TAG = "FALSE"; + parameter [17:0] AXISTEN_IF_ENABLE_MSG_ROUTE = 18'h00000; + parameter AXISTEN_IF_ENABLE_RX_MSG_INTFC = "FALSE"; + parameter AXISTEN_IF_RC_ALIGNMENT_MODE = "FALSE"; + parameter AXISTEN_IF_RC_STRADDLE = "FALSE"; + parameter AXISTEN_IF_RQ_ALIGNMENT_MODE = "FALSE"; + parameter AXISTEN_IF_RQ_PARITY_CHK = "TRUE"; + parameter [1:0] AXISTEN_IF_WIDTH = 2'h2; + parameter CRM_CORE_CLK_FREQ_500 = "TRUE"; + parameter [1:0] CRM_USER_CLK_FREQ = 2'h2; + parameter DEBUG_CFG_LOCAL_MGMT_REG_ACCESS_OVERRIDE = "FALSE"; + parameter DEBUG_PL_DISABLE_EI_INFER_IN_L0 = "FALSE"; + parameter DEBUG_TL_DISABLE_RX_TLP_ORDER_CHECKS = "FALSE"; + parameter [7:0] DNSTREAM_LINK_NUM = 8'h00; + parameter [8:0] LL_ACK_TIMEOUT = 9'h000; + parameter LL_ACK_TIMEOUT_EN = "FALSE"; + parameter integer LL_ACK_TIMEOUT_FUNC = 0; + parameter [15:0] LL_CPL_FC_UPDATE_TIMER = 16'h0000; + parameter LL_CPL_FC_UPDATE_TIMER_OVERRIDE = "FALSE"; + parameter [15:0] LL_FC_UPDATE_TIMER = 16'h0000; + parameter LL_FC_UPDATE_TIMER_OVERRIDE = "FALSE"; + parameter [15:0] LL_NP_FC_UPDATE_TIMER = 16'h0000; + parameter LL_NP_FC_UPDATE_TIMER_OVERRIDE = "FALSE"; + parameter [15:0] LL_P_FC_UPDATE_TIMER = 16'h0000; + parameter LL_P_FC_UPDATE_TIMER_OVERRIDE = "FALSE"; + parameter [8:0] LL_REPLAY_TIMEOUT = 9'h000; + parameter LL_REPLAY_TIMEOUT_EN = "FALSE"; + parameter integer LL_REPLAY_TIMEOUT_FUNC = 0; + parameter [9:0] LTR_TX_MESSAGE_MINIMUM_INTERVAL = 10'h0FA; + parameter LTR_TX_MESSAGE_ON_FUNC_POWER_STATE_CHANGE = "FALSE"; + parameter LTR_TX_MESSAGE_ON_LTR_ENABLE = "FALSE"; + parameter [11:0] MCAP_CAP_NEXTPTR = 12'h000; + parameter MCAP_CONFIGURE_OVERRIDE = "FALSE"; + parameter MCAP_ENABLE = "FALSE"; + parameter MCAP_EOS_DESIGN_SWITCH = "FALSE"; + parameter [31:0] MCAP_FPGA_BITSTREAM_VERSION = 32'h00000000; + parameter MCAP_GATE_IO_ENABLE_DESIGN_SWITCH = "FALSE"; + parameter MCAP_GATE_MEM_ENABLE_DESIGN_SWITCH = "FALSE"; + parameter MCAP_INPUT_GATE_DESIGN_SWITCH = "FALSE"; + parameter MCAP_INTERRUPT_ON_MCAP_EOS = "FALSE"; + parameter MCAP_INTERRUPT_ON_MCAP_ERROR = "FALSE"; + parameter [15:0] MCAP_VSEC_ID = 16'h0000; + parameter [11:0] MCAP_VSEC_LEN = 12'h02C; + parameter [3:0] MCAP_VSEC_REV = 4'h0; + parameter PF0_AER_CAP_ECRC_CHECK_CAPABLE = "FALSE"; + parameter PF0_AER_CAP_ECRC_GEN_CAPABLE = "FALSE"; + parameter [11:0] PF0_AER_CAP_NEXTPTR = 12'h000; + parameter [11:0] PF0_ARI_CAP_NEXTPTR = 12'h000; + parameter [7:0] PF0_ARI_CAP_NEXT_FUNC = 8'h00; + parameter [3:0] PF0_ARI_CAP_VER = 4'h1; + parameter [5:0] PF0_BAR0_APERTURE_SIZE = 6'h03; + parameter [2:0] PF0_BAR0_CONTROL = 3'h4; + parameter [5:0] PF0_BAR1_APERTURE_SIZE = 6'h00; + parameter [2:0] PF0_BAR1_CONTROL = 3'h0; + parameter [4:0] PF0_BAR2_APERTURE_SIZE = 5'h03; + parameter [2:0] PF0_BAR2_CONTROL = 3'h4; + parameter [4:0] PF0_BAR3_APERTURE_SIZE = 5'h03; + parameter [2:0] PF0_BAR3_CONTROL = 3'h0; + parameter [4:0] PF0_BAR4_APERTURE_SIZE = 5'h03; + parameter [2:0] PF0_BAR4_CONTROL = 3'h4; + parameter [4:0] PF0_BAR5_APERTURE_SIZE = 5'h03; + parameter [2:0] PF0_BAR5_CONTROL = 3'h0; + parameter [7:0] PF0_BIST_REGISTER = 8'h00; + parameter [7:0] PF0_CAPABILITY_POINTER = 8'h50; + parameter [23:0] PF0_CLASS_CODE = 24'h000000; + parameter [15:0] PF0_DEVICE_ID = 16'h0000; + parameter PF0_DEV_CAP2_128B_CAS_ATOMIC_COMPLETER_SUPPORT = "TRUE"; + parameter PF0_DEV_CAP2_32B_ATOMIC_COMPLETER_SUPPORT = "TRUE"; + parameter PF0_DEV_CAP2_64B_ATOMIC_COMPLETER_SUPPORT = "TRUE"; + parameter PF0_DEV_CAP2_ARI_FORWARD_ENABLE = "FALSE"; + parameter PF0_DEV_CAP2_CPL_TIMEOUT_DISABLE = "TRUE"; + parameter PF0_DEV_CAP2_LTR_SUPPORT = "TRUE"; + parameter [1:0] PF0_DEV_CAP2_OBFF_SUPPORT = 2'h0; + parameter PF0_DEV_CAP2_TPH_COMPLETER_SUPPORT = "FALSE"; + parameter integer PF0_DEV_CAP_ENDPOINT_L0S_LATENCY = 0; + parameter integer PF0_DEV_CAP_ENDPOINT_L1_LATENCY = 0; + parameter PF0_DEV_CAP_EXT_TAG_SUPPORTED = "TRUE"; + parameter PF0_DEV_CAP_FUNCTION_LEVEL_RESET_CAPABLE = "TRUE"; + parameter [2:0] PF0_DEV_CAP_MAX_PAYLOAD_SIZE = 3'h3; + parameter [11:0] PF0_DPA_CAP_NEXTPTR = 12'h000; + parameter [4:0] PF0_DPA_CAP_SUB_STATE_CONTROL = 5'h00; + parameter PF0_DPA_CAP_SUB_STATE_CONTROL_EN = "TRUE"; + parameter [7:0] PF0_DPA_CAP_SUB_STATE_POWER_ALLOCATION0 = 8'h00; + parameter [7:0] PF0_DPA_CAP_SUB_STATE_POWER_ALLOCATION1 = 8'h00; + parameter [7:0] PF0_DPA_CAP_SUB_STATE_POWER_ALLOCATION2 = 8'h00; + parameter [7:0] PF0_DPA_CAP_SUB_STATE_POWER_ALLOCATION3 = 8'h00; + parameter [7:0] PF0_DPA_CAP_SUB_STATE_POWER_ALLOCATION4 = 8'h00; + parameter [7:0] PF0_DPA_CAP_SUB_STATE_POWER_ALLOCATION5 = 8'h00; + parameter [7:0] PF0_DPA_CAP_SUB_STATE_POWER_ALLOCATION6 = 8'h00; + parameter [7:0] PF0_DPA_CAP_SUB_STATE_POWER_ALLOCATION7 = 8'h00; + parameter [3:0] PF0_DPA_CAP_VER = 4'h1; + parameter [11:0] PF0_DSN_CAP_NEXTPTR = 12'h10C; + parameter [4:0] PF0_EXPANSION_ROM_APERTURE_SIZE = 5'h03; + parameter PF0_EXPANSION_ROM_ENABLE = "FALSE"; + parameter [7:0] PF0_INTERRUPT_LINE = 8'h00; + parameter [2:0] PF0_INTERRUPT_PIN = 3'h1; + parameter integer PF0_LINK_CAP_ASPM_SUPPORT = 0; + parameter integer PF0_LINK_CAP_L0S_EXIT_LATENCY_COMCLK_GEN1 = 7; + parameter integer PF0_LINK_CAP_L0S_EXIT_LATENCY_COMCLK_GEN2 = 7; + parameter integer PF0_LINK_CAP_L0S_EXIT_LATENCY_COMCLK_GEN3 = 7; + parameter integer PF0_LINK_CAP_L0S_EXIT_LATENCY_GEN1 = 7; + parameter integer PF0_LINK_CAP_L0S_EXIT_LATENCY_GEN2 = 7; + parameter integer PF0_LINK_CAP_L0S_EXIT_LATENCY_GEN3 = 7; + parameter integer PF0_LINK_CAP_L1_EXIT_LATENCY_COMCLK_GEN1 = 7; + parameter integer PF0_LINK_CAP_L1_EXIT_LATENCY_COMCLK_GEN2 = 7; + parameter integer PF0_LINK_CAP_L1_EXIT_LATENCY_COMCLK_GEN3 = 7; + parameter integer PF0_LINK_CAP_L1_EXIT_LATENCY_GEN1 = 7; + parameter integer PF0_LINK_CAP_L1_EXIT_LATENCY_GEN2 = 7; + parameter integer PF0_LINK_CAP_L1_EXIT_LATENCY_GEN3 = 7; + parameter PF0_LINK_STATUS_SLOT_CLOCK_CONFIG = "TRUE"; + parameter [9:0] PF0_LTR_CAP_MAX_NOSNOOP_LAT = 10'h000; + parameter [9:0] PF0_LTR_CAP_MAX_SNOOP_LAT = 10'h000; + parameter [11:0] PF0_LTR_CAP_NEXTPTR = 12'h000; + parameter [3:0] PF0_LTR_CAP_VER = 4'h1; + parameter [7:0] PF0_MSIX_CAP_NEXTPTR = 8'h00; + parameter integer PF0_MSIX_CAP_PBA_BIR = 0; + parameter [28:0] PF0_MSIX_CAP_PBA_OFFSET = 29'h00000050; + parameter integer PF0_MSIX_CAP_TABLE_BIR = 0; + parameter [28:0] PF0_MSIX_CAP_TABLE_OFFSET = 29'h00000040; + parameter [10:0] PF0_MSIX_CAP_TABLE_SIZE = 11'h000; + parameter integer PF0_MSI_CAP_MULTIMSGCAP = 0; + parameter [7:0] PF0_MSI_CAP_NEXTPTR = 8'h00; + parameter PF0_MSI_CAP_PERVECMASKCAP = "FALSE"; + parameter [31:0] PF0_PB_CAP_DATA_REG_D0 = 32'h00000000; + parameter [31:0] PF0_PB_CAP_DATA_REG_D0_SUSTAINED = 32'h00000000; + parameter [31:0] PF0_PB_CAP_DATA_REG_D1 = 32'h00000000; + parameter [31:0] PF0_PB_CAP_DATA_REG_D3HOT = 32'h00000000; + parameter [11:0] PF0_PB_CAP_NEXTPTR = 12'h000; + parameter PF0_PB_CAP_SYSTEM_ALLOCATED = "FALSE"; + parameter [3:0] PF0_PB_CAP_VER = 4'h1; + parameter [7:0] PF0_PM_CAP_ID = 8'h01; + parameter [7:0] PF0_PM_CAP_NEXTPTR = 8'h00; + parameter PF0_PM_CAP_PMESUPPORT_D0 = "TRUE"; + parameter PF0_PM_CAP_PMESUPPORT_D1 = "TRUE"; + parameter PF0_PM_CAP_PMESUPPORT_D3HOT = "TRUE"; + parameter PF0_PM_CAP_SUPP_D1_STATE = "TRUE"; + parameter [2:0] PF0_PM_CAP_VER_ID = 3'h3; + parameter PF0_PM_CSR_NOSOFTRESET = "TRUE"; + parameter PF0_RBAR_CAP_ENABLE = "FALSE"; + parameter [11:0] PF0_RBAR_CAP_NEXTPTR = 12'h000; + parameter [19:0] PF0_RBAR_CAP_SIZE0 = 20'h00000; + parameter [19:0] PF0_RBAR_CAP_SIZE1 = 20'h00000; + parameter [19:0] PF0_RBAR_CAP_SIZE2 = 20'h00000; + parameter [3:0] PF0_RBAR_CAP_VER = 4'h1; + parameter [2:0] PF0_RBAR_CONTROL_INDEX0 = 3'h0; + parameter [2:0] PF0_RBAR_CONTROL_INDEX1 = 3'h0; + parameter [2:0] PF0_RBAR_CONTROL_INDEX2 = 3'h0; + parameter [4:0] PF0_RBAR_CONTROL_SIZE0 = 5'h00; + parameter [4:0] PF0_RBAR_CONTROL_SIZE1 = 5'h00; + parameter [4:0] PF0_RBAR_CONTROL_SIZE2 = 5'h00; + parameter [2:0] PF0_RBAR_NUM = 3'h1; + parameter [7:0] PF0_REVISION_ID = 8'h00; + parameter [11:0] PF0_SECONDARY_PCIE_CAP_NEXTPTR = 12'h000; + parameter [4:0] PF0_SRIOV_BAR0_APERTURE_SIZE = 5'h03; + parameter [2:0] PF0_SRIOV_BAR0_CONTROL = 3'h4; + parameter [4:0] PF0_SRIOV_BAR1_APERTURE_SIZE = 5'h00; + parameter [2:0] PF0_SRIOV_BAR1_CONTROL = 3'h0; + parameter [4:0] PF0_SRIOV_BAR2_APERTURE_SIZE = 5'h03; + parameter [2:0] PF0_SRIOV_BAR2_CONTROL = 3'h4; + parameter [4:0] PF0_SRIOV_BAR3_APERTURE_SIZE = 5'h03; + parameter [2:0] PF0_SRIOV_BAR3_CONTROL = 3'h0; + parameter [4:0] PF0_SRIOV_BAR4_APERTURE_SIZE = 5'h03; + parameter [2:0] PF0_SRIOV_BAR4_CONTROL = 3'h4; + parameter [4:0] PF0_SRIOV_BAR5_APERTURE_SIZE = 5'h03; + parameter [2:0] PF0_SRIOV_BAR5_CONTROL = 3'h0; + parameter [15:0] PF0_SRIOV_CAP_INITIAL_VF = 16'h0000; + parameter [11:0] PF0_SRIOV_CAP_NEXTPTR = 12'h000; + parameter [15:0] PF0_SRIOV_CAP_TOTAL_VF = 16'h0000; + parameter [3:0] PF0_SRIOV_CAP_VER = 4'h1; + parameter [15:0] PF0_SRIOV_FIRST_VF_OFFSET = 16'h0000; + parameter [15:0] PF0_SRIOV_FUNC_DEP_LINK = 16'h0000; + parameter [31:0] PF0_SRIOV_SUPPORTED_PAGE_SIZE = 32'h00000000; + parameter [15:0] PF0_SRIOV_VF_DEVICE_ID = 16'h0000; + parameter [15:0] PF0_SUBSYSTEM_ID = 16'h0000; + parameter PF0_TPHR_CAP_DEV_SPECIFIC_MODE = "TRUE"; + parameter PF0_TPHR_CAP_ENABLE = "FALSE"; + parameter PF0_TPHR_CAP_INT_VEC_MODE = "TRUE"; + parameter [11:0] PF0_TPHR_CAP_NEXTPTR = 12'h000; + parameter [2:0] PF0_TPHR_CAP_ST_MODE_SEL = 3'h0; + parameter [1:0] PF0_TPHR_CAP_ST_TABLE_LOC = 2'h0; + parameter [10:0] PF0_TPHR_CAP_ST_TABLE_SIZE = 11'h000; + parameter [3:0] PF0_TPHR_CAP_VER = 4'h1; + parameter PF0_VC_CAP_ENABLE = "FALSE"; + parameter [11:0] PF0_VC_CAP_NEXTPTR = 12'h000; + parameter [3:0] PF0_VC_CAP_VER = 4'h1; + parameter PF1_AER_CAP_ECRC_CHECK_CAPABLE = "FALSE"; + parameter PF1_AER_CAP_ECRC_GEN_CAPABLE = "FALSE"; + parameter [11:0] PF1_AER_CAP_NEXTPTR = 12'h000; + parameter [11:0] PF1_ARI_CAP_NEXTPTR = 12'h000; + parameter [7:0] PF1_ARI_CAP_NEXT_FUNC = 8'h00; + parameter [5:0] PF1_BAR0_APERTURE_SIZE = 6'h03; + parameter [2:0] PF1_BAR0_CONTROL = 3'h4; + parameter [5:0] PF1_BAR1_APERTURE_SIZE = 6'h00; + parameter [2:0] PF1_BAR1_CONTROL = 3'h0; + parameter [4:0] PF1_BAR2_APERTURE_SIZE = 5'h03; + parameter [2:0] PF1_BAR2_CONTROL = 3'h4; + parameter [4:0] PF1_BAR3_APERTURE_SIZE = 5'h03; + parameter [2:0] PF1_BAR3_CONTROL = 3'h0; + parameter [4:0] PF1_BAR4_APERTURE_SIZE = 5'h03; + parameter [2:0] PF1_BAR4_CONTROL = 3'h4; + parameter [4:0] PF1_BAR5_APERTURE_SIZE = 5'h03; + parameter [2:0] PF1_BAR5_CONTROL = 3'h0; + parameter [7:0] PF1_BIST_REGISTER = 8'h00; + parameter [7:0] PF1_CAPABILITY_POINTER = 8'h50; + parameter [23:0] PF1_CLASS_CODE = 24'h000000; + parameter [15:0] PF1_DEVICE_ID = 16'h0000; + parameter [2:0] PF1_DEV_CAP_MAX_PAYLOAD_SIZE = 3'h3; + parameter [11:0] PF1_DPA_CAP_NEXTPTR = 12'h000; + parameter [4:0] PF1_DPA_CAP_SUB_STATE_CONTROL = 5'h00; + parameter PF1_DPA_CAP_SUB_STATE_CONTROL_EN = "TRUE"; + parameter [7:0] PF1_DPA_CAP_SUB_STATE_POWER_ALLOCATION0 = 8'h00; + parameter [7:0] PF1_DPA_CAP_SUB_STATE_POWER_ALLOCATION1 = 8'h00; + parameter [7:0] PF1_DPA_CAP_SUB_STATE_POWER_ALLOCATION2 = 8'h00; + parameter [7:0] PF1_DPA_CAP_SUB_STATE_POWER_ALLOCATION3 = 8'h00; + parameter [7:0] PF1_DPA_CAP_SUB_STATE_POWER_ALLOCATION4 = 8'h00; + parameter [7:0] PF1_DPA_CAP_SUB_STATE_POWER_ALLOCATION5 = 8'h00; + parameter [7:0] PF1_DPA_CAP_SUB_STATE_POWER_ALLOCATION6 = 8'h00; + parameter [7:0] PF1_DPA_CAP_SUB_STATE_POWER_ALLOCATION7 = 8'h00; + parameter [3:0] PF1_DPA_CAP_VER = 4'h1; + parameter [11:0] PF1_DSN_CAP_NEXTPTR = 12'h10C; + parameter [4:0] PF1_EXPANSION_ROM_APERTURE_SIZE = 5'h03; + parameter PF1_EXPANSION_ROM_ENABLE = "FALSE"; + parameter [7:0] PF1_INTERRUPT_LINE = 8'h00; + parameter [2:0] PF1_INTERRUPT_PIN = 3'h1; + parameter [7:0] PF1_MSIX_CAP_NEXTPTR = 8'h00; + parameter integer PF1_MSIX_CAP_PBA_BIR = 0; + parameter [28:0] PF1_MSIX_CAP_PBA_OFFSET = 29'h00000050; + parameter integer PF1_MSIX_CAP_TABLE_BIR = 0; + parameter [28:0] PF1_MSIX_CAP_TABLE_OFFSET = 29'h00000040; + parameter [10:0] PF1_MSIX_CAP_TABLE_SIZE = 11'h000; + parameter integer PF1_MSI_CAP_MULTIMSGCAP = 0; + parameter [7:0] PF1_MSI_CAP_NEXTPTR = 8'h00; + parameter PF1_MSI_CAP_PERVECMASKCAP = "FALSE"; + parameter [31:0] PF1_PB_CAP_DATA_REG_D0 = 32'h00000000; + parameter [31:0] PF1_PB_CAP_DATA_REG_D0_SUSTAINED = 32'h00000000; + parameter [31:0] PF1_PB_CAP_DATA_REG_D1 = 32'h00000000; + parameter [31:0] PF1_PB_CAP_DATA_REG_D3HOT = 32'h00000000; + parameter [11:0] PF1_PB_CAP_NEXTPTR = 12'h000; + parameter PF1_PB_CAP_SYSTEM_ALLOCATED = "FALSE"; + parameter [3:0] PF1_PB_CAP_VER = 4'h1; + parameter [7:0] PF1_PM_CAP_ID = 8'h01; + parameter [7:0] PF1_PM_CAP_NEXTPTR = 8'h00; + parameter [2:0] PF1_PM_CAP_VER_ID = 3'h3; + parameter PF1_RBAR_CAP_ENABLE = "FALSE"; + parameter [11:0] PF1_RBAR_CAP_NEXTPTR = 12'h000; + parameter [19:0] PF1_RBAR_CAP_SIZE0 = 20'h00000; + parameter [19:0] PF1_RBAR_CAP_SIZE1 = 20'h00000; + parameter [19:0] PF1_RBAR_CAP_SIZE2 = 20'h00000; + parameter [3:0] PF1_RBAR_CAP_VER = 4'h1; + parameter [2:0] PF1_RBAR_CONTROL_INDEX0 = 3'h0; + parameter [2:0] PF1_RBAR_CONTROL_INDEX1 = 3'h0; + parameter [2:0] PF1_RBAR_CONTROL_INDEX2 = 3'h0; + parameter [4:0] PF1_RBAR_CONTROL_SIZE0 = 5'h00; + parameter [4:0] PF1_RBAR_CONTROL_SIZE1 = 5'h00; + parameter [4:0] PF1_RBAR_CONTROL_SIZE2 = 5'h00; + parameter [2:0] PF1_RBAR_NUM = 3'h1; + parameter [7:0] PF1_REVISION_ID = 8'h00; + parameter [4:0] PF1_SRIOV_BAR0_APERTURE_SIZE = 5'h03; + parameter [2:0] PF1_SRIOV_BAR0_CONTROL = 3'h4; + parameter [4:0] PF1_SRIOV_BAR1_APERTURE_SIZE = 5'h00; + parameter [2:0] PF1_SRIOV_BAR1_CONTROL = 3'h0; + parameter [4:0] PF1_SRIOV_BAR2_APERTURE_SIZE = 5'h03; + parameter [2:0] PF1_SRIOV_BAR2_CONTROL = 3'h4; + parameter [4:0] PF1_SRIOV_BAR3_APERTURE_SIZE = 5'h03; + parameter [2:0] PF1_SRIOV_BAR3_CONTROL = 3'h0; + parameter [4:0] PF1_SRIOV_BAR4_APERTURE_SIZE = 5'h03; + parameter [2:0] PF1_SRIOV_BAR4_CONTROL = 3'h4; + parameter [4:0] PF1_SRIOV_BAR5_APERTURE_SIZE = 5'h03; + parameter [2:0] PF1_SRIOV_BAR5_CONTROL = 3'h0; + parameter [15:0] PF1_SRIOV_CAP_INITIAL_VF = 16'h0000; + parameter [11:0] PF1_SRIOV_CAP_NEXTPTR = 12'h000; + parameter [15:0] PF1_SRIOV_CAP_TOTAL_VF = 16'h0000; + parameter [3:0] PF1_SRIOV_CAP_VER = 4'h1; + parameter [15:0] PF1_SRIOV_FIRST_VF_OFFSET = 16'h0000; + parameter [15:0] PF1_SRIOV_FUNC_DEP_LINK = 16'h0000; + parameter [31:0] PF1_SRIOV_SUPPORTED_PAGE_SIZE = 32'h00000000; + parameter [15:0] PF1_SRIOV_VF_DEVICE_ID = 16'h0000; + parameter [15:0] PF1_SUBSYSTEM_ID = 16'h0000; + parameter PF1_TPHR_CAP_DEV_SPECIFIC_MODE = "TRUE"; + parameter PF1_TPHR_CAP_ENABLE = "FALSE"; + parameter PF1_TPHR_CAP_INT_VEC_MODE = "TRUE"; + parameter [11:0] PF1_TPHR_CAP_NEXTPTR = 12'h000; + parameter [2:0] PF1_TPHR_CAP_ST_MODE_SEL = 3'h0; + parameter [1:0] PF1_TPHR_CAP_ST_TABLE_LOC = 2'h0; + parameter [10:0] PF1_TPHR_CAP_ST_TABLE_SIZE = 11'h000; + parameter [3:0] PF1_TPHR_CAP_VER = 4'h1; + parameter PF2_AER_CAP_ECRC_CHECK_CAPABLE = "FALSE"; + parameter PF2_AER_CAP_ECRC_GEN_CAPABLE = "FALSE"; + parameter [11:0] PF2_AER_CAP_NEXTPTR = 12'h000; + parameter [11:0] PF2_ARI_CAP_NEXTPTR = 12'h000; + parameter [7:0] PF2_ARI_CAP_NEXT_FUNC = 8'h00; + parameter [5:0] PF2_BAR0_APERTURE_SIZE = 6'h03; + parameter [2:0] PF2_BAR0_CONTROL = 3'h4; + parameter [5:0] PF2_BAR1_APERTURE_SIZE = 6'h00; + parameter [2:0] PF2_BAR1_CONTROL = 3'h0; + parameter [4:0] PF2_BAR2_APERTURE_SIZE = 5'h03; + parameter [2:0] PF2_BAR2_CONTROL = 3'h4; + parameter [4:0] PF2_BAR3_APERTURE_SIZE = 5'h03; + parameter [2:0] PF2_BAR3_CONTROL = 3'h0; + parameter [4:0] PF2_BAR4_APERTURE_SIZE = 5'h03; + parameter [2:0] PF2_BAR4_CONTROL = 3'h4; + parameter [4:0] PF2_BAR5_APERTURE_SIZE = 5'h03; + parameter [2:0] PF2_BAR5_CONTROL = 3'h0; + parameter [7:0] PF2_BIST_REGISTER = 8'h00; + parameter [7:0] PF2_CAPABILITY_POINTER = 8'h50; + parameter [23:0] PF2_CLASS_CODE = 24'h000000; + parameter [15:0] PF2_DEVICE_ID = 16'h0000; + parameter [2:0] PF2_DEV_CAP_MAX_PAYLOAD_SIZE = 3'h3; + parameter [11:0] PF2_DPA_CAP_NEXTPTR = 12'h000; + parameter [4:0] PF2_DPA_CAP_SUB_STATE_CONTROL = 5'h00; + parameter PF2_DPA_CAP_SUB_STATE_CONTROL_EN = "TRUE"; + parameter [7:0] PF2_DPA_CAP_SUB_STATE_POWER_ALLOCATION0 = 8'h00; + parameter [7:0] PF2_DPA_CAP_SUB_STATE_POWER_ALLOCATION1 = 8'h00; + parameter [7:0] PF2_DPA_CAP_SUB_STATE_POWER_ALLOCATION2 = 8'h00; + parameter [7:0] PF2_DPA_CAP_SUB_STATE_POWER_ALLOCATION3 = 8'h00; + parameter [7:0] PF2_DPA_CAP_SUB_STATE_POWER_ALLOCATION4 = 8'h00; + parameter [7:0] PF2_DPA_CAP_SUB_STATE_POWER_ALLOCATION5 = 8'h00; + parameter [7:0] PF2_DPA_CAP_SUB_STATE_POWER_ALLOCATION6 = 8'h00; + parameter [7:0] PF2_DPA_CAP_SUB_STATE_POWER_ALLOCATION7 = 8'h00; + parameter [3:0] PF2_DPA_CAP_VER = 4'h1; + parameter [11:0] PF2_DSN_CAP_NEXTPTR = 12'h10C; + parameter [4:0] PF2_EXPANSION_ROM_APERTURE_SIZE = 5'h03; + parameter PF2_EXPANSION_ROM_ENABLE = "FALSE"; + parameter [7:0] PF2_INTERRUPT_LINE = 8'h00; + parameter [2:0] PF2_INTERRUPT_PIN = 3'h1; + parameter [7:0] PF2_MSIX_CAP_NEXTPTR = 8'h00; + parameter integer PF2_MSIX_CAP_PBA_BIR = 0; + parameter [28:0] PF2_MSIX_CAP_PBA_OFFSET = 29'h00000050; + parameter integer PF2_MSIX_CAP_TABLE_BIR = 0; + parameter [28:0] PF2_MSIX_CAP_TABLE_OFFSET = 29'h00000040; + parameter [10:0] PF2_MSIX_CAP_TABLE_SIZE = 11'h000; + parameter integer PF2_MSI_CAP_MULTIMSGCAP = 0; + parameter [7:0] PF2_MSI_CAP_NEXTPTR = 8'h00; + parameter PF2_MSI_CAP_PERVECMASKCAP = "FALSE"; + parameter [31:0] PF2_PB_CAP_DATA_REG_D0 = 32'h00000000; + parameter [31:0] PF2_PB_CAP_DATA_REG_D0_SUSTAINED = 32'h00000000; + parameter [31:0] PF2_PB_CAP_DATA_REG_D1 = 32'h00000000; + parameter [31:0] PF2_PB_CAP_DATA_REG_D3HOT = 32'h00000000; + parameter [11:0] PF2_PB_CAP_NEXTPTR = 12'h000; + parameter PF2_PB_CAP_SYSTEM_ALLOCATED = "FALSE"; + parameter [3:0] PF2_PB_CAP_VER = 4'h1; + parameter [7:0] PF2_PM_CAP_ID = 8'h01; + parameter [7:0] PF2_PM_CAP_NEXTPTR = 8'h00; + parameter [2:0] PF2_PM_CAP_VER_ID = 3'h3; + parameter PF2_RBAR_CAP_ENABLE = "FALSE"; + parameter [11:0] PF2_RBAR_CAP_NEXTPTR = 12'h000; + parameter [19:0] PF2_RBAR_CAP_SIZE0 = 20'h00000; + parameter [19:0] PF2_RBAR_CAP_SIZE1 = 20'h00000; + parameter [19:0] PF2_RBAR_CAP_SIZE2 = 20'h00000; + parameter [3:0] PF2_RBAR_CAP_VER = 4'h1; + parameter [2:0] PF2_RBAR_CONTROL_INDEX0 = 3'h0; + parameter [2:0] PF2_RBAR_CONTROL_INDEX1 = 3'h0; + parameter [2:0] PF2_RBAR_CONTROL_INDEX2 = 3'h0; + parameter [4:0] PF2_RBAR_CONTROL_SIZE0 = 5'h00; + parameter [4:0] PF2_RBAR_CONTROL_SIZE1 = 5'h00; + parameter [4:0] PF2_RBAR_CONTROL_SIZE2 = 5'h00; + parameter [2:0] PF2_RBAR_NUM = 3'h1; + parameter [7:0] PF2_REVISION_ID = 8'h00; + parameter [4:0] PF2_SRIOV_BAR0_APERTURE_SIZE = 5'h03; + parameter [2:0] PF2_SRIOV_BAR0_CONTROL = 3'h4; + parameter [4:0] PF2_SRIOV_BAR1_APERTURE_SIZE = 5'h00; + parameter [2:0] PF2_SRIOV_BAR1_CONTROL = 3'h0; + parameter [4:0] PF2_SRIOV_BAR2_APERTURE_SIZE = 5'h03; + parameter [2:0] PF2_SRIOV_BAR2_CONTROL = 3'h4; + parameter [4:0] PF2_SRIOV_BAR3_APERTURE_SIZE = 5'h03; + parameter [2:0] PF2_SRIOV_BAR3_CONTROL = 3'h0; + parameter [4:0] PF2_SRIOV_BAR4_APERTURE_SIZE = 5'h03; + parameter [2:0] PF2_SRIOV_BAR4_CONTROL = 3'h4; + parameter [4:0] PF2_SRIOV_BAR5_APERTURE_SIZE = 5'h03; + parameter [2:0] PF2_SRIOV_BAR5_CONTROL = 3'h0; + parameter [15:0] PF2_SRIOV_CAP_INITIAL_VF = 16'h0000; + parameter [11:0] PF2_SRIOV_CAP_NEXTPTR = 12'h000; + parameter [15:0] PF2_SRIOV_CAP_TOTAL_VF = 16'h0000; + parameter [3:0] PF2_SRIOV_CAP_VER = 4'h1; + parameter [15:0] PF2_SRIOV_FIRST_VF_OFFSET = 16'h0000; + parameter [15:0] PF2_SRIOV_FUNC_DEP_LINK = 16'h0000; + parameter [31:0] PF2_SRIOV_SUPPORTED_PAGE_SIZE = 32'h00000000; + parameter [15:0] PF2_SRIOV_VF_DEVICE_ID = 16'h0000; + parameter [15:0] PF2_SUBSYSTEM_ID = 16'h0000; + parameter PF2_TPHR_CAP_DEV_SPECIFIC_MODE = "TRUE"; + parameter PF2_TPHR_CAP_ENABLE = "FALSE"; + parameter PF2_TPHR_CAP_INT_VEC_MODE = "TRUE"; + parameter [11:0] PF2_TPHR_CAP_NEXTPTR = 12'h000; + parameter [2:0] PF2_TPHR_CAP_ST_MODE_SEL = 3'h0; + parameter [1:0] PF2_TPHR_CAP_ST_TABLE_LOC = 2'h0; + parameter [10:0] PF2_TPHR_CAP_ST_TABLE_SIZE = 11'h000; + parameter [3:0] PF2_TPHR_CAP_VER = 4'h1; + parameter PF3_AER_CAP_ECRC_CHECK_CAPABLE = "FALSE"; + parameter PF3_AER_CAP_ECRC_GEN_CAPABLE = "FALSE"; + parameter [11:0] PF3_AER_CAP_NEXTPTR = 12'h000; + parameter [11:0] PF3_ARI_CAP_NEXTPTR = 12'h000; + parameter [7:0] PF3_ARI_CAP_NEXT_FUNC = 8'h00; + parameter [5:0] PF3_BAR0_APERTURE_SIZE = 6'h03; + parameter [2:0] PF3_BAR0_CONTROL = 3'h4; + parameter [5:0] PF3_BAR1_APERTURE_SIZE = 6'h00; + parameter [2:0] PF3_BAR1_CONTROL = 3'h0; + parameter [4:0] PF3_BAR2_APERTURE_SIZE = 5'h03; + parameter [2:0] PF3_BAR2_CONTROL = 3'h4; + parameter [4:0] PF3_BAR3_APERTURE_SIZE = 5'h03; + parameter [2:0] PF3_BAR3_CONTROL = 3'h0; + parameter [4:0] PF3_BAR4_APERTURE_SIZE = 5'h03; + parameter [2:0] PF3_BAR4_CONTROL = 3'h4; + parameter [4:0] PF3_BAR5_APERTURE_SIZE = 5'h03; + parameter [2:0] PF3_BAR5_CONTROL = 3'h0; + parameter [7:0] PF3_BIST_REGISTER = 8'h00; + parameter [7:0] PF3_CAPABILITY_POINTER = 8'h50; + parameter [23:0] PF3_CLASS_CODE = 24'h000000; + parameter [15:0] PF3_DEVICE_ID = 16'h0000; + parameter [2:0] PF3_DEV_CAP_MAX_PAYLOAD_SIZE = 3'h3; + parameter [11:0] PF3_DPA_CAP_NEXTPTR = 12'h000; + parameter [4:0] PF3_DPA_CAP_SUB_STATE_CONTROL = 5'h00; + parameter PF3_DPA_CAP_SUB_STATE_CONTROL_EN = "TRUE"; + parameter [7:0] PF3_DPA_CAP_SUB_STATE_POWER_ALLOCATION0 = 8'h00; + parameter [7:0] PF3_DPA_CAP_SUB_STATE_POWER_ALLOCATION1 = 8'h00; + parameter [7:0] PF3_DPA_CAP_SUB_STATE_POWER_ALLOCATION2 = 8'h00; + parameter [7:0] PF3_DPA_CAP_SUB_STATE_POWER_ALLOCATION3 = 8'h00; + parameter [7:0] PF3_DPA_CAP_SUB_STATE_POWER_ALLOCATION4 = 8'h00; + parameter [7:0] PF3_DPA_CAP_SUB_STATE_POWER_ALLOCATION5 = 8'h00; + parameter [7:0] PF3_DPA_CAP_SUB_STATE_POWER_ALLOCATION6 = 8'h00; + parameter [7:0] PF3_DPA_CAP_SUB_STATE_POWER_ALLOCATION7 = 8'h00; + parameter [3:0] PF3_DPA_CAP_VER = 4'h1; + parameter [11:0] PF3_DSN_CAP_NEXTPTR = 12'h10C; + parameter [4:0] PF3_EXPANSION_ROM_APERTURE_SIZE = 5'h03; + parameter PF3_EXPANSION_ROM_ENABLE = "FALSE"; + parameter [7:0] PF3_INTERRUPT_LINE = 8'h00; + parameter [2:0] PF3_INTERRUPT_PIN = 3'h1; + parameter [7:0] PF3_MSIX_CAP_NEXTPTR = 8'h00; + parameter integer PF3_MSIX_CAP_PBA_BIR = 0; + parameter [28:0] PF3_MSIX_CAP_PBA_OFFSET = 29'h00000050; + parameter integer PF3_MSIX_CAP_TABLE_BIR = 0; + parameter [28:0] PF3_MSIX_CAP_TABLE_OFFSET = 29'h00000040; + parameter [10:0] PF3_MSIX_CAP_TABLE_SIZE = 11'h000; + parameter integer PF3_MSI_CAP_MULTIMSGCAP = 0; + parameter [7:0] PF3_MSI_CAP_NEXTPTR = 8'h00; + parameter PF3_MSI_CAP_PERVECMASKCAP = "FALSE"; + parameter [31:0] PF3_PB_CAP_DATA_REG_D0 = 32'h00000000; + parameter [31:0] PF3_PB_CAP_DATA_REG_D0_SUSTAINED = 32'h00000000; + parameter [31:0] PF3_PB_CAP_DATA_REG_D1 = 32'h00000000; + parameter [31:0] PF3_PB_CAP_DATA_REG_D3HOT = 32'h00000000; + parameter [11:0] PF3_PB_CAP_NEXTPTR = 12'h000; + parameter PF3_PB_CAP_SYSTEM_ALLOCATED = "FALSE"; + parameter [3:0] PF3_PB_CAP_VER = 4'h1; + parameter [7:0] PF3_PM_CAP_ID = 8'h01; + parameter [7:0] PF3_PM_CAP_NEXTPTR = 8'h00; + parameter [2:0] PF3_PM_CAP_VER_ID = 3'h3; + parameter PF3_RBAR_CAP_ENABLE = "FALSE"; + parameter [11:0] PF3_RBAR_CAP_NEXTPTR = 12'h000; + parameter [19:0] PF3_RBAR_CAP_SIZE0 = 20'h00000; + parameter [19:0] PF3_RBAR_CAP_SIZE1 = 20'h00000; + parameter [19:0] PF3_RBAR_CAP_SIZE2 = 20'h00000; + parameter [3:0] PF3_RBAR_CAP_VER = 4'h1; + parameter [2:0] PF3_RBAR_CONTROL_INDEX0 = 3'h0; + parameter [2:0] PF3_RBAR_CONTROL_INDEX1 = 3'h0; + parameter [2:0] PF3_RBAR_CONTROL_INDEX2 = 3'h0; + parameter [4:0] PF3_RBAR_CONTROL_SIZE0 = 5'h00; + parameter [4:0] PF3_RBAR_CONTROL_SIZE1 = 5'h00; + parameter [4:0] PF3_RBAR_CONTROL_SIZE2 = 5'h00; + parameter [2:0] PF3_RBAR_NUM = 3'h1; + parameter [7:0] PF3_REVISION_ID = 8'h00; + parameter [4:0] PF3_SRIOV_BAR0_APERTURE_SIZE = 5'h03; + parameter [2:0] PF3_SRIOV_BAR0_CONTROL = 3'h4; + parameter [4:0] PF3_SRIOV_BAR1_APERTURE_SIZE = 5'h00; + parameter [2:0] PF3_SRIOV_BAR1_CONTROL = 3'h0; + parameter [4:0] PF3_SRIOV_BAR2_APERTURE_SIZE = 5'h03; + parameter [2:0] PF3_SRIOV_BAR2_CONTROL = 3'h4; + parameter [4:0] PF3_SRIOV_BAR3_APERTURE_SIZE = 5'h03; + parameter [2:0] PF3_SRIOV_BAR3_CONTROL = 3'h0; + parameter [4:0] PF3_SRIOV_BAR4_APERTURE_SIZE = 5'h03; + parameter [2:0] PF3_SRIOV_BAR4_CONTROL = 3'h4; + parameter [4:0] PF3_SRIOV_BAR5_APERTURE_SIZE = 5'h03; + parameter [2:0] PF3_SRIOV_BAR5_CONTROL = 3'h0; + parameter [15:0] PF3_SRIOV_CAP_INITIAL_VF = 16'h0000; + parameter [11:0] PF3_SRIOV_CAP_NEXTPTR = 12'h000; + parameter [15:0] PF3_SRIOV_CAP_TOTAL_VF = 16'h0000; + parameter [3:0] PF3_SRIOV_CAP_VER = 4'h1; + parameter [15:0] PF3_SRIOV_FIRST_VF_OFFSET = 16'h0000; + parameter [15:0] PF3_SRIOV_FUNC_DEP_LINK = 16'h0000; + parameter [31:0] PF3_SRIOV_SUPPORTED_PAGE_SIZE = 32'h00000000; + parameter [15:0] PF3_SRIOV_VF_DEVICE_ID = 16'h0000; + parameter [15:0] PF3_SUBSYSTEM_ID = 16'h0000; + parameter PF3_TPHR_CAP_DEV_SPECIFIC_MODE = "TRUE"; + parameter PF3_TPHR_CAP_ENABLE = "FALSE"; + parameter PF3_TPHR_CAP_INT_VEC_MODE = "TRUE"; + parameter [11:0] PF3_TPHR_CAP_NEXTPTR = 12'h000; + parameter [2:0] PF3_TPHR_CAP_ST_MODE_SEL = 3'h0; + parameter [1:0] PF3_TPHR_CAP_ST_TABLE_LOC = 2'h0; + parameter [10:0] PF3_TPHR_CAP_ST_TABLE_SIZE = 11'h000; + parameter [3:0] PF3_TPHR_CAP_VER = 4'h1; + parameter PL_DISABLE_AUTO_EQ_SPEED_CHANGE_TO_GEN3 = "FALSE"; + parameter PL_DISABLE_AUTO_SPEED_CHANGE_TO_GEN2 = "FALSE"; + parameter PL_DISABLE_EI_INFER_IN_L0 = "FALSE"; + parameter PL_DISABLE_GEN3_DC_BALANCE = "FALSE"; + parameter PL_DISABLE_GEN3_LFSR_UPDATE_ON_SKP = "TRUE"; + parameter PL_DISABLE_RETRAIN_ON_FRAMING_ERROR = "FALSE"; + parameter PL_DISABLE_SCRAMBLING = "FALSE"; + parameter PL_DISABLE_SYNC_HEADER_FRAMING_ERROR = "FALSE"; + parameter PL_DISABLE_UPCONFIG_CAPABLE = "FALSE"; + parameter PL_EQ_ADAPT_DISABLE_COEFF_CHECK = "FALSE"; + parameter PL_EQ_ADAPT_DISABLE_PRESET_CHECK = "FALSE"; + parameter [4:0] PL_EQ_ADAPT_ITER_COUNT = 5'h02; + parameter [1:0] PL_EQ_ADAPT_REJECT_RETRY_COUNT = 2'h1; + parameter PL_EQ_BYPASS_PHASE23 = "FALSE"; + parameter [2:0] PL_EQ_DEFAULT_GEN3_RX_PRESET_HINT = 3'h3; + parameter [3:0] PL_EQ_DEFAULT_GEN3_TX_PRESET = 4'h4; + parameter PL_EQ_PHASE01_RX_ADAPT = "FALSE"; + parameter PL_EQ_SHORT_ADAPT_PHASE = "FALSE"; + parameter [15:0] PL_LANE0_EQ_CONTROL = 16'h3F00; + parameter [15:0] PL_LANE1_EQ_CONTROL = 16'h3F00; + parameter [15:0] PL_LANE2_EQ_CONTROL = 16'h3F00; + parameter [15:0] PL_LANE3_EQ_CONTROL = 16'h3F00; + parameter [15:0] PL_LANE4_EQ_CONTROL = 16'h3F00; + parameter [15:0] PL_LANE5_EQ_CONTROL = 16'h3F00; + parameter [15:0] PL_LANE6_EQ_CONTROL = 16'h3F00; + parameter [15:0] PL_LANE7_EQ_CONTROL = 16'h3F00; + parameter [2:0] PL_LINK_CAP_MAX_LINK_SPEED = 3'h4; + parameter [3:0] PL_LINK_CAP_MAX_LINK_WIDTH = 4'h8; + parameter integer PL_N_FTS_COMCLK_GEN1 = 255; + parameter integer PL_N_FTS_COMCLK_GEN2 = 255; + parameter integer PL_N_FTS_COMCLK_GEN3 = 255; + parameter integer PL_N_FTS_GEN1 = 255; + parameter integer PL_N_FTS_GEN2 = 255; + parameter integer PL_N_FTS_GEN3 = 255; + parameter PL_REPORT_ALL_PHY_ERRORS = "TRUE"; + parameter PL_SIM_FAST_LINK_TRAINING = "FALSE"; + parameter PL_UPSTREAM_FACING = "TRUE"; + parameter [15:0] PM_ASPML0S_TIMEOUT = 16'h05DC; + parameter [19:0] PM_ASPML1_ENTRY_DELAY = 20'h00000; + parameter PM_ENABLE_L23_ENTRY = "FALSE"; + parameter PM_ENABLE_SLOT_POWER_CAPTURE = "TRUE"; + parameter [31:0] PM_L1_REENTRY_DELAY = 32'h00000000; + parameter [19:0] PM_PME_SERVICE_TIMEOUT_DELAY = 20'h186A0; + parameter [15:0] PM_PME_TURNOFF_ACK_DELAY = 16'h0064; + parameter [31:0] SIM_JTAG_IDCODE = 32'h00000000; + parameter SIM_VERSION = "1.0"; + parameter integer SPARE_BIT0 = 0; + parameter integer SPARE_BIT1 = 0; + parameter integer SPARE_BIT2 = 0; + parameter integer SPARE_BIT3 = 0; + parameter integer SPARE_BIT4 = 0; + parameter integer SPARE_BIT5 = 0; + parameter integer SPARE_BIT6 = 0; + parameter integer SPARE_BIT7 = 0; + parameter integer SPARE_BIT8 = 0; + parameter [7:0] SPARE_BYTE0 = 8'h00; + parameter [7:0] SPARE_BYTE1 = 8'h00; + parameter [7:0] SPARE_BYTE2 = 8'h00; + parameter [7:0] SPARE_BYTE3 = 8'h00; + parameter [31:0] SPARE_WORD0 = 32'h00000000; + parameter [31:0] SPARE_WORD1 = 32'h00000000; + parameter [31:0] SPARE_WORD2 = 32'h00000000; + parameter [31:0] SPARE_WORD3 = 32'h00000000; + parameter SRIOV_CAP_ENABLE = "FALSE"; + parameter TL_COMPLETION_RAM_SIZE_16K = "TRUE"; + parameter [23:0] TL_COMPL_TIMEOUT_REG0 = 24'hBEBC20; + parameter [27:0] TL_COMPL_TIMEOUT_REG1 = 28'h2FAF080; + parameter [11:0] TL_CREDITS_CD = 12'h3E0; + parameter [7:0] TL_CREDITS_CH = 8'h20; + parameter [11:0] TL_CREDITS_NPD = 12'h028; + parameter [7:0] TL_CREDITS_NPH = 8'h20; + parameter [11:0] TL_CREDITS_PD = 12'h198; + parameter [7:0] TL_CREDITS_PH = 8'h20; + parameter TL_ENABLE_MESSAGE_RID_CHECK_ENABLE = "TRUE"; + parameter TL_EXTENDED_CFG_EXTEND_INTERFACE_ENABLE = "FALSE"; + parameter TL_LEGACY_CFG_EXTEND_INTERFACE_ENABLE = "FALSE"; + parameter TL_LEGACY_MODE_ENABLE = "FALSE"; + parameter [1:0] TL_PF_ENABLE_REG = 2'h0; + parameter TL_TX_MUX_STRICT_PRIORITY = "TRUE"; + parameter TWO_LAYER_MODE_DLCMSM_ENABLE = "TRUE"; + parameter TWO_LAYER_MODE_ENABLE = "FALSE"; + parameter TWO_LAYER_MODE_WIDTH_256 = "TRUE"; + parameter [11:0] VF0_ARI_CAP_NEXTPTR = 12'h000; + parameter [7:0] VF0_CAPABILITY_POINTER = 8'h50; + parameter integer VF0_MSIX_CAP_PBA_BIR = 0; + parameter [28:0] VF0_MSIX_CAP_PBA_OFFSET = 29'h00000050; + parameter integer VF0_MSIX_CAP_TABLE_BIR = 0; + parameter [28:0] VF0_MSIX_CAP_TABLE_OFFSET = 29'h00000040; + parameter [10:0] VF0_MSIX_CAP_TABLE_SIZE = 11'h000; + parameter integer VF0_MSI_CAP_MULTIMSGCAP = 0; + parameter [7:0] VF0_PM_CAP_ID = 8'h01; + parameter [7:0] VF0_PM_CAP_NEXTPTR = 8'h00; + parameter [2:0] VF0_PM_CAP_VER_ID = 3'h3; + parameter VF0_TPHR_CAP_DEV_SPECIFIC_MODE = "TRUE"; + parameter VF0_TPHR_CAP_ENABLE = "FALSE"; + parameter VF0_TPHR_CAP_INT_VEC_MODE = "TRUE"; + parameter [11:0] VF0_TPHR_CAP_NEXTPTR = 12'h000; + parameter [2:0] VF0_TPHR_CAP_ST_MODE_SEL = 3'h0; + parameter [1:0] VF0_TPHR_CAP_ST_TABLE_LOC = 2'h0; + parameter [10:0] VF0_TPHR_CAP_ST_TABLE_SIZE = 11'h000; + parameter [3:0] VF0_TPHR_CAP_VER = 4'h1; + parameter [11:0] VF1_ARI_CAP_NEXTPTR = 12'h000; + parameter integer VF1_MSIX_CAP_PBA_BIR = 0; + parameter [28:0] VF1_MSIX_CAP_PBA_OFFSET = 29'h00000050; + parameter integer VF1_MSIX_CAP_TABLE_BIR = 0; + parameter [28:0] VF1_MSIX_CAP_TABLE_OFFSET = 29'h00000040; + parameter [10:0] VF1_MSIX_CAP_TABLE_SIZE = 11'h000; + parameter integer VF1_MSI_CAP_MULTIMSGCAP = 0; + parameter [7:0] VF1_PM_CAP_ID = 8'h01; + parameter [7:0] VF1_PM_CAP_NEXTPTR = 8'h00; + parameter [2:0] VF1_PM_CAP_VER_ID = 3'h3; + parameter VF1_TPHR_CAP_DEV_SPECIFIC_MODE = "TRUE"; + parameter VF1_TPHR_CAP_ENABLE = "FALSE"; + parameter VF1_TPHR_CAP_INT_VEC_MODE = "TRUE"; + parameter [11:0] VF1_TPHR_CAP_NEXTPTR = 12'h000; + parameter [2:0] VF1_TPHR_CAP_ST_MODE_SEL = 3'h0; + parameter [1:0] VF1_TPHR_CAP_ST_TABLE_LOC = 2'h0; + parameter [10:0] VF1_TPHR_CAP_ST_TABLE_SIZE = 11'h000; + parameter [3:0] VF1_TPHR_CAP_VER = 4'h1; + parameter [11:0] VF2_ARI_CAP_NEXTPTR = 12'h000; + parameter integer VF2_MSIX_CAP_PBA_BIR = 0; + parameter [28:0] VF2_MSIX_CAP_PBA_OFFSET = 29'h00000050; + parameter integer VF2_MSIX_CAP_TABLE_BIR = 0; + parameter [28:0] VF2_MSIX_CAP_TABLE_OFFSET = 29'h00000040; + parameter [10:0] VF2_MSIX_CAP_TABLE_SIZE = 11'h000; + parameter integer VF2_MSI_CAP_MULTIMSGCAP = 0; + parameter [7:0] VF2_PM_CAP_ID = 8'h01; + parameter [7:0] VF2_PM_CAP_NEXTPTR = 8'h00; + parameter [2:0] VF2_PM_CAP_VER_ID = 3'h3; + parameter VF2_TPHR_CAP_DEV_SPECIFIC_MODE = "TRUE"; + parameter VF2_TPHR_CAP_ENABLE = "FALSE"; + parameter VF2_TPHR_CAP_INT_VEC_MODE = "TRUE"; + parameter [11:0] VF2_TPHR_CAP_NEXTPTR = 12'h000; + parameter [2:0] VF2_TPHR_CAP_ST_MODE_SEL = 3'h0; + parameter [1:0] VF2_TPHR_CAP_ST_TABLE_LOC = 2'h0; + parameter [10:0] VF2_TPHR_CAP_ST_TABLE_SIZE = 11'h000; + parameter [3:0] VF2_TPHR_CAP_VER = 4'h1; + parameter [11:0] VF3_ARI_CAP_NEXTPTR = 12'h000; + parameter integer VF3_MSIX_CAP_PBA_BIR = 0; + parameter [28:0] VF3_MSIX_CAP_PBA_OFFSET = 29'h00000050; + parameter integer VF3_MSIX_CAP_TABLE_BIR = 0; + parameter [28:0] VF3_MSIX_CAP_TABLE_OFFSET = 29'h00000040; + parameter [10:0] VF3_MSIX_CAP_TABLE_SIZE = 11'h000; + parameter integer VF3_MSI_CAP_MULTIMSGCAP = 0; + parameter [7:0] VF3_PM_CAP_ID = 8'h01; + parameter [7:0] VF3_PM_CAP_NEXTPTR = 8'h00; + parameter [2:0] VF3_PM_CAP_VER_ID = 3'h3; + parameter VF3_TPHR_CAP_DEV_SPECIFIC_MODE = "TRUE"; + parameter VF3_TPHR_CAP_ENABLE = "FALSE"; + parameter VF3_TPHR_CAP_INT_VEC_MODE = "TRUE"; + parameter [11:0] VF3_TPHR_CAP_NEXTPTR = 12'h000; + parameter [2:0] VF3_TPHR_CAP_ST_MODE_SEL = 3'h0; + parameter [1:0] VF3_TPHR_CAP_ST_TABLE_LOC = 2'h0; + parameter [10:0] VF3_TPHR_CAP_ST_TABLE_SIZE = 11'h000; + parameter [3:0] VF3_TPHR_CAP_VER = 4'h1; + parameter [11:0] VF4_ARI_CAP_NEXTPTR = 12'h000; + parameter integer VF4_MSIX_CAP_PBA_BIR = 0; + parameter [28:0] VF4_MSIX_CAP_PBA_OFFSET = 29'h00000050; + parameter integer VF4_MSIX_CAP_TABLE_BIR = 0; + parameter [28:0] VF4_MSIX_CAP_TABLE_OFFSET = 29'h00000040; + parameter [10:0] VF4_MSIX_CAP_TABLE_SIZE = 11'h000; + parameter integer VF4_MSI_CAP_MULTIMSGCAP = 0; + parameter [7:0] VF4_PM_CAP_ID = 8'h01; + parameter [7:0] VF4_PM_CAP_NEXTPTR = 8'h00; + parameter [2:0] VF4_PM_CAP_VER_ID = 3'h3; + parameter VF4_TPHR_CAP_DEV_SPECIFIC_MODE = "TRUE"; + parameter VF4_TPHR_CAP_ENABLE = "FALSE"; + parameter VF4_TPHR_CAP_INT_VEC_MODE = "TRUE"; + parameter [11:0] VF4_TPHR_CAP_NEXTPTR = 12'h000; + parameter [2:0] VF4_TPHR_CAP_ST_MODE_SEL = 3'h0; + parameter [1:0] VF4_TPHR_CAP_ST_TABLE_LOC = 2'h0; + parameter [10:0] VF4_TPHR_CAP_ST_TABLE_SIZE = 11'h000; + parameter [3:0] VF4_TPHR_CAP_VER = 4'h1; + parameter [11:0] VF5_ARI_CAP_NEXTPTR = 12'h000; + parameter integer VF5_MSIX_CAP_PBA_BIR = 0; + parameter [28:0] VF5_MSIX_CAP_PBA_OFFSET = 29'h00000050; + parameter integer VF5_MSIX_CAP_TABLE_BIR = 0; + parameter [28:0] VF5_MSIX_CAP_TABLE_OFFSET = 29'h00000040; + parameter [10:0] VF5_MSIX_CAP_TABLE_SIZE = 11'h000; + parameter integer VF5_MSI_CAP_MULTIMSGCAP = 0; + parameter [7:0] VF5_PM_CAP_ID = 8'h01; + parameter [7:0] VF5_PM_CAP_NEXTPTR = 8'h00; + parameter [2:0] VF5_PM_CAP_VER_ID = 3'h3; + parameter VF5_TPHR_CAP_DEV_SPECIFIC_MODE = "TRUE"; + parameter VF5_TPHR_CAP_ENABLE = "FALSE"; + parameter VF5_TPHR_CAP_INT_VEC_MODE = "TRUE"; + parameter [11:0] VF5_TPHR_CAP_NEXTPTR = 12'h000; + parameter [2:0] VF5_TPHR_CAP_ST_MODE_SEL = 3'h0; + parameter [1:0] VF5_TPHR_CAP_ST_TABLE_LOC = 2'h0; + parameter [10:0] VF5_TPHR_CAP_ST_TABLE_SIZE = 11'h000; + parameter [3:0] VF5_TPHR_CAP_VER = 4'h1; + parameter [11:0] VF6_ARI_CAP_NEXTPTR = 12'h000; + parameter integer VF6_MSIX_CAP_PBA_BIR = 0; + parameter [28:0] VF6_MSIX_CAP_PBA_OFFSET = 29'h00000050; + parameter integer VF6_MSIX_CAP_TABLE_BIR = 0; + parameter [28:0] VF6_MSIX_CAP_TABLE_OFFSET = 29'h00000040; + parameter [10:0] VF6_MSIX_CAP_TABLE_SIZE = 11'h000; + parameter integer VF6_MSI_CAP_MULTIMSGCAP = 0; + parameter [7:0] VF6_PM_CAP_ID = 8'h01; + parameter [7:0] VF6_PM_CAP_NEXTPTR = 8'h00; + parameter [2:0] VF6_PM_CAP_VER_ID = 3'h3; + parameter VF6_TPHR_CAP_DEV_SPECIFIC_MODE = "TRUE"; + parameter VF6_TPHR_CAP_ENABLE = "FALSE"; + parameter VF6_TPHR_CAP_INT_VEC_MODE = "TRUE"; + parameter [11:0] VF6_TPHR_CAP_NEXTPTR = 12'h000; + parameter [2:0] VF6_TPHR_CAP_ST_MODE_SEL = 3'h0; + parameter [1:0] VF6_TPHR_CAP_ST_TABLE_LOC = 2'h0; + parameter [10:0] VF6_TPHR_CAP_ST_TABLE_SIZE = 11'h000; + parameter [3:0] VF6_TPHR_CAP_VER = 4'h1; + parameter [11:0] VF7_ARI_CAP_NEXTPTR = 12'h000; + parameter integer VF7_MSIX_CAP_PBA_BIR = 0; + parameter [28:0] VF7_MSIX_CAP_PBA_OFFSET = 29'h00000050; + parameter integer VF7_MSIX_CAP_TABLE_BIR = 0; + parameter [28:0] VF7_MSIX_CAP_TABLE_OFFSET = 29'h00000040; + parameter [10:0] VF7_MSIX_CAP_TABLE_SIZE = 11'h000; + parameter integer VF7_MSI_CAP_MULTIMSGCAP = 0; + parameter [7:0] VF7_PM_CAP_ID = 8'h01; + parameter [7:0] VF7_PM_CAP_NEXTPTR = 8'h00; + parameter [2:0] VF7_PM_CAP_VER_ID = 3'h3; + parameter VF7_TPHR_CAP_DEV_SPECIFIC_MODE = "TRUE"; + parameter VF7_TPHR_CAP_ENABLE = "FALSE"; + parameter VF7_TPHR_CAP_INT_VEC_MODE = "TRUE"; + parameter [11:0] VF7_TPHR_CAP_NEXTPTR = 12'h000; + parameter [2:0] VF7_TPHR_CAP_ST_MODE_SEL = 3'h0; + parameter [1:0] VF7_TPHR_CAP_ST_TABLE_LOC = 2'h0; + parameter [10:0] VF7_TPHR_CAP_ST_TABLE_SIZE = 11'h000; + parameter [3:0] VF7_TPHR_CAP_VER = 4'h1; + output [2:0] CFGCURRENTSPEED; + output [3:0] CFGDPASUBSTATECHANGE; + output CFGERRCOROUT; + output CFGERRFATALOUT; + output CFGERRNONFATALOUT; + output [7:0] CFGEXTFUNCTIONNUMBER; + output CFGEXTREADRECEIVED; + output [9:0] CFGEXTREGISTERNUMBER; + output [3:0] CFGEXTWRITEBYTEENABLE; + output [31:0] CFGEXTWRITEDATA; + output CFGEXTWRITERECEIVED; + output [11:0] CFGFCCPLD; + output [7:0] CFGFCCPLH; + output [11:0] CFGFCNPD; + output [7:0] CFGFCNPH; + output [11:0] CFGFCPD; + output [7:0] CFGFCPH; + output [3:0] CFGFLRINPROCESS; + output [11:0] CFGFUNCTIONPOWERSTATE; + output [15:0] CFGFUNCTIONSTATUS; + output CFGHOTRESETOUT; + output [31:0] CFGINTERRUPTMSIDATA; + output [3:0] CFGINTERRUPTMSIENABLE; + output CFGINTERRUPTMSIFAIL; + output CFGINTERRUPTMSIMASKUPDATE; + output [11:0] CFGINTERRUPTMSIMMENABLE; + output CFGINTERRUPTMSISENT; + output [7:0] CFGINTERRUPTMSIVFENABLE; + output [3:0] CFGINTERRUPTMSIXENABLE; + output CFGINTERRUPTMSIXFAIL; + output [3:0] CFGINTERRUPTMSIXMASK; + output CFGINTERRUPTMSIXSENT; + output [7:0] CFGINTERRUPTMSIXVFENABLE; + output [7:0] CFGINTERRUPTMSIXVFMASK; + output CFGINTERRUPTSENT; + output [1:0] CFGLINKPOWERSTATE; + output CFGLOCALERROR; + output CFGLTRENABLE; + output [5:0] CFGLTSSMSTATE; + output [2:0] CFGMAXPAYLOAD; + output [2:0] CFGMAXREADREQ; + output [31:0] CFGMGMTREADDATA; + output CFGMGMTREADWRITEDONE; + output CFGMSGRECEIVED; + output [7:0] CFGMSGRECEIVEDDATA; + output [4:0] CFGMSGRECEIVEDTYPE; + output CFGMSGTRANSMITDONE; + output [3:0] CFGNEGOTIATEDWIDTH; + output [1:0] CFGOBFFENABLE; + output [15:0] CFGPERFUNCSTATUSDATA; + output CFGPERFUNCTIONUPDATEDONE; + output CFGPHYLINKDOWN; + output [1:0] CFGPHYLINKSTATUS; + output CFGPLSTATUSCHANGE; + output CFGPOWERSTATECHANGEINTERRUPT; + output [3:0] CFGRCBSTATUS; + output [3:0] CFGTPHFUNCTIONNUM; + output [3:0] CFGTPHREQUESTERENABLE; + output [11:0] CFGTPHSTMODE; + output [4:0] CFGTPHSTTADDRESS; + output CFGTPHSTTREADENABLE; + output [3:0] CFGTPHSTTWRITEBYTEVALID; + output [31:0] CFGTPHSTTWRITEDATA; + output CFGTPHSTTWRITEENABLE; + output [7:0] CFGVFFLRINPROCESS; + output [23:0] CFGVFPOWERSTATE; + output [15:0] CFGVFSTATUS; + output [7:0] CFGVFTPHREQUESTERENABLE; + output [23:0] CFGVFTPHSTMODE; + output CONFMCAPDESIGNSWITCH; + output CONFMCAPEOS; + output CONFMCAPINUSEBYPCIE; + output CONFREQREADY; + output [31:0] CONFRESPRDATA; + output CONFRESPVALID; + output [15:0] DBGDATAOUT; + output DBGMCAPCSB; + output [31:0] DBGMCAPDATA; + output DBGMCAPEOS; + output DBGMCAPERROR; + output DBGMCAPMODE; + output DBGMCAPRDATAVALID; + output DBGMCAPRDWRB; + output DBGMCAPRESET; + output DBGPLDATABLOCKRECEIVEDAFTEREDS; + output DBGPLGEN3FRAMINGERRORDETECTED; + output DBGPLGEN3SYNCHEADERERRORDETECTED; + output [7:0] DBGPLINFERREDRXELECTRICALIDLE; + output [15:0] DRPDO; + output DRPRDY; + output LL2LMMASTERTLPSENT0; + output LL2LMMASTERTLPSENT1; + output [3:0] LL2LMMASTERTLPSENTTLPID0; + output [3:0] LL2LMMASTERTLPSENTTLPID1; + output [255:0] LL2LMMAXISRXTDATA; + output [17:0] LL2LMMAXISRXTUSER; + output [7:0] LL2LMMAXISRXTVALID; + output [7:0] LL2LMSAXISTXTREADY; + output [255:0] MAXISCQTDATA; + output [7:0] MAXISCQTKEEP; + output MAXISCQTLAST; + output [84:0] MAXISCQTUSER; + output MAXISCQTVALID; + output [255:0] MAXISRCTDATA; + output [7:0] MAXISRCTKEEP; + output MAXISRCTLAST; + output [74:0] MAXISRCTUSER; + output MAXISRCTVALID; + output [9:0] MICOMPLETIONRAMREADADDRESSAL; + output [9:0] MICOMPLETIONRAMREADADDRESSAU; + output [9:0] MICOMPLETIONRAMREADADDRESSBL; + output [9:0] MICOMPLETIONRAMREADADDRESSBU; + output [3:0] MICOMPLETIONRAMREADENABLEL; + output [3:0] MICOMPLETIONRAMREADENABLEU; + output [9:0] MICOMPLETIONRAMWRITEADDRESSAL; + output [9:0] MICOMPLETIONRAMWRITEADDRESSAU; + output [9:0] MICOMPLETIONRAMWRITEADDRESSBL; + output [9:0] MICOMPLETIONRAMWRITEADDRESSBU; + output [71:0] MICOMPLETIONRAMWRITEDATAL; + output [71:0] MICOMPLETIONRAMWRITEDATAU; + output [3:0] MICOMPLETIONRAMWRITEENABLEL; + output [3:0] MICOMPLETIONRAMWRITEENABLEU; + output [8:0] MIREPLAYRAMADDRESS; + output [1:0] MIREPLAYRAMREADENABLE; + output [143:0] MIREPLAYRAMWRITEDATA; + output [1:0] MIREPLAYRAMWRITEENABLE; + output [8:0] MIREQUESTRAMREADADDRESSA; + output [8:0] MIREQUESTRAMREADADDRESSB; + output [3:0] MIREQUESTRAMREADENABLE; + output [8:0] MIREQUESTRAMWRITEADDRESSA; + output [8:0] MIREQUESTRAMWRITEADDRESSB; + output [143:0] MIREQUESTRAMWRITEDATA; + output [3:0] MIREQUESTRAMWRITEENABLE; + output [5:0] PCIECQNPREQCOUNT; + output PCIEPERST0B; + output PCIEPERST1B; + output [3:0] PCIERQSEQNUM; + output PCIERQSEQNUMVLD; + output [5:0] PCIERQTAG; + output [1:0] PCIERQTAGAV; + output PCIERQTAGVLD; + output [1:0] PCIETFCNPDAV; + output [1:0] PCIETFCNPHAV; + output [1:0] PIPERX0EQCONTROL; + output [5:0] PIPERX0EQLPLFFS; + output [3:0] PIPERX0EQLPTXPRESET; + output [2:0] PIPERX0EQPRESET; + output PIPERX0POLARITY; + output [1:0] PIPERX1EQCONTROL; + output [5:0] PIPERX1EQLPLFFS; + output [3:0] PIPERX1EQLPTXPRESET; + output [2:0] PIPERX1EQPRESET; + output PIPERX1POLARITY; + output [1:0] PIPERX2EQCONTROL; + output [5:0] PIPERX2EQLPLFFS; + output [3:0] PIPERX2EQLPTXPRESET; + output [2:0] PIPERX2EQPRESET; + output PIPERX2POLARITY; + output [1:0] PIPERX3EQCONTROL; + output [5:0] PIPERX3EQLPLFFS; + output [3:0] PIPERX3EQLPTXPRESET; + output [2:0] PIPERX3EQPRESET; + output PIPERX3POLARITY; + output [1:0] PIPERX4EQCONTROL; + output [5:0] PIPERX4EQLPLFFS; + output [3:0] PIPERX4EQLPTXPRESET; + output [2:0] PIPERX4EQPRESET; + output PIPERX4POLARITY; + output [1:0] PIPERX5EQCONTROL; + output [5:0] PIPERX5EQLPLFFS; + output [3:0] PIPERX5EQLPTXPRESET; + output [2:0] PIPERX5EQPRESET; + output PIPERX5POLARITY; + output [1:0] PIPERX6EQCONTROL; + output [5:0] PIPERX6EQLPLFFS; + output [3:0] PIPERX6EQLPTXPRESET; + output [2:0] PIPERX6EQPRESET; + output PIPERX6POLARITY; + output [1:0] PIPERX7EQCONTROL; + output [5:0] PIPERX7EQLPLFFS; + output [3:0] PIPERX7EQLPTXPRESET; + output [2:0] PIPERX7EQPRESET; + output PIPERX7POLARITY; + output [1:0] PIPETX0CHARISK; + output PIPETX0COMPLIANCE; + output [31:0] PIPETX0DATA; + output PIPETX0DATAVALID; + output PIPETX0DEEMPH; + output PIPETX0ELECIDLE; + output [1:0] PIPETX0EQCONTROL; + output [5:0] PIPETX0EQDEEMPH; + output [3:0] PIPETX0EQPRESET; + output [2:0] PIPETX0MARGIN; + output [1:0] PIPETX0POWERDOWN; + output [1:0] PIPETX0RATE; + output PIPETX0RCVRDET; + output PIPETX0RESET; + output PIPETX0STARTBLOCK; + output PIPETX0SWING; + output [1:0] PIPETX0SYNCHEADER; + output [1:0] PIPETX1CHARISK; + output PIPETX1COMPLIANCE; + output [31:0] PIPETX1DATA; + output PIPETX1DATAVALID; + output PIPETX1DEEMPH; + output PIPETX1ELECIDLE; + output [1:0] PIPETX1EQCONTROL; + output [5:0] PIPETX1EQDEEMPH; + output [3:0] PIPETX1EQPRESET; + output [2:0] PIPETX1MARGIN; + output [1:0] PIPETX1POWERDOWN; + output [1:0] PIPETX1RATE; + output PIPETX1RCVRDET; + output PIPETX1RESET; + output PIPETX1STARTBLOCK; + output PIPETX1SWING; + output [1:0] PIPETX1SYNCHEADER; + output [1:0] PIPETX2CHARISK; + output PIPETX2COMPLIANCE; + output [31:0] PIPETX2DATA; + output PIPETX2DATAVALID; + output PIPETX2DEEMPH; + output PIPETX2ELECIDLE; + output [1:0] PIPETX2EQCONTROL; + output [5:0] PIPETX2EQDEEMPH; + output [3:0] PIPETX2EQPRESET; + output [2:0] PIPETX2MARGIN; + output [1:0] PIPETX2POWERDOWN; + output [1:0] PIPETX2RATE; + output PIPETX2RCVRDET; + output PIPETX2RESET; + output PIPETX2STARTBLOCK; + output PIPETX2SWING; + output [1:0] PIPETX2SYNCHEADER; + output [1:0] PIPETX3CHARISK; + output PIPETX3COMPLIANCE; + output [31:0] PIPETX3DATA; + output PIPETX3DATAVALID; + output PIPETX3DEEMPH; + output PIPETX3ELECIDLE; + output [1:0] PIPETX3EQCONTROL; + output [5:0] PIPETX3EQDEEMPH; + output [3:0] PIPETX3EQPRESET; + output [2:0] PIPETX3MARGIN; + output [1:0] PIPETX3POWERDOWN; + output [1:0] PIPETX3RATE; + output PIPETX3RCVRDET; + output PIPETX3RESET; + output PIPETX3STARTBLOCK; + output PIPETX3SWING; + output [1:0] PIPETX3SYNCHEADER; + output [1:0] PIPETX4CHARISK; + output PIPETX4COMPLIANCE; + output [31:0] PIPETX4DATA; + output PIPETX4DATAVALID; + output PIPETX4DEEMPH; + output PIPETX4ELECIDLE; + output [1:0] PIPETX4EQCONTROL; + output [5:0] PIPETX4EQDEEMPH; + output [3:0] PIPETX4EQPRESET; + output [2:0] PIPETX4MARGIN; + output [1:0] PIPETX4POWERDOWN; + output [1:0] PIPETX4RATE; + output PIPETX4RCVRDET; + output PIPETX4RESET; + output PIPETX4STARTBLOCK; + output PIPETX4SWING; + output [1:0] PIPETX4SYNCHEADER; + output [1:0] PIPETX5CHARISK; + output PIPETX5COMPLIANCE; + output [31:0] PIPETX5DATA; + output PIPETX5DATAVALID; + output PIPETX5DEEMPH; + output PIPETX5ELECIDLE; + output [1:0] PIPETX5EQCONTROL; + output [5:0] PIPETX5EQDEEMPH; + output [3:0] PIPETX5EQPRESET; + output [2:0] PIPETX5MARGIN; + output [1:0] PIPETX5POWERDOWN; + output [1:0] PIPETX5RATE; + output PIPETX5RCVRDET; + output PIPETX5RESET; + output PIPETX5STARTBLOCK; + output PIPETX5SWING; + output [1:0] PIPETX5SYNCHEADER; + output [1:0] PIPETX6CHARISK; + output PIPETX6COMPLIANCE; + output [31:0] PIPETX6DATA; + output PIPETX6DATAVALID; + output PIPETX6DEEMPH; + output PIPETX6ELECIDLE; + output [1:0] PIPETX6EQCONTROL; + output [5:0] PIPETX6EQDEEMPH; + output [3:0] PIPETX6EQPRESET; + output [2:0] PIPETX6MARGIN; + output [1:0] PIPETX6POWERDOWN; + output [1:0] PIPETX6RATE; + output PIPETX6RCVRDET; + output PIPETX6RESET; + output PIPETX6STARTBLOCK; + output PIPETX6SWING; + output [1:0] PIPETX6SYNCHEADER; + output [1:0] PIPETX7CHARISK; + output PIPETX7COMPLIANCE; + output [31:0] PIPETX7DATA; + output PIPETX7DATAVALID; + output PIPETX7DEEMPH; + output PIPETX7ELECIDLE; + output [1:0] PIPETX7EQCONTROL; + output [5:0] PIPETX7EQDEEMPH; + output [3:0] PIPETX7EQPRESET; + output [2:0] PIPETX7MARGIN; + output [1:0] PIPETX7POWERDOWN; + output [1:0] PIPETX7RATE; + output PIPETX7RCVRDET; + output PIPETX7RESET; + output PIPETX7STARTBLOCK; + output PIPETX7SWING; + output [1:0] PIPETX7SYNCHEADER; + output PLEQINPROGRESS; + output [1:0] PLEQPHASE; + output [3:0] SAXISCCTREADY; + output [3:0] SAXISRQTREADY; + output [31:0] SPAREOUT; + input CFGCONFIGSPACEENABLE; + input [15:0] CFGDEVID; + input [7:0] CFGDSBUSNUMBER; + input [4:0] CFGDSDEVICENUMBER; + input [2:0] CFGDSFUNCTIONNUMBER; + input [63:0] CFGDSN; + input [7:0] CFGDSPORTNUMBER; + input CFGERRCORIN; + input CFGERRUNCORIN; + input [31:0] CFGEXTREADDATA; + input CFGEXTREADDATAVALID; + input [2:0] CFGFCSEL; + input [3:0] CFGFLRDONE; + input CFGHOTRESETIN; + input [3:0] CFGINTERRUPTINT; + input [2:0] CFGINTERRUPTMSIATTR; + input [3:0] CFGINTERRUPTMSIFUNCTIONNUMBER; + input [31:0] CFGINTERRUPTMSIINT; + input [31:0] CFGINTERRUPTMSIPENDINGSTATUS; + input CFGINTERRUPTMSIPENDINGSTATUSDATAENABLE; + input [3:0] CFGINTERRUPTMSIPENDINGSTATUSFUNCTIONNUM; + input [3:0] CFGINTERRUPTMSISELECT; + input CFGINTERRUPTMSITPHPRESENT; + input [8:0] CFGINTERRUPTMSITPHSTTAG; + input [1:0] CFGINTERRUPTMSITPHTYPE; + input [63:0] CFGINTERRUPTMSIXADDRESS; + input [31:0] CFGINTERRUPTMSIXDATA; + input CFGINTERRUPTMSIXINT; + input [3:0] CFGINTERRUPTPENDING; + input CFGLINKTRAININGENABLE; + input [18:0] CFGMGMTADDR; + input [3:0] CFGMGMTBYTEENABLE; + input CFGMGMTREAD; + input CFGMGMTTYPE1CFGREGACCESS; + input CFGMGMTWRITE; + input [31:0] CFGMGMTWRITEDATA; + input CFGMSGTRANSMIT; + input [31:0] CFGMSGTRANSMITDATA; + input [2:0] CFGMSGTRANSMITTYPE; + input [2:0] CFGPERFUNCSTATUSCONTROL; + input [3:0] CFGPERFUNCTIONNUMBER; + input CFGPERFUNCTIONOUTPUTREQUEST; + input CFGPOWERSTATECHANGEACK; + input CFGREQPMTRANSITIONL23READY; + input [7:0] CFGREVID; + input [15:0] CFGSUBSYSID; + input [15:0] CFGSUBSYSVENDID; + input [31:0] CFGTPHSTTREADDATA; + input CFGTPHSTTREADDATAVALID; + input [15:0] CFGVENDID; + input [7:0] CFGVFFLRDONE; + input CONFMCAPREQUESTBYCONF; + input [31:0] CONFREQDATA; + input [3:0] CONFREQREGNUM; + input [1:0] CONFREQTYPE; + input CONFREQVALID; + input CORECLK; + input CORECLKMICOMPLETIONRAML; + input CORECLKMICOMPLETIONRAMU; + input CORECLKMIREPLAYRAM; + input CORECLKMIREQUESTRAM; + input DBGCFGLOCALMGMTREGOVERRIDE; + input [3:0] DBGDATASEL; + input [9:0] DRPADDR; + input DRPCLK; + input [15:0] DRPDI; + input DRPEN; + input DRPWE; + input [13:0] LL2LMSAXISTXTUSER; + input LL2LMSAXISTXTVALID; + input [3:0] LL2LMTXTLPID0; + input [3:0] LL2LMTXTLPID1; + input [21:0] MAXISCQTREADY; + input [21:0] MAXISRCTREADY; + input MCAPCLK; + input MCAPPERST0B; + input MCAPPERST1B; + input MGMTRESETN; + input MGMTSTICKYRESETN; + input [143:0] MICOMPLETIONRAMREADDATA; + input [143:0] MIREPLAYRAMREADDATA; + input [143:0] MIREQUESTRAMREADDATA; + input PCIECQNPREQ; + input PIPECLK; + input [5:0] PIPEEQFS; + input [5:0] PIPEEQLF; + input PIPERESETN; + input [1:0] PIPERX0CHARISK; + input [31:0] PIPERX0DATA; + input PIPERX0DATAVALID; + input PIPERX0ELECIDLE; + input PIPERX0EQDONE; + input PIPERX0EQLPADAPTDONE; + input PIPERX0EQLPLFFSSEL; + input [17:0] PIPERX0EQLPNEWTXCOEFFORPRESET; + input PIPERX0PHYSTATUS; + input PIPERX0STARTBLOCK; + input [2:0] PIPERX0STATUS; + input [1:0] PIPERX0SYNCHEADER; + input PIPERX0VALID; + input [1:0] PIPERX1CHARISK; + input [31:0] PIPERX1DATA; + input PIPERX1DATAVALID; + input PIPERX1ELECIDLE; + input PIPERX1EQDONE; + input PIPERX1EQLPADAPTDONE; + input PIPERX1EQLPLFFSSEL; + input [17:0] PIPERX1EQLPNEWTXCOEFFORPRESET; + input PIPERX1PHYSTATUS; + input PIPERX1STARTBLOCK; + input [2:0] PIPERX1STATUS; + input [1:0] PIPERX1SYNCHEADER; + input PIPERX1VALID; + input [1:0] PIPERX2CHARISK; + input [31:0] PIPERX2DATA; + input PIPERX2DATAVALID; + input PIPERX2ELECIDLE; + input PIPERX2EQDONE; + input PIPERX2EQLPADAPTDONE; + input PIPERX2EQLPLFFSSEL; + input [17:0] PIPERX2EQLPNEWTXCOEFFORPRESET; + input PIPERX2PHYSTATUS; + input PIPERX2STARTBLOCK; + input [2:0] PIPERX2STATUS; + input [1:0] PIPERX2SYNCHEADER; + input PIPERX2VALID; + input [1:0] PIPERX3CHARISK; + input [31:0] PIPERX3DATA; + input PIPERX3DATAVALID; + input PIPERX3ELECIDLE; + input PIPERX3EQDONE; + input PIPERX3EQLPADAPTDONE; + input PIPERX3EQLPLFFSSEL; + input [17:0] PIPERX3EQLPNEWTXCOEFFORPRESET; + input PIPERX3PHYSTATUS; + input PIPERX3STARTBLOCK; + input [2:0] PIPERX3STATUS; + input [1:0] PIPERX3SYNCHEADER; + input PIPERX3VALID; + input [1:0] PIPERX4CHARISK; + input [31:0] PIPERX4DATA; + input PIPERX4DATAVALID; + input PIPERX4ELECIDLE; + input PIPERX4EQDONE; + input PIPERX4EQLPADAPTDONE; + input PIPERX4EQLPLFFSSEL; + input [17:0] PIPERX4EQLPNEWTXCOEFFORPRESET; + input PIPERX4PHYSTATUS; + input PIPERX4STARTBLOCK; + input [2:0] PIPERX4STATUS; + input [1:0] PIPERX4SYNCHEADER; + input PIPERX4VALID; + input [1:0] PIPERX5CHARISK; + input [31:0] PIPERX5DATA; + input PIPERX5DATAVALID; + input PIPERX5ELECIDLE; + input PIPERX5EQDONE; + input PIPERX5EQLPADAPTDONE; + input PIPERX5EQLPLFFSSEL; + input [17:0] PIPERX5EQLPNEWTXCOEFFORPRESET; + input PIPERX5PHYSTATUS; + input PIPERX5STARTBLOCK; + input [2:0] PIPERX5STATUS; + input [1:0] PIPERX5SYNCHEADER; + input PIPERX5VALID; + input [1:0] PIPERX6CHARISK; + input [31:0] PIPERX6DATA; + input PIPERX6DATAVALID; + input PIPERX6ELECIDLE; + input PIPERX6EQDONE; + input PIPERX6EQLPADAPTDONE; + input PIPERX6EQLPLFFSSEL; + input [17:0] PIPERX6EQLPNEWTXCOEFFORPRESET; + input PIPERX6PHYSTATUS; + input PIPERX6STARTBLOCK; + input [2:0] PIPERX6STATUS; + input [1:0] PIPERX6SYNCHEADER; + input PIPERX6VALID; + input [1:0] PIPERX7CHARISK; + input [31:0] PIPERX7DATA; + input PIPERX7DATAVALID; + input PIPERX7ELECIDLE; + input PIPERX7EQDONE; + input PIPERX7EQLPADAPTDONE; + input PIPERX7EQLPLFFSSEL; + input [17:0] PIPERX7EQLPNEWTXCOEFFORPRESET; + input PIPERX7PHYSTATUS; + input PIPERX7STARTBLOCK; + input [2:0] PIPERX7STATUS; + input [1:0] PIPERX7SYNCHEADER; + input PIPERX7VALID; + input [17:0] PIPETX0EQCOEFF; + input PIPETX0EQDONE; + input [17:0] PIPETX1EQCOEFF; + input PIPETX1EQDONE; + input [17:0] PIPETX2EQCOEFF; + input PIPETX2EQDONE; + input [17:0] PIPETX3EQCOEFF; + input PIPETX3EQDONE; + input [17:0] PIPETX4EQCOEFF; + input PIPETX4EQDONE; + input [17:0] PIPETX5EQCOEFF; + input PIPETX5EQDONE; + input [17:0] PIPETX6EQCOEFF; + input PIPETX6EQDONE; + input [17:0] PIPETX7EQCOEFF; + input PIPETX7EQDONE; + input PLEQRESETEIEOSCOUNT; + input PLGEN2UPSTREAMPREFERDEEMPH; + input RESETN; + input [255:0] SAXISCCTDATA; + input [7:0] SAXISCCTKEEP; + input SAXISCCTLAST; + input [32:0] SAXISCCTUSER; + input SAXISCCTVALID; + input [255:0] SAXISRQTDATA; + input [7:0] SAXISRQTKEEP; + input SAXISRQTLAST; + input [59:0] SAXISRQTUSER; + input SAXISRQTVALID; + input [31:0] SPAREIN; + input USERCLK; +endmodule + +module SYSMONE1 (...); + parameter [15:0] INIT_40 = 16'h0; + parameter [15:0] INIT_41 = 16'h0; + parameter [15:0] INIT_42 = 16'h0; + parameter [15:0] INIT_43 = 16'h0; + parameter [15:0] INIT_44 = 16'h0; + parameter [15:0] INIT_45 = 16'h0; + parameter [15:0] INIT_46 = 16'h0; + parameter [15:0] INIT_47 = 16'h0; + parameter [15:0] INIT_48 = 16'h0; + parameter [15:0] INIT_49 = 16'h0; + parameter [15:0] INIT_4A = 16'h0; + parameter [15:0] INIT_4B = 16'h0; + parameter [15:0] INIT_4C = 16'h0; + parameter [15:0] INIT_4D = 16'h0; + parameter [15:0] INIT_4E = 16'h0; + parameter [15:0] INIT_4F = 16'h0; + parameter [15:0] INIT_50 = 16'h0; + parameter [15:0] INIT_51 = 16'h0; + parameter [15:0] INIT_52 = 16'h0; + parameter [15:0] INIT_53 = 16'h0; + parameter [15:0] INIT_54 = 16'h0; + parameter [15:0] INIT_55 = 16'h0; + parameter [15:0] INIT_56 = 16'h0; + parameter [15:0] INIT_57 = 16'h0; + parameter [15:0] INIT_58 = 16'h0; + parameter [15:0] INIT_59 = 16'h0; + parameter [15:0] INIT_5A = 16'h0; + parameter [15:0] INIT_5B = 16'h0; + parameter [15:0] INIT_5C = 16'h0; + parameter [15:0] INIT_5D = 16'h0; + parameter [15:0] INIT_5E = 16'h0; + parameter [15:0] INIT_5F = 16'h0; + parameter [15:0] INIT_60 = 16'h0; + parameter [15:0] INIT_61 = 16'h0; + parameter [15:0] INIT_62 = 16'h0; + parameter [15:0] INIT_63 = 16'h0; + parameter [15:0] INIT_64 = 16'h0; + parameter [15:0] INIT_65 = 16'h0; + parameter [15:0] INIT_66 = 16'h0; + parameter [15:0] INIT_67 = 16'h0; + parameter [15:0] INIT_68 = 16'h0; + parameter [15:0] INIT_69 = 16'h0; + parameter [15:0] INIT_6A = 16'h0; + parameter [15:0] INIT_6B = 16'h0; + parameter [15:0] INIT_6C = 16'h0; + parameter [15:0] INIT_6D = 16'h0; + parameter [15:0] INIT_6E = 16'h0; + parameter [15:0] INIT_6F = 16'h0; + parameter [15:0] INIT_70 = 16'h0; + parameter [15:0] INIT_71 = 16'h0; + parameter [15:0] INIT_72 = 16'h0; + parameter [15:0] INIT_73 = 16'h0; + parameter [15:0] INIT_74 = 16'h0; + parameter [15:0] INIT_75 = 16'h0; + parameter [15:0] INIT_76 = 16'h0; + parameter [15:0] INIT_77 = 16'h0; + parameter [15:0] INIT_78 = 16'h0; + parameter [15:0] INIT_79 = 16'h0; + parameter [15:0] INIT_7A = 16'h0; + parameter [15:0] INIT_7B = 16'h0; + parameter [15:0] INIT_7C = 16'h0; + parameter [15:0] INIT_7D = 16'h0; + parameter [15:0] INIT_7E = 16'h0; + parameter [15:0] INIT_7F = 16'h0; + parameter [0:0] IS_CONVSTCLK_INVERTED = 1'b0; + parameter [0:0] IS_DCLK_INVERTED = 1'b0; + parameter SIM_MONITOR_FILE = "design.txt"; + parameter integer SYSMON_VUSER0_BANK = 0; + parameter SYSMON_VUSER0_MONITOR = "NONE"; + parameter integer SYSMON_VUSER1_BANK = 0; + parameter SYSMON_VUSER1_MONITOR = "NONE"; + parameter integer SYSMON_VUSER2_BANK = 0; + parameter SYSMON_VUSER2_MONITOR = "NONE"; + parameter integer SYSMON_VUSER3_BANK = 0; + parameter SYSMON_VUSER3_MONITOR = "NONE"; + output [15:0] ALM; + output BUSY; + output [5:0] CHANNEL; + output [15:0] DO; + output DRDY; + output EOC; + output EOS; + output I2C_SCLK_TS; + output I2C_SDA_TS; + output JTAGBUSY; + output JTAGLOCKED; + output JTAGMODIFIED; + output [4:0] MUXADDR; + output OT; + input CONVST; + (* invertible_pin = "IS_CONVSTCLK_INVERTED" *) + input CONVSTCLK; + input [7:0] DADDR; + (* invertible_pin = "IS_DCLK_INVERTED" *) + input DCLK; + input DEN; + input [15:0] DI; + input DWE; + input I2C_SCLK; + input I2C_SDA; + input RESET; + input [15:0] VAUXN; + input [15:0] VAUXP; + input VN; + input VP; +endmodule + +module SYSMONE4 (...); + parameter [15:0] COMMON_N_SOURCE = 16'hFFFF; + parameter [15:0] INIT_40 = 16'h0000; + parameter [15:0] INIT_41 = 16'h0000; + parameter [15:0] INIT_42 = 16'h0000; + parameter [15:0] INIT_43 = 16'h0000; + parameter [15:0] INIT_44 = 16'h0000; + parameter [15:0] INIT_45 = 16'h0000; + parameter [15:0] INIT_46 = 16'h0000; + parameter [15:0] INIT_47 = 16'h0000; + parameter [15:0] INIT_48 = 16'h0000; + parameter [15:0] INIT_49 = 16'h0000; + parameter [15:0] INIT_4A = 16'h0000; + parameter [15:0] INIT_4B = 16'h0000; + parameter [15:0] INIT_4C = 16'h0000; + parameter [15:0] INIT_4D = 16'h0000; + parameter [15:0] INIT_4E = 16'h0000; + parameter [15:0] INIT_4F = 16'h0000; + parameter [15:0] INIT_50 = 16'h0000; + parameter [15:0] INIT_51 = 16'h0000; + parameter [15:0] INIT_52 = 16'h0000; + parameter [15:0] INIT_53 = 16'h0000; + parameter [15:0] INIT_54 = 16'h0000; + parameter [15:0] INIT_55 = 16'h0000; + parameter [15:0] INIT_56 = 16'h0000; + parameter [15:0] INIT_57 = 16'h0000; + parameter [15:0] INIT_58 = 16'h0000; + parameter [15:0] INIT_59 = 16'h0000; + parameter [15:0] INIT_5A = 16'h0000; + parameter [15:0] INIT_5B = 16'h0000; + parameter [15:0] INIT_5C = 16'h0000; + parameter [15:0] INIT_5D = 16'h0000; + parameter [15:0] INIT_5E = 16'h0000; + parameter [15:0] INIT_5F = 16'h0000; + parameter [15:0] INIT_60 = 16'h0000; + parameter [15:0] INIT_61 = 16'h0000; + parameter [15:0] INIT_62 = 16'h0000; + parameter [15:0] INIT_63 = 16'h0000; + parameter [15:0] INIT_64 = 16'h0000; + parameter [15:0] INIT_65 = 16'h0000; + parameter [15:0] INIT_66 = 16'h0000; + parameter [15:0] INIT_67 = 16'h0000; + parameter [15:0] INIT_68 = 16'h0000; + parameter [15:0] INIT_69 = 16'h0000; + parameter [15:0] INIT_6A = 16'h0000; + parameter [15:0] INIT_6B = 16'h0000; + parameter [15:0] INIT_6C = 16'h0000; + parameter [15:0] INIT_6D = 16'h0000; + parameter [15:0] INIT_6E = 16'h0000; + parameter [15:0] INIT_6F = 16'h0000; + parameter [15:0] INIT_70 = 16'h0000; + parameter [15:0] INIT_71 = 16'h0000; + parameter [15:0] INIT_72 = 16'h0000; + parameter [15:0] INIT_73 = 16'h0000; + parameter [15:0] INIT_74 = 16'h0000; + parameter [15:0] INIT_75 = 16'h0000; + parameter [15:0] INIT_76 = 16'h0000; + parameter [15:0] INIT_77 = 16'h0000; + parameter [15:0] INIT_78 = 16'h0000; + parameter [15:0] INIT_79 = 16'h0000; + parameter [15:0] INIT_7A = 16'h0000; + parameter [15:0] INIT_7B = 16'h0000; + parameter [15:0] INIT_7C = 16'h0000; + parameter [15:0] INIT_7D = 16'h0000; + parameter [15:0] INIT_7E = 16'h0000; + parameter [15:0] INIT_7F = 16'h0000; + parameter [0:0] IS_CONVSTCLK_INVERTED = 1'b0; + parameter [0:0] IS_DCLK_INVERTED = 1'b0; + parameter SIM_DEVICE = "ULTRASCALE_PLUS"; + parameter SIM_MONITOR_FILE = "design.txt"; + parameter integer SYSMON_VUSER0_BANK = 0; + parameter SYSMON_VUSER0_MONITOR = "NONE"; + parameter integer SYSMON_VUSER1_BANK = 0; + parameter SYSMON_VUSER1_MONITOR = "NONE"; + parameter integer SYSMON_VUSER2_BANK = 0; + parameter SYSMON_VUSER2_MONITOR = "NONE"; + parameter integer SYSMON_VUSER3_BANK = 0; + parameter SYSMON_VUSER3_MONITOR = "NONE"; + output [15:0] ADC_DATA; + output [15:0] ALM; + output BUSY; + output [5:0] CHANNEL; + output [15:0] DO; + output DRDY; + output EOC; + output EOS; + output I2C_SCLK_TS; + output I2C_SDA_TS; + output JTAGBUSY; + output JTAGLOCKED; + output JTAGMODIFIED; + output [4:0] MUXADDR; + output OT; + output SMBALERT_TS; + input CONVST; + (* invertible_pin = "IS_CONVSTCLK_INVERTED" *) + input CONVSTCLK; + input [7:0] DADDR; + (* invertible_pin = "IS_DCLK_INVERTED" *) + input DCLK; + input DEN; + input [15:0] DI; + input DWE; + input I2C_SCLK; + input I2C_SDA; + input RESET; + input [15:0] VAUXN; + input [15:0] VAUXP; + input VN; + input VP; +endmodule + +module DSP48E2 (...); + parameter integer ACASCREG = 1; + parameter integer ADREG = 1; + parameter integer ALUMODEREG = 1; + parameter AMULTSEL = "A"; + parameter integer AREG = 1; + parameter AUTORESET_PATDET = "NO_RESET"; + parameter AUTORESET_PRIORITY = "RESET"; + parameter A_INPUT = "DIRECT"; + parameter integer BCASCREG = 1; + parameter BMULTSEL = "B"; + parameter integer BREG = 1; + parameter B_INPUT = "DIRECT"; + parameter integer CARRYINREG = 1; + parameter integer CARRYINSELREG = 1; + parameter integer CREG = 1; + parameter integer DREG = 1; + parameter integer INMODEREG = 1; + parameter [3:0] IS_ALUMODE_INVERTED = 4'b0000; + parameter [0:0] IS_CARRYIN_INVERTED = 1'b0; + parameter [0:0] IS_CLK_INVERTED = 1'b0; + parameter [4:0] IS_INMODE_INVERTED = 5'b00000; + parameter [8:0] IS_OPMODE_INVERTED = 9'b000000000; + parameter [0:0] IS_RSTALLCARRYIN_INVERTED = 1'b0; + parameter [0:0] IS_RSTALUMODE_INVERTED = 1'b0; + parameter [0:0] IS_RSTA_INVERTED = 1'b0; + parameter [0:0] IS_RSTB_INVERTED = 1'b0; + parameter [0:0] IS_RSTCTRL_INVERTED = 1'b0; + parameter [0:0] IS_RSTC_INVERTED = 1'b0; + parameter [0:0] IS_RSTD_INVERTED = 1'b0; + parameter [0:0] IS_RSTINMODE_INVERTED = 1'b0; + parameter [0:0] IS_RSTM_INVERTED = 1'b0; + parameter [0:0] IS_RSTP_INVERTED = 1'b0; + parameter [47:0] MASK = 48'h3FFFFFFFFFFF; + parameter integer MREG = 1; + parameter integer OPMODEREG = 1; + parameter [47:0] PATTERN = 48'h000000000000; + parameter PREADDINSEL = "A"; + parameter integer PREG = 1; + parameter [47:0] RND = 48'h000000000000; + parameter SEL_MASK = "MASK"; + parameter SEL_PATTERN = "PATTERN"; + parameter USE_MULT = "MULTIPLY"; + parameter USE_PATTERN_DETECT = "NO_PATDET"; + parameter USE_SIMD = "ONE48"; + parameter USE_WIDEXOR = "FALSE"; + parameter XORSIMD = "XOR24_48_96"; + output [29:0] ACOUT; + output [17:0] BCOUT; + output CARRYCASCOUT; + output [3:0] CARRYOUT; + output MULTSIGNOUT; + output OVERFLOW; + output [47:0] P; + output PATTERNBDETECT; + output PATTERNDETECT; + output [47:0] PCOUT; + output UNDERFLOW; + output [7:0] XOROUT; + input [29:0] A; + input [29:0] ACIN; + (* invertible_pin = "IS_ALUMODE_INVERTED" *) + input [3:0] ALUMODE; + input [17:0] B; + input [17:0] BCIN; + input [47:0] C; + input CARRYCASCIN; + (* invertible_pin = "IS_CARRYIN_INVERTED" *) + input CARRYIN; + input [2:0] CARRYINSEL; + input CEA1; + input CEA2; + input CEAD; + input CEALUMODE; + input CEB1; + input CEB2; + input CEC; + input CECARRYIN; + input CECTRL; + input CED; + input CEINMODE; + input CEM; + input CEP; + (* clkbuf_sink *) + (* invertible_pin = "IS_CLK_INVERTED" *) + input CLK; + input [26:0] D; + (* invertible_pin = "IS_INMODE_INVERTED" *) + input [4:0] INMODE; + input MULTSIGNIN; + (* invertible_pin = "IS_OPMODE_INVERTED" *) + input [8:0] OPMODE; + input [47:0] PCIN; + (* invertible_pin = "IS_RSTA_INVERTED" *) + input RSTA; + (* invertible_pin = "IS_RSTALLCARRYIN_INVERTED" *) + input RSTALLCARRYIN; + (* invertible_pin = "IS_RSTALUMODE_INVERTED" *) + input RSTALUMODE; + (* invertible_pin = "IS_RSTB_INVERTED" *) + input RSTB; + (* invertible_pin = "IS_RSTC_INVERTED" *) + input RSTC; + (* invertible_pin = "IS_RSTCTRL_INVERTED" *) + input RSTCTRL; + (* invertible_pin = "IS_RSTD_INVERTED" *) + input RSTD; + (* invertible_pin = "IS_RSTINMODE_INVERTED" *) + input RSTINMODE; + (* invertible_pin = "IS_RSTM_INVERTED" *) + input RSTM; + (* invertible_pin = "IS_RSTP_INVERTED" *) + input RSTP; +endmodule + +module FIFO18E2 (...); + parameter CASCADE_ORDER = "NONE"; + parameter CLOCK_DOMAINS = "INDEPENDENT"; + parameter FIRST_WORD_FALL_THROUGH = "FALSE"; + parameter [35:0] INIT = 36'h000000000; + parameter [0:0] IS_RDCLK_INVERTED = 1'b0; + parameter [0:0] IS_RDEN_INVERTED = 1'b0; + parameter [0:0] IS_RSTREG_INVERTED = 1'b0; + parameter [0:0] IS_RST_INVERTED = 1'b0; + parameter [0:0] IS_WRCLK_INVERTED = 1'b0; + parameter [0:0] IS_WREN_INVERTED = 1'b0; + parameter integer PROG_EMPTY_THRESH = 256; + parameter integer PROG_FULL_THRESH = 256; + parameter RDCOUNT_TYPE = "RAW_PNTR"; + parameter integer READ_WIDTH = 4; + parameter REGISTER_MODE = "UNREGISTERED"; + parameter RSTREG_PRIORITY = "RSTREG"; + parameter SLEEP_ASYNC = "FALSE"; + parameter [35:0] SRVAL = 36'h000000000; + parameter WRCOUNT_TYPE = "RAW_PNTR"; + parameter integer WRITE_WIDTH = 4; + output [31:0] CASDOUT; + output [3:0] CASDOUTP; + output CASNXTEMPTY; + output CASPRVRDEN; + output [31:0] DOUT; + output [3:0] DOUTP; + output EMPTY; + output FULL; + output PROGEMPTY; + output PROGFULL; + output [12:0] RDCOUNT; + output RDERR; + output RDRSTBUSY; + output [12:0] WRCOUNT; + output WRERR; + output WRRSTBUSY; + input [31:0] CASDIN; + input [3:0] CASDINP; + input CASDOMUX; + input CASDOMUXEN; + input CASNXTRDEN; + input CASOREGIMUX; + input CASOREGIMUXEN; + input CASPRVEMPTY; + input [31:0] DIN; + input [3:0] DINP; + (* clkbuf_sink *) + (* invertible_pin = "IS_RDCLK_INVERTED" *) + input RDCLK; + (* invertible_pin = "IS_RDEN_INVERTED" *) + input RDEN; + input REGCE; + (* invertible_pin = "IS_RST_INVERTED" *) + input RST; + (* invertible_pin = "IS_RSTREG_INVERTED" *) + input RSTREG; + input SLEEP; + (* clkbuf_sink *) + (* invertible_pin = "IS_WRCLK_INVERTED" *) + input WRCLK; + (* invertible_pin = "IS_WREN_INVERTED" *) + input WREN; +endmodule + +module FIFO36E2 (...); + parameter CASCADE_ORDER = "NONE"; + parameter CLOCK_DOMAINS = "INDEPENDENT"; + parameter EN_ECC_PIPE = "FALSE"; + parameter EN_ECC_READ = "FALSE"; + parameter EN_ECC_WRITE = "FALSE"; + parameter FIRST_WORD_FALL_THROUGH = "FALSE"; + parameter [71:0] INIT = 72'h000000000000000000; + parameter [0:0] IS_RDCLK_INVERTED = 1'b0; + parameter [0:0] IS_RDEN_INVERTED = 1'b0; + parameter [0:0] IS_RSTREG_INVERTED = 1'b0; + parameter [0:0] IS_RST_INVERTED = 1'b0; + parameter [0:0] IS_WRCLK_INVERTED = 1'b0; + parameter [0:0] IS_WREN_INVERTED = 1'b0; + parameter integer PROG_EMPTY_THRESH = 256; + parameter integer PROG_FULL_THRESH = 256; + parameter RDCOUNT_TYPE = "RAW_PNTR"; + parameter integer READ_WIDTH = 4; + parameter REGISTER_MODE = "UNREGISTERED"; + parameter RSTREG_PRIORITY = "RSTREG"; + parameter SLEEP_ASYNC = "FALSE"; + parameter [71:0] SRVAL = 72'h000000000000000000; + parameter WRCOUNT_TYPE = "RAW_PNTR"; + parameter integer WRITE_WIDTH = 4; + output [63:0] CASDOUT; + output [7:0] CASDOUTP; + output CASNXTEMPTY; + output CASPRVRDEN; + output DBITERR; + output [63:0] DOUT; + output [7:0] DOUTP; + output [7:0] ECCPARITY; + output EMPTY; + output FULL; + output PROGEMPTY; + output PROGFULL; + output [13:0] RDCOUNT; + output RDERR; + output RDRSTBUSY; + output SBITERR; + output [13:0] WRCOUNT; + output WRERR; + output WRRSTBUSY; + input [63:0] CASDIN; + input [7:0] CASDINP; + input CASDOMUX; + input CASDOMUXEN; + input CASNXTRDEN; + input CASOREGIMUX; + input CASOREGIMUXEN; + input CASPRVEMPTY; + input [63:0] DIN; + input [7:0] DINP; + input INJECTDBITERR; + input INJECTSBITERR; + (* clkbuf_sink *) + (* invertible_pin = "IS_RDCLK_INVERTED" *) + input RDCLK; + (* invertible_pin = "IS_RDEN_INVERTED" *) + input RDEN; + input REGCE; + (* invertible_pin = "IS_RST_INVERTED" *) + input RST; + (* invertible_pin = "IS_RSTREG_INVERTED" *) + input RSTREG; + input SLEEP; + (* clkbuf_sink *) + (* invertible_pin = "IS_WRCLK_INVERTED" *) + input WRCLK; + (* invertible_pin = "IS_WREN_INVERTED" *) + input WREN; +endmodule + +module RAMB18E2 (...); + parameter CASCADE_ORDER_A = "NONE"; + parameter CASCADE_ORDER_B = "NONE"; + parameter CLOCK_DOMAINS = "INDEPENDENT"; + parameter integer DOA_REG = 1; + parameter integer DOB_REG = 1; + parameter ENADDRENA = "FALSE"; + parameter ENADDRENB = "FALSE"; + parameter [255:0] INITP_00 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INITP_01 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INITP_02 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INITP_03 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INITP_04 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INITP_05 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INITP_06 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INITP_07 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_00 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_01 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_02 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_03 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_04 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_05 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_06 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_07 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_08 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_09 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_0A = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_0B = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_0C = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_0D = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_0E = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_0F = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_10 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_11 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_12 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_13 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_14 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_15 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_16 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_17 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_18 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_19 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_1A = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_1B = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_1C = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_1D = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_1E = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_1F = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_20 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_21 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_22 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_23 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_24 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_25 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_26 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_27 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_28 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_29 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_2A = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_2B = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_2C = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_2D = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_2E = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_2F = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_30 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_31 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_32 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_33 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_34 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_35 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_36 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_37 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_38 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_39 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_3A = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_3B = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_3C = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_3D = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_3E = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_3F = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [17:0] INIT_A = 18'h00000; + parameter [17:0] INIT_B = 18'h00000; + parameter INIT_FILE = "NONE"; + parameter [0:0] IS_CLKARDCLK_INVERTED = 1'b0; + parameter [0:0] IS_CLKBWRCLK_INVERTED = 1'b0; + parameter [0:0] IS_ENARDEN_INVERTED = 1'b0; + parameter [0:0] IS_ENBWREN_INVERTED = 1'b0; + parameter [0:0] IS_RSTRAMARSTRAM_INVERTED = 1'b0; + parameter [0:0] IS_RSTRAMB_INVERTED = 1'b0; + parameter [0:0] IS_RSTREGARSTREG_INVERTED = 1'b0; + parameter [0:0] IS_RSTREGB_INVERTED = 1'b0; + parameter RDADDRCHANGEA = "FALSE"; + parameter RDADDRCHANGEB = "FALSE"; + parameter integer READ_WIDTH_A = 0; + parameter integer READ_WIDTH_B = 0; + parameter RSTREG_PRIORITY_A = "RSTREG"; + parameter RSTREG_PRIORITY_B = "RSTREG"; + parameter SIM_COLLISION_CHECK = "ALL"; + parameter SLEEP_ASYNC = "FALSE"; + parameter [17:0] SRVAL_A = 18'h00000; + parameter [17:0] SRVAL_B = 18'h00000; + parameter WRITE_MODE_A = "NO_CHANGE"; + parameter WRITE_MODE_B = "NO_CHANGE"; + parameter integer WRITE_WIDTH_A = 0; + parameter integer WRITE_WIDTH_B = 0; + output [15:0] CASDOUTA; + output [15:0] CASDOUTB; + output [1:0] CASDOUTPA; + output [1:0] CASDOUTPB; + output [15:0] DOUTADOUT; + output [15:0] DOUTBDOUT; + output [1:0] DOUTPADOUTP; + output [1:0] DOUTPBDOUTP; + input [13:0] ADDRARDADDR; + input [13:0] ADDRBWRADDR; + input ADDRENA; + input ADDRENB; + input CASDIMUXA; + input CASDIMUXB; + input [15:0] CASDINA; + input [15:0] CASDINB; + input [1:0] CASDINPA; + input [1:0] CASDINPB; + input CASDOMUXA; + input CASDOMUXB; + input CASDOMUXEN_A; + input CASDOMUXEN_B; + input CASOREGIMUXA; + input CASOREGIMUXB; + input CASOREGIMUXEN_A; + input CASOREGIMUXEN_B; + (* clkbuf_sink *) + (* invertible_pin = "IS_CLKARDCLK_INVERTED" *) + input CLKARDCLK; + (* clkbuf_sink *) + (* invertible_pin = "IS_CLKBWRCLK_INVERTED" *) + input CLKBWRCLK; + input [15:0] DINADIN; + input [15:0] DINBDIN; + input [1:0] DINPADINP; + input [1:0] DINPBDINP; + (* invertible_pin = "IS_ENARDEN_INVERTED" *) + input ENARDEN; + (* invertible_pin = "IS_ENBWREN_INVERTED" *) + input ENBWREN; + input REGCEAREGCE; + input REGCEB; + (* invertible_pin = "IS_RSTRAMARSTRAM_INVERTED" *) + input RSTRAMARSTRAM; + (* invertible_pin = "IS_RSTRAMB_INVERTED" *) + input RSTRAMB; + (* invertible_pin = "IS_RSTREGARSTREG_INVERTED" *) + input RSTREGARSTREG; + (* invertible_pin = "IS_RSTREGB_INVERTED" *) + input RSTREGB; + input SLEEP; + input [1:0] WEA; + input [3:0] WEBWE; +endmodule + +module RAMB36E2 (...); + parameter CASCADE_ORDER_A = "NONE"; + parameter CASCADE_ORDER_B = "NONE"; + parameter CLOCK_DOMAINS = "INDEPENDENT"; + parameter integer DOA_REG = 1; + parameter integer DOB_REG = 1; + parameter ENADDRENA = "FALSE"; + parameter ENADDRENB = "FALSE"; + parameter EN_ECC_PIPE = "FALSE"; + parameter EN_ECC_READ = "FALSE"; + parameter EN_ECC_WRITE = "FALSE"; + parameter [255:0] INITP_00 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INITP_01 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INITP_02 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INITP_03 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INITP_04 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INITP_05 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INITP_06 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INITP_07 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INITP_08 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INITP_09 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INITP_0A = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INITP_0B = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INITP_0C = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INITP_0D = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INITP_0E = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INITP_0F = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_00 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_01 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_02 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_03 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_04 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_05 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_06 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_07 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_08 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_09 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_0A = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_0B = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_0C = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_0D = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_0E = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_0F = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_10 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_11 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_12 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_13 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_14 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_15 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_16 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_17 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_18 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_19 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_1A = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_1B = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_1C = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_1D = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_1E = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_1F = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_20 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_21 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_22 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_23 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_24 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_25 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_26 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_27 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_28 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_29 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_2A = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_2B = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_2C = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_2D = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_2E = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_2F = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_30 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_31 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_32 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_33 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_34 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_35 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_36 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_37 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_38 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_39 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_3A = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_3B = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_3C = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_3D = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_3E = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_3F = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_40 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_41 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_42 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_43 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_44 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_45 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_46 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_47 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_48 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_49 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_4A = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_4B = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_4C = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_4D = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_4E = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_4F = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_50 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_51 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_52 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_53 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_54 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_55 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_56 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_57 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_58 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_59 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_5A = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_5B = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_5C = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_5D = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_5E = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_5F = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_60 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_61 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_62 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_63 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_64 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_65 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_66 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_67 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_68 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_69 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_6A = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_6B = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_6C = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_6D = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_6E = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_6F = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_70 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_71 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_72 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_73 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_74 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_75 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_76 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_77 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_78 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_79 = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_7A = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_7B = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_7C = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_7D = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_7E = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [255:0] INIT_7F = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [35:0] INIT_A = 36'h000000000; + parameter [35:0] INIT_B = 36'h000000000; + parameter INIT_FILE = "NONE"; + parameter [0:0] IS_CLKARDCLK_INVERTED = 1'b0; + parameter [0:0] IS_CLKBWRCLK_INVERTED = 1'b0; + parameter [0:0] IS_ENARDEN_INVERTED = 1'b0; + parameter [0:0] IS_ENBWREN_INVERTED = 1'b0; + parameter [0:0] IS_RSTRAMARSTRAM_INVERTED = 1'b0; + parameter [0:0] IS_RSTRAMB_INVERTED = 1'b0; + parameter [0:0] IS_RSTREGARSTREG_INVERTED = 1'b0; + parameter [0:0] IS_RSTREGB_INVERTED = 1'b0; + parameter RDADDRCHANGEA = "FALSE"; + parameter RDADDRCHANGEB = "FALSE"; + parameter integer READ_WIDTH_A = 0; + parameter integer READ_WIDTH_B = 0; + parameter RSTREG_PRIORITY_A = "RSTREG"; + parameter RSTREG_PRIORITY_B = "RSTREG"; + parameter SIM_COLLISION_CHECK = "ALL"; + parameter SLEEP_ASYNC = "FALSE"; + parameter [35:0] SRVAL_A = 36'h000000000; + parameter [35:0] SRVAL_B = 36'h000000000; + parameter WRITE_MODE_A = "NO_CHANGE"; + parameter WRITE_MODE_B = "NO_CHANGE"; + parameter integer WRITE_WIDTH_A = 0; + parameter integer WRITE_WIDTH_B = 0; + output [31:0] CASDOUTA; + output [31:0] CASDOUTB; + output [3:0] CASDOUTPA; + output [3:0] CASDOUTPB; + output CASOUTDBITERR; + output CASOUTSBITERR; + output DBITERR; + output [31:0] DOUTADOUT; + output [31:0] DOUTBDOUT; + output [3:0] DOUTPADOUTP; + output [3:0] DOUTPBDOUTP; + output [7:0] ECCPARITY; + output [8:0] RDADDRECC; + output SBITERR; + input [14:0] ADDRARDADDR; + input [14:0] ADDRBWRADDR; + input ADDRENA; + input ADDRENB; + input CASDIMUXA; + input CASDIMUXB; + input [31:0] CASDINA; + input [31:0] CASDINB; + input [3:0] CASDINPA; + input [3:0] CASDINPB; + input CASDOMUXA; + input CASDOMUXB; + input CASDOMUXEN_A; + input CASDOMUXEN_B; + input CASINDBITERR; + input CASINSBITERR; + input CASOREGIMUXA; + input CASOREGIMUXB; + input CASOREGIMUXEN_A; + input CASOREGIMUXEN_B; + (* clkbuf_sink *) + (* invertible_pin = "IS_CLKARDCLK_INVERTED" *) + input CLKARDCLK; + (* clkbuf_sink *) + (* invertible_pin = "IS_CLKBWRCLK_INVERTED" *) + input CLKBWRCLK; + input [31:0] DINADIN; + input [31:0] DINBDIN; + input [3:0] DINPADINP; + input [3:0] DINPBDINP; + input ECCPIPECE; + (* invertible_pin = "IS_ENARDEN_INVERTED" *) + input ENARDEN; + (* invertible_pin = "IS_ENBWREN_INVERTED" *) + input ENBWREN; + input INJECTDBITERR; + input INJECTSBITERR; + input REGCEAREGCE; + input REGCEB; + (* invertible_pin = "IS_RSTRAMARSTRAM_INVERTED" *) + input RSTRAMARSTRAM; + (* invertible_pin = "IS_RSTRAMB_INVERTED" *) + input RSTRAMB; + (* invertible_pin = "IS_RSTREGARSTREG_INVERTED" *) + input RSTREGARSTREG; + (* invertible_pin = "IS_RSTREGB_INVERTED" *) + input RSTREGB; + input SLEEP; + input [3:0] WEA; + input [7:0] WEBWE; +endmodule + +module URAM288 (...); + parameter integer AUTO_SLEEP_LATENCY = 8; + parameter integer AVG_CONS_INACTIVE_CYCLES = 10; + parameter BWE_MODE_A = "PARITY_INTERLEAVED"; + parameter BWE_MODE_B = "PARITY_INTERLEAVED"; + parameter CASCADE_ORDER_A = "NONE"; + parameter CASCADE_ORDER_B = "NONE"; + parameter EN_AUTO_SLEEP_MODE = "FALSE"; + parameter EN_ECC_RD_A = "FALSE"; + parameter EN_ECC_RD_B = "FALSE"; + parameter EN_ECC_WR_A = "FALSE"; + parameter EN_ECC_WR_B = "FALSE"; + parameter IREG_PRE_A = "FALSE"; + parameter IREG_PRE_B = "FALSE"; + parameter [0:0] IS_CLK_INVERTED = 1'b0; + parameter [0:0] IS_EN_A_INVERTED = 1'b0; + parameter [0:0] IS_EN_B_INVERTED = 1'b0; + parameter [0:0] IS_RDB_WR_A_INVERTED = 1'b0; + parameter [0:0] IS_RDB_WR_B_INVERTED = 1'b0; + parameter [0:0] IS_RST_A_INVERTED = 1'b0; + parameter [0:0] IS_RST_B_INVERTED = 1'b0; + parameter MATRIX_ID = "NONE"; + parameter integer NUM_UNIQUE_SELF_ADDR_A = 1; + parameter integer NUM_UNIQUE_SELF_ADDR_B = 1; + parameter integer NUM_URAM_IN_MATRIX = 1; + parameter OREG_A = "FALSE"; + parameter OREG_B = "FALSE"; + parameter OREG_ECC_A = "FALSE"; + parameter OREG_ECC_B = "FALSE"; + parameter REG_CAS_A = "FALSE"; + parameter REG_CAS_B = "FALSE"; + parameter RST_MODE_A = "SYNC"; + parameter RST_MODE_B = "SYNC"; + parameter [10:0] SELF_ADDR_A = 11'h000; + parameter [10:0] SELF_ADDR_B = 11'h000; + parameter [10:0] SELF_MASK_A = 11'h7FF; + parameter [10:0] SELF_MASK_B = 11'h7FF; + parameter USE_EXT_CE_A = "FALSE"; + parameter USE_EXT_CE_B = "FALSE"; + output [22:0] CAS_OUT_ADDR_A; + output [22:0] CAS_OUT_ADDR_B; + output [8:0] CAS_OUT_BWE_A; + output [8:0] CAS_OUT_BWE_B; + output CAS_OUT_DBITERR_A; + output CAS_OUT_DBITERR_B; + output [71:0] CAS_OUT_DIN_A; + output [71:0] CAS_OUT_DIN_B; + output [71:0] CAS_OUT_DOUT_A; + output [71:0] CAS_OUT_DOUT_B; + output CAS_OUT_EN_A; + output CAS_OUT_EN_B; + output CAS_OUT_RDACCESS_A; + output CAS_OUT_RDACCESS_B; + output CAS_OUT_RDB_WR_A; + output CAS_OUT_RDB_WR_B; + output CAS_OUT_SBITERR_A; + output CAS_OUT_SBITERR_B; + output DBITERR_A; + output DBITERR_B; + output [71:0] DOUT_A; + output [71:0] DOUT_B; + output RDACCESS_A; + output RDACCESS_B; + output SBITERR_A; + output SBITERR_B; + input [22:0] ADDR_A; + input [22:0] ADDR_B; + input [8:0] BWE_A; + input [8:0] BWE_B; + input [22:0] CAS_IN_ADDR_A; + input [22:0] CAS_IN_ADDR_B; + input [8:0] CAS_IN_BWE_A; + input [8:0] CAS_IN_BWE_B; + input CAS_IN_DBITERR_A; + input CAS_IN_DBITERR_B; + input [71:0] CAS_IN_DIN_A; + input [71:0] CAS_IN_DIN_B; + input [71:0] CAS_IN_DOUT_A; + input [71:0] CAS_IN_DOUT_B; + input CAS_IN_EN_A; + input CAS_IN_EN_B; + input CAS_IN_RDACCESS_A; + input CAS_IN_RDACCESS_B; + input CAS_IN_RDB_WR_A; + input CAS_IN_RDB_WR_B; + input CAS_IN_SBITERR_A; + input CAS_IN_SBITERR_B; + (* clkbuf_sink *) + (* invertible_pin = "IS_CLK_INVERTED" *) + input CLK; + input [71:0] DIN_A; + input [71:0] DIN_B; + (* invertible_pin = "IS_EN_A_INVERTED" *) + input EN_A; + (* invertible_pin = "IS_EN_B_INVERTED" *) + input EN_B; + input INJECT_DBITERR_A; + input INJECT_DBITERR_B; + input INJECT_SBITERR_A; + input INJECT_SBITERR_B; + input OREG_CE_A; + input OREG_CE_B; + input OREG_ECC_CE_A; + input OREG_ECC_CE_B; + (* invertible_pin = "IS_RDB_WR_A_INVERTED" *) + input RDB_WR_A; + (* invertible_pin = "IS_RDB_WR_B_INVERTED" *) + input RDB_WR_B; + (* invertible_pin = "IS_RST_A_INVERTED" *) + input RST_A; + (* invertible_pin = "IS_RST_B_INVERTED" *) + input RST_B; + input SLEEP; +endmodule + +module URAM288_BASE (...); + parameter integer AUTO_SLEEP_LATENCY = 8; + parameter integer AVG_CONS_INACTIVE_CYCLES = 10; + parameter BWE_MODE_A = "PARITY_INTERLEAVED"; + parameter BWE_MODE_B = "PARITY_INTERLEAVED"; + parameter EN_AUTO_SLEEP_MODE = "FALSE"; + parameter EN_ECC_RD_A = "FALSE"; + parameter EN_ECC_RD_B = "FALSE"; + parameter EN_ECC_WR_A = "FALSE"; + parameter EN_ECC_WR_B = "FALSE"; + parameter IREG_PRE_A = "FALSE"; + parameter IREG_PRE_B = "FALSE"; + parameter [0:0] IS_CLK_INVERTED = 1'b0; + parameter [0:0] IS_EN_A_INVERTED = 1'b0; + parameter [0:0] IS_EN_B_INVERTED = 1'b0; + parameter [0:0] IS_RDB_WR_A_INVERTED = 1'b0; + parameter [0:0] IS_RDB_WR_B_INVERTED = 1'b0; + parameter [0:0] IS_RST_A_INVERTED = 1'b0; + parameter [0:0] IS_RST_B_INVERTED = 1'b0; + parameter OREG_A = "FALSE"; + parameter OREG_B = "FALSE"; + parameter OREG_ECC_A = "FALSE"; + parameter OREG_ECC_B = "FALSE"; + parameter RST_MODE_A = "SYNC"; + parameter RST_MODE_B = "SYNC"; + parameter USE_EXT_CE_A = "FALSE"; + parameter USE_EXT_CE_B = "FALSE"; + output DBITERR_A; + output DBITERR_B; + output [71:0] DOUT_A; + output [71:0] DOUT_B; + output SBITERR_A; + output SBITERR_B; + input [22:0] ADDR_A; + input [22:0] ADDR_B; + input [8:0] BWE_A; + input [8:0] BWE_B; + (* clkbuf_sink *) + (* invertible_pin = "IS_CLK_INVERTED" *) + input CLK; + input [71:0] DIN_A; + input [71:0] DIN_B; + (* invertible_pin = "IS_EN_A_INVERTED" *) + input EN_A; + (* invertible_pin = "IS_EN_B_INVERTED" *) + input EN_B; + input INJECT_DBITERR_A; + input INJECT_DBITERR_B; + input INJECT_SBITERR_A; + input INJECT_SBITERR_B; + input OREG_CE_A; + input OREG_CE_B; + input OREG_ECC_CE_A; + input OREG_ECC_CE_B; + (* invertible_pin = "IS_RDB_WR_A_INVERTED" *) + input RDB_WR_A; + (* invertible_pin = "IS_RDB_WR_B_INVERTED" *) + input RDB_WR_B; + (* invertible_pin = "IS_RST_A_INVERTED" *) + input RST_A; + (* invertible_pin = "IS_RST_B_INVERTED" *) + input RST_B; + input SLEEP; +endmodule + +module RAM128X1S (...); + parameter [127:0] INIT = 128'h00000000000000000000000000000000; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + output O; + input A0; + input A1; + input A2; + input A3; + input A4; + input A5; + input A6; + input D; + (* clkbuf_sink *) + (* invertible_pin = "IS_WCLK_INVERTED" *) + input WCLK; + input WE; +endmodule + +module RAM256X1D (...); + parameter [255:0] INIT = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + output DPO; + output SPO; + input [7:0] A; + input D; + input [7:0] DPRA; + (* clkbuf_sink *) + (* invertible_pin = "IS_WCLK_INVERTED" *) + input WCLK; + input WE; +endmodule + +module RAM256X1S (...); + parameter [255:0] INIT = 256'h0; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + output O; + input [7:0] A; + input D; + (* clkbuf_sink *) + (* invertible_pin = "IS_WCLK_INVERTED" *) + input WCLK; + input WE; +endmodule + +module RAM32M (...); + parameter [63:0] INIT_A = 64'h0000000000000000; + parameter [63:0] INIT_B = 64'h0000000000000000; + parameter [63:0] INIT_C = 64'h0000000000000000; + parameter [63:0] INIT_D = 64'h0000000000000000; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + output [1:0] DOA; + output [1:0] DOB; + output [1:0] DOC; + output [1:0] DOD; + input [4:0] ADDRA; + input [4:0] ADDRB; + input [4:0] ADDRC; + input [4:0] ADDRD; + input [1:0] DIA; + input [1:0] DIB; + input [1:0] DIC; + input [1:0] DID; + (* clkbuf_sink *) + (* invertible_pin = "IS_WCLK_INVERTED" *) + input WCLK; + input WE; +endmodule + +module RAM32M16 (...); + parameter [63:0] INIT_A = 64'h0000000000000000; + parameter [63:0] INIT_B = 64'h0000000000000000; + parameter [63:0] INIT_C = 64'h0000000000000000; + parameter [63:0] INIT_D = 64'h0000000000000000; + parameter [63:0] INIT_E = 64'h0000000000000000; + parameter [63:0] INIT_F = 64'h0000000000000000; + parameter [63:0] INIT_G = 64'h0000000000000000; + parameter [63:0] INIT_H = 64'h0000000000000000; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + output [1:0] DOA; + output [1:0] DOB; + output [1:0] DOC; + output [1:0] DOD; + output [1:0] DOE; + output [1:0] DOF; + output [1:0] DOG; + output [1:0] DOH; + input [4:0] ADDRA; + input [4:0] ADDRB; + input [4:0] ADDRC; + input [4:0] ADDRD; + input [4:0] ADDRE; + input [4:0] ADDRF; + input [4:0] ADDRG; + input [4:0] ADDRH; + input [1:0] DIA; + input [1:0] DIB; + input [1:0] DIC; + input [1:0] DID; + input [1:0] DIE; + input [1:0] DIF; + input [1:0] DIG; + input [1:0] DIH; + (* clkbuf_sink *) + (* invertible_pin = "IS_WCLK_INVERTED" *) + input WCLK; + input WE; +endmodule + +module RAM32X1S (...); + parameter [31:0] INIT = 32'h00000000; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + output O; + input A0; + input A1; + input A2; + input A3; + input A4; + input D; + (* clkbuf_sink *) + (* invertible_pin = "IS_WCLK_INVERTED" *) + input WCLK; + input WE; +endmodule + +module RAM512X1S (...); + parameter [511:0] INIT = 512'h0; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + output O; + input [8:0] A; + input D; + (* clkbuf_sink *) + (* invertible_pin = "IS_WCLK_INVERTED" *) + input WCLK; + input WE; +endmodule + +module RAM64M (...); + parameter [63:0] INIT_A = 64'h0000000000000000; + parameter [63:0] INIT_B = 64'h0000000000000000; + parameter [63:0] INIT_C = 64'h0000000000000000; + parameter [63:0] INIT_D = 64'h0000000000000000; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + output DOA; + output DOB; + output DOC; + output DOD; + input [5:0] ADDRA; + input [5:0] ADDRB; + input [5:0] ADDRC; + input [5:0] ADDRD; + input DIA; + input DIB; + input DIC; + input DID; + (* clkbuf_sink *) + (* invertible_pin = "IS_WCLK_INVERTED" *) + input WCLK; + input WE; +endmodule + +module RAM64M8 (...); + parameter [63:0] INIT_A = 64'h0000000000000000; + parameter [63:0] INIT_B = 64'h0000000000000000; + parameter [63:0] INIT_C = 64'h0000000000000000; + parameter [63:0] INIT_D = 64'h0000000000000000; + parameter [63:0] INIT_E = 64'h0000000000000000; + parameter [63:0] INIT_F = 64'h0000000000000000; + parameter [63:0] INIT_G = 64'h0000000000000000; + parameter [63:0] INIT_H = 64'h0000000000000000; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + output DOA; + output DOB; + output DOC; + output DOD; + output DOE; + output DOF; + output DOG; + output DOH; + input [5:0] ADDRA; + input [5:0] ADDRB; + input [5:0] ADDRC; + input [5:0] ADDRD; + input [5:0] ADDRE; + input [5:0] ADDRF; + input [5:0] ADDRG; + input [5:0] ADDRH; + input DIA; + input DIB; + input DIC; + input DID; + input DIE; + input DIF; + input DIG; + input DIH; + (* clkbuf_sink *) + (* invertible_pin = "IS_WCLK_INVERTED" *) + input WCLK; + input WE; +endmodule + +module RAM64X1S (...); + parameter [63:0] INIT = 64'h0000000000000000; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + output O; + input A0; + input A1; + input A2; + input A3; + input A4; + input A5; + input D; + (* clkbuf_sink *) + (* invertible_pin = "IS_WCLK_INVERTED" *) + input WCLK; + input WE; +endmodule + +module AND2B1L (...); + parameter [0:0] IS_SRI_INVERTED = 1'b0; + output O; + input DI; + (* invertible_pin = "IS_SRI_INVERTED" *) + input SRI; +endmodule + +module CARRY8 (...); + parameter CARRY_TYPE = "SINGLE_CY8"; + output [7:0] CO; + output [7:0] O; + input CI; + input CI_TOP; + input [7:0] DI; + input [7:0] S; +endmodule + +module CFGLUT5 (...); + parameter [31:0] INIT = 32'h00000000; + parameter [0:0] IS_CLK_INVERTED = 1'b0; + output CDO; + output O5; + output O6; + input I4; + input I3; + input I2; + input I1; + input I0; + input CDI; + input CE; + (* clkbuf_sink *) + (* invertible_pin = "IS_CLK_INVERTED" *) + input CLK; +endmodule + +module MUXF9 (...); + output O; + input I0; + input I1; + input S; +endmodule + +module OR2L (...); + parameter [0:0] IS_SRI_INVERTED = 1'b0; + output O; + input DI; + (* invertible_pin = "IS_SRI_INVERTED" *) + input SRI; +endmodule + +module BUFG_GT (...); + (* clkbuf_driver *) + output O; + input CE; + input CEMASK; + input CLR; + input CLRMASK; + input [2:0] DIV; + input I; +endmodule + +module BUFG_GT_SYNC (...); + output CESYNC; + output CLRSYNC; + input CE; + input CLK; + input CLR; +endmodule + +module BUFG_PS (...); + (* clkbuf_driver *) + output O; + input I; +endmodule + +module BUFGCE (...); + parameter CE_TYPE = "SYNC"; + parameter [0:0] IS_CE_INVERTED = 1'b0; + parameter [0:0] IS_I_INVERTED = 1'b0; + (* clkbuf_driver *) + output O; + (* invertible_pin = "IS_CE_INVERTED" *) + input CE; + (* invertible_pin = "IS_I_INVERTED" *) + input I; +endmodule + +module BUFGCE_1 (...); + (* clkbuf_driver *) + output O; + input CE; + input I; +endmodule + +module BUFGCE_DIV (...); + parameter integer BUFGCE_DIVIDE = 1; + parameter [0:0] IS_CE_INVERTED = 1'b0; + parameter [0:0] IS_CLR_INVERTED = 1'b0; + parameter [0:0] IS_I_INVERTED = 1'b0; + (* clkbuf_driver *) + output O; + (* invertible_pin = "IS_CE_INVERTED" *) + input CE; + (* invertible_pin = "IS_CLR_INVERTED" *) + input CLR; + (* invertible_pin = "IS_I_INVERTED" *) + input I; +endmodule + +module BUFGMUX (...); + parameter CLK_SEL_TYPE = "SYNC"; + (* clkbuf_driver *) + output O; + input I0; + input I1; + input S; +endmodule + +module BUFGMUX_1 (...); + parameter CLK_SEL_TYPE = "SYNC"; + (* clkbuf_driver *) + output O; + input I0; + input I1; + input S; +endmodule + +module BUFGMUX_CTRL (...); + (* clkbuf_driver *) + output O; + input I0; + input I1; + input S; +endmodule + +module MMCME3_ADV (...); + parameter BANDWIDTH = "OPTIMIZED"; + parameter real CLKFBOUT_MULT_F = 5.000; + parameter real CLKFBOUT_PHASE = 0.000; + parameter CLKFBOUT_USE_FINE_PS = "FALSE"; + parameter real CLKIN1_PERIOD = 0.000; + parameter real CLKIN2_PERIOD = 0.000; + parameter real CLKIN_FREQ_MAX = 1066.000; + parameter real CLKIN_FREQ_MIN = 10.000; + parameter real CLKOUT0_DIVIDE_F = 1.000; + parameter real CLKOUT0_DUTY_CYCLE = 0.500; + parameter real CLKOUT0_PHASE = 0.000; + parameter CLKOUT0_USE_FINE_PS = "FALSE"; + parameter integer CLKOUT1_DIVIDE = 1; + parameter real CLKOUT1_DUTY_CYCLE = 0.500; + parameter real CLKOUT1_PHASE = 0.000; + parameter CLKOUT1_USE_FINE_PS = "FALSE"; + parameter integer CLKOUT2_DIVIDE = 1; + parameter real CLKOUT2_DUTY_CYCLE = 0.500; + parameter real CLKOUT2_PHASE = 0.000; + parameter CLKOUT2_USE_FINE_PS = "FALSE"; + parameter integer CLKOUT3_DIVIDE = 1; + parameter real CLKOUT3_DUTY_CYCLE = 0.500; + parameter real CLKOUT3_PHASE = 0.000; + parameter CLKOUT3_USE_FINE_PS = "FALSE"; + parameter CLKOUT4_CASCADE = "FALSE"; + parameter integer CLKOUT4_DIVIDE = 1; + parameter real CLKOUT4_DUTY_CYCLE = 0.500; + parameter real CLKOUT4_PHASE = 0.000; + parameter CLKOUT4_USE_FINE_PS = "FALSE"; + parameter integer CLKOUT5_DIVIDE = 1; + parameter real CLKOUT5_DUTY_CYCLE = 0.500; + parameter real CLKOUT5_PHASE = 0.000; + parameter CLKOUT5_USE_FINE_PS = "FALSE"; + parameter integer CLKOUT6_DIVIDE = 1; + parameter real CLKOUT6_DUTY_CYCLE = 0.500; + parameter real CLKOUT6_PHASE = 0.000; + parameter CLKOUT6_USE_FINE_PS = "FALSE"; + parameter real CLKPFD_FREQ_MAX = 550.000; + parameter real CLKPFD_FREQ_MIN = 10.000; + parameter COMPENSATION = "AUTO"; + parameter integer DIVCLK_DIVIDE = 1; + parameter [0:0] IS_CLKFBIN_INVERTED = 1'b0; + parameter [0:0] IS_CLKIN1_INVERTED = 1'b0; + parameter [0:0] IS_CLKIN2_INVERTED = 1'b0; + parameter [0:0] IS_CLKINSEL_INVERTED = 1'b0; + parameter [0:0] IS_PSEN_INVERTED = 1'b0; + parameter [0:0] IS_PSINCDEC_INVERTED = 1'b0; + parameter [0:0] IS_PWRDWN_INVERTED = 1'b0; + parameter [0:0] IS_RST_INVERTED = 1'b0; + parameter real REF_JITTER1 = 0.010; + parameter real REF_JITTER2 = 0.010; + parameter SS_EN = "FALSE"; + parameter SS_MODE = "CENTER_HIGH"; + parameter integer SS_MOD_PERIOD = 10000; + parameter STARTUP_WAIT = "FALSE"; + parameter real VCOCLK_FREQ_MAX = 1600.000; + parameter real VCOCLK_FREQ_MIN = 600.000; + parameter STARTUP_WAIT = "FALSE"; + output CDDCDONE; + output CLKFBOUT; + output CLKFBOUTB; + output CLKFBSTOPPED; + output CLKINSTOPPED; + output CLKOUT0; + output CLKOUT0B; + output CLKOUT1; + output CLKOUT1B; + output CLKOUT2; + output CLKOUT2B; + output CLKOUT3; + output CLKOUT3B; + output CLKOUT4; + output CLKOUT5; + output CLKOUT6; + output [15:0] DO; + output DRDY; + output LOCKED; + output PSDONE; + input CDDCREQ; + (* invertible_pin = "IS_CLKFBIN_INVERTED" *) + input CLKFBIN; + (* invertible_pin = "IS_CLKIN1_INVERTED" *) + input CLKIN1; + (* invertible_pin = "IS_CLKIN2_INVERTED" *) + input CLKIN2; + (* invertible_pin = "IS_CLKINSEL_INVERTED" *) + input CLKINSEL; + input [6:0] DADDR; + input DCLK; + input DEN; + input [15:0] DI; + input DWE; + input PSCLK; + (* invertible_pin = "IS_PSEN_INVERTED" *) + input PSEN; + (* invertible_pin = "IS_PSINCDEC_INVERTED" *) + input PSINCDEC; + (* invertible_pin = "IS_PWRDWN_INVERTED" *) + input PWRDWN; + (* invertible_pin = "IS_RST_INVERTED" *) + input RST; +endmodule + +module MMCME3_BASE (...); + parameter BANDWIDTH = "OPTIMIZED"; + parameter real CLKFBOUT_MULT_F = 5.000; + parameter real CLKFBOUT_PHASE = 0.000; + parameter real CLKIN1_PERIOD = 0.000; + parameter real CLKOUT0_DIVIDE_F = 1.000; + parameter real CLKOUT0_DUTY_CYCLE = 0.500; + parameter real CLKOUT0_PHASE = 0.000; + parameter integer CLKOUT1_DIVIDE = 1; + parameter real CLKOUT1_DUTY_CYCLE = 0.500; + parameter real CLKOUT1_PHASE = 0.000; + parameter integer CLKOUT2_DIVIDE = 1; + parameter real CLKOUT2_DUTY_CYCLE = 0.500; + parameter real CLKOUT2_PHASE = 0.000; + parameter integer CLKOUT3_DIVIDE = 1; + parameter real CLKOUT3_DUTY_CYCLE = 0.500; + parameter real CLKOUT3_PHASE = 0.000; + parameter CLKOUT4_CASCADE = "FALSE"; + parameter integer CLKOUT4_DIVIDE = 1; + parameter real CLKOUT4_DUTY_CYCLE = 0.500; + parameter real CLKOUT4_PHASE = 0.000; + parameter integer CLKOUT5_DIVIDE = 1; + parameter real CLKOUT5_DUTY_CYCLE = 0.500; + parameter real CLKOUT5_PHASE = 0.000; + parameter integer CLKOUT6_DIVIDE = 1; + parameter real CLKOUT6_DUTY_CYCLE = 0.500; + parameter real CLKOUT6_PHASE = 0.000; + parameter integer DIVCLK_DIVIDE = 1; + parameter [0:0] IS_CLKFBIN_INVERTED = 1'b0; + parameter [0:0] IS_CLKIN1_INVERTED = 1'b0; + parameter [0:0] IS_PWRDWN_INVERTED = 1'b0; + parameter [0:0] IS_RST_INVERTED = 1'b0; + parameter real REF_JITTER1 = 0.010; + parameter STARTUP_WAIT = "FALSE"; + output CLKFBOUT; + output CLKFBOUTB; + output CLKOUT0; + output CLKOUT0B; + output CLKOUT1; + output CLKOUT1B; + output CLKOUT2; + output CLKOUT2B; + output CLKOUT3; + output CLKOUT3B; + output CLKOUT4; + output CLKOUT5; + output CLKOUT6; + output LOCKED; + (* invertible_pin = "IS_CLKFBIN_INVERTED" *) + input CLKFBIN; + (* invertible_pin = "IS_CLKIN1_INVERTED" *) + input CLKIN1; + (* invertible_pin = "IS_PWRDWN_INVERTED" *) + input PWRDWN; + (* invertible_pin = "IS_RST_INVERTED" *) + input RST; +endmodule + +module MMCME4_ADV (...); + parameter BANDWIDTH = "OPTIMIZED"; + parameter real CLKFBOUT_MULT_F = 5.000; + parameter real CLKFBOUT_PHASE = 0.000; + parameter CLKFBOUT_USE_FINE_PS = "FALSE"; + parameter real CLKIN1_PERIOD = 0.000; + parameter real CLKIN2_PERIOD = 0.000; + parameter real CLKIN_FREQ_MAX = 1066.000; + parameter real CLKIN_FREQ_MIN = 10.000; + parameter real CLKOUT0_DIVIDE_F = 1.000; + parameter real CLKOUT0_DUTY_CYCLE = 0.500; + parameter real CLKOUT0_PHASE = 0.000; + parameter CLKOUT0_USE_FINE_PS = "FALSE"; + parameter integer CLKOUT1_DIVIDE = 1; + parameter real CLKOUT1_DUTY_CYCLE = 0.500; + parameter real CLKOUT1_PHASE = 0.000; + parameter CLKOUT1_USE_FINE_PS = "FALSE"; + parameter integer CLKOUT2_DIVIDE = 1; + parameter real CLKOUT2_DUTY_CYCLE = 0.500; + parameter real CLKOUT2_PHASE = 0.000; + parameter CLKOUT2_USE_FINE_PS = "FALSE"; + parameter integer CLKOUT3_DIVIDE = 1; + parameter real CLKOUT3_DUTY_CYCLE = 0.500; + parameter real CLKOUT3_PHASE = 0.000; + parameter CLKOUT3_USE_FINE_PS = "FALSE"; + parameter CLKOUT4_CASCADE = "FALSE"; + parameter integer CLKOUT4_DIVIDE = 1; + parameter real CLKOUT4_DUTY_CYCLE = 0.500; + parameter real CLKOUT4_PHASE = 0.000; + parameter CLKOUT4_USE_FINE_PS = "FALSE"; + parameter integer CLKOUT5_DIVIDE = 1; + parameter real CLKOUT5_DUTY_CYCLE = 0.500; + parameter real CLKOUT5_PHASE = 0.000; + parameter CLKOUT5_USE_FINE_PS = "FALSE"; + parameter integer CLKOUT6_DIVIDE = 1; + parameter real CLKOUT6_DUTY_CYCLE = 0.500; + parameter real CLKOUT6_PHASE = 0.000; + parameter CLKOUT6_USE_FINE_PS = "FALSE"; + parameter real CLKPFD_FREQ_MAX = 550.000; + parameter real CLKPFD_FREQ_MIN = 10.000; + parameter COMPENSATION = "AUTO"; + parameter integer DIVCLK_DIVIDE = 1; + parameter [0:0] IS_CLKFBIN_INVERTED = 1'b0; + parameter [0:0] IS_CLKIN1_INVERTED = 1'b0; + parameter [0:0] IS_CLKIN2_INVERTED = 1'b0; + parameter [0:0] IS_CLKINSEL_INVERTED = 1'b0; + parameter [0:0] IS_PSEN_INVERTED = 1'b0; + parameter [0:0] IS_PSINCDEC_INVERTED = 1'b0; + parameter [0:0] IS_PWRDWN_INVERTED = 1'b0; + parameter [0:0] IS_RST_INVERTED = 1'b0; + parameter real REF_JITTER1 = 0.010; + parameter real REF_JITTER2 = 0.010; + parameter SS_EN = "FALSE"; + parameter SS_MODE = "CENTER_HIGH"; + parameter integer SS_MOD_PERIOD = 10000; + parameter STARTUP_WAIT = "FALSE"; + parameter real VCOCLK_FREQ_MAX = 1600.000; + parameter real VCOCLK_FREQ_MIN = 800.000; + parameter STARTUP_WAIT = "FALSE"; + output CDDCDONE; + output CLKFBOUT; + output CLKFBOUTB; + output CLKFBSTOPPED; + output CLKINSTOPPED; + output CLKOUT0; + output CLKOUT0B; + output CLKOUT1; + output CLKOUT1B; + output CLKOUT2; + output CLKOUT2B; + output CLKOUT3; + output CLKOUT3B; + output CLKOUT4; + output CLKOUT5; + output CLKOUT6; + output [15:0] DO; + output DRDY; + output LOCKED; + output PSDONE; + input CDDCREQ; + (* invertible_pin = "IS_CLKFBIN_INVERTED" *) + input CLKFBIN; + (* invertible_pin = "IS_CLKIN1_INVERTED" *) + input CLKIN1; + (* invertible_pin = "IS_CLKIN2_INVERTED" *) + input CLKIN2; + (* invertible_pin = "IS_CLKINSEL_INVERTED" *) + input CLKINSEL; + input [6:0] DADDR; + input DCLK; + input DEN; + input [15:0] DI; + input DWE; + input PSCLK; + (* invertible_pin = "IS_PSEN_INVERTED" *) + input PSEN; + (* invertible_pin = "IS_PSINCDEC_INVERTED" *) + input PSINCDEC; + (* invertible_pin = "IS_PWRDWN_INVERTED" *) + input PWRDWN; + (* invertible_pin = "IS_RST_INVERTED" *) + input RST; +endmodule + +module MMCME4_BASE (...); + parameter BANDWIDTH = "OPTIMIZED"; + parameter real CLKFBOUT_MULT_F = 5.000; + parameter real CLKFBOUT_PHASE = 0.000; + parameter real CLKIN1_PERIOD = 0.000; + parameter real CLKOUT0_DIVIDE_F = 1.000; + parameter real CLKOUT0_DUTY_CYCLE = 0.500; + parameter real CLKOUT0_PHASE = 0.000; + parameter integer CLKOUT1_DIVIDE = 1; + parameter real CLKOUT1_DUTY_CYCLE = 0.500; + parameter real CLKOUT1_PHASE = 0.000; + parameter integer CLKOUT2_DIVIDE = 1; + parameter real CLKOUT2_DUTY_CYCLE = 0.500; + parameter real CLKOUT2_PHASE = 0.000; + parameter integer CLKOUT3_DIVIDE = 1; + parameter real CLKOUT3_DUTY_CYCLE = 0.500; + parameter real CLKOUT3_PHASE = 0.000; + parameter CLKOUT4_CASCADE = "FALSE"; + parameter integer CLKOUT4_DIVIDE = 1; + parameter real CLKOUT4_DUTY_CYCLE = 0.500; + parameter real CLKOUT4_PHASE = 0.000; + parameter integer CLKOUT5_DIVIDE = 1; + parameter real CLKOUT5_DUTY_CYCLE = 0.500; + parameter real CLKOUT5_PHASE = 0.000; + parameter integer CLKOUT6_DIVIDE = 1; + parameter real CLKOUT6_DUTY_CYCLE = 0.500; + parameter real CLKOUT6_PHASE = 0.000; + parameter integer DIVCLK_DIVIDE = 1; + parameter [0:0] IS_CLKFBIN_INVERTED = 1'b0; + parameter [0:0] IS_CLKIN1_INVERTED = 1'b0; + parameter [0:0] IS_PWRDWN_INVERTED = 1'b0; + parameter [0:0] IS_RST_INVERTED = 1'b0; + parameter real REF_JITTER1 = 0.010; + parameter STARTUP_WAIT = "FALSE"; + output CLKFBOUT; + output CLKFBOUTB; + output CLKOUT0; + output CLKOUT0B; + output CLKOUT1; + output CLKOUT1B; + output CLKOUT2; + output CLKOUT2B; + output CLKOUT3; + output CLKOUT3B; + output CLKOUT4; + output CLKOUT5; + output CLKOUT6; + output LOCKED; + (* invertible_pin = "IS_CLKFBIN_INVERTED" *) + input CLKFBIN; + (* invertible_pin = "IS_CLKIN1_INVERTED" *) + input CLKIN1; + (* invertible_pin = "IS_PWRDWN_INVERTED" *) + input PWRDWN; + (* invertible_pin = "IS_RST_INVERTED" *) + input RST; +endmodule + +module PLLE3_ADV (...); + parameter integer CLKFBOUT_MULT = 5; + parameter real CLKFBOUT_PHASE = 0.000; + parameter real CLKIN_FREQ_MAX = 1066.000; + parameter real CLKIN_FREQ_MIN = 70.000; + parameter real CLKIN_PERIOD = 0.000; + parameter integer CLKOUT0_DIVIDE = 1; + parameter real CLKOUT0_DUTY_CYCLE = 0.500; + parameter real CLKOUT0_PHASE = 0.000; + parameter integer CLKOUT1_DIVIDE = 1; + parameter real CLKOUT1_DUTY_CYCLE = 0.500; + parameter real CLKOUT1_PHASE = 0.000; + parameter CLKOUTPHY_MODE = "VCO_2X"; + parameter real CLKPFD_FREQ_MAX = 667.500; + parameter real CLKPFD_FREQ_MIN = 70.000; + parameter COMPENSATION = "AUTO"; + parameter integer DIVCLK_DIVIDE = 1; + parameter [0:0] IS_CLKFBIN_INVERTED = 1'b0; + parameter [0:0] IS_CLKIN_INVERTED = 1'b0; + parameter [0:0] IS_PWRDWN_INVERTED = 1'b0; + parameter [0:0] IS_RST_INVERTED = 1'b0; + parameter real REF_JITTER = 0.010; + parameter STARTUP_WAIT = "FALSE"; + parameter real VCOCLK_FREQ_MAX = 1335.000; + parameter real VCOCLK_FREQ_MIN = 600.000; + parameter STARTUP_WAIT = "FALSE"; + output CLKFBOUT; + output CLKOUT0; + output CLKOUT0B; + output CLKOUT1; + output CLKOUT1B; + output CLKOUTPHY; + output [15:0] DO; + output DRDY; + output LOCKED; + (* invertible_pin = "IS_CLKFBIN_INVERTED" *) + input CLKFBIN; + (* invertible_pin = "IS_CLKIN_INVERTED" *) + input CLKIN; + input CLKOUTPHYEN; + input [6:0] DADDR; + input DCLK; + input DEN; + input [15:0] DI; + input DWE; + (* invertible_pin = "IS_PWRDWN_INVERTED" *) + input PWRDWN; + (* invertible_pin = "IS_RST_INVERTED" *) + input RST; +endmodule + +module PLLE3_BASE (...); + parameter integer CLKFBOUT_MULT = 5; + parameter real CLKFBOUT_PHASE = 0.000; + parameter real CLKIN_PERIOD = 0.000; + parameter integer CLKOUT0_DIVIDE = 1; + parameter real CLKOUT0_DUTY_CYCLE = 0.500; + parameter real CLKOUT0_PHASE = 0.000; + parameter integer CLKOUT1_DIVIDE = 1; + parameter real CLKOUT1_DUTY_CYCLE = 0.500; + parameter real CLKOUT1_PHASE = 0.000; + parameter CLKOUTPHY_MODE = "VCO_2X"; + parameter integer DIVCLK_DIVIDE = 1; + parameter [0:0] IS_CLKFBIN_INVERTED = 1'b0; + parameter [0:0] IS_CLKIN_INVERTED = 1'b0; + parameter [0:0] IS_PWRDWN_INVERTED = 1'b0; + parameter [0:0] IS_RST_INVERTED = 1'b0; + parameter real REF_JITTER = 0.010; + parameter STARTUP_WAIT = "FALSE"; + output CLKFBOUT; + output CLKOUT0; + output CLKOUT0B; + output CLKOUT1; + output CLKOUT1B; + output CLKOUTPHY; + output LOCKED; + (* invertible_pin = "IS_CLKFBIN_INVERTED" *) + input CLKFBIN; + (* invertible_pin = "IS_CLKIN_INVERTED" *) + input CLKIN; + input CLKOUTPHYEN; + (* invertible_pin = "IS_PWRDWN_INVERTED" *) + input PWRDWN; + (* invertible_pin = "IS_RST_INVERTED" *) + input RST; +endmodule + +module PLLE4_ADV (...); + parameter integer CLKFBOUT_MULT = 5; + parameter real CLKFBOUT_PHASE = 0.000; + parameter real CLKIN_FREQ_MAX = 1066.000; + parameter real CLKIN_FREQ_MIN = 70.000; + parameter real CLKIN_PERIOD = 0.000; + parameter integer CLKOUT0_DIVIDE = 1; + parameter real CLKOUT0_DUTY_CYCLE = 0.500; + parameter real CLKOUT0_PHASE = 0.000; + parameter integer CLKOUT1_DIVIDE = 1; + parameter real CLKOUT1_DUTY_CYCLE = 0.500; + parameter real CLKOUT1_PHASE = 0.000; + parameter CLKOUTPHY_MODE = "VCO_2X"; + parameter real CLKPFD_FREQ_MAX = 667.500; + parameter real CLKPFD_FREQ_MIN = 70.000; + parameter COMPENSATION = "AUTO"; + parameter integer DIVCLK_DIVIDE = 1; + parameter [0:0] IS_CLKFBIN_INVERTED = 1'b0; + parameter [0:0] IS_CLKIN_INVERTED = 1'b0; + parameter [0:0] IS_PWRDWN_INVERTED = 1'b0; + parameter [0:0] IS_RST_INVERTED = 1'b0; + parameter real REF_JITTER = 0.010; + parameter STARTUP_WAIT = "FALSE"; + parameter real VCOCLK_FREQ_MAX = 1500.000; + parameter real VCOCLK_FREQ_MIN = 750.000; + parameter STARTUP_WAIT = "FALSE"; + output CLKFBOUT; + output CLKOUT0; + output CLKOUT0B; + output CLKOUT1; + output CLKOUT1B; + output CLKOUTPHY; + output [15:0] DO; + output DRDY; + output LOCKED; + (* invertible_pin = "IS_CLKFBIN_INVERTED" *) + input CLKFBIN; + (* invertible_pin = "IS_CLKIN_INVERTED" *) + input CLKIN; + input CLKOUTPHYEN; + input [6:0] DADDR; + input DCLK; + input DEN; + input [15:0] DI; + input DWE; + (* invertible_pin = "IS_PWRDWN_INVERTED" *) + input PWRDWN; + (* invertible_pin = "IS_RST_INVERTED" *) + input RST; +endmodule + +module PLLE4_BASE (...); + parameter integer CLKFBOUT_MULT = 5; + parameter real CLKFBOUT_PHASE = 0.000; + parameter real CLKIN_PERIOD = 0.000; + parameter integer CLKOUT0_DIVIDE = 1; + parameter real CLKOUT0_DUTY_CYCLE = 0.500; + parameter real CLKOUT0_PHASE = 0.000; + parameter integer CLKOUT1_DIVIDE = 1; + parameter real CLKOUT1_DUTY_CYCLE = 0.500; + parameter real CLKOUT1_PHASE = 0.000; + parameter CLKOUTPHY_MODE = "VCO_2X"; + parameter integer DIVCLK_DIVIDE = 1; + parameter [0:0] IS_CLKFBIN_INVERTED = 1'b0; + parameter [0:0] IS_CLKIN_INVERTED = 1'b0; + parameter [0:0] IS_PWRDWN_INVERTED = 1'b0; + parameter [0:0] IS_RST_INVERTED = 1'b0; + parameter real REF_JITTER = 0.010; + parameter STARTUP_WAIT = "FALSE"; + output CLKFBOUT; + output CLKOUT0; + output CLKOUT0B; + output CLKOUT1; + output CLKOUT1B; + output CLKOUTPHY; + output LOCKED; + (* invertible_pin = "IS_CLKFBIN_INVERTED" *) + input CLKFBIN; + (* invertible_pin = "IS_CLKIN_INVERTED" *) + input CLKIN; + input CLKOUTPHYEN; + (* invertible_pin = "IS_PWRDWN_INVERTED" *) + input PWRDWN; + (* invertible_pin = "IS_RST_INVERTED" *) + input RST; +endmodule + +(* keep *) +module BSCANE2 (...); + parameter DISABLE_JTAG = "FALSE"; + parameter integer JTAG_CHAIN = 1; + output CAPTURE; + output DRCK; + output RESET; + output RUNTEST; + output SEL; + output SHIFT; + output TCK; + output TDI; + output TMS; + output UPDATE; + input TDO; +endmodule + +module DNA_PORTE2 (...); + parameter [95:0] SIM_DNA_VALUE = 96'h000000000000000000000000; + output DOUT; + input CLK; + input DIN; + input READ; + input SHIFT; +endmodule + +module EFUSE_USR (...); + parameter [31:0] SIM_EFUSE_VALUE = 32'h00000000; + output [31:0] EFUSEUSR; +endmodule + +module FRAME_ECCE3 (...); + output CRCERROR; + output ECCERRORNOTSINGLE; + output ECCERRORSINGLE; + output ENDOFFRAME; + output ENDOFSCAN; + output [25:0] FAR; + input [1:0] FARSEL; + input ICAPBOTCLK; + input ICAPTOPCLK; +endmodule + +(* keep *) +module ICAPE3 (...); + parameter [31:0] DEVICE_ID = 32'h03628093; + parameter ICAP_AUTO_SWITCH = "DISABLE"; + parameter SIM_CFG_FILE_NAME = "NONE"; + output AVAIL; + output [31:0] O; + output PRDONE; + output PRERROR; + input CLK; + input CSIB; + input RDWRB; + input [31:0] I; +endmodule + +(* keep *) +module MASTER_JTAG (...); + output TDO; + input TCK; + input TDI; + input TMS; +endmodule + +(* keep *) +module STARTUPE3 (...); + parameter PROG_USR = "FALSE"; + parameter real SIM_CCLK_FREQ = 0.0; + output CFGCLK; + output CFGMCLK; + output [3:0] DI; + output EOS; + output PREQ; + input [3:0] DO; + input [3:0] DTS; + input FCSBO; + input FCSBTS; + input GSR; + input GTS; + input KEYCLEARB; + input PACK; + input USRCCLKO; + input USRCCLKTS; + input USRDONEO; + input USRDONETS; +endmodule + +module USR_ACCESSE2 (...); + output CFGCLK; + output DATAVALID; + output [31:0] DATA; +endmodule + +(* keep *) +module BITSLICE_CONTROL (...); + parameter CTRL_CLK = "EXTERNAL"; + parameter DIV_MODE = "DIV2"; + parameter EN_CLK_TO_EXT_NORTH = "DISABLE"; + parameter EN_CLK_TO_EXT_SOUTH = "DISABLE"; + parameter EN_DYN_ODLY_MODE = "FALSE"; + parameter EN_OTHER_NCLK = "FALSE"; + parameter EN_OTHER_PCLK = "FALSE"; + parameter IDLY_VT_TRACK = "TRUE"; + parameter INV_RXCLK = "FALSE"; + parameter ODLY_VT_TRACK = "TRUE"; + parameter QDLY_VT_TRACK = "TRUE"; + parameter [5:0] READ_IDLE_COUNT = 6'h00; + parameter REFCLK_SRC = "PLLCLK"; + parameter integer ROUNDING_FACTOR = 16; + parameter RXGATE_EXTEND = "FALSE"; + parameter RX_CLK_PHASE_N = "SHIFT_0"; + parameter RX_CLK_PHASE_P = "SHIFT_0"; + parameter RX_GATING = "DISABLE"; + parameter SELF_CALIBRATE = "ENABLE"; + parameter SERIAL_MODE = "FALSE"; + parameter SIM_DEVICE = "ULTRASCALE"; + parameter SIM_SPEEDUP = "FAST"; + parameter real SIM_VERSION = 2.0; + parameter TX_GATING = "DISABLE"; + output CLK_TO_EXT_NORTH; + output CLK_TO_EXT_SOUTH; + output DLY_RDY; + output [6:0] DYN_DCI; + output NCLK_NIBBLE_OUT; + output PCLK_NIBBLE_OUT; + output [15:0] RIU_RD_DATA; + output RIU_VALID; + output [39:0] RX_BIT_CTRL_OUT0; + output [39:0] RX_BIT_CTRL_OUT1; + output [39:0] RX_BIT_CTRL_OUT2; + output [39:0] RX_BIT_CTRL_OUT3; + output [39:0] RX_BIT_CTRL_OUT4; + output [39:0] RX_BIT_CTRL_OUT5; + output [39:0] RX_BIT_CTRL_OUT6; + output [39:0] TX_BIT_CTRL_OUT0; + output [39:0] TX_BIT_CTRL_OUT1; + output [39:0] TX_BIT_CTRL_OUT2; + output [39:0] TX_BIT_CTRL_OUT3; + output [39:0] TX_BIT_CTRL_OUT4; + output [39:0] TX_BIT_CTRL_OUT5; + output [39:0] TX_BIT_CTRL_OUT6; + output [39:0] TX_BIT_CTRL_OUT_TRI; + output VTC_RDY; + input CLK_FROM_EXT; + input EN_VTC; + input NCLK_NIBBLE_IN; + input PCLK_NIBBLE_IN; + input [3:0] PHY_RDCS0; + input [3:0] PHY_RDCS1; + input [3:0] PHY_RDEN; + input [3:0] PHY_WRCS0; + input [3:0] PHY_WRCS1; + input PLL_CLK; + input REFCLK; + input [5:0] RIU_ADDR; + input RIU_CLK; + input RIU_NIBBLE_SEL; + input [15:0] RIU_WR_DATA; + input RIU_WR_EN; + input RST; + input [39:0] RX_BIT_CTRL_IN0; + input [39:0] RX_BIT_CTRL_IN1; + input [39:0] RX_BIT_CTRL_IN2; + input [39:0] RX_BIT_CTRL_IN3; + input [39:0] RX_BIT_CTRL_IN4; + input [39:0] RX_BIT_CTRL_IN5; + input [39:0] RX_BIT_CTRL_IN6; + input [3:0] TBYTE_IN; + input [39:0] TX_BIT_CTRL_IN0; + input [39:0] TX_BIT_CTRL_IN1; + input [39:0] TX_BIT_CTRL_IN2; + input [39:0] TX_BIT_CTRL_IN3; + input [39:0] TX_BIT_CTRL_IN4; + input [39:0] TX_BIT_CTRL_IN5; + input [39:0] TX_BIT_CTRL_IN6; + input [39:0] TX_BIT_CTRL_IN_TRI; +endmodule + +(* keep *) +module DCIRESET (...); + output LOCKED; + input RST; +endmodule + +module HPIO_VREF (...); + parameter VREF_CNTR = "OFF"; + output VREF; + input [6:0] FABRIC_VREF_TUNE; +endmodule + +module IBUF_ANALOG (...); + output O; + (* iopad_external_pin *) + input I; +endmodule + +module IBUF_IBUFDISABLE (...); + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + parameter SIM_DEVICE = "7SERIES"; + parameter USE_IBUFDISABLE = "TRUE"; + output O; + (* iopad_external_pin *) + input I; + input IBUFDISABLE; +endmodule + +module IBUF_INTERMDISABLE (...); + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + parameter SIM_DEVICE = "7SERIES"; + parameter USE_IBUFDISABLE = "TRUE"; + output O; + (* iopad_external_pin *) + input I; + input IBUFDISABLE; + input INTERMDISABLE; +endmodule + +module IBUFDS (...); + parameter CAPACITANCE = "DONT_CARE"; + parameter DIFF_TERM = "FALSE"; + parameter DQS_BIAS = "FALSE"; + parameter IBUF_DELAY_VALUE = "0"; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IFD_DELAY_VALUE = "AUTO"; + parameter IOSTANDARD = "DEFAULT"; + output O; + (* iopad_external_pin *) + input I; + (* iopad_external_pin *) + input IB; +endmodule + +module IBUFDS_DIFF_OUT (...); + parameter DIFF_TERM = "FALSE"; + parameter DQS_BIAS = "FALSE"; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + output O; + output OB; + (* iopad_external_pin *) + input I; + (* iopad_external_pin *) + input IB; +endmodule + +module IBUFDS_DIFF_OUT_IBUFDISABLE (...); + parameter DIFF_TERM = "FALSE"; + parameter DQS_BIAS = "FALSE"; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + parameter SIM_DEVICE = "7SERIES"; + parameter USE_IBUFDISABLE = "TRUE"; + output O; + output OB; + (* iopad_external_pin *) + input I; + (* iopad_external_pin *) + input IB; + input IBUFDISABLE; +endmodule + +module IBUFDS_DIFF_OUT_INTERMDISABLE (...); + parameter DIFF_TERM = "FALSE"; + parameter DQS_BIAS = "FALSE"; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + parameter SIM_DEVICE = "7SERIES"; + parameter USE_IBUFDISABLE = "TRUE"; + output O; + output OB; + (* iopad_external_pin *) + input I; + (* iopad_external_pin *) + input IB; + input IBUFDISABLE; + input INTERMDISABLE; +endmodule + +module IBUFDS_DPHY (...); + parameter DIFF_TERM = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + output HSRX_O; + output LPRX_O_N; + output LPRX_O_P; + input HSRX_DISABLE; + (* iopad_external_pin *) + input I; + (* iopad_external_pin *) + input IB; + input LPRX_DISABLE; +endmodule + +module IBUFDS_IBUFDISABLE (...); + parameter DIFF_TERM = "FALSE"; + parameter DQS_BIAS = "FALSE"; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + parameter SIM_DEVICE = "7SERIES"; + parameter USE_IBUFDISABLE = "TRUE"; + output O; + (* iopad_external_pin *) + input I; + (* iopad_external_pin *) + input IB; + input IBUFDISABLE; +endmodule + +module IBUFDS_INTERMDISABLE (...); + parameter DIFF_TERM = "FALSE"; + parameter DQS_BIAS = "FALSE"; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + parameter SIM_DEVICE = "7SERIES"; + parameter USE_IBUFDISABLE = "TRUE"; + output O; + (* iopad_external_pin *) + input I; + (* iopad_external_pin *) + input IB; + input IBUFDISABLE; + input INTERMDISABLE; +endmodule + +module IBUFDSE3 (...); + parameter DIFF_TERM = "FALSE"; + parameter DQS_BIAS = "FALSE"; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + parameter USE_IBUFDISABLE = "FALSE"; + parameter integer SIM_INPUT_BUFFER_OFFSET = 0; + output O; + (* iopad_external_pin *) + input I; + (* iopad_external_pin *) + input IB; + input IBUFDISABLE; + input [3:0] OSC; + input [1:0] OSC_EN; +endmodule + +module IBUFE3 (...); + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + parameter USE_IBUFDISABLE = "FALSE"; + parameter integer SIM_INPUT_BUFFER_OFFSET = 0; + output O; + (* iopad_external_pin *) + input I; + input IBUFDISABLE; + input [3:0] OSC; + input OSC_EN; + input VREF; +endmodule + +(* keep *) +module IDELAYCTRL (...); + parameter SIM_DEVICE = "7SERIES"; + output RDY; + (* clkbuf_sink *) + input REFCLK; + input RST; +endmodule + +module IDELAYE3 (...); + parameter CASCADE = "NONE"; + parameter DELAY_FORMAT = "TIME"; + parameter DELAY_SRC = "IDATAIN"; + parameter DELAY_TYPE = "FIXED"; + parameter integer DELAY_VALUE = 0; + parameter [0:0] IS_CLK_INVERTED = 1'b0; + parameter [0:0] IS_RST_INVERTED = 1'b0; + parameter LOOPBACK = "FALSE"; + parameter real REFCLK_FREQUENCY = 300.0; + parameter SIM_DEVICE = "ULTRASCALE"; + parameter real SIM_VERSION = 2.0; + parameter UPDATE_MODE = "ASYNC"; + output CASC_OUT; + output [8:0] CNTVALUEOUT; + output DATAOUT; + input CASC_IN; + input CASC_RETURN; + input CE; + (* clkbuf_sink *) + (* invertible_pin = "IS_CLK_INVERTED" *) + input CLK; + input [8:0] CNTVALUEIN; + input DATAIN; + input EN_VTC; + input IDATAIN; + input INC; + input LOAD; + (* invertible_pin = "IS_RST_INVERTED" *) + input RST; +endmodule + +module IOBUF (...); + parameter integer DRIVE = 12; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + parameter SLEW = "SLOW"; + output O; + (* iopad_external_pin *) + inout IO; + input I; + input T; +endmodule + +module IOBUF_DCIEN (...); + parameter integer DRIVE = 12; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + parameter SIM_DEVICE = "7SERIES"; + parameter SLEW = "SLOW"; + parameter USE_IBUFDISABLE = "TRUE"; + output O; + (* iopad_external_pin *) + inout IO; + input DCITERMDISABLE; + input I; + input IBUFDISABLE; + input T; +endmodule + +module IOBUF_INTERMDISABLE (...); + parameter integer DRIVE = 12; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + parameter SIM_DEVICE = "7SERIES"; + parameter SLEW = "SLOW"; + parameter USE_IBUFDISABLE = "TRUE"; + output O; + (* iopad_external_pin *) + inout IO; + input I; + input IBUFDISABLE; + input INTERMDISABLE; + input T; +endmodule + +module IOBUFDS (...); + parameter DIFF_TERM = "FALSE"; + parameter DQS_BIAS = "FALSE"; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + parameter SLEW = "SLOW"; + output O; + (* iopad_external_pin *) + inout IO; + inout IOB; + input I; + input T; +endmodule + +module IOBUFDS_DCIEN (...); + parameter DIFF_TERM = "FALSE"; + parameter DQS_BIAS = "FALSE"; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + parameter SIM_DEVICE = "7SERIES"; + parameter SLEW = "SLOW"; + parameter USE_IBUFDISABLE = "TRUE"; + output O; + (* iopad_external_pin *) + inout IO; + (* iopad_external_pin *) + inout IOB; + input DCITERMDISABLE; + input I; + input IBUFDISABLE; + input T; +endmodule + +module IOBUFDS_DIFF_OUT (...); + parameter DIFF_TERM = "FALSE"; + parameter DQS_BIAS = "FALSE"; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + output O; + output OB; + (* iopad_external_pin *) + inout IO; + (* iopad_external_pin *) + inout IOB; + input I; + input TM; + input TS; +endmodule + +module IOBUFDS_DIFF_OUT_DCIEN (...); + parameter DIFF_TERM = "FALSE"; + parameter DQS_BIAS = "FALSE"; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + parameter SIM_DEVICE = "7SERIES"; + parameter USE_IBUFDISABLE = "TRUE"; + output O; + output OB; + (* iopad_external_pin *) + inout IO; + (* iopad_external_pin *) + inout IOB; + input DCITERMDISABLE; + input I; + input IBUFDISABLE; + input TM; + input TS; +endmodule + +module IOBUFDS_DIFF_OUT_INTERMDISABLE (...); + parameter DIFF_TERM = "FALSE"; + parameter DQS_BIAS = "FALSE"; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + parameter SIM_DEVICE = "7SERIES"; + parameter USE_IBUFDISABLE = "TRUE"; + output O; + output OB; + (* iopad_external_pin *) + inout IO; + (* iopad_external_pin *) + inout IOB; + input I; + input IBUFDISABLE; + input INTERMDISABLE; + input TM; + input TS; +endmodule + +module IOBUFDS_INTERMDISABLE (...); + parameter DIFF_TERM = "FALSE"; + parameter DQS_BIAS = "FALSE"; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + parameter SIM_DEVICE = "7SERIES"; + parameter SLEW = "SLOW"; + parameter USE_IBUFDISABLE = "TRUE"; + output O; + (* iopad_external_pin *) + inout IO; + (* iopad_external_pin *) + inout IOB; + input I; + input IBUFDISABLE; + input INTERMDISABLE; + input T; +endmodule + +module IOBUFDSE3 (...); + parameter DIFF_TERM = "FALSE"; + parameter DQS_BIAS = "FALSE"; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + parameter integer SIM_INPUT_BUFFER_OFFSET = 0; + parameter USE_IBUFDISABLE = "FALSE"; + output O; + (* iopad_external_pin *) + inout IO; + inout IOB; + input DCITERMDISABLE; + input I; + input IBUFDISABLE; + input [3:0] OSC; + input [1:0] OSC_EN; + input T; +endmodule + +module IOBUFE3 (...); + parameter integer DRIVE = 12; + parameter IBUF_LOW_PWR = "TRUE"; + parameter IOSTANDARD = "DEFAULT"; + parameter USE_IBUFDISABLE = "FALSE"; + parameter integer SIM_INPUT_BUFFER_OFFSET = 0; + output O; + (* iopad_external_pin *) + inout IO; + input DCITERMDISABLE; + input I; + input IBUFDISABLE; + input [3:0] OSC; + input OSC_EN; + input T; + input VREF; +endmodule + +module ISERDESE3 (...); + parameter integer DATA_WIDTH = 8; + parameter DDR_CLK_EDGE = "OPPOSITE_EDGE"; + parameter FIFO_ENABLE = "FALSE"; + parameter FIFO_SYNC_MODE = "FALSE"; + parameter IDDR_MODE = "FALSE"; + parameter [0:0] IS_CLK_B_INVERTED = 1'b0; + parameter [0:0] IS_CLK_INVERTED = 1'b0; + parameter [0:0] IS_RST_INVERTED = 1'b0; + parameter SIM_DEVICE = "ULTRASCALE"; + parameter real SIM_VERSION = 2.0; + output FIFO_EMPTY; + output INTERNAL_DIVCLK; + output [7:0] Q; + (* clkbuf_sink *) + (* invertible_pin = "IS_CLK_INVERTED" *) + input CLK; + (* clkbuf_sink *) + input CLKDIV; + (* clkbuf_sink *) + (* invertible_pin = "IS_CLK_B_INVERTED" *) + input CLK_B; + input D; + (* clkbuf_sink *) + input FIFO_RD_CLK; + input FIFO_RD_EN; + (* invertible_pin = "IS_RST_INVERTED" *) + input RST; +endmodule + +module KEEPER (...); + inout O; +endmodule + +module OBUFDS (...); + parameter CAPACITANCE = "DONT_CARE"; + parameter IOSTANDARD = "DEFAULT"; + parameter SLEW = "SLOW"; + (* iopad_external_pin *) + output O; + (* iopad_external_pin *) + output OB; + input I; +endmodule + +module OBUFDS_DPHY (...); + parameter IOSTANDARD = "DEFAULT"; + (* iopad_external_pin *) + output O; + (* iopad_external_pin *) + output OB; + input HSTX_I; + input HSTX_T; + input LPTX_I_N; + input LPTX_I_P; + input LPTX_T; +endmodule + +module OBUFT (...); + parameter CAPACITANCE = "DONT_CARE"; + parameter integer DRIVE = 12; + parameter IOSTANDARD = "DEFAULT"; + parameter SLEW = "SLOW"; + (* iopad_external_pin *) + output O; + input I; + input T; +endmodule + +module OBUFTDS (...); + parameter CAPACITANCE = "DONT_CARE"; + parameter IOSTANDARD = "DEFAULT"; + parameter SLEW = "SLOW"; + (* iopad_external_pin *) + output O; + (* iopad_external_pin *) + output OB; + input I; + input T; +endmodule + +module ODELAYE3 (...); + parameter CASCADE = "NONE"; + parameter DELAY_FORMAT = "TIME"; + parameter DELAY_TYPE = "FIXED"; + parameter integer DELAY_VALUE = 0; + parameter [0:0] IS_CLK_INVERTED = 1'b0; + parameter [0:0] IS_RST_INVERTED = 1'b0; + parameter real REFCLK_FREQUENCY = 300.0; + parameter SIM_DEVICE = "ULTRASCALE"; + parameter real SIM_VERSION = 2.0; + parameter UPDATE_MODE = "ASYNC"; + output CASC_OUT; + output [8:0] CNTVALUEOUT; + output DATAOUT; + input CASC_IN; + input CASC_RETURN; + input CE; + (* clkbuf_sink *) + (* invertible_pin = "IS_CLK_INVERTED" *) + input CLK; + input [8:0] CNTVALUEIN; + input EN_VTC; + input INC; + input LOAD; + input ODATAIN; + (* invertible_pin = "IS_RST_INVERTED" *) + input RST; +endmodule + +module OSERDESE3 (...); + parameter integer DATA_WIDTH = 8; + parameter [0:0] INIT = 1'b0; + parameter [0:0] IS_CLKDIV_INVERTED = 1'b0; + parameter [0:0] IS_CLK_INVERTED = 1'b0; + parameter [0:0] IS_RST_INVERTED = 1'b0; + parameter ODDR_MODE = "FALSE"; + parameter OSERDES_D_BYPASS = "FALSE"; + parameter OSERDES_T_BYPASS = "FALSE"; + parameter SIM_DEVICE = "ULTRASCALE"; + parameter real SIM_VERSION = 2.0; + output OQ; + output T_OUT; + (* clkbuf_sink *) + (* invertible_pin = "IS_CLK_INVERTED" *) + input CLK; + (* clkbuf_sink *) + (* invertible_pin = "IS_CLKDIV_INVERTED" *) + input CLKDIV; + input [7:0] D; + (* invertible_pin = "IS_RST_INVERTED" *) + input RST; + input T; +endmodule + +module PULLDOWN (...); + output O; +endmodule + +module PULLUP (...); + output O; +endmodule + +module RIU_OR (...); + parameter SIM_DEVICE = "ULTRASCALE"; + parameter real SIM_VERSION = 2.0; + output [15:0] RIU_RD_DATA; + output RIU_RD_VALID; + input [15:0] RIU_RD_DATA_LOW; + input [15:0] RIU_RD_DATA_UPP; + input RIU_RD_VALID_LOW; + input RIU_RD_VALID_UPP; +endmodule + +module RX_BITSLICE (...); + parameter CASCADE = "TRUE"; + parameter DATA_TYPE = "NONE"; + parameter integer DATA_WIDTH = 8; + parameter DELAY_FORMAT = "TIME"; + parameter DELAY_TYPE = "FIXED"; + parameter integer DELAY_VALUE = 0; + parameter integer DELAY_VALUE_EXT = 0; + parameter FIFO_SYNC_MODE = "FALSE"; + parameter [0:0] IS_CLK_EXT_INVERTED = 1'b0; + parameter [0:0] IS_CLK_INVERTED = 1'b0; + parameter [0:0] IS_RST_DLY_EXT_INVERTED = 1'b0; + parameter [0:0] IS_RST_DLY_INVERTED = 1'b0; + parameter [0:0] IS_RST_INVERTED = 1'b0; + parameter real REFCLK_FREQUENCY = 300.0; + parameter SIM_DEVICE = "ULTRASCALE"; + parameter real SIM_VERSION = 2.0; + parameter UPDATE_MODE = "ASYNC"; + parameter UPDATE_MODE_EXT = "ASYNC"; + output [8:0] CNTVALUEOUT; + output [8:0] CNTVALUEOUT_EXT; + output FIFO_EMPTY; + output FIFO_WRCLK_OUT; + output [7:0] Q; + output [39:0] RX_BIT_CTRL_OUT; + output [39:0] TX_BIT_CTRL_OUT; + input CE; + input CE_EXT; + (* invertible_pin = "IS_CLK_INVERTED" *) + input CLK; + (* invertible_pin = "IS_CLK_EXT_INVERTED" *) + input CLK_EXT; + input [8:0] CNTVALUEIN; + input [8:0] CNTVALUEIN_EXT; + input DATAIN; + input EN_VTC; + input EN_VTC_EXT; + input FIFO_RD_CLK; + input FIFO_RD_EN; + input INC; + input INC_EXT; + input LOAD; + input LOAD_EXT; + (* invertible_pin = "IS_RST_INVERTED" *) + input RST; + (* invertible_pin = "IS_RST_DLY_INVERTED" *) + input RST_DLY; + (* invertible_pin = "IS_RST_DLY_EXT_INVERTED" *) + input RST_DLY_EXT; + input [39:0] RX_BIT_CTRL_IN; + input [39:0] TX_BIT_CTRL_IN; +endmodule + +module RXTX_BITSLICE (...); + parameter FIFO_SYNC_MODE = "FALSE"; + parameter [0:0] INIT = 1'b1; + parameter [0:0] IS_RX_CLK_INVERTED = 1'b0; + parameter [0:0] IS_RX_RST_DLY_INVERTED = 1'b0; + parameter [0:0] IS_RX_RST_INVERTED = 1'b0; + parameter [0:0] IS_TX_CLK_INVERTED = 1'b0; + parameter [0:0] IS_TX_RST_DLY_INVERTED = 1'b0; + parameter [0:0] IS_TX_RST_INVERTED = 1'b0; + parameter LOOPBACK = "FALSE"; + parameter NATIVE_ODELAY_BYPASS = "FALSE"; + parameter ENABLE_PRE_EMPHASIS = "FALSE"; + parameter RX_DATA_TYPE = "NONE"; + parameter integer RX_DATA_WIDTH = 8; + parameter RX_DELAY_FORMAT = "TIME"; + parameter RX_DELAY_TYPE = "FIXED"; + parameter integer RX_DELAY_VALUE = 0; + parameter real RX_REFCLK_FREQUENCY = 300.0; + parameter RX_UPDATE_MODE = "ASYNC"; + parameter SIM_DEVICE = "ULTRASCALE"; + parameter real SIM_VERSION = 2.0; + parameter TBYTE_CTL = "TBYTE_IN"; + parameter integer TX_DATA_WIDTH = 8; + parameter TX_DELAY_FORMAT = "TIME"; + parameter TX_DELAY_TYPE = "FIXED"; + parameter integer TX_DELAY_VALUE = 0; + parameter TX_OUTPUT_PHASE_90 = "FALSE"; + parameter real TX_REFCLK_FREQUENCY = 300.0; + parameter TX_UPDATE_MODE = "ASYNC"; + output FIFO_EMPTY; + output FIFO_WRCLK_OUT; + output O; + output [7:0] Q; + output [39:0] RX_BIT_CTRL_OUT; + output [8:0] RX_CNTVALUEOUT; + output [39:0] TX_BIT_CTRL_OUT; + output [8:0] TX_CNTVALUEOUT; + output T_OUT; + input [7:0] D; + input DATAIN; + input FIFO_RD_CLK; + input FIFO_RD_EN; + input [39:0] RX_BIT_CTRL_IN; + input RX_CE; + (* invertible_pin = "IS_RX_CLK_INVERTED" *) + input RX_CLK; + input [8:0] RX_CNTVALUEIN; + input RX_EN_VTC; + input RX_INC; + input RX_LOAD; + (* invertible_pin = "IS_RX_RST_INVERTED" *) + input RX_RST; + (* invertible_pin = "IS_RX_RST_DLY_INVERTED" *) + input RX_RST_DLY; + input T; + input TBYTE_IN; + input [39:0] TX_BIT_CTRL_IN; + input TX_CE; + (* invertible_pin = "IS_TX_CLK_INVERTED" *) + input TX_CLK; + input [8:0] TX_CNTVALUEIN; + input TX_EN_VTC; + input TX_INC; + input TX_LOAD; + (* invertible_pin = "IS_TX_RST_INVERTED" *) + input TX_RST; + (* invertible_pin = "IS_TX_RST_DLY_INVERTED" *) + input TX_RST_DLY; +endmodule + +module TX_BITSLICE (...); + parameter integer DATA_WIDTH = 8; + parameter DELAY_FORMAT = "TIME"; + parameter DELAY_TYPE = "FIXED"; + parameter integer DELAY_VALUE = 0; + parameter ENABLE_PRE_EMPHASIS = "FALSE"; + parameter [0:0] INIT = 1'b1; + parameter [0:0] IS_CLK_INVERTED = 1'b0; + parameter [0:0] IS_RST_DLY_INVERTED = 1'b0; + parameter [0:0] IS_RST_INVERTED = 1'b0; + parameter NATIVE_ODELAY_BYPASS = "FALSE"; + parameter OUTPUT_PHASE_90 = "FALSE"; + parameter real REFCLK_FREQUENCY = 300.0; + parameter SIM_DEVICE = "ULTRASCALE"; + parameter real SIM_VERSION = 2.0; + parameter TBYTE_CTL = "TBYTE_IN"; + parameter UPDATE_MODE = "ASYNC"; + output [8:0] CNTVALUEOUT; + output O; + output [39:0] RX_BIT_CTRL_OUT; + output [39:0] TX_BIT_CTRL_OUT; + output T_OUT; + input CE; + (* invertible_pin = "IS_CLK_INVERTED" *) + input CLK; + input [8:0] CNTVALUEIN; + input [7:0] D; + input EN_VTC; + input INC; + input LOAD; + (* invertible_pin = "IS_RST_INVERTED" *) + input RST; + (* invertible_pin = "IS_RST_DLY_INVERTED" *) + input RST_DLY; + input [39:0] RX_BIT_CTRL_IN; + input T; + input TBYTE_IN; + input [39:0] TX_BIT_CTRL_IN; +endmodule + +module TX_BITSLICE_TRI (...); + parameter integer DATA_WIDTH = 8; + parameter DELAY_FORMAT = "TIME"; + parameter DELAY_TYPE = "FIXED"; + parameter integer DELAY_VALUE = 0; + parameter [0:0] INIT = 1'b1; + parameter [0:0] IS_CLK_INVERTED = 1'b0; + parameter [0:0] IS_RST_DLY_INVERTED = 1'b0; + parameter [0:0] IS_RST_INVERTED = 1'b0; + parameter NATIVE_ODELAY_BYPASS = "FALSE"; + parameter OUTPUT_PHASE_90 = "FALSE"; + parameter real REFCLK_FREQUENCY = 300.0; + parameter SIM_DEVICE = "ULTRASCALE"; + parameter real SIM_VERSION = 2.0; + parameter UPDATE_MODE = "ASYNC"; + output [39:0] BIT_CTRL_OUT; + output [8:0] CNTVALUEOUT; + output TRI_OUT; + input [39:0] BIT_CTRL_IN; + input CE; + (* invertible_pin = "IS_CLK_INVERTED" *) + input CLK; + input [8:0] CNTVALUEIN; + input EN_VTC; + input INC; + input LOAD; + (* invertible_pin = "IS_RST_INVERTED" *) + input RST; + (* invertible_pin = "IS_RST_DLY_INVERTED" *) + input RST_DLY; +endmodule + +module HARD_SYNC (...); + parameter [0:0] INIT = 1'b0; + parameter [0:0] IS_CLK_INVERTED = 1'b0; + parameter integer LATENCY = 2; + output DOUT; + (* clkbuf_sink *) + (* invertible_pin = "IS_CLK_INVERTED" *) + input CLK; + input DIN; +endmodule + +module IDDRE1 (...); + parameter DDR_CLK_EDGE = "OPPOSITE_EDGE"; + parameter [0:0] IS_CB_INVERTED = 1'b0; + parameter [0:0] IS_C_INVERTED = 1'b0; + output Q1; + output Q2; + (* clkbuf_sink *) + (* invertible_pin = "IS_C_INVERTED" *) + input C; + (* clkbuf_sink *) + (* invertible_pin = "IS_CB_INVERTED" *) + input CB; + input D; + input R; +endmodule + +module LDCE (...); + parameter [0:0] INIT = 1'b0; + parameter [0:0] IS_CLR_INVERTED = 1'b0; + parameter [0:0] IS_G_INVERTED = 1'b0; + parameter MSGON = "TRUE"; + parameter XON = "TRUE"; + output Q; + (* invertible_pin = "IS_CLR_INVERTED" *) + input CLR; + input D; + (* invertible_pin = "IS_G_INVERTED" *) + input G; + input GE; +endmodule + +module LDPE (...); + parameter [0:0] INIT = 1'b1; + parameter [0:0] IS_G_INVERTED = 1'b0; + parameter [0:0] IS_PRE_INVERTED = 1'b0; + parameter MSGON = "TRUE"; + parameter XON = "TRUE"; + output Q; + input D; + (* invertible_pin = "IS_G_INVERTED" *) + input G; + input GE; + (* invertible_pin = "IS_PRE_INVERTED" *) + input PRE; +endmodule + +module ODDRE1 (...); + parameter [0:0] IS_C_INVERTED = 1'b0; + parameter [0:0] IS_D1_INVERTED = 1'b0; + parameter [0:0] IS_D2_INVERTED = 1'b0; + parameter [0:0] SRVAL = 1'b0; + output Q; + (* clkbuf_sink *) + (* invertible_pin = "IS_C_INVERTED" *) + input C; + (* invertible_pin = "IS_D1_INVERTED" *) + input D1; + (* invertible_pin = "IS_D2_INVERTED" *) + input D2; + input SR; +endmodule + +(* keep *) +module PS8 (...); + output [7:0] ADMA2PLCACK; + output [7:0] ADMA2PLTVLD; + output DPAUDIOREFCLK; + output DPAUXDATAOEN; + output DPAUXDATAOUT; + output DPLIVEVIDEODEOUT; + output [31:0] DPMAXISMIXEDAUDIOTDATA; + output DPMAXISMIXEDAUDIOTID; + output DPMAXISMIXEDAUDIOTVALID; + output DPSAXISAUDIOTREADY; + output DPVIDEOOUTHSYNC; + output [35:0] DPVIDEOOUTPIXEL1; + output DPVIDEOOUTVSYNC; + output DPVIDEOREFCLK; + output EMIOCAN0PHYTX; + output EMIOCAN1PHYTX; + output [1:0] EMIOENET0DMABUSWIDTH; + output EMIOENET0DMATXENDTOG; + output [93:0] EMIOENET0GEMTSUTIMERCNT; + output [7:0] EMIOENET0GMIITXD; + output EMIOENET0GMIITXEN; + output EMIOENET0GMIITXER; + output EMIOENET0MDIOMDC; + output EMIOENET0MDIOO; + output EMIOENET0MDIOTN; + output [7:0] EMIOENET0RXWDATA; + output EMIOENET0RXWEOP; + output EMIOENET0RXWERR; + output EMIOENET0RXWFLUSH; + output EMIOENET0RXWSOP; + output [44:0] EMIOENET0RXWSTATUS; + output EMIOENET0RXWWR; + output [2:0] EMIOENET0SPEEDMODE; + output EMIOENET0TXRRD; + output [3:0] EMIOENET0TXRSTATUS; + output [1:0] EMIOENET1DMABUSWIDTH; + output EMIOENET1DMATXENDTOG; + output [7:0] EMIOENET1GMIITXD; + output EMIOENET1GMIITXEN; + output EMIOENET1GMIITXER; + output EMIOENET1MDIOMDC; + output EMIOENET1MDIOO; + output EMIOENET1MDIOTN; + output [7:0] EMIOENET1RXWDATA; + output EMIOENET1RXWEOP; + output EMIOENET1RXWERR; + output EMIOENET1RXWFLUSH; + output EMIOENET1RXWSOP; + output [44:0] EMIOENET1RXWSTATUS; + output EMIOENET1RXWWR; + output [2:0] EMIOENET1SPEEDMODE; + output EMIOENET1TXRRD; + output [3:0] EMIOENET1TXRSTATUS; + output [1:0] EMIOENET2DMABUSWIDTH; + output EMIOENET2DMATXENDTOG; + output [7:0] EMIOENET2GMIITXD; + output EMIOENET2GMIITXEN; + output EMIOENET2GMIITXER; + output EMIOENET2MDIOMDC; + output EMIOENET2MDIOO; + output EMIOENET2MDIOTN; + output [7:0] EMIOENET2RXWDATA; + output EMIOENET2RXWEOP; + output EMIOENET2RXWERR; + output EMIOENET2RXWFLUSH; + output EMIOENET2RXWSOP; + output [44:0] EMIOENET2RXWSTATUS; + output EMIOENET2RXWWR; + output [2:0] EMIOENET2SPEEDMODE; + output EMIOENET2TXRRD; + output [3:0] EMIOENET2TXRSTATUS; + output [1:0] EMIOENET3DMABUSWIDTH; + output EMIOENET3DMATXENDTOG; + output [7:0] EMIOENET3GMIITXD; + output EMIOENET3GMIITXEN; + output EMIOENET3GMIITXER; + output EMIOENET3MDIOMDC; + output EMIOENET3MDIOO; + output EMIOENET3MDIOTN; + output [7:0] EMIOENET3RXWDATA; + output EMIOENET3RXWEOP; + output EMIOENET3RXWERR; + output EMIOENET3RXWFLUSH; + output EMIOENET3RXWSOP; + output [44:0] EMIOENET3RXWSTATUS; + output EMIOENET3RXWWR; + output [2:0] EMIOENET3SPEEDMODE; + output EMIOENET3TXRRD; + output [3:0] EMIOENET3TXRSTATUS; + output EMIOGEM0DELAYREQRX; + output EMIOGEM0DELAYREQTX; + output EMIOGEM0PDELAYREQRX; + output EMIOGEM0PDELAYREQTX; + output EMIOGEM0PDELAYRESPRX; + output EMIOGEM0PDELAYRESPTX; + output EMIOGEM0RXSOF; + output EMIOGEM0SYNCFRAMERX; + output EMIOGEM0SYNCFRAMETX; + output EMIOGEM0TSUTIMERCMPVAL; + output EMIOGEM0TXRFIXEDLAT; + output EMIOGEM0TXSOF; + output EMIOGEM1DELAYREQRX; + output EMIOGEM1DELAYREQTX; + output EMIOGEM1PDELAYREQRX; + output EMIOGEM1PDELAYREQTX; + output EMIOGEM1PDELAYRESPRX; + output EMIOGEM1PDELAYRESPTX; + output EMIOGEM1RXSOF; + output EMIOGEM1SYNCFRAMERX; + output EMIOGEM1SYNCFRAMETX; + output EMIOGEM1TSUTIMERCMPVAL; + output EMIOGEM1TXRFIXEDLAT; + output EMIOGEM1TXSOF; + output EMIOGEM2DELAYREQRX; + output EMIOGEM2DELAYREQTX; + output EMIOGEM2PDELAYREQRX; + output EMIOGEM2PDELAYREQTX; + output EMIOGEM2PDELAYRESPRX; + output EMIOGEM2PDELAYRESPTX; + output EMIOGEM2RXSOF; + output EMIOGEM2SYNCFRAMERX; + output EMIOGEM2SYNCFRAMETX; + output EMIOGEM2TSUTIMERCMPVAL; + output EMIOGEM2TXRFIXEDLAT; + output EMIOGEM2TXSOF; + output EMIOGEM3DELAYREQRX; + output EMIOGEM3DELAYREQTX; + output EMIOGEM3PDELAYREQRX; + output EMIOGEM3PDELAYREQTX; + output EMIOGEM3PDELAYRESPRX; + output EMIOGEM3PDELAYRESPTX; + output EMIOGEM3RXSOF; + output EMIOGEM3SYNCFRAMERX; + output EMIOGEM3SYNCFRAMETX; + output EMIOGEM3TSUTIMERCMPVAL; + output EMIOGEM3TXRFIXEDLAT; + output EMIOGEM3TXSOF; + output [95:0] EMIOGPIOO; + output [95:0] EMIOGPIOTN; + output EMIOI2C0SCLO; + output EMIOI2C0SCLTN; + output EMIOI2C0SDAO; + output EMIOI2C0SDATN; + output EMIOI2C1SCLO; + output EMIOI2C1SCLTN; + output EMIOI2C1SDAO; + output EMIOI2C1SDATN; + output EMIOSDIO0BUSPOWER; + output [2:0] EMIOSDIO0BUSVOLT; + output EMIOSDIO0CLKOUT; + output EMIOSDIO0CMDENA; + output EMIOSDIO0CMDOUT; + output [7:0] EMIOSDIO0DATAENA; + output [7:0] EMIOSDIO0DATAOUT; + output EMIOSDIO0LEDCONTROL; + output EMIOSDIO1BUSPOWER; + output [2:0] EMIOSDIO1BUSVOLT; + output EMIOSDIO1CLKOUT; + output EMIOSDIO1CMDENA; + output EMIOSDIO1CMDOUT; + output [7:0] EMIOSDIO1DATAENA; + output [7:0] EMIOSDIO1DATAOUT; + output EMIOSDIO1LEDCONTROL; + output EMIOSPI0MO; + output EMIOSPI0MOTN; + output EMIOSPI0SCLKO; + output EMIOSPI0SCLKTN; + output EMIOSPI0SO; + output EMIOSPI0SSNTN; + output [2:0] EMIOSPI0SSON; + output EMIOSPI0STN; + output EMIOSPI1MO; + output EMIOSPI1MOTN; + output EMIOSPI1SCLKO; + output EMIOSPI1SCLKTN; + output EMIOSPI1SO; + output EMIOSPI1SSNTN; + output [2:0] EMIOSPI1SSON; + output EMIOSPI1STN; + output [2:0] EMIOTTC0WAVEO; + output [2:0] EMIOTTC1WAVEO; + output [2:0] EMIOTTC2WAVEO; + output [2:0] EMIOTTC3WAVEO; + output EMIOU2DSPORTVBUSCTRLUSB30; + output EMIOU2DSPORTVBUSCTRLUSB31; + output EMIOU3DSPORTVBUSCTRLUSB30; + output EMIOU3DSPORTVBUSCTRLUSB31; + output EMIOUART0DTRN; + output EMIOUART0RTSN; + output EMIOUART0TX; + output EMIOUART1DTRN; + output EMIOUART1RTSN; + output EMIOUART1TX; + output EMIOWDT0RSTO; + output EMIOWDT1RSTO; + output FMIOGEM0FIFORXCLKTOPLBUFG; + output FMIOGEM0FIFOTXCLKTOPLBUFG; + output FMIOGEM1FIFORXCLKTOPLBUFG; + output FMIOGEM1FIFOTXCLKTOPLBUFG; + output FMIOGEM2FIFORXCLKTOPLBUFG; + output FMIOGEM2FIFOTXCLKTOPLBUFG; + output FMIOGEM3FIFORXCLKTOPLBUFG; + output FMIOGEM3FIFOTXCLKTOPLBUFG; + output FMIOGEMTSUCLKTOPLBUFG; + output [31:0] FTMGPO; + output [7:0] GDMA2PLCACK; + output [7:0] GDMA2PLTVLD; + output [39:0] MAXIGP0ARADDR; + output [1:0] MAXIGP0ARBURST; + output [3:0] MAXIGP0ARCACHE; + output [15:0] MAXIGP0ARID; + output [7:0] MAXIGP0ARLEN; + output MAXIGP0ARLOCK; + output [2:0] MAXIGP0ARPROT; + output [3:0] MAXIGP0ARQOS; + output [2:0] MAXIGP0ARSIZE; + output [15:0] MAXIGP0ARUSER; + output MAXIGP0ARVALID; + output [39:0] MAXIGP0AWADDR; + output [1:0] MAXIGP0AWBURST; + output [3:0] MAXIGP0AWCACHE; + output [15:0] MAXIGP0AWID; + output [7:0] MAXIGP0AWLEN; + output MAXIGP0AWLOCK; + output [2:0] MAXIGP0AWPROT; + output [3:0] MAXIGP0AWQOS; + output [2:0] MAXIGP0AWSIZE; + output [15:0] MAXIGP0AWUSER; + output MAXIGP0AWVALID; + output MAXIGP0BREADY; + output MAXIGP0RREADY; + output [127:0] MAXIGP0WDATA; + output MAXIGP0WLAST; + output [15:0] MAXIGP0WSTRB; + output MAXIGP0WVALID; + output [39:0] MAXIGP1ARADDR; + output [1:0] MAXIGP1ARBURST; + output [3:0] MAXIGP1ARCACHE; + output [15:0] MAXIGP1ARID; + output [7:0] MAXIGP1ARLEN; + output MAXIGP1ARLOCK; + output [2:0] MAXIGP1ARPROT; + output [3:0] MAXIGP1ARQOS; + output [2:0] MAXIGP1ARSIZE; + output [15:0] MAXIGP1ARUSER; + output MAXIGP1ARVALID; + output [39:0] MAXIGP1AWADDR; + output [1:0] MAXIGP1AWBURST; + output [3:0] MAXIGP1AWCACHE; + output [15:0] MAXIGP1AWID; + output [7:0] MAXIGP1AWLEN; + output MAXIGP1AWLOCK; + output [2:0] MAXIGP1AWPROT; + output [3:0] MAXIGP1AWQOS; + output [2:0] MAXIGP1AWSIZE; + output [15:0] MAXIGP1AWUSER; + output MAXIGP1AWVALID; + output MAXIGP1BREADY; + output MAXIGP1RREADY; + output [127:0] MAXIGP1WDATA; + output MAXIGP1WLAST; + output [15:0] MAXIGP1WSTRB; + output MAXIGP1WVALID; + output [39:0] MAXIGP2ARADDR; + output [1:0] MAXIGP2ARBURST; + output [3:0] MAXIGP2ARCACHE; + output [15:0] MAXIGP2ARID; + output [7:0] MAXIGP2ARLEN; + output MAXIGP2ARLOCK; + output [2:0] MAXIGP2ARPROT; + output [3:0] MAXIGP2ARQOS; + output [2:0] MAXIGP2ARSIZE; + output [15:0] MAXIGP2ARUSER; + output MAXIGP2ARVALID; + output [39:0] MAXIGP2AWADDR; + output [1:0] MAXIGP2AWBURST; + output [3:0] MAXIGP2AWCACHE; + output [15:0] MAXIGP2AWID; + output [7:0] MAXIGP2AWLEN; + output MAXIGP2AWLOCK; + output [2:0] MAXIGP2AWPROT; + output [3:0] MAXIGP2AWQOS; + output [2:0] MAXIGP2AWSIZE; + output [15:0] MAXIGP2AWUSER; + output MAXIGP2AWVALID; + output MAXIGP2BREADY; + output MAXIGP2RREADY; + output [127:0] MAXIGP2WDATA; + output MAXIGP2WLAST; + output [15:0] MAXIGP2WSTRB; + output MAXIGP2WVALID; + output OSCRTCCLK; + output [3:0] PLCLK; + output PMUAIBAFIFMFPDREQ; + output PMUAIBAFIFMLPDREQ; + output [46:0] PMUERRORTOPL; + output [31:0] PMUPLGPO; + output PSPLEVENTO; + output [63:0] PSPLIRQFPD; + output [99:0] PSPLIRQLPD; + output [3:0] PSPLSTANDBYWFE; + output [3:0] PSPLSTANDBYWFI; + output PSPLTRACECTL; + output [31:0] PSPLTRACEDATA; + output [3:0] PSPLTRIGACK; + output [3:0] PSPLTRIGGER; + output PSS_ALTO_CORE_PAD_MGTTXN0OUT; + output PSS_ALTO_CORE_PAD_MGTTXN1OUT; + output PSS_ALTO_CORE_PAD_MGTTXN2OUT; + output PSS_ALTO_CORE_PAD_MGTTXN3OUT; + output PSS_ALTO_CORE_PAD_MGTTXP0OUT; + output PSS_ALTO_CORE_PAD_MGTTXP1OUT; + output PSS_ALTO_CORE_PAD_MGTTXP2OUT; + output PSS_ALTO_CORE_PAD_MGTTXP3OUT; + output PSS_ALTO_CORE_PAD_PADO; + output RPUEVENTO0; + output RPUEVENTO1; + output [43:0] SACEFPDACADDR; + output [2:0] SACEFPDACPROT; + output [3:0] SACEFPDACSNOOP; + output SACEFPDACVALID; + output SACEFPDARREADY; + output SACEFPDAWREADY; + output [5:0] SACEFPDBID; + output [1:0] SACEFPDBRESP; + output SACEFPDBUSER; + output SACEFPDBVALID; + output SACEFPDCDREADY; + output SACEFPDCRREADY; + output [127:0] SACEFPDRDATA; + output [5:0] SACEFPDRID; + output SACEFPDRLAST; + output [3:0] SACEFPDRRESP; + output SACEFPDRUSER; + output SACEFPDRVALID; + output SACEFPDWREADY; + output SAXIACPARREADY; + output SAXIACPAWREADY; + output [4:0] SAXIACPBID; + output [1:0] SAXIACPBRESP; + output SAXIACPBVALID; + output [127:0] SAXIACPRDATA; + output [4:0] SAXIACPRID; + output SAXIACPRLAST; + output [1:0] SAXIACPRRESP; + output SAXIACPRVALID; + output SAXIACPWREADY; + output SAXIGP0ARREADY; + output SAXIGP0AWREADY; + output [5:0] SAXIGP0BID; + output [1:0] SAXIGP0BRESP; + output SAXIGP0BVALID; + output [3:0] SAXIGP0RACOUNT; + output [7:0] SAXIGP0RCOUNT; + output [127:0] SAXIGP0RDATA; + output [5:0] SAXIGP0RID; + output SAXIGP0RLAST; + output [1:0] SAXIGP0RRESP; + output SAXIGP0RVALID; + output [3:0] SAXIGP0WACOUNT; + output [7:0] SAXIGP0WCOUNT; + output SAXIGP0WREADY; + output SAXIGP1ARREADY; + output SAXIGP1AWREADY; + output [5:0] SAXIGP1BID; + output [1:0] SAXIGP1BRESP; + output SAXIGP1BVALID; + output [3:0] SAXIGP1RACOUNT; + output [7:0] SAXIGP1RCOUNT; + output [127:0] SAXIGP1RDATA; + output [5:0] SAXIGP1RID; + output SAXIGP1RLAST; + output [1:0] SAXIGP1RRESP; + output SAXIGP1RVALID; + output [3:0] SAXIGP1WACOUNT; + output [7:0] SAXIGP1WCOUNT; + output SAXIGP1WREADY; + output SAXIGP2ARREADY; + output SAXIGP2AWREADY; + output [5:0] SAXIGP2BID; + output [1:0] SAXIGP2BRESP; + output SAXIGP2BVALID; + output [3:0] SAXIGP2RACOUNT; + output [7:0] SAXIGP2RCOUNT; + output [127:0] SAXIGP2RDATA; + output [5:0] SAXIGP2RID; + output SAXIGP2RLAST; + output [1:0] SAXIGP2RRESP; + output SAXIGP2RVALID; + output [3:0] SAXIGP2WACOUNT; + output [7:0] SAXIGP2WCOUNT; + output SAXIGP2WREADY; + output SAXIGP3ARREADY; + output SAXIGP3AWREADY; + output [5:0] SAXIGP3BID; + output [1:0] SAXIGP3BRESP; + output SAXIGP3BVALID; + output [3:0] SAXIGP3RACOUNT; + output [7:0] SAXIGP3RCOUNT; + output [127:0] SAXIGP3RDATA; + output [5:0] SAXIGP3RID; + output SAXIGP3RLAST; + output [1:0] SAXIGP3RRESP; + output SAXIGP3RVALID; + output [3:0] SAXIGP3WACOUNT; + output [7:0] SAXIGP3WCOUNT; + output SAXIGP3WREADY; + output SAXIGP4ARREADY; + output SAXIGP4AWREADY; + output [5:0] SAXIGP4BID; + output [1:0] SAXIGP4BRESP; + output SAXIGP4BVALID; + output [3:0] SAXIGP4RACOUNT; + output [7:0] SAXIGP4RCOUNT; + output [127:0] SAXIGP4RDATA; + output [5:0] SAXIGP4RID; + output SAXIGP4RLAST; + output [1:0] SAXIGP4RRESP; + output SAXIGP4RVALID; + output [3:0] SAXIGP4WACOUNT; + output [7:0] SAXIGP4WCOUNT; + output SAXIGP4WREADY; + output SAXIGP5ARREADY; + output SAXIGP5AWREADY; + output [5:0] SAXIGP5BID; + output [1:0] SAXIGP5BRESP; + output SAXIGP5BVALID; + output [3:0] SAXIGP5RACOUNT; + output [7:0] SAXIGP5RCOUNT; + output [127:0] SAXIGP5RDATA; + output [5:0] SAXIGP5RID; + output SAXIGP5RLAST; + output [1:0] SAXIGP5RRESP; + output SAXIGP5RVALID; + output [3:0] SAXIGP5WACOUNT; + output [7:0] SAXIGP5WCOUNT; + output SAXIGP5WREADY; + output SAXIGP6ARREADY; + output SAXIGP6AWREADY; + output [5:0] SAXIGP6BID; + output [1:0] SAXIGP6BRESP; + output SAXIGP6BVALID; + output [3:0] SAXIGP6RACOUNT; + output [7:0] SAXIGP6RCOUNT; + output [127:0] SAXIGP6RDATA; + output [5:0] SAXIGP6RID; + output SAXIGP6RLAST; + output [1:0] SAXIGP6RRESP; + output SAXIGP6RVALID; + output [3:0] SAXIGP6WACOUNT; + output [7:0] SAXIGP6WCOUNT; + output SAXIGP6WREADY; + inout [3:0] PSS_ALTO_CORE_PAD_BOOTMODE; + inout PSS_ALTO_CORE_PAD_CLK; + inout PSS_ALTO_CORE_PAD_DONEB; + inout [17:0] PSS_ALTO_CORE_PAD_DRAMA; + inout PSS_ALTO_CORE_PAD_DRAMACTN; + inout PSS_ALTO_CORE_PAD_DRAMALERTN; + inout [1:0] PSS_ALTO_CORE_PAD_DRAMBA; + inout [1:0] PSS_ALTO_CORE_PAD_DRAMBG; + inout [1:0] PSS_ALTO_CORE_PAD_DRAMCK; + inout [1:0] PSS_ALTO_CORE_PAD_DRAMCKE; + inout [1:0] PSS_ALTO_CORE_PAD_DRAMCKN; + inout [1:0] PSS_ALTO_CORE_PAD_DRAMCSN; + inout [8:0] PSS_ALTO_CORE_PAD_DRAMDM; + inout [71:0] PSS_ALTO_CORE_PAD_DRAMDQ; + inout [8:0] PSS_ALTO_CORE_PAD_DRAMDQS; + inout [8:0] PSS_ALTO_CORE_PAD_DRAMDQSN; + inout [1:0] PSS_ALTO_CORE_PAD_DRAMODT; + inout PSS_ALTO_CORE_PAD_DRAMPARITY; + inout PSS_ALTO_CORE_PAD_DRAMRAMRSTN; + inout PSS_ALTO_CORE_PAD_ERROROUT; + inout PSS_ALTO_CORE_PAD_ERRORSTATUS; + inout PSS_ALTO_CORE_PAD_INITB; + inout PSS_ALTO_CORE_PAD_JTAGTCK; + inout PSS_ALTO_CORE_PAD_JTAGTDI; + inout PSS_ALTO_CORE_PAD_JTAGTDO; + inout PSS_ALTO_CORE_PAD_JTAGTMS; + inout [77:0] PSS_ALTO_CORE_PAD_MIO; + inout PSS_ALTO_CORE_PAD_PORB; + inout PSS_ALTO_CORE_PAD_PROGB; + inout PSS_ALTO_CORE_PAD_RCALIBINOUT; + inout PSS_ALTO_CORE_PAD_SRSTB; + inout PSS_ALTO_CORE_PAD_ZQ; + input [7:0] ADMAFCICLK; + input AIBPMUAFIFMFPDACK; + input AIBPMUAFIFMLPDACK; + input DDRCEXTREFRESHRANK0REQ; + input DDRCEXTREFRESHRANK1REQ; + input DDRCREFRESHPLCLK; + input DPAUXDATAIN; + input DPEXTERNALCUSTOMEVENT1; + input DPEXTERNALCUSTOMEVENT2; + input DPEXTERNALVSYNCEVENT; + input DPHOTPLUGDETECT; + input [7:0] DPLIVEGFXALPHAIN; + input [35:0] DPLIVEGFXPIXEL1IN; + input DPLIVEVIDEOINDE; + input DPLIVEVIDEOINHSYNC; + input [35:0] DPLIVEVIDEOINPIXEL1; + input DPLIVEVIDEOINVSYNC; + input DPMAXISMIXEDAUDIOTREADY; + input DPSAXISAUDIOCLK; + input [31:0] DPSAXISAUDIOTDATA; + input DPSAXISAUDIOTID; + input DPSAXISAUDIOTVALID; + input DPVIDEOINCLK; + input EMIOCAN0PHYRX; + input EMIOCAN1PHYRX; + input EMIOENET0DMATXSTATUSTOG; + input EMIOENET0EXTINTIN; + input EMIOENET0GMIICOL; + input EMIOENET0GMIICRS; + input EMIOENET0GMIIRXCLK; + input [7:0] EMIOENET0GMIIRXD; + input EMIOENET0GMIIRXDV; + input EMIOENET0GMIIRXER; + input EMIOENET0GMIITXCLK; + input EMIOENET0MDIOI; + input EMIOENET0RXWOVERFLOW; + input EMIOENET0TXRCONTROL; + input [7:0] EMIOENET0TXRDATA; + input EMIOENET0TXRDATARDY; + input EMIOENET0TXREOP; + input EMIOENET0TXRERR; + input EMIOENET0TXRFLUSHED; + input EMIOENET0TXRSOP; + input EMIOENET0TXRUNDERFLOW; + input EMIOENET0TXRVALID; + input EMIOENET1DMATXSTATUSTOG; + input EMIOENET1EXTINTIN; + input EMIOENET1GMIICOL; + input EMIOENET1GMIICRS; + input EMIOENET1GMIIRXCLK; + input [7:0] EMIOENET1GMIIRXD; + input EMIOENET1GMIIRXDV; + input EMIOENET1GMIIRXER; + input EMIOENET1GMIITXCLK; + input EMIOENET1MDIOI; + input EMIOENET1RXWOVERFLOW; + input EMIOENET1TXRCONTROL; + input [7:0] EMIOENET1TXRDATA; + input EMIOENET1TXRDATARDY; + input EMIOENET1TXREOP; + input EMIOENET1TXRERR; + input EMIOENET1TXRFLUSHED; + input EMIOENET1TXRSOP; + input EMIOENET1TXRUNDERFLOW; + input EMIOENET1TXRVALID; + input EMIOENET2DMATXSTATUSTOG; + input EMIOENET2EXTINTIN; + input EMIOENET2GMIICOL; + input EMIOENET2GMIICRS; + input EMIOENET2GMIIRXCLK; + input [7:0] EMIOENET2GMIIRXD; + input EMIOENET2GMIIRXDV; + input EMIOENET2GMIIRXER; + input EMIOENET2GMIITXCLK; + input EMIOENET2MDIOI; + input EMIOENET2RXWOVERFLOW; + input EMIOENET2TXRCONTROL; + input [7:0] EMIOENET2TXRDATA; + input EMIOENET2TXRDATARDY; + input EMIOENET2TXREOP; + input EMIOENET2TXRERR; + input EMIOENET2TXRFLUSHED; + input EMIOENET2TXRSOP; + input EMIOENET2TXRUNDERFLOW; + input EMIOENET2TXRVALID; + input EMIOENET3DMATXSTATUSTOG; + input EMIOENET3EXTINTIN; + input EMIOENET3GMIICOL; + input EMIOENET3GMIICRS; + input EMIOENET3GMIIRXCLK; + input [7:0] EMIOENET3GMIIRXD; + input EMIOENET3GMIIRXDV; + input EMIOENET3GMIIRXER; + input EMIOENET3GMIITXCLK; + input EMIOENET3MDIOI; + input EMIOENET3RXWOVERFLOW; + input EMIOENET3TXRCONTROL; + input [7:0] EMIOENET3TXRDATA; + input EMIOENET3TXRDATARDY; + input EMIOENET3TXREOP; + input EMIOENET3TXRERR; + input EMIOENET3TXRFLUSHED; + input EMIOENET3TXRSOP; + input EMIOENET3TXRUNDERFLOW; + input EMIOENET3TXRVALID; + input EMIOENETTSUCLK; + input [1:0] EMIOGEM0TSUINCCTRL; + input [1:0] EMIOGEM1TSUINCCTRL; + input [1:0] EMIOGEM2TSUINCCTRL; + input [1:0] EMIOGEM3TSUINCCTRL; + input [95:0] EMIOGPIOI; + input EMIOHUBPORTOVERCRNTUSB20; + input EMIOHUBPORTOVERCRNTUSB21; + input EMIOHUBPORTOVERCRNTUSB30; + input EMIOHUBPORTOVERCRNTUSB31; + input EMIOI2C0SCLI; + input EMIOI2C0SDAI; + input EMIOI2C1SCLI; + input EMIOI2C1SDAI; + input EMIOSDIO0CDN; + input EMIOSDIO0CMDIN; + input [7:0] EMIOSDIO0DATAIN; + input EMIOSDIO0FBCLKIN; + input EMIOSDIO0WP; + input EMIOSDIO1CDN; + input EMIOSDIO1CMDIN; + input [7:0] EMIOSDIO1DATAIN; + input EMIOSDIO1FBCLKIN; + input EMIOSDIO1WP; + input EMIOSPI0MI; + input EMIOSPI0SCLKI; + input EMIOSPI0SI; + input EMIOSPI0SSIN; + input EMIOSPI1MI; + input EMIOSPI1SCLKI; + input EMIOSPI1SI; + input EMIOSPI1SSIN; + input [2:0] EMIOTTC0CLKI; + input [2:0] EMIOTTC1CLKI; + input [2:0] EMIOTTC2CLKI; + input [2:0] EMIOTTC3CLKI; + input EMIOUART0CTSN; + input EMIOUART0DCDN; + input EMIOUART0DSRN; + input EMIOUART0RIN; + input EMIOUART0RX; + input EMIOUART1CTSN; + input EMIOUART1DCDN; + input EMIOUART1DSRN; + input EMIOUART1RIN; + input EMIOUART1RX; + input EMIOWDT0CLKI; + input EMIOWDT1CLKI; + input FMIOGEM0FIFORXCLKFROMPL; + input FMIOGEM0FIFOTXCLKFROMPL; + input FMIOGEM0SIGNALDETECT; + input FMIOGEM1FIFORXCLKFROMPL; + input FMIOGEM1FIFOTXCLKFROMPL; + input FMIOGEM1SIGNALDETECT; + input FMIOGEM2FIFORXCLKFROMPL; + input FMIOGEM2FIFOTXCLKFROMPL; + input FMIOGEM2SIGNALDETECT; + input FMIOGEM3FIFORXCLKFROMPL; + input FMIOGEM3FIFOTXCLKFROMPL; + input FMIOGEM3SIGNALDETECT; + input FMIOGEMTSUCLKFROMPL; + input [31:0] FTMGPI; + input [7:0] GDMAFCICLK; + input MAXIGP0ACLK; + input MAXIGP0ARREADY; + input MAXIGP0AWREADY; + input [15:0] MAXIGP0BID; + input [1:0] MAXIGP0BRESP; + input MAXIGP0BVALID; + input [127:0] MAXIGP0RDATA; + input [15:0] MAXIGP0RID; + input MAXIGP0RLAST; + input [1:0] MAXIGP0RRESP; + input MAXIGP0RVALID; + input MAXIGP0WREADY; + input MAXIGP1ACLK; + input MAXIGP1ARREADY; + input MAXIGP1AWREADY; + input [15:0] MAXIGP1BID; + input [1:0] MAXIGP1BRESP; + input MAXIGP1BVALID; + input [127:0] MAXIGP1RDATA; + input [15:0] MAXIGP1RID; + input MAXIGP1RLAST; + input [1:0] MAXIGP1RRESP; + input MAXIGP1RVALID; + input MAXIGP1WREADY; + input MAXIGP2ACLK; + input MAXIGP2ARREADY; + input MAXIGP2AWREADY; + input [15:0] MAXIGP2BID; + input [1:0] MAXIGP2BRESP; + input MAXIGP2BVALID; + input [127:0] MAXIGP2RDATA; + input [15:0] MAXIGP2RID; + input MAXIGP2RLAST; + input [1:0] MAXIGP2RRESP; + input MAXIGP2RVALID; + input MAXIGP2WREADY; + input NFIQ0LPDRPU; + input NFIQ1LPDRPU; + input NIRQ0LPDRPU; + input NIRQ1LPDRPU; + input [7:0] PL2ADMACVLD; + input [7:0] PL2ADMATACK; + input [7:0] PL2GDMACVLD; + input [7:0] PL2GDMATACK; + input PLACECLK; + input PLACPINACT; + input [3:0] PLFPGASTOP; + input [2:0] PLLAUXREFCLKFPD; + input [1:0] PLLAUXREFCLKLPD; + input [31:0] PLPMUGPI; + input [3:0] PLPSAPUGICFIQ; + input [3:0] PLPSAPUGICIRQ; + input PLPSEVENTI; + input [7:0] PLPSIRQ0; + input [7:0] PLPSIRQ1; + input PLPSTRACECLK; + input [3:0] PLPSTRIGACK; + input [3:0] PLPSTRIGGER; + input [3:0] PMUERRORFROMPL; + input PSS_ALTO_CORE_PAD_MGTRXN0IN; + input PSS_ALTO_CORE_PAD_MGTRXN1IN; + input PSS_ALTO_CORE_PAD_MGTRXN2IN; + input PSS_ALTO_CORE_PAD_MGTRXN3IN; + input PSS_ALTO_CORE_PAD_MGTRXP0IN; + input PSS_ALTO_CORE_PAD_MGTRXP1IN; + input PSS_ALTO_CORE_PAD_MGTRXP2IN; + input PSS_ALTO_CORE_PAD_MGTRXP3IN; + input PSS_ALTO_CORE_PAD_PADI; + input PSS_ALTO_CORE_PAD_REFN0IN; + input PSS_ALTO_CORE_PAD_REFN1IN; + input PSS_ALTO_CORE_PAD_REFN2IN; + input PSS_ALTO_CORE_PAD_REFN3IN; + input PSS_ALTO_CORE_PAD_REFP0IN; + input PSS_ALTO_CORE_PAD_REFP1IN; + input PSS_ALTO_CORE_PAD_REFP2IN; + input PSS_ALTO_CORE_PAD_REFP3IN; + input RPUEVENTI0; + input RPUEVENTI1; + input SACEFPDACREADY; + input [43:0] SACEFPDARADDR; + input [1:0] SACEFPDARBAR; + input [1:0] SACEFPDARBURST; + input [3:0] SACEFPDARCACHE; + input [1:0] SACEFPDARDOMAIN; + input [5:0] SACEFPDARID; + input [7:0] SACEFPDARLEN; + input SACEFPDARLOCK; + input [2:0] SACEFPDARPROT; + input [3:0] SACEFPDARQOS; + input [3:0] SACEFPDARREGION; + input [2:0] SACEFPDARSIZE; + input [3:0] SACEFPDARSNOOP; + input [15:0] SACEFPDARUSER; + input SACEFPDARVALID; + input [43:0] SACEFPDAWADDR; + input [1:0] SACEFPDAWBAR; + input [1:0] SACEFPDAWBURST; + input [3:0] SACEFPDAWCACHE; + input [1:0] SACEFPDAWDOMAIN; + input [5:0] SACEFPDAWID; + input [7:0] SACEFPDAWLEN; + input SACEFPDAWLOCK; + input [2:0] SACEFPDAWPROT; + input [3:0] SACEFPDAWQOS; + input [3:0] SACEFPDAWREGION; + input [2:0] SACEFPDAWSIZE; + input [2:0] SACEFPDAWSNOOP; + input [15:0] SACEFPDAWUSER; + input SACEFPDAWVALID; + input SACEFPDBREADY; + input [127:0] SACEFPDCDDATA; + input SACEFPDCDLAST; + input SACEFPDCDVALID; + input [4:0] SACEFPDCRRESP; + input SACEFPDCRVALID; + input SACEFPDRACK; + input SACEFPDRREADY; + input SACEFPDWACK; + input [127:0] SACEFPDWDATA; + input SACEFPDWLAST; + input [15:0] SACEFPDWSTRB; + input SACEFPDWUSER; + input SACEFPDWVALID; + input SAXIACPACLK; + input [39:0] SAXIACPARADDR; + input [1:0] SAXIACPARBURST; + input [3:0] SAXIACPARCACHE; + input [4:0] SAXIACPARID; + input [7:0] SAXIACPARLEN; + input SAXIACPARLOCK; + input [2:0] SAXIACPARPROT; + input [3:0] SAXIACPARQOS; + input [2:0] SAXIACPARSIZE; + input [1:0] SAXIACPARUSER; + input SAXIACPARVALID; + input [39:0] SAXIACPAWADDR; + input [1:0] SAXIACPAWBURST; + input [3:0] SAXIACPAWCACHE; + input [4:0] SAXIACPAWID; + input [7:0] SAXIACPAWLEN; + input SAXIACPAWLOCK; + input [2:0] SAXIACPAWPROT; + input [3:0] SAXIACPAWQOS; + input [2:0] SAXIACPAWSIZE; + input [1:0] SAXIACPAWUSER; + input SAXIACPAWVALID; + input SAXIACPBREADY; + input SAXIACPRREADY; + input [127:0] SAXIACPWDATA; + input SAXIACPWLAST; + input [15:0] SAXIACPWSTRB; + input SAXIACPWVALID; + input [48:0] SAXIGP0ARADDR; + input [1:0] SAXIGP0ARBURST; + input [3:0] SAXIGP0ARCACHE; + input [5:0] SAXIGP0ARID; + input [7:0] SAXIGP0ARLEN; + input SAXIGP0ARLOCK; + input [2:0] SAXIGP0ARPROT; + input [3:0] SAXIGP0ARQOS; + input [2:0] SAXIGP0ARSIZE; + input SAXIGP0ARUSER; + input SAXIGP0ARVALID; + input [48:0] SAXIGP0AWADDR; + input [1:0] SAXIGP0AWBURST; + input [3:0] SAXIGP0AWCACHE; + input [5:0] SAXIGP0AWID; + input [7:0] SAXIGP0AWLEN; + input SAXIGP0AWLOCK; + input [2:0] SAXIGP0AWPROT; + input [3:0] SAXIGP0AWQOS; + input [2:0] SAXIGP0AWSIZE; + input SAXIGP0AWUSER; + input SAXIGP0AWVALID; + input SAXIGP0BREADY; + input SAXIGP0RCLK; + input SAXIGP0RREADY; + input SAXIGP0WCLK; + input [127:0] SAXIGP0WDATA; + input SAXIGP0WLAST; + input [15:0] SAXIGP0WSTRB; + input SAXIGP0WVALID; + input [48:0] SAXIGP1ARADDR; + input [1:0] SAXIGP1ARBURST; + input [3:0] SAXIGP1ARCACHE; + input [5:0] SAXIGP1ARID; + input [7:0] SAXIGP1ARLEN; + input SAXIGP1ARLOCK; + input [2:0] SAXIGP1ARPROT; + input [3:0] SAXIGP1ARQOS; + input [2:0] SAXIGP1ARSIZE; + input SAXIGP1ARUSER; + input SAXIGP1ARVALID; + input [48:0] SAXIGP1AWADDR; + input [1:0] SAXIGP1AWBURST; + input [3:0] SAXIGP1AWCACHE; + input [5:0] SAXIGP1AWID; + input [7:0] SAXIGP1AWLEN; + input SAXIGP1AWLOCK; + input [2:0] SAXIGP1AWPROT; + input [3:0] SAXIGP1AWQOS; + input [2:0] SAXIGP1AWSIZE; + input SAXIGP1AWUSER; + input SAXIGP1AWVALID; + input SAXIGP1BREADY; + input SAXIGP1RCLK; + input SAXIGP1RREADY; + input SAXIGP1WCLK; + input [127:0] SAXIGP1WDATA; + input SAXIGP1WLAST; + input [15:0] SAXIGP1WSTRB; + input SAXIGP1WVALID; + input [48:0] SAXIGP2ARADDR; + input [1:0] SAXIGP2ARBURST; + input [3:0] SAXIGP2ARCACHE; + input [5:0] SAXIGP2ARID; + input [7:0] SAXIGP2ARLEN; + input SAXIGP2ARLOCK; + input [2:0] SAXIGP2ARPROT; + input [3:0] SAXIGP2ARQOS; + input [2:0] SAXIGP2ARSIZE; + input SAXIGP2ARUSER; + input SAXIGP2ARVALID; + input [48:0] SAXIGP2AWADDR; + input [1:0] SAXIGP2AWBURST; + input [3:0] SAXIGP2AWCACHE; + input [5:0] SAXIGP2AWID; + input [7:0] SAXIGP2AWLEN; + input SAXIGP2AWLOCK; + input [2:0] SAXIGP2AWPROT; + input [3:0] SAXIGP2AWQOS; + input [2:0] SAXIGP2AWSIZE; + input SAXIGP2AWUSER; + input SAXIGP2AWVALID; + input SAXIGP2BREADY; + input SAXIGP2RCLK; + input SAXIGP2RREADY; + input SAXIGP2WCLK; + input [127:0] SAXIGP2WDATA; + input SAXIGP2WLAST; + input [15:0] SAXIGP2WSTRB; + input SAXIGP2WVALID; + input [48:0] SAXIGP3ARADDR; + input [1:0] SAXIGP3ARBURST; + input [3:0] SAXIGP3ARCACHE; + input [5:0] SAXIGP3ARID; + input [7:0] SAXIGP3ARLEN; + input SAXIGP3ARLOCK; + input [2:0] SAXIGP3ARPROT; + input [3:0] SAXIGP3ARQOS; + input [2:0] SAXIGP3ARSIZE; + input SAXIGP3ARUSER; + input SAXIGP3ARVALID; + input [48:0] SAXIGP3AWADDR; + input [1:0] SAXIGP3AWBURST; + input [3:0] SAXIGP3AWCACHE; + input [5:0] SAXIGP3AWID; + input [7:0] SAXIGP3AWLEN; + input SAXIGP3AWLOCK; + input [2:0] SAXIGP3AWPROT; + input [3:0] SAXIGP3AWQOS; + input [2:0] SAXIGP3AWSIZE; + input SAXIGP3AWUSER; + input SAXIGP3AWVALID; + input SAXIGP3BREADY; + input SAXIGP3RCLK; + input SAXIGP3RREADY; + input SAXIGP3WCLK; + input [127:0] SAXIGP3WDATA; + input SAXIGP3WLAST; + input [15:0] SAXIGP3WSTRB; + input SAXIGP3WVALID; + input [48:0] SAXIGP4ARADDR; + input [1:0] SAXIGP4ARBURST; + input [3:0] SAXIGP4ARCACHE; + input [5:0] SAXIGP4ARID; + input [7:0] SAXIGP4ARLEN; + input SAXIGP4ARLOCK; + input [2:0] SAXIGP4ARPROT; + input [3:0] SAXIGP4ARQOS; + input [2:0] SAXIGP4ARSIZE; + input SAXIGP4ARUSER; + input SAXIGP4ARVALID; + input [48:0] SAXIGP4AWADDR; + input [1:0] SAXIGP4AWBURST; + input [3:0] SAXIGP4AWCACHE; + input [5:0] SAXIGP4AWID; + input [7:0] SAXIGP4AWLEN; + input SAXIGP4AWLOCK; + input [2:0] SAXIGP4AWPROT; + input [3:0] SAXIGP4AWQOS; + input [2:0] SAXIGP4AWSIZE; + input SAXIGP4AWUSER; + input SAXIGP4AWVALID; + input SAXIGP4BREADY; + input SAXIGP4RCLK; + input SAXIGP4RREADY; + input SAXIGP4WCLK; + input [127:0] SAXIGP4WDATA; + input SAXIGP4WLAST; + input [15:0] SAXIGP4WSTRB; + input SAXIGP4WVALID; + input [48:0] SAXIGP5ARADDR; + input [1:0] SAXIGP5ARBURST; + input [3:0] SAXIGP5ARCACHE; + input [5:0] SAXIGP5ARID; + input [7:0] SAXIGP5ARLEN; + input SAXIGP5ARLOCK; + input [2:0] SAXIGP5ARPROT; + input [3:0] SAXIGP5ARQOS; + input [2:0] SAXIGP5ARSIZE; + input SAXIGP5ARUSER; + input SAXIGP5ARVALID; + input [48:0] SAXIGP5AWADDR; + input [1:0] SAXIGP5AWBURST; + input [3:0] SAXIGP5AWCACHE; + input [5:0] SAXIGP5AWID; + input [7:0] SAXIGP5AWLEN; + input SAXIGP5AWLOCK; + input [2:0] SAXIGP5AWPROT; + input [3:0] SAXIGP5AWQOS; + input [2:0] SAXIGP5AWSIZE; + input SAXIGP5AWUSER; + input SAXIGP5AWVALID; + input SAXIGP5BREADY; + input SAXIGP5RCLK; + input SAXIGP5RREADY; + input SAXIGP5WCLK; + input [127:0] SAXIGP5WDATA; + input SAXIGP5WLAST; + input [15:0] SAXIGP5WSTRB; + input SAXIGP5WVALID; + input [48:0] SAXIGP6ARADDR; + input [1:0] SAXIGP6ARBURST; + input [3:0] SAXIGP6ARCACHE; + input [5:0] SAXIGP6ARID; + input [7:0] SAXIGP6ARLEN; + input SAXIGP6ARLOCK; + input [2:0] SAXIGP6ARPROT; + input [3:0] SAXIGP6ARQOS; + input [2:0] SAXIGP6ARSIZE; + input SAXIGP6ARUSER; + input SAXIGP6ARVALID; + input [48:0] SAXIGP6AWADDR; + input [1:0] SAXIGP6AWBURST; + input [3:0] SAXIGP6AWCACHE; + input [5:0] SAXIGP6AWID; + input [7:0] SAXIGP6AWLEN; + input SAXIGP6AWLOCK; + input [2:0] SAXIGP6AWPROT; + input [3:0] SAXIGP6AWQOS; + input [2:0] SAXIGP6AWSIZE; + input SAXIGP6AWUSER; + input SAXIGP6AWVALID; + input SAXIGP6BREADY; + input SAXIGP6RCLK; + input SAXIGP6RREADY; + input SAXIGP6WCLK; + input [127:0] SAXIGP6WDATA; + input SAXIGP6WLAST; + input [15:0] SAXIGP6WSTRB; + input SAXIGP6WVALID; + input [59:0] STMEVENT; +endmodule + diff --git a/tests/aiger/.gitignore b/tests/aiger/.gitignore new file mode 100644 index 000000000..9a26bb8f4 --- /dev/null +++ b/tests/aiger/.gitignore @@ -0,0 +1 @@ +/*_ref.v diff --git a/tests/aiger/and_.aag b/tests/aiger/and_.aag new file mode 100644 index 000000000..cadd505f0 --- /dev/null +++ b/tests/aiger/and_.aag @@ -0,0 +1,8 @@ +aag 3 2 0 1 1 +2 +4 +6 +6 2 4 +i0 pi0 +i1 pi1 +o0 po0 diff --git a/tests/aiger/and_.aig b/tests/aiger/and_.aig new file mode 100644 index 000000000..13c7a0c17 --- /dev/null +++ b/tests/aiger/and_.aig @@ -0,0 +1,5 @@ +aig 3 2 0 1 1 +6 +i0 pi0 +i1 pi1 +o0 po0 diff --git a/tests/aiger/buffer.aag b/tests/aiger/buffer.aag new file mode 100644 index 000000000..211106ed6 --- /dev/null +++ b/tests/aiger/buffer.aag @@ -0,0 +1,5 @@ +aag 1 1 0 1 0 +2 +2 +i0 pi0 +o0 po0 diff --git a/tests/aiger/buffer.aig b/tests/aiger/buffer.aig new file mode 100644 index 000000000..01df6f1cf --- /dev/null +++ b/tests/aiger/buffer.aig @@ -0,0 +1,4 @@ +aig 1 1 0 1 0 +2 +i0 pi0 +o0 po0 diff --git a/tests/aiger/cnt1.aag b/tests/aiger/cnt1.aag new file mode 100644 index 000000000..75598862c --- /dev/null +++ b/tests/aiger/cnt1.aag @@ -0,0 +1,4 @@ +aag 1 0 1 0 0 1 +2 3 +2 +b0 po0 diff --git a/tests/aiger/cnt1.aig b/tests/aiger/cnt1.aig new file mode 100644 index 000000000..6fcf62522 --- /dev/null +++ b/tests/aiger/cnt1.aig @@ -0,0 +1,4 @@ +aig 1 0 1 0 0 1 +3 +2 +b0 po0 diff --git a/tests/aiger/cnt1e.aag b/tests/aiger/cnt1e.aag new file mode 100644 index 000000000..35cd5a482 --- /dev/null +++ b/tests/aiger/cnt1e.aag @@ -0,0 +1,9 @@ +aag 5 1 1 0 3 1 +2 +4 10 +4 +6 5 3 +8 4 2 +10 9 7 +b0 AIGER_NEVER +i0 po0 diff --git a/tests/aiger/cnt1e.aig b/tests/aiger/cnt1e.aig new file mode 100644 index 000000000..7284dd42a --- /dev/null +++ b/tests/aiger/cnt1e.aig @@ -0,0 +1,5 @@ +aig 5 1 1 0 3 1 +10 +4 +i0 po0 +b0 AIGER_NEVER diff --git a/tests/aiger/empty.aag b/tests/aiger/empty.aag new file mode 100644 index 000000000..40c0f00cb --- /dev/null +++ b/tests/aiger/empty.aag @@ -0,0 +1 @@ +aag 0 0 0 0 0 diff --git a/tests/aiger/empty.aig b/tests/aiger/empty.aig new file mode 100644 index 000000000..a28373cd3 --- /dev/null +++ b/tests/aiger/empty.aig @@ -0,0 +1 @@ +aig 0 0 0 0 0 diff --git a/tests/aiger/false.aag b/tests/aiger/false.aag new file mode 100644 index 000000000..bab4a06a6 --- /dev/null +++ b/tests/aiger/false.aag @@ -0,0 +1,3 @@ +aag 0 0 0 1 0 +0 +o0 po0 diff --git a/tests/aiger/false.aig b/tests/aiger/false.aig new file mode 100644 index 000000000..4dc442d7b --- /dev/null +++ b/tests/aiger/false.aig @@ -0,0 +1,3 @@ +aig 0 0 0 1 0 +0 +o0 po0 diff --git a/tests/aiger/halfadder.aag b/tests/aiger/halfadder.aag new file mode 100644 index 000000000..5bf54d38d --- /dev/null +++ b/tests/aiger/halfadder.aag @@ -0,0 +1,14 @@ +aag 7 2 0 2 3 +2 +4 +6 +12 +6 13 15 +12 2 4 +14 3 5 +i0 x +i1 y +o0 s +o1 c +c +half adder diff --git a/tests/aiger/halfadder.aig b/tests/aiger/halfadder.aig new file mode 100644 index 000000000..83727ee63 --- /dev/null +++ b/tests/aiger/halfadder.aig @@ -0,0 +1,9 @@ +aig 5 2 0 2 3 +10 +6 +i0 x +i1 y +o0 s +o1 c +c +half adder diff --git a/tests/aiger/inverter.aag b/tests/aiger/inverter.aag new file mode 100644 index 000000000..428bad9e4 --- /dev/null +++ b/tests/aiger/inverter.aag @@ -0,0 +1,5 @@ +aag 1 1 0 1 0 +2 +3 +i0 pi0 +o0 po0 diff --git a/tests/aiger/inverter.aig b/tests/aiger/inverter.aig new file mode 100644 index 000000000..5bec90ae3 --- /dev/null +++ b/tests/aiger/inverter.aig @@ -0,0 +1,4 @@ +aig 1 1 0 1 0 +3 +i0 pi0 +o0 po0 diff --git a/tests/aiger/notcnt1.aag b/tests/aiger/notcnt1.aag new file mode 100644 index 000000000..e92815f23 --- /dev/null +++ b/tests/aiger/notcnt1.aag @@ -0,0 +1,4 @@ +aag 1 0 1 0 0 1 +2 3 +3 +b0 AIGER_NEVER diff --git a/tests/aiger/notcnt1.aig b/tests/aiger/notcnt1.aig new file mode 100644 index 000000000..f8a667f1f --- /dev/null +++ b/tests/aiger/notcnt1.aig @@ -0,0 +1,4 @@ +aig 1 0 1 0 0 1 +3 +3 +b0 AIGER_NEVER diff --git a/tests/aiger/notcnt1e.aag b/tests/aiger/notcnt1e.aag new file mode 100644 index 000000000..2ed645d84 --- /dev/null +++ b/tests/aiger/notcnt1e.aag @@ -0,0 +1,9 @@ +aag 5 1 1 0 3 1 +2 +4 10 +5 +6 5 3 +8 4 2 +10 9 7 +b0 AIGER_NEVER +i0 pi0 diff --git a/tests/aiger/notcnt1e.aig b/tests/aiger/notcnt1e.aig new file mode 100644 index 000000000..fd7e94508 --- /dev/null +++ b/tests/aiger/notcnt1e.aig @@ -0,0 +1,5 @@ +aig 5 1 1 0 3 1 +10 +5 +i0 pi0 +b0 AIGER_NEVER diff --git a/tests/aiger/or_.aag b/tests/aiger/or_.aag new file mode 100644 index 000000000..0f619dba3 --- /dev/null +++ b/tests/aiger/or_.aag @@ -0,0 +1,8 @@ +aag 3 2 0 1 1 +2 +4 +7 +6 3 5 +i0 pi0 +i1 pi1 +o0 po0 diff --git a/tests/aiger/or_.aig b/tests/aiger/or_.aig new file mode 100644 index 000000000..051687512 --- /dev/null +++ b/tests/aiger/or_.aig @@ -0,0 +1,5 @@ +aig 3 2 0 1 1 +7 +i0 pi0 +i1 pi1 +o0 po0 diff --git a/tests/aiger/run-test.sh b/tests/aiger/run-test.sh new file mode 100755 index 000000000..deaf48a3d --- /dev/null +++ b/tests/aiger/run-test.sh @@ -0,0 +1,54 @@ +#!/bin/bash + +set -e + +OPTIND=1 +abcprog="../../yosys-abc" # default to built-in version of abc +while getopts "A:" opt +do + case "$opt" in + A) abcprog="$OPTARG" ;; + esac +done +shift "$((OPTIND-1))" + +# 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). + +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 + +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/tests/aiger/toggle-re.aag b/tests/aiger/toggle-re.aag new file mode 100644 index 000000000..b662bb386 --- /dev/null +++ b/tests/aiger/toggle-re.aag @@ -0,0 +1,14 @@ +aag 7 2 1 2 4 +2 +4 +6 8 +6 +7 +8 4 10 +10 13 15 +12 2 6 +14 3 7 +i0 enable +i1 reset +o0 Q +o1 !Q diff --git a/tests/aiger/toggle-re.aig b/tests/aiger/toggle-re.aig new file mode 100644 index 000000000..9d6730f21 --- /dev/null +++ b/tests/aiger/toggle-re.aig @@ -0,0 +1,8 @@ +aig 7 2 1 2 4 +14 +6 +7 +i0 enable +i1 reset +o0 Q +o1 !Q diff --git a/tests/aiger/toggle.aag b/tests/aiger/toggle.aag new file mode 100644 index 000000000..b1a1582d7 --- /dev/null +++ b/tests/aiger/toggle.aag @@ -0,0 +1,6 @@ +aag 1 0 1 2 0 +2 3 +2 +3 +o0 po0 +o1 po1 diff --git a/tests/aiger/toggle.aig b/tests/aiger/toggle.aig new file mode 100644 index 000000000..68b41763f --- /dev/null +++ b/tests/aiger/toggle.aig @@ -0,0 +1,6 @@ +aig 1 0 1 2 0 +3 +2 +3 +o0 po0 +o1 po1 diff --git a/tests/aiger/true.aag b/tests/aiger/true.aag new file mode 100644 index 000000000..66a9eab46 --- /dev/null +++ b/tests/aiger/true.aag @@ -0,0 +1,3 @@ +aag 0 0 0 1 0 +1 +o0 po0 diff --git a/tests/aiger/true.aig b/tests/aiger/true.aig new file mode 100644 index 000000000..f9bad6000 --- /dev/null +++ b/tests/aiger/true.aig @@ -0,0 +1,3 @@ +aig 0 0 0 1 0 +1 +o0 po0 diff --git a/tests/arch/run-test.sh b/tests/arch/run-test.sh new file mode 100755 index 000000000..5292d1615 --- /dev/null +++ b/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/tests/asicworld/code_hdl_models_misc1.v b/tests/asicworld/code_hdl_models_misc1.v deleted file mode 100644 index e3d9d5d64..000000000 --- a/tests/asicworld/code_hdl_models_misc1.v +++ /dev/null @@ -1,22 +0,0 @@ -module misc1 (a,b,c,d,y); -input a, b,c,d; -output y; - -wire net1,net2,net3; - -supply1 vdd; -supply0 vss; - -// y = !((a+b+c).d) - -pmos p1 (vdd,net1,a); -pmos p2 (net1,net2,b); -pmos p3 (net2,y,c); -pmos p4 (vdd,y,d); - -nmos n1 (vss,net3,a); -nmos n2 (vss,net3,b); -nmos n3 (vss,net3,c); -nmos n4 (net3,y,d); - -endmodule diff --git a/tests/asicworld/code_hdl_models_mux21_switch.v b/tests/asicworld/code_hdl_models_mux21_switch.v deleted file mode 100644 index 519c07fc5..000000000 --- a/tests/asicworld/code_hdl_models_mux21_switch.v +++ /dev/null @@ -1,22 +0,0 @@ -//----------------------------------------------------- -// Design Name : mux21_switch -// File Name : mux21_switch.v -// Function : 2:1 Mux using Switch Primitives -// Coder : Deepak Kumar Tala -//----------------------------------------------------- -module mux21_switch (out, ctrl, in1, in2); - - output out; - input ctrl, in1, in2; - wire w; - - supply1 power; - supply0 ground; - - pmos N1 (w, power, ctrl); - nmos N2 (w, ground, ctrl); - - cmos C1 (out, in1, w, ctrl); - cmos C2 (out, in2, ctrl, w); - -endmodule diff --git a/tests/asicworld/code_hdl_models_nand_switch.v b/tests/asicworld/code_hdl_models_nand_switch.v deleted file mode 100644 index 1ccdd3a7c..000000000 --- a/tests/asicworld/code_hdl_models_nand_switch.v +++ /dev/null @@ -1,14 +0,0 @@ -module nand_switch(a,b,out); -input a,b; -output out; - -supply0 vss; -supply1 vdd; -wire net1; - -pmos p1 (vdd,out,a); -pmos p2 (vdd,out,b); -nmos n1 (vss,net1,a); -nmos n2 (net1,out,b); - -endmodule
\ No newline at end of file diff --git a/tests/asicworld/code_hdl_models_t_gate_switch.v b/tests/asicworld/code_hdl_models_t_gate_switch.v deleted file mode 100644 index 5a7e0eaff..000000000 --- a/tests/asicworld/code_hdl_models_t_gate_switch.v +++ /dev/null @@ -1,11 +0,0 @@ -module t_gate_switch (L,R,nC,C); - inout L; - inout R; - input nC; - input C; - - //Syntax: keyword unique_name (drain. source, gate); - pmos p1 (L,R,nC); - nmos p2 (L,R,C); - -endmodule diff --git a/tests/asicworld/run-test.sh b/tests/asicworld/run-test.sh index d5708c456..c22ab6928 100755 --- a/tests/asicworld/run-test.sh +++ b/tests/asicworld/run-test.sh @@ -11,4 +11,4 @@ do done shift "$((OPTIND-1))" -exec ${MAKE:-make} -f ../tools/autotest.mk $seed EXTRA_FLAGS="-e" *.v +exec ${MAKE:-make} -f ../tools/autotest.mk $seed EXTRA_FLAGS+="-e" *.v diff --git a/tests/asicworld/xfirrtl b/tests/asicworld/xfirrtl new file mode 100644 index 000000000..08bf4ccd8 --- /dev/null +++ b/tests/asicworld/xfirrtl @@ -0,0 +1,23 @@ +# This file contains the names of verilog files to exclude from verilog to FIRRTL regression tests due to known failures. +code_hdl_models_arbiter.v error: reg rst; cannot be driven by primitives or continuous assignment. +code_hdl_models_clk_div_45.v yosys issue: 2nd PMUXTREE pass yields: ERROR: Negative edge clock on FF clk_div_45.$procdff$49. +code_hdl_models_d_ff_gates.v combinational loop +code_hdl_models_d_latch_gates.v combinational loop +code_hdl_models_dff_async_reset.v $adff +code_hdl_models_tff_async_reset.v $adff +code_hdl_models_uart.v $adff +code_tidbits_asyn_reset.v $adff +code_tidbits_reg_seq_example.v $adff +code_verilog_tutorial_always_example.v empty module +code_verilog_tutorial_escape_id.v make_id issues (name begins with a digit) +code_verilog_tutorial_explicit.v firrtl backend bug (empty module) +code_verilog_tutorial_first_counter.v error: reg rst; cannot be driven by primitives or continuous assignment. +code_verilog_tutorial_fsm_full.v error: reg reset; cannot be driven by primitives or continuous assignment. +code_verilog_tutorial_if_else.v empty module (everything is under 'always @ (posedge clk)') +[code_verilog_tutorial_n_out_primitive.v empty module +code_verilog_tutorial_parallel_if.v empty module (everything is under 'always @ (posedge clk)') +code_verilog_tutorial_simple_function.v empty module (no hardware) +code_verilog_tutorial_simple_if.v empty module (everything is under 'always @ (posedge clk)') +code_verilog_tutorial_task_global.v empty module (everything is under 'always @ (posedge clk)') +code_verilog_tutorial_v2k_reg.v empty module +code_verilog_tutorial_which_clock.v $adff diff --git a/tests/errors/syntax_err01.v b/tests/errors/syntax_err01.v new file mode 100644 index 000000000..68e9b1d50 --- /dev/null +++ b/tests/errors/syntax_err01.v @@ -0,0 +1,4 @@ +module a; +integer [31:0]w; +endmodule + diff --git a/tests/errors/syntax_err02.v b/tests/errors/syntax_err02.v new file mode 100644 index 000000000..c72e976a8 --- /dev/null +++ b/tests/errors/syntax_err02.v @@ -0,0 +1,7 @@ +module a; +task to ( + input integer [3:0]x +); +endtask +endmodule + diff --git a/tests/errors/syntax_err03.v b/tests/errors/syntax_err03.v new file mode 100644 index 000000000..6eec44ade --- /dev/null +++ b/tests/errors/syntax_err03.v @@ -0,0 +1,7 @@ +module a; +task to ( + input [3]x +); +endtask +endmodule + diff --git a/tests/errors/syntax_err04.v b/tests/errors/syntax_err04.v new file mode 100644 index 000000000..d488e5dbb --- /dev/null +++ b/tests/errors/syntax_err04.v @@ -0,0 +1,4 @@ +module a; +wire [3]x; +endmodule + diff --git a/tests/errors/syntax_err05.v b/tests/errors/syntax_err05.v new file mode 100644 index 000000000..8a1f11532 --- /dev/null +++ b/tests/errors/syntax_err05.v @@ -0,0 +1,4 @@ +module a; +input x[2:0]; +endmodule + diff --git a/tests/errors/syntax_err06.v b/tests/errors/syntax_err06.v new file mode 100644 index 000000000..b35a1dea2 --- /dev/null +++ b/tests/errors/syntax_err06.v @@ -0,0 +1,6 @@ +module a; +initial +begin : label1 +end: label2 +endmodule + diff --git a/tests/errors/syntax_err07.v b/tests/errors/syntax_err07.v new file mode 100644 index 000000000..62bcc6b3e --- /dev/null +++ b/tests/errors/syntax_err07.v @@ -0,0 +1,6 @@ +module a; +wire [5:0]x; +wire [3:0]y; +assign y = (4)55; +endmodule + diff --git a/tests/errors/syntax_err08.v b/tests/errors/syntax_err08.v new file mode 100644 index 000000000..d41bfd6c9 --- /dev/null +++ b/tests/errors/syntax_err08.v @@ -0,0 +1,6 @@ +module a; +wire [5:0]x; +wire [3:0]y; +assign y = x 55; +endmodule + diff --git a/tests/errors/syntax_err09.v b/tests/errors/syntax_err09.v new file mode 100644 index 000000000..1e472eb94 --- /dev/null +++ b/tests/errors/syntax_err09.v @@ -0,0 +1,3 @@ +module a(input wire x = 1'b0); +endmodule + diff --git a/tests/errors/syntax_err10.v b/tests/errors/syntax_err10.v new file mode 100644 index 000000000..d3280405c --- /dev/null +++ b/tests/errors/syntax_err10.v @@ -0,0 +1,3 @@ +module a; +parameter integer [2:0]x=0; +endmodule diff --git a/tests/errors/syntax_err11.v b/tests/errors/syntax_err11.v new file mode 100644 index 000000000..f3cde9dfc --- /dev/null +++ b/tests/errors/syntax_err11.v @@ -0,0 +1,3 @@ +module a; +parameter integer real x=0; +endmodule diff --git a/tests/errors/syntax_err12.v b/tests/errors/syntax_err12.v new file mode 100644 index 000000000..f9b5d5b0b --- /dev/null +++ b/tests/errors/syntax_err12.v @@ -0,0 +1,7 @@ +interface iface; +endinterface + +module a ( + iface x = 1'b0 +); +endmodule diff --git a/tests/errors/syntax_err13.v b/tests/errors/syntax_err13.v new file mode 100644 index 000000000..b5c942fca --- /dev/null +++ b/tests/errors/syntax_err13.v @@ -0,0 +1,4 @@ +module a #(p = 0) +(); +endmodule + diff --git a/tests/fsm/run-test.sh b/tests/fsm/run-test.sh index cf506470d..fbdcbf048 100755 --- a/tests/fsm/run-test.sh +++ b/tests/fsm/run-test.sh @@ -6,7 +6,7 @@ set -e OPTIND=1 -count=100 +count=50 seed="" # default to no seed specified while getopts "c:S:" opt do diff --git a/tests/ice40/.gitignore b/tests/ice40/.gitignore new file mode 100644 index 000000000..9a71dca69 --- /dev/null +++ b/tests/ice40/.gitignore @@ -0,0 +1,4 @@ +*.log +/run-test.mk ++*_synth.v ++*_testbench diff --git a/tests/ice40/add_sub.v b/tests/ice40/add_sub.v new file mode 100644 index 000000000..177c32e30 --- /dev/null +++ b/tests/ice40/add_sub.v @@ -0,0 +1,13 @@ +module top +( + input [3:0] x, + input [3:0] y, + + output [3:0] A, + output [3:0] B + ); + +assign A = x + y; +assign B = x - y; + +endmodule diff --git a/tests/ice40/add_sub.ys b/tests/ice40/add_sub.ys new file mode 100644 index 000000000..4a998d98d --- /dev/null +++ b/tests/ice40/add_sub.ys @@ -0,0 +1,9 @@ +read_verilog add_sub.v +hierarchy -top top +equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd top # Constrain all select calls below inside the top module +select -assert-count 11 t:SB_LUT4 +select -assert-count 6 t:SB_CARRY +select -assert-none t:SB_LUT4 t:SB_CARRY %% t:* %D + diff --git a/tests/ice40/adffs.v b/tests/ice40/adffs.v new file mode 100644 index 000000000..09dc36001 --- /dev/null +++ b/tests/ice40/adffs.v @@ -0,0 +1,87 @@ +module adff + ( input d, clk, clr, output reg q ); + initial begin + q = 0; + end + always @( posedge clk, posedge clr ) + if ( clr ) + q <= 1'b0; + else + q <= d; +endmodule + +module adffn + ( input d, clk, clr, output reg q ); + initial begin + q = 0; + end + always @( posedge clk, negedge clr ) + if ( !clr ) + q <= 1'b0; + else + q <= d; +endmodule + +module dffs + ( input d, clk, pre, clr, output reg q ); + initial begin + q = 0; + end + always @( posedge clk, posedge pre ) + if ( pre ) + q <= 1'b1; + else + q <= d; +endmodule + +module ndffnr + ( input d, clk, pre, clr, output reg q ); + initial begin + q = 0; + end + always @( negedge clk, negedge pre ) + if ( !pre ) + q <= 1'b1; + else + q <= d; +endmodule + +module top ( +input clk, +input clr, +input pre, +input a, +output b,b1,b2,b3 +); + +dffs u_dffs ( + .clk (clk ), + .clr (clr), + .pre (pre), + .d (a ), + .q (b ) + ); + +ndffnr u_ndffnr ( + .clk (clk ), + .clr (clr), + .pre (pre), + .d (a ), + .q (b1 ) + ); + +adff u_adff ( + .clk (clk ), + .clr (clr), + .d (a ), + .q (b2 ) + ); + +adffn u_adffn ( + .clk (clk ), + .clr (clr), + .d (a ), + .q (b3 ) + ); + +endmodule diff --git a/tests/ice40/adffs.ys b/tests/ice40/adffs.ys new file mode 100644 index 000000000..548060b66 --- /dev/null +++ b/tests/ice40/adffs.ys @@ -0,0 +1,11 @@ +read_verilog adffs.v +proc +flatten +equiv_opt -multiclock -assert -map +/ice40/cells_sim.v synth_ice40 # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd top # Constrain all select calls below inside the top module +select -assert-count 1 t:SB_DFFNS +select -assert-count 2 t:SB_DFFR +select -assert-count 1 t:SB_DFFS +select -assert-count 2 t:SB_LUT4 +select -assert-none t:SB_DFFNS t:SB_DFFR t:SB_DFFS t:SB_LUT4 %% t:* %D diff --git a/tests/ice40/alu.v b/tests/ice40/alu.v new file mode 100644 index 000000000..f82cc2e21 --- /dev/null +++ b/tests/ice40/alu.v @@ -0,0 +1,19 @@ +module top ( + input clock, + input [31:0] dinA, dinB, + input [2:0] opcode, + output reg [31:0] dout +); + always @(posedge clock) begin + case (opcode) + 0: dout <= dinA + dinB; + 1: dout <= dinA - dinB; + 2: dout <= dinA >> dinB; + 3: dout <= $signed(dinA) >>> dinB; + 4: dout <= dinA << dinB; + 5: dout <= dinA & dinB; + 6: dout <= dinA | dinB; + 7: dout <= dinA ^ dinB; + endcase + end +endmodule diff --git a/tests/ice40/alu.ys b/tests/ice40/alu.ys new file mode 100644 index 000000000..bd859efc4 --- /dev/null +++ b/tests/ice40/alu.ys @@ -0,0 +1,11 @@ +read_verilog alu.v +hierarchy -top top +proc +flatten +equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd top # Constrain all select calls below inside the top module +select -assert-count 62 t:SB_CARRY +select -assert-count 32 t:SB_DFF +select -assert-count 655 t:SB_LUT4 +select -assert-none t:SB_CARRY t:SB_DFF t:SB_LUT4 %% t:* %D diff --git a/tests/ice40/counter.v b/tests/ice40/counter.v new file mode 100644 index 000000000..52852f8ac --- /dev/null +++ b/tests/ice40/counter.v @@ -0,0 +1,17 @@ +module top (
+out,
+clk,
+reset
+);
+ output [7:0] out;
+ input clk, reset;
+ reg [7:0] out;
+
+ always @(posedge clk, posedge reset)
+ if (reset) begin
+ out <= 8'b0 ;
+ end else
+ out <= out + 1;
+
+
+endmodule
diff --git a/tests/ice40/counter.ys b/tests/ice40/counter.ys new file mode 100644 index 000000000..c65c21622 --- /dev/null +++ b/tests/ice40/counter.ys @@ -0,0 +1,11 @@ +read_verilog counter.v +hierarchy -top top +proc +flatten +equiv_opt -map +/ice40/cells_sim.v synth_ice40 # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd top # Constrain all select calls below inside the top module +select -assert-count 6 t:SB_CARRY +select -assert-count 8 t:SB_DFFR +select -assert-count 8 t:SB_LUT4 +select -assert-none t:SB_CARRY t:SB_DFFR t:SB_LUT4 %% t:* %D diff --git a/tests/ice40/dffs.v b/tests/ice40/dffs.v new file mode 100644 index 000000000..d97840c43 --- /dev/null +++ b/tests/ice40/dffs.v @@ -0,0 +1,37 @@ +module dff + ( input d, clk, output reg q ); + always @( posedge clk ) + q <= d; +endmodule + +module dffe + ( input d, clk, en, output reg q ); + initial begin + q = 0; + end + always @( posedge clk ) + if ( en ) + q <= d; +endmodule + +module top ( +input clk, +input en, +input a, +output b,b1, +); + +dff u_dff ( + .clk (clk ), + .d (a ), + .q (b ) + ); + +dffe u_ndffe ( + .clk (clk ), + .en (en), + .d (a ), + .q (b1 ) + ); + +endmodule diff --git a/tests/ice40/dffs.ys b/tests/ice40/dffs.ys new file mode 100644 index 000000000..ee7f884b1 --- /dev/null +++ b/tests/ice40/dffs.ys @@ -0,0 +1,10 @@ +read_verilog dffs.v +hierarchy -top top +proc +flatten +equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd top # Constrain all select calls below inside the top module +select -assert-count 1 t:SB_DFF +select -assert-count 1 t:SB_DFFE +select -assert-none t:SB_DFF t:SB_DFFE %% t:* %D diff --git a/tests/ice40/div_mod.v b/tests/ice40/div_mod.v new file mode 100644 index 000000000..64a36707d --- /dev/null +++ b/tests/ice40/div_mod.v @@ -0,0 +1,13 @@ +module top +( + input [3:0] x, + input [3:0] y, + + output [3:0] A, + output [3:0] B + ); + +assign A = x % y; +assign B = x / y; + +endmodule diff --git a/tests/ice40/div_mod.ys b/tests/ice40/div_mod.ys new file mode 100644 index 000000000..821d6c301 --- /dev/null +++ b/tests/ice40/div_mod.ys @@ -0,0 +1,9 @@ +read_verilog div_mod.v +hierarchy -top top +flatten +equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd top # Constrain all select calls below inside the top module +select -assert-count 59 t:SB_LUT4 +select -assert-count 41 t:SB_CARRY +select -assert-none t:SB_LUT4 t:SB_CARRY %% t:* %D diff --git a/tests/ice40/dpram.v b/tests/ice40/dpram.v new file mode 100644 index 000000000..3ea4c1f27 --- /dev/null +++ b/tests/ice40/dpram.v @@ -0,0 +1,23 @@ +/* +Example from: https://www.latticesemi.com/-/media/LatticeSemi/Documents/UserManuals/EI/iCEcube201701UserGuide.ashx?document_id=52071 [p. 72]. +*/ +module top (din, write_en, waddr, wclk, raddr, rclk, dout); +parameter addr_width = 8; +parameter data_width = 8; +input [addr_width-1:0] waddr, raddr; +input [data_width-1:0] din; +input write_en, wclk, rclk; +output [data_width-1:0] dout; +reg [data_width-1:0] dout; +reg [data_width-1:0] mem [(1<<addr_width)-1:0] +/* synthesis syn_ramstyle = "no_rw_check" */ ; +always @(posedge wclk) // Write memory. +begin +if (write_en) +mem[waddr] <= din; // Using write address bus. +end +always @(posedge rclk) // Read memory. +begin +dout <= mem[raddr]; // Using read address bus. +end +endmodule diff --git a/tests/ice40/dpram.ys b/tests/ice40/dpram.ys new file mode 100644 index 000000000..4f6a253ea --- /dev/null +++ b/tests/ice40/dpram.ys @@ -0,0 +1,15 @@ +read_verilog dpram.v +hierarchy -top top +proc +memory -nomap +equiv_opt -run :prove -map +/ice40/cells_sim.v synth_ice40 +memory +opt -full + +miter -equiv -flatten -make_assert -make_outputs gold gate miter +sat -verify -prove-asserts -seq 3 -set-init-zero -show-inputs -show-outputs miter + +design -load postopt +cd top +select -assert-count 1 t:SB_RAM40_4K +select -assert-none t:SB_RAM40_4K %% t:* %D diff --git a/tests/ice40/fsm.v b/tests/ice40/fsm.v new file mode 100644 index 000000000..0605bd102 --- /dev/null +++ b/tests/ice40/fsm.v @@ -0,0 +1,73 @@ + module fsm (
+ clock,
+ reset,
+ req_0,
+ req_1,
+ gnt_0,
+ gnt_1
+ );
+ input clock,reset,req_0,req_1;
+ output gnt_0,gnt_1;
+ wire clock,reset,req_0,req_1;
+ reg gnt_0,gnt_1;
+
+ parameter SIZE = 3 ;
+ parameter IDLE = 3'b001,GNT0 = 3'b010,GNT1 = 3'b100,GNT2 = 3'b101 ;
+
+ reg [SIZE-1:0] state;
+ reg [SIZE-1:0] next_state;
+
+ always @ (posedge clock)
+ begin : FSM
+ if (reset == 1'b1) begin
+ state <= #1 IDLE;
+ gnt_0 <= 0;
+ gnt_1 <= 0;
+ end else
+ case(state)
+ IDLE : if (req_0 == 1'b1) begin
+ state <= #1 GNT0;
+ gnt_0 <= 1;
+ end else if (req_1 == 1'b1) begin
+ gnt_1 <= 1;
+ state <= #1 GNT0;
+ end else begin
+ state <= #1 IDLE;
+ end
+ GNT0 : if (req_0 == 1'b1) begin
+ state <= #1 GNT0;
+ end else begin
+ gnt_0 <= 0;
+ state <= #1 IDLE;
+ end
+ GNT1 : if (req_1 == 1'b1) begin
+ state <= #1 GNT2;
+ gnt_1 <= req_0;
+ end
+ GNT2 : if (req_0 == 1'b1) begin
+ state <= #1 GNT1;
+ gnt_1 <= req_1;
+ end
+ default : state <= #1 IDLE;
+ endcase
+ end
+
+ endmodule
+
+ module top (
+input clk,
+input rst,
+input a,
+input b,
+output g0,
+output g1
+);
+
+fsm u_fsm ( .clock(clk),
+ .reset(rst),
+ .req_0(a),
+ .req_1(b),
+ .gnt_0(g0),
+ .gnt_1(g1));
+
+endmodule
diff --git a/tests/ice40/fsm.ys b/tests/ice40/fsm.ys new file mode 100644 index 000000000..4cc8629d6 --- /dev/null +++ b/tests/ice40/fsm.ys @@ -0,0 +1,13 @@ +read_verilog fsm.v +hierarchy -top top +proc +flatten +equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd top # Constrain all select calls below inside the top module + +select -assert-count 2 t:SB_DFFESR +select -assert-count 2 t:SB_DFFSR +select -assert-count 1 t:SB_DFFSS +select -assert-count 13 t:SB_LUT4 +select -assert-none t:SB_DFFESR t:SB_DFFSR t:SB_DFFSS t:SB_LUT4 %% t:* %D diff --git a/tests/ice40/ice40_opt.ys b/tests/ice40/ice40_opt.ys new file mode 100644 index 000000000..b17c69c91 --- /dev/null +++ b/tests/ice40/ice40_opt.ys @@ -0,0 +1,26 @@ +read_verilog -icells -formal <<EOT +module top(input CI, I0, output [1:0] CO, output O); + wire A = 1'b0, B = 1'b0; + \$__ICE40_CARRY_WRAPPER #( + // A[0]: 1010 1010 1010 1010 + // A[1]: 1100 1100 1100 1100 + // A[2]: 1111 0000 1111 0000 + // A[3]: 1111 1111 0000 0000 + .LUT(~16'b 0110_1001_1001_0110) + ) u0 ( + .A(A), + .B(B), + .CI(CI), + .I0(I0), + .I3(CI), + .CO(CO[0]), + .O(O) + ); + SB_CARRY u1 (.I0(~A), .I1(~B), .CI(CI), .CO(CO[1])); +endmodule +EOT + +equiv_opt -assert -map +/ice40/cells_map.v -map +/ice40/cells_sim.v ice40_opt +design -load postopt +select -assert-count 1 t:* +select -assert-count 1 t:$lut diff --git a/tests/ice40/latches.v b/tests/ice40/latches.v new file mode 100644 index 000000000..9dc43e4c2 --- /dev/null +++ b/tests/ice40/latches.v @@ -0,0 +1,58 @@ +module latchp + ( input d, clk, en, output reg q ); + always @* + if ( en ) + q <= d; +endmodule + +module latchn + ( input d, clk, en, output reg q ); + always @* + if ( !en ) + q <= d; +endmodule + +module latchsr + ( input d, clk, en, clr, pre, output reg q ); + always @* + if ( clr ) + q <= 1'b0; + else if ( pre ) + q <= 1'b1; + else if ( en ) + q <= d; +endmodule + + +module top ( +input clk, +input clr, +input pre, +input a, +output b,b1,b2 +); + + +latchp u_latchp ( + .en (clk ), + .d (a ), + .q (b ) + ); + + +latchn u_latchn ( + .en (clk ), + .d (a ), + .q (b1 ) + ); + + +latchsr u_latchsr ( + .en (clk ), + .clr (clr), + .pre (pre), + .d (a ), + .q (b2 ) + ); + +endmodule diff --git a/tests/ice40/latches.ys b/tests/ice40/latches.ys new file mode 100644 index 000000000..f3562559e --- /dev/null +++ b/tests/ice40/latches.ys @@ -0,0 +1,15 @@ +read_verilog latches.v +design -save read + +proc +async2sync # converts latches to a 'sync' variant clocked by a 'super'-clock +flatten +synth_ice40 +equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) + +design -load read +synth_ice40 +cd top +select -assert-count 4 t:SB_LUT4 +select -assert-none t:SB_LUT4 %% t:* %D diff --git a/tests/ice40/logic.v b/tests/ice40/logic.v new file mode 100644 index 000000000..e5343cae0 --- /dev/null +++ b/tests/ice40/logic.v @@ -0,0 +1,18 @@ +module top +( + input [0:7] in, + output B1,B2,B3,B4,B5,B6,B7,B8,B9,B10 + ); + + assign B1 = in[0] & in[1]; + assign B2 = in[0] | in[1]; + assign B3 = in[0] ~& in[1]; + assign B4 = in[0] ~| in[1]; + assign B5 = in[0] ^ in[1]; + assign B6 = in[0] ~^ in[1]; + assign B7 = ~in[0]; + assign B8 = in[0]; + assign B9 = in[0:1] && in [2:3]; + assign B10 = in[0:1] || in [2:3]; + +endmodule diff --git a/tests/ice40/logic.ys b/tests/ice40/logic.ys new file mode 100644 index 000000000..fc5e5b1d8 --- /dev/null +++ b/tests/ice40/logic.ys @@ -0,0 +1,7 @@ +read_verilog logic.v +hierarchy -top top +equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd top # Constrain all select calls below inside the top module +select -assert-count 9 t:SB_LUT4 +select -assert-none t:SB_LUT4 %% t:* %D diff --git a/tests/ice40/macc.v b/tests/ice40/macc.v new file mode 100644 index 000000000..6c3676c83 --- /dev/null +++ b/tests/ice40/macc.v @@ -0,0 +1,25 @@ +/* +Example from: https://www.latticesemi.com/-/media/LatticeSemi/Documents/UserManuals/EI/iCEcube201701UserGuide.ashx?document_id=52071 [p. 77]. +*/ +module top(clk,a,b,c,set); +parameter A_WIDTH = 6 /*4*/; +parameter B_WIDTH = 6 /*3*/; +input set; +input clk; +input signed [(A_WIDTH - 1):0] a; +input signed [(B_WIDTH - 1):0] b; +output signed [(A_WIDTH + B_WIDTH - 1):0] c; +reg [(A_WIDTH + B_WIDTH - 1):0] reg_tmp_c; +assign c = reg_tmp_c; +always @(posedge clk) +begin +if(set) +begin +reg_tmp_c <= 0; +end +else +begin +reg_tmp_c <= a * b + c; +end +end +endmodule diff --git a/tests/ice40/macc.ys b/tests/ice40/macc.ys new file mode 100644 index 000000000..0f4c19be5 --- /dev/null +++ b/tests/ice40/macc.ys @@ -0,0 +1,13 @@ +read_verilog macc.v +proc +hierarchy -top top +#equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 -dsp # equivalency check + +equiv_opt -run :prove -map +/ice40/cells_sim.v synth_ice40 -dsp +async2sync +equiv_opt -run prove: -assert null + +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd top # Constrain all select calls below inside the top module +select -assert-count 1 t:SB_MAC16 +select -assert-none t:SB_MAC16 %% t:* %D diff --git a/tests/ice40/memory.v b/tests/ice40/memory.v new file mode 100644 index 000000000..cb7753f7b --- /dev/null +++ b/tests/ice40/memory.v @@ -0,0 +1,21 @@ +module top +( + input [7:0] data_a, + input [6:1] addr_a, + input we_a, clk, + output reg [7:0] q_a +); + // Declare the RAM variable + reg [7:0] ram[63:0]; + + // Port A + always @ (posedge clk) + begin + if (we_a) + begin + ram[addr_a] <= data_a; + q_a <= data_a; + end + q_a <= ram[addr_a]; + end +endmodule diff --git a/tests/ice40/memory.ys b/tests/ice40/memory.ys new file mode 100644 index 000000000..a66afbae6 --- /dev/null +++ b/tests/ice40/memory.ys @@ -0,0 +1,15 @@ +read_verilog memory.v +hierarchy -top top +proc +memory -nomap +equiv_opt -run :prove -map +/ice40/cells_sim.v synth_ice40 +memory +opt -full + +miter -equiv -flatten -make_assert -make_outputs gold gate miter +sat -verify -prove-asserts -seq 5 -set-init-zero -show-inputs -show-outputs miter + +design -load postopt +cd top +select -assert-count 1 t:SB_RAM40_4K +select -assert-none t:SB_RAM40_4K %% t:* %D diff --git a/tests/ice40/mul.v b/tests/ice40/mul.v new file mode 100644 index 000000000..d5b48b1d7 --- /dev/null +++ b/tests/ice40/mul.v @@ -0,0 +1,11 @@ +module top +( + input [5:0] x, + input [5:0] y, + + output [11:0] A, + ); + +assign A = x * y; + +endmodule diff --git a/tests/ice40/mul.ys b/tests/ice40/mul.ys new file mode 100644 index 000000000..8a0822a84 --- /dev/null +++ b/tests/ice40/mul.ys @@ -0,0 +1,7 @@ +read_verilog mul.v +hierarchy -top top +equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 -dsp # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd top # Constrain all select calls below inside the top module +select -assert-count 1 t:SB_MAC16 +select -assert-none t:SB_MAC16 %% t:* %D diff --git a/tests/ice40/mux.v b/tests/ice40/mux.v new file mode 100644 index 000000000..0814b733e --- /dev/null +++ b/tests/ice40/mux.v @@ -0,0 +1,100 @@ +module mux2 (S,A,B,Y); + input S; + input A,B; + output reg Y; + + always @(*) + Y = (S)? B : A; +endmodule + +module mux4 ( S, D, Y ); + +input[1:0] S; +input[3:0] D; +output Y; + +reg Y; +wire[1:0] S; +wire[3:0] D; + +always @* +begin + case( S ) + 0 : Y = D[0]; + 1 : Y = D[1]; + 2 : Y = D[2]; + 3 : Y = D[3]; + endcase +end + +endmodule + +module mux8 ( S, D, Y ); + +input[2:0] S; +input[7:0] D; +output Y; + +reg Y; +wire[2:0] S; +wire[7:0] D; + +always @* +begin + case( S ) + 0 : Y = D[0]; + 1 : Y = D[1]; + 2 : Y = D[2]; + 3 : Y = D[3]; + 4 : Y = D[4]; + 5 : Y = D[5]; + 6 : Y = D[6]; + 7 : Y = D[7]; + endcase +end + +endmodule + +module mux16 (D, S, Y); + input [15:0] D; + input [3:0] S; + output Y; + +assign Y = D[S]; + +endmodule + + +module top ( +input [3:0] S, +input [15:0] D, +output M2,M4,M8,M16 +); + +mux2 u_mux2 ( + .S (S[0]), + .A (D[0]), + .B (D[1]), + .Y (M2) + ); + + +mux4 u_mux4 ( + .S (S[1:0]), + .D (D[3:0]), + .Y (M4) + ); + +mux8 u_mux8 ( + .S (S[2:0]), + .D (D[7:0]), + .Y (M8) + ); + +mux16 u_mux16 ( + .S (S[3:0]), + .D (D[15:0]), + .Y (M16) + ); + +endmodule diff --git a/tests/ice40/mux.ys b/tests/ice40/mux.ys new file mode 100644 index 000000000..182b49499 --- /dev/null +++ b/tests/ice40/mux.ys @@ -0,0 +1,8 @@ +read_verilog mux.v +proc +flatten +equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd top # Constrain all select calls below inside the top module +select -assert-count 19 t:SB_LUT4 +select -assert-none t:SB_LUT4 %% t:* %D diff --git a/tests/ice40/rom.v b/tests/ice40/rom.v new file mode 100644 index 000000000..0a0f41f37 --- /dev/null +++ b/tests/ice40/rom.v @@ -0,0 +1,18 @@ +/* +Example from: https://www.latticesemi.com/-/media/LatticeSemi/Documents/UserManuals/EI/iCEcube201701UserGuide.ashx?document_id=52071 [p. 74]. +*/ +module top(data, addr); +output [3:0] data; +input [4:0] addr; +always @(addr) begin +case (addr) +0 : data = 'h4; +1 : data = 'h9; +2 : data = 'h1; +15 : data = 'h8; +16 : data = 'h1; +17 : data = 'h0; +default : data = 'h0; +endcase +end +endmodule diff --git a/tests/ice40/rom.ys b/tests/ice40/rom.ys new file mode 100644 index 000000000..41d214e2a --- /dev/null +++ b/tests/ice40/rom.ys @@ -0,0 +1,8 @@ +read_verilog rom.v +proc +flatten +equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd top # Constrain all select calls below inside the top module +select -assert-count 5 t:SB_LUT4 +select -assert-none t:SB_LUT4 %% t:* %D diff --git a/tests/ice40/run-test.sh b/tests/ice40/run-test.sh new file mode 100755 index 000000000..46716f9a0 --- /dev/null +++ b/tests/ice40/run-test.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +set -e +{ +echo "all::" +for x in *.ys; do + echo "all:: run-$x" + echo "run-$x:" + echo " @echo 'Running $x..'" + echo " @../../yosys -ql ${x%.ys}.log -w 'Yosys has only limited support for tri-state logic at the moment.' $x" +done +for s in *.sh; do + if [ "$s" != "run-test.sh" ]; then + echo "all:: run-$s" + echo "run-$s:" + echo " @echo 'Running $s..'" + echo " @bash $s" + fi +done +} > run-test.mk +exec ${MAKE:-make} -f run-test.mk diff --git a/tests/ice40/shifter.v b/tests/ice40/shifter.v new file mode 100644 index 000000000..c55632552 --- /dev/null +++ b/tests/ice40/shifter.v @@ -0,0 +1,22 @@ +module top (
+out,
+clk,
+in
+);
+ output [7:0] out;
+ input signed clk, in;
+ reg signed [7:0] out = 0;
+
+ always @(posedge clk)
+ begin
+`ifndef BUG
+ out <= out >> 1;
+ out[7] <= in;
+`else
+
+ out <= out << 1;
+ out[7] <= in;
+`endif
+ end
+
+endmodule
diff --git a/tests/ice40/shifter.ys b/tests/ice40/shifter.ys new file mode 100644 index 000000000..47d95d298 --- /dev/null +++ b/tests/ice40/shifter.ys @@ -0,0 +1,9 @@ +read_verilog shifter.v +hierarchy -top top +proc +flatten +equiv_opt -assert -map +/ice40/cells_sim.v synth_ice40 # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd top # Constrain all select calls below inside the top module +select -assert-count 8 t:SB_DFF +select -assert-none t:SB_DFF %% t:* %D diff --git a/tests/ice40/tribuf.v b/tests/ice40/tribuf.v new file mode 100644 index 000000000..870a02584 --- /dev/null +++ b/tests/ice40/tribuf.v @@ -0,0 +1,23 @@ +module tristate (en, i, o); + input en; + input i; + output o; + + assign o = en ? i : 1'bz; + +endmodule + + +module top ( +input en, +input a, +output b +); + +tristate u_tri ( + .en (en ), + .i (a ), + .o (b ) + ); + +endmodule diff --git a/tests/ice40/tribuf.ys b/tests/ice40/tribuf.ys new file mode 100644 index 000000000..d1e1b3108 --- /dev/null +++ b/tests/ice40/tribuf.ys @@ -0,0 +1,9 @@ +read_verilog tribuf.v +hierarchy -top top +proc +flatten +equiv_opt -assert -map +/ice40/cells_sim.v -map +/simcells.v synth_ice40 # equivalency check +design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +cd top # Constrain all select calls below inside the top module +select -assert-count 1 t:$_TBUF_ +select -assert-none t:$_TBUF_ %% t:* %D diff --git a/tests/liberty/.gitignore b/tests/liberty/.gitignore new file mode 100644 index 000000000..e6ec49c4a --- /dev/null +++ b/tests/liberty/.gitignore @@ -0,0 +1,2 @@ +*.log +test.ys diff --git a/tests/liberty/busdef.lib b/tests/liberty/busdef.lib new file mode 100644 index 000000000..b5e3d50b9 --- /dev/null +++ b/tests/liberty/busdef.lib @@ -0,0 +1,81 @@ +/********************************************/ +/* */ +/* Supergate cell library for Bench marking */ +/* */ +/* Symbiotic EDA GmbH / Moseley Instruments */ +/* Niels A. Moseley */ +/* */ +/* Process: none */ +/* */ +/* Date : 02-11-2018 */ +/* Version: 1.0 */ +/* */ +/********************************************/ + +library(supergate) { + technology (cmos); + revision : 1.0; + + time_unit : "1ps"; + pulling_resistance_unit : "1kohm"; + voltage_unit : "1V"; + current_unit : "1uA"; + + capacitive_load_unit(1,ff); + + default_inout_pin_cap : 7.0; + default_input_pin_cap : 7.0; + default_output_pin_cap : 0.0; + default_fanout_load : 1.0; + + default_wire_load_capacitance : 0.1; + default_wire_load_resistance : 1.0e-3; + default_wire_load_area : 0.0; + + nom_process : 1.0; + nom_temperature : 25.0; + nom_voltage : 1.2; + + delay_model : generic_cmos; + + type( IO_bus_3_to_0 ) { + base_type : array ; + data_type : bit ; + bit_width : 4; + bit_from : 3 ; + bit_to : 0 ; + downto : true ; + } + + cell (SRAM) { + area : 1 ; + memory() { + type : ram; + address_width : 4; + word_width : 4; + } + pin(CE1) { + direction : input; + capacitance : 0.021; + max_transition : 1.024; + switch_pin : true; + } + bus(I1) { + bus_type : IO_bus_3_to_0 ; + direction : input; + pin (I1[3:0]) { + timing() { + related_pin : "CE1" ; + timing_type : setup_rising ; + rise_constraint (scalar) { + values("0.0507786"); + } + fall_constraint (scalar) { + values("0.0507786"); + } + } + } + } + } + +} /* end */ diff --git a/tests/liberty/normal.lib b/tests/liberty/normal.lib new file mode 100644 index 000000000..4621194dd --- /dev/null +++ b/tests/liberty/normal.lib @@ -0,0 +1,359 @@ +/********************************************/ +/* */ +/* Supergate cell library for Bench marking */ +/* */ +/* Symbiotic EDA GmbH / Moseley Instruments */ +/* Niels A. Moseley */ +/* */ +/* Process: none */ +/* */ +/* Date : 02-11-2018 */ +/* Version: 1.0 */ +/* */ +/********************************************/ + +library(supergate) { + technology (cmos); + revision : 1.0; + + time_unit : "1ps"; + pulling_resistance_unit : "1kohm"; + voltage_unit : "1V"; + current_unit : "1uA"; + + capacitive_load_unit(1,ff); + + default_inout_pin_cap : 7.0; + default_input_pin_cap : 7.0; + default_output_pin_cap : 0.0; + default_fanout_load : 1.0; + + default_wire_load_capacitance : 0.1; + default_wire_load_resistance : 1.0e-3; + default_wire_load_area : 0.0; + + nom_process : 1.0; + nom_temperature : 25.0; + nom_voltage : 1.2; + + delay_model : generic_cmos; + + /* Inverter */ + cell (inv) { + area : 1; + pin(A) { + direction : input; + } + + pin(Y) { + direction : output; + function : "A'"; + } + } + + /* tri-state inverter */ + cell (tri_inv) { + area : 4; + pin(A) { + direction : input; + } + pin(S) { + direction : input; + } + pin(Z) { + direction : output; + function : "A'"; + three_State : "S'"; + } + } + + cell (buffer) { + area : 5; + pin(A) { + direction : input; + } + pin(Y) { + direction : output; + function : "A"; + } + } + + /* 2-input NAND gate */ + cell (nand2) { + area : 3; + pin(A) { + direction : input; + } + pin(B) { + direction : input; + } + pin(Y) { + direction: output; + function : "(A * B)'"; + } + } + + /* 2-input NOR gate */ + cell (nor2) { + area : 3; + pin(A) { + direction : input; + } + pin(B) { + direction : input; + } + pin(Y) { + direction: output; + function : "(A + B)'"; + } + } + + /* 2-input XOR */ + cell (xor2) { + area : 6; + pin(A) { + direction : input; + } + pin(B) { + direction : input; + } + pin(Y) { + direction: output; + function : "(A *B') + (A' * B)"; + } + } + + /* 2-input inverting MUX */ + cell (imux2) { + area : 5; + pin(A) { + direction : input; + } + pin(B) { + direction : input; + } + pin(S) { + direction : input; + } + pin(Y) { + direction: output; + function : "( (A * S) + (B * S') )'"; + } + } + + /* D-type flip-flop with asynchronous reset and preset */ + cell (dff) { + area : 6; + ff("IQ", "IQN") { + next_state : "D"; + clocked_on : "CLK"; + clear : "RESET"; + preset : "PRESET"; + clear_preset_var1 : L; + clear_preset_var2 : L; + } + pin(D) { + direction : input; + } + pin(CLK) { + direction : input; + } + pin(RESET) { + direction : input; + } + pin(PRESET) { + direction : input; + } + pin(Q) { + direction: output; + function : "IQ"; + timing() { + timing_type : rising_edge; + intrinsic_rise : 65; + intrinsic_fall : 65; + rise_resistance : 0; + fall_resistance : 0; + related_pin : "CLK"; + } + timing () { + timing_type : clear; + timing_sense : positive_unate; + intrinsic_fall : 75; + related_pin : "RESET"; + } + timing () { + timing_type : preset; + timing_sense : negative_unate; + intrinsic_rise : 75; + related_pin : "PRESET"; + } + } + pin(QN) { + direction: output; + function : "IQN"; + timing() { + timing_type : rising_edge; + intrinsic_rise : 65; + intrinsic_fall : 65; + rise_resistance : 0; + fall_resistance : 0; + related_pin : "CLK"; + } + timing () { + timing_type : preset; + timing_sense : negative_unate; + intrinsic_rise : 75; + related_pin : "RESET"; + } + timing () { + timing_type : clear; + timing_sense : positive_unate; + intrinsic_fall : 75; + related_pin : "PRESET"; + } + } + } + + /* Latch */ + cell(latch) { + area : 5; + latch ("IQ","IQN") { + enable : "G"; + data_in : "D"; + } + + pin(D) { + direction : input; + } + pin(G) { + direction : input; + } + + pin(Q) { + direction : output; + function : "IQ"; + internal_node : "Q"; + + timing() { + timing_type : rising_edge; + intrinsic_rise : 65; + intrinsic_fall : 65; + rise_resistance : 0; + fall_resistance : 0; + related_pin : "G"; + } + + timing() { + timing_sense : positive_unate; + intrinsic_rise : 65; + intrinsic_fall : 65; + rise_resistance : 0; + fall_resistance : 0; + related_pin : "D"; + } + } + + pin(QN) { + direction : output; + function : "IQN"; + internal_node : "QN"; + + timing() { + timing_type : rising_edge; + intrinsic_rise : 65; + intrinsic_fall : 65; + rise_resistance : 0; + fall_resistance : 0; + related_pin : "G"; + } + + timing() { + timing_sense : negative_unate; + intrinsic_rise : 65; + intrinsic_fall : 65; + rise_resistance : 0; + fall_resistance : 0; + related_pin : "D"; + } + } + } + + /* 3 input AND-OR-INVERT gate */ + cell (aoi211) { + area : 3; + pin(A) { + direction : input; + } + pin(B) { + direction : input; + } + pin(C) { + direction : input; + } + pin(Y) { + direction: output; + function : "((A * B) + C)'"; + } + } + + + /* 3 input OR-AND-INVERT gate */ + cell (oai211) { + area : 3; + pin(A) { + direction : input; + } + pin(B) { + direction : input; + } + pin(C) { + direction : input; + } + pin(Y) { + direction: output; + function : "((A + B) * C)'"; + } + } + + /* half adder */ + cell (halfadder) { + area : 5; + pin(A) { + direction : input; + } + pin(B) { + direction : input; + } + pin(C) { + direction : output; + function : "(A * B)"; + } + pin(Y) { + direction: output; + function : "(A *B') + (A' * B)"; + } + } + + /* full adder */ + cell (fulladder) { + area : 8; + pin(A) { + direction : input; + } + pin(B) { + direction : input; + } + pin(CI) { + direction : input; + } + pin(CO) { + direction : output; + function : "(((A * B)+(B * CI))+(CI * A))"; + } + pin(Y) { + direction: output; + function : "((A^B)^CI)"; + } + } + +} /* end */ diff --git a/tests/liberty/processdefs.lib b/tests/liberty/processdefs.lib new file mode 100644 index 000000000..37a6bbaf8 --- /dev/null +++ b/tests/liberty/processdefs.lib @@ -0,0 +1,48 @@ +/********************************************/ +/* */ +/* Supergate cell library for Bench marking */ +/* */ +/* Symbiotic EDA GmbH / Moseley Instruments */ +/* Niels A. Moseley */ +/* */ +/* Process: none */ +/* */ +/* Date : 25-03-2019 */ +/* Version: 1.0 */ +/* */ +/********************************************/ + +library(processdefs) { + technology (cmos); + revision : 1.0; + + time_unit : "1ps"; + pulling_resistance_unit : "1kohm"; + voltage_unit : "1V"; + current_unit : "1uA"; + + capacitive_load_unit(1,ff); + + default_inout_pin_cap : 7.0; + default_input_pin_cap : 7.0; + default_output_pin_cap : 0.0; + default_fanout_load : 1.0; + + default_wire_load_capacitance : 0.1; + default_wire_load_resistance : 1.0e-3; + default_wire_load_area : 0.0; + + nom_process : 1.0; + nom_temperature : 25.0; + nom_voltage : 1.2; + + delay_model : generic_cmos; + + define_cell_area(bond_pads,pad_slots) + input_voltage(cmos) { + vil : 0.3 * VDD ; + vih : 0.7 * VDD ; + vimin : -0.5 ; + vimax : VDD + 0.5 ; + } +} diff --git a/tests/liberty/run-test.sh b/tests/liberty/run-test.sh new file mode 100755 index 000000000..7e2ed2370 --- /dev/null +++ b/tests/liberty/run-test.sh @@ -0,0 +1,10 @@ +#!/bin/bash +set -e + +for x in *.lib; do + echo "Running $x.." + echo "read_verilog small.v" > test.ys + echo "synth -top small" >> test.ys + echo "dfflibmap -liberty ${x}" >> test.ys + ../../yosys -ql ${x%.lib}.log -s test.ys +done diff --git a/tests/liberty/semicolextra.lib b/tests/liberty/semicolextra.lib new file mode 100644 index 000000000..6a7fa77cc --- /dev/null +++ b/tests/liberty/semicolextra.lib @@ -0,0 +1,48 @@ +/* + + Test case for https://www.reddit.com/r/yosys/comments/b5texg/yosys_fails_to_parse_apparentlycorrect_liberty/ + + fall_constraint (SETUP_HOLD) formatting. + +*/ + +library(supergate) { + technology (cmos); + revision : 1.0; + + cell (DFF) { + cell_footprint : dff; + area : 50; + pin(D) { + direction : input; + capacitance : 0.002; + timing() { + related_pin : "CK"; + timing_type : setup_rising; + + fall_constraint (SETUP_HOLD) { values ("0.4000, 0.3000, 0.2000, 0.1000, 0.0000", \ + "0.4000, 0.3000, 0.2000, 0.1000, 0.000", \ + "0.5000, 0.4000, 0.3000, 0.2000, 0.0000", \ + "0.7000, 0.6000, 0.5000, 0.4000, 0.2000", \ + "1.0000, 1.0000, 0.9000, 0.8000, 0.6000"); }; + } + } + + pin(CK) { + direction : input; + clock : true; + capacitance : 0.00290; + } + + ff(IQ,IQN) { + clocked_on : "CK"; + next_state : "D"; + } + pin(Q) { + direction : output; + capacitance : 0.003; + max_capacitance : 0.3; + } + cell_leakage_power : 0.3; + } +} diff --git a/tests/liberty/semicolmissing.lib b/tests/liberty/semicolmissing.lib new file mode 100644 index 000000000..f7c20750a --- /dev/null +++ b/tests/liberty/semicolmissing.lib @@ -0,0 +1,72 @@ +/********************************************/ +/* */ +/* Supergate cell library for Bench marking */ +/* */ +/* Symbiotic EDA GmbH / Moseley Instruments */ +/* Niels A. Moseley */ +/* */ +/* Process: none */ +/* */ +/* Date : 24-03-2019 */ +/* Version: 1.0 */ +/* Version: 1.1 - Removed semicolons in */ +/* full adder */ +/* */ +/********************************************/ + +/* + semi colon is missing in full-adder specification + some TSMC liberty files are formatted this way.. +*/ + +library(supergate) { + technology (cmos); + revision : 1.0; + + time_unit : "1ps"; + pulling_resistance_unit : "1kohm"; + voltage_unit : "1V"; + current_unit : "1uA"; + + capacitive_load_unit(1,ff); + + default_inout_pin_cap : 7.0; + default_input_pin_cap : 7.0; + default_output_pin_cap : 0.0; + default_fanout_load : 1.0; + + default_wire_load_capacitance : 0.1; + default_wire_load_resistance : 1.0e-3; + default_wire_load_area : 0.0; + + nom_process : 1.0; + nom_temperature : 25.0; + nom_voltage : 1.2; + + delay_model : generic_cmos; + + /* full adder */ + cell (fulladder) { + area : 8 + pin(A) { + direction : input + } + pin(B) { + direction : input + } + pin(CI) { + direction : input + } + pin(CO) { + direction : output + function : "(((A * B)+(B * CI))+(CI * A))" + } + pin(Y) { + direction: output + function : "((A^B)^CI)" + } + } + +} /* end */ + + diff --git a/tests/liberty/small.v b/tests/liberty/small.v new file mode 100644 index 000000000..bd94be4fc --- /dev/null +++ b/tests/liberty/small.v @@ -0,0 +1,16 @@ +/** small, meaningless design to test loading of liberty files */ + +module small +( + input clk, + output reg[7:0] count +); + +initial count = 0; + +always @ (posedge clk) +begin + count <= count + 1'b1; +end + +endmodule diff --git a/tests/lut/.gitignore b/tests/lut/.gitignore new file mode 100644 index 000000000..397b4a762 --- /dev/null +++ b/tests/lut/.gitignore @@ -0,0 +1 @@ +*.log diff --git a/tests/lut/check_map.ys b/tests/lut/check_map.ys new file mode 100644 index 000000000..46854e82e --- /dev/null +++ b/tests/lut/check_map.ys @@ -0,0 +1,6 @@ +simplemap +equiv_opt -assert techmap -D LUT_WIDTH=4 -map +/cmp2lut.v +design -load postopt +equiv_opt -assert techmap -D LUT_WIDTH=4 -map +/gate2lut.v +design -load postopt +select -assert-count 0 t:* t:$lut %d diff --git a/tests/lut/check_map_lut6.ys b/tests/lut/check_map_lut6.ys new file mode 100644 index 000000000..8a32e4d10 --- /dev/null +++ b/tests/lut/check_map_lut6.ys @@ -0,0 +1,7 @@ +chparam -set LUT_WIDTH 6 top +simplemap +equiv_opt -assert techmap -D LUT_WIDTH=6 -map +/cmp2lut.v +design -load postopt +equiv_opt -assert techmap -D LUT_WIDTH=6 -map +/gate2lut.v +design -load postopt +select -assert-count 0 t:* t:$lut %d diff --git a/tests/lut/map_and.v b/tests/lut/map_and.v new file mode 100644 index 000000000..68ae33fd6 --- /dev/null +++ b/tests/lut/map_and.v @@ -0,0 +1,5 @@ +module top(...); + input a, b; + output y; + assign y = a&b; +endmodule diff --git a/tests/lut/map_cmp.v b/tests/lut/map_cmp.v new file mode 100644 index 000000000..0014eb9ac --- /dev/null +++ b/tests/lut/map_cmp.v @@ -0,0 +1,30 @@ +module top(...); + parameter LUT_WIDTH = 4; // Multiples of 2 only + input [LUT_WIDTH-1:0] a; + + output o1_1 = {(LUT_WIDTH/2){2'b10}} <= a; + output o1_2 = {(LUT_WIDTH/2){2'b10}} < a; + output o1_3 = {(LUT_WIDTH/2){2'b10}} >= a; + output o1_4 = {(LUT_WIDTH/2){2'b10}} > a; + output o1_5 = {(LUT_WIDTH/2){2'b10}} == a; + output o1_6 = {(LUT_WIDTH/2){2'b10}} != a; + + output o2_1 = a <= {(LUT_WIDTH/2){2'b10}}; + output o2_2 = a < {(LUT_WIDTH/2){2'b10}}; + output o2_3 = a >= {(LUT_WIDTH/2){2'b10}}; + output o2_4 = a > {(LUT_WIDTH/2){2'b10}}; + output o2_5 = a == {(LUT_WIDTH/2){2'b10}}; + output o2_6 = a != {(LUT_WIDTH/2){2'b10}}; + + output o3_1 = {(LUT_WIDTH/2){2'sb01}} <= $signed(a); + output o3_2 = {(LUT_WIDTH/2){2'sb01}} < $signed(a); + output o3_3 = {(LUT_WIDTH/2){2'sb01}} >= $signed(a); + output o3_4 = {(LUT_WIDTH/2){2'sb01}} > $signed(a); + output o3_5 = {(LUT_WIDTH/2){2'sb01}} == $signed(a); + output o3_6 = {(LUT_WIDTH/2){2'sb01}} != $signed(a); + + output o4_1 = $signed(a) <= {LUT_WIDTH{1'sb0}}; + output o4_2 = $signed(a) < {LUT_WIDTH{1'sb0}}; + output o4_3 = $signed(a) >= {LUT_WIDTH{1'sb0}}; + output o4_4 = $signed(a) > {LUT_WIDTH{1'sb0}}; +endmodule diff --git a/tests/lut/map_mux.v b/tests/lut/map_mux.v new file mode 100644 index 000000000..ccecf3023 --- /dev/null +++ b/tests/lut/map_mux.v @@ -0,0 +1,5 @@ +module top(...); + input a, b, s; + output y; + assign y = s?a:b; +endmodule diff --git a/tests/lut/map_not.v b/tests/lut/map_not.v new file mode 100644 index 000000000..385997414 --- /dev/null +++ b/tests/lut/map_not.v @@ -0,0 +1,5 @@ +module top(...); + input a; + output y; + assign y = ~a; +endmodule diff --git a/tests/lut/map_or.v b/tests/lut/map_or.v new file mode 100644 index 000000000..8b8c55188 --- /dev/null +++ b/tests/lut/map_or.v @@ -0,0 +1,5 @@ +module top(...); + input a, b; + output y; + assign y = a|b; +endmodule diff --git a/tests/lut/map_xor.v b/tests/lut/map_xor.v new file mode 100644 index 000000000..708a05789 --- /dev/null +++ b/tests/lut/map_xor.v @@ -0,0 +1,5 @@ +module top(...); + input a, b; + output y; + assign y = a^b; +endmodule diff --git a/tests/lut/run-test.sh b/tests/lut/run-test.sh new file mode 100755 index 000000000..f8964f146 --- /dev/null +++ b/tests/lut/run-test.sh @@ -0,0 +1,11 @@ +#!/bin/bash +set -e +for x in *.v; do + echo "Running $x.." + ../../yosys -q -s check_map.ys -l ${x%.v}.log $x +done + +for x in map_cmp.v; do + echo "Running $x.." + ../../yosys -q -s check_map_lut6.ys -l ${x%.v}_lut6.log $x +done diff --git a/tests/memories/firrtl_938.v b/tests/memories/firrtl_938.v new file mode 100644 index 000000000..af5efcd25 --- /dev/null +++ b/tests/memories/firrtl_938.v @@ -0,0 +1,22 @@ +module top +( + input [7:0] data_a, + input [6:1] addr_a, + input we_a, clk, + output reg [7:0] q_a +); + // Declare the RAM variable + reg [7:0] ram[63:0]; + + // Port A + always @ (posedge clk) + begin + if (we_a) + begin + ram[addr_a] <= data_a; + q_a <= data_a; + end + q_a <= ram[addr_a]; + end + +endmodule diff --git a/tests/memories/issue00335.v b/tests/memories/issue00335.v new file mode 100644 index 000000000..f3b6e5dfe --- /dev/null +++ b/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<<SIZE) - 1; i = i + 1) + mem[i] <= 0; + end + + always @(posedge clk) + if (sel) begin + if (~we) + dat_o <= mem[adr]; + else + mem[adr] <= dat_i; + end +endmodule diff --git a/tests/memories/issue00710.v b/tests/memories/issue00710.v new file mode 100644 index 000000000..7a5fad1c2 --- /dev/null +++ b/tests/memories/issue00710.v @@ -0,0 +1,17 @@ +// expect-wr-ports 1 +// expect-rd-ports 1 +// expect-rd-clk \clk + +module top(input clk, input we, re, reset, input [7:0] addr, wdata, output reg [7:0] rdata); + +reg [7:0] bram[0:255]; +(* keep *) reg dummy; + +always @(posedge clk) + if (reset) + dummy <= 1'b0; + else if (re) + rdata <= bram[addr]; + else if (we) + bram[addr] <= wdata; +endmodule diff --git a/tests/memories/read_two_mux.v b/tests/memories/read_two_mux.v new file mode 100644 index 000000000..4f2e7e1cd --- /dev/null +++ b/tests/memories/read_two_mux.v @@ -0,0 +1,16 @@ +// expect-wr-ports 1 +// expect-rd-ports 1 +// expect-no-rd-clk + +module top(input clk, input we, re, reset, input [7:0] addr, wdata, output reg [7:0] rdata); + +reg [7:0] bram[0:255]; +(* keep *) reg dummy; + +always @(posedge clk) begin + rdata <= re ? (reset ? 8'b0 : bram[addr]) : rdata; + if (we) + bram[addr] <= wdata; +end + +endmodule diff --git a/tests/memories/run-test.sh b/tests/memories/run-test.sh index 734a96682..8d1a8b413 100755 --- a/tests/memories/run-test.sh +++ b/tests/memories/run-test.sh @@ -4,17 +4,19 @@ set -e OPTIND=1 seed="" # default to no seed specified -while getopts "S:" opt +abcopt="" +while getopts "A:S:" opt do case "$opt" in + A) abcopt="-A $OPTARG" ;; S) seed="-S $OPTARG" ;; esac done shift "$((OPTIND-1))" -bash ../tools/autotest.sh $seed -G *.v +bash ../tools/autotest.sh $abcopt $seed -G *.v -for f in `egrep -l 'expect-(wr|rd)-ports' *.v`; do +for f in `egrep -l 'expect-(wr-ports|rd-ports|rd-clk)' *.v`; do echo -n "Testing expectations for $f .." ../../yosys -qp "proc; opt; memory -nomap;; dump -outfile ${f%.v}.dmp t:\$mem" $f if grep -q expect-wr-ports $f; then @@ -25,6 +27,14 @@ for f in `egrep -l 'expect-(wr|rd)-ports' *.v`; do grep -q "parameter \\\\RD_PORTS $(gawk '/expect-rd-ports/ { print $3; }' $f)\$" ${f%.v}.dmp || { echo " ERROR: Unexpected number of read ports."; false; } fi + if grep -q expect-rd-clk $f; then + grep -q "connect \\\\RD_CLK \\$(gawk '/expect-rd-clk/ { print $3; }' $f)\$" ${f%.v}.dmp || + { echo " ERROR: Unexpected read clock."; false; } + fi + if grep -q expect-no-rd-clk $f; then + grep -q "connect \\\\RD_CLK 1'x\$" ${f%.v}.dmp || + { echo " ERROR: Expected no read clock."; false; } + fi echo " ok." done diff --git a/tests/opt/.gitignore b/tests/opt/.gitignore new file mode 100644 index 000000000..397b4a762 --- /dev/null +++ b/tests/opt/.gitignore @@ -0,0 +1 @@ +*.log diff --git a/tests/opt/opt_expr.ys b/tests/opt/opt_expr.ys new file mode 100644 index 000000000..e0acead82 --- /dev/null +++ b/tests/opt/opt_expr.ys @@ -0,0 +1,293 @@ + +read_verilog <<EOT +module opt_expr_add_test(input [3:0] i, input [7:0] j, output [8:0] o); + assign o = (i << 4) + j; +endmodule +EOT + +equiv_opt -assert opt_expr -fine +design -load postopt + +select -assert-count 1 t:$add r:A_WIDTH=5 r:B_WIDTH=4 r:Y_WIDTH=5 %i %i %i + +########## + +# alumacc version of above +design -reset +read_verilog <<EOT +module opt_expr_add_test(input [3:0] i, input [7:0] j, output [8:0] o); + assign o = (i << 4) + j; +endmodule +EOT + +alumacc +equiv_opt -assert opt_expr -fine +design -load postopt + +select -assert-count 1 t:$alu r:A_WIDTH=4 r:B_WIDTH=5 r:Y_WIDTH=5 %i %i %i + +########## + +design -reset +read_verilog <<EOT +module opt_expr_add_signed_test(input signed [3:0] i, input signed [7:0] j, output signed [8:0] o); + assign o = (i << 4) + j; +endmodule +EOT + +equiv_opt -assert opt_expr -fine +design -load postopt + +select -assert-count 1 t:$add r:A_WIDTH=5 r:B_WIDTH=4 r:Y_WIDTH=5 %i %i %i + +########## + +# alumacc version of above +design -reset +read_verilog <<EOT +module opt_expr_add_signed_test(input signed [3:0] i, input signed [7:0] j, output signed [8:0] o); + assign o = (i << 4) + j; +endmodule +EOT + +alumacc +equiv_opt -assert opt_expr -fine +design -load postopt + +select -assert-count 1 t:$alu r:A_WIDTH=4 r:B_WIDTH=5 r:Y_WIDTH=5 %i %i %i + +########## + +design -reset +read_verilog <<EOT +module opt_expr_sub_test1(input [3:0] i, input [7:0] j, output [8:0] o); + assign o = j - (i << 4); +endmodule +EOT + +equiv_opt -assert opt_expr -fine +design -load postopt + +select -assert-count 1 t:$sub r:A_WIDTH=4 r:B_WIDTH=5 r:Y_WIDTH=5 %i %i %i + +########## + +# alumacc version of above +design -reset +read_verilog <<EOT +module opt_expr_sub_test1(input [3:0] i, input [7:0] j, output [8:0] o); + assign o = j - (i << 4); +endmodule +EOT + +alumacc +equiv_opt -assert opt_expr -fine +design -load postopt + +dump +select -assert-count 1 t:$alu r:A_WIDTH=4 r:B_WIDTH=5 r:Y_WIDTH=5 %i %i %i + +########## + +design -reset +read_verilog <<EOT +module opt_expr_sub_signed_test1(input signed [3:0] i, input signed [7:0] j, output signed [8:0] o); + assign o = j - (i << 4); +endmodule +EOT + +equiv_opt -assert opt_expr -fine +design -load postopt + +select -assert-count 1 t:$sub r:A_WIDTH=4 r:B_WIDTH=5 r:Y_WIDTH=5 %i %i %i + +########## + +# alumacc version of above +design -reset +read_verilog <<EOT +module opt_expr_sub_signed_test1(input signed [3:0] i, input signed [7:0] j, output signed [8:0] o); + assign o = j - (i << 4); +endmodule +EOT + +alumacc +equiv_opt -assert opt_expr -fine +design -load postopt + +select -assert-count 1 t:$alu r:A_WIDTH=4 r:B_WIDTH=5 r:Y_WIDTH=5 %i %i %i + +########## + +design -reset +read_verilog <<EOT +module opt_expr_sub_test2(input [3:0] i, input [7:0] j, output [8:0] o); + assign o = (i << 4) - j; +endmodule +EOT + +equiv_opt -assert opt_expr -fine +design -load postopt + +select -assert-count 1 t:$sub r:A_WIDTH=9 r:B_WIDTH=8 r:Y_WIDTH=9 %i %i %i + +########## + +# alumacc version of above +design -reset +read_verilog <<EOT +module opt_expr_sub_test2(input [3:0] i, input [7:0] j, output [8:0] o); + assign o = (i << 4) - j; +endmodule +EOT + +alumacc +opt_expr -fine +equiv_opt -assert opt_expr -fine +design -load postopt + +select -assert-count 1 t:$alu r:A_WIDTH=9 r:B_WIDTH=8 r:Y_WIDTH=9 %i %i %i + +########## + +design -reset +read_verilog <<EOT +module opt_expr_sub_test4(input [3:0] i, output [8:0] o); + assign o = 5'b00010 - i; +endmodule +EOT + +wreduce +equiv_opt -assert opt_expr -fine +design -load postopt + +select -assert-count 1 t:$sub r:A_WIDTH=2 r:B_WIDTH=4 r:Y_WIDTH=5 %i %i %i + +########## + +# alumacc version of above +design -reset +read_verilog <<EOT +module opt_expr_sub_test4(input [3:0] i, output [8:0] o); + assign o = 5'b00010 - i; +endmodule +EOT + +wreduce +alumacc +equiv_opt -assert opt_expr -fine +design -load postopt + +select -assert-count 1 t:$alu r:A_WIDTH=2 r:B_WIDTH=4 r:Y_WIDTH=5 %i %i %i + +########### + +design -reset +read_verilog -icells <<EOT +module opt_expr_alu_test_ci0_bi0(input [7:0] a, input [3:0] b, output [8:0] x, y, co); + \$alu #(.A_SIGNED(0), .B_SIGNED(0), .A_WIDTH(8), .B_WIDTH(8), .Y_WIDTH(9)) alu (.A(a), .B({b, 4'b0000}), .CI(1'b0), .BI(1'b0), .X(x), .Y(y), .CO(co)); +endmodule +EOT +check + +equiv_opt -assert opt_expr -fine +design -load postopt +select -assert-count 1 t:$alu r:A_WIDTH=4 r:B_WIDTH=4 r:Y_WIDTH=5 %i %i %i + +########### + +design -reset +read_verilog -icells <<EOT +module opt_expr_alu_test_ci1_bi1(input [7:0] a, input [3:0] b, output [8:0] x, y, co); + \$alu #(.A_SIGNED(0), .B_SIGNED(0), .A_WIDTH(8), .B_WIDTH(8), .Y_WIDTH(9)) alu (.A(a), .B({b, 4'b0000}), .CI(1'b1), .BI(1'b1), .X(x), .Y(y), .CO(co)); +endmodule +EOT +check + +equiv_opt -assert opt_expr -fine +design -load postopt +select -assert-count 1 t:$alu r:A_WIDTH=4 r:B_WIDTH=4 r:Y_WIDTH=5 %i %i %i + +########### + +design -reset +read_verilog -icells <<EOT +module opt_expr_alu_test_ci0_bi1(input [7:0] a, input [3:0] b, output [8:0] x, y, co); + \$alu #(.A_SIGNED(0), .B_SIGNED(0), .A_WIDTH(8), .B_WIDTH(8), .Y_WIDTH(9)) alu (.A(a), .B({b, 4'b0000}), .CI(1'b0), .BI(1'b1), .X(x), .Y(y), .CO(co)); +endmodule +EOT +check + +equiv_opt -assert opt_expr -fine +design -load postopt +select -assert-count 1 t:$alu r:A_WIDTH=8 r:B_WIDTH=8 r:Y_WIDTH=9 %i %i %i + +########### + +design -reset +read_verilog -icells <<EOT +module opt_expr_shiftx_1bit(input [2:0] a, input [1:0] b, output y); + \$shiftx #(.A_SIGNED(0), .B_SIGNED(0), .A_WIDTH(4), .B_WIDTH(2), .Y_WIDTH(1)) shiftx (.A({1'bx,a}), .B(b), .Y(y)); +endmodule +EOT +check + +equiv_opt -assert opt_expr +design -load postopt +select -assert-count 1 t:$shiftx r:A_WIDTH=3 %i + +########### + +design -reset +read_verilog -icells <<EOT +module opt_expr_shiftx_3bit(input [9:0] a, input [3:0] b, output [2:0] y); + \$shiftx #(.A_SIGNED(0), .B_SIGNED(0), .A_WIDTH(14), .B_WIDTH(4), .Y_WIDTH(3)) shiftx (.A({4'bxx00,a}), .B(b), .Y(y)); +endmodule +EOT +check + +equiv_opt -assert opt_expr +design -load postopt +select -assert-count 1 t:$shiftx r:A_WIDTH=12 %i + +########### + +design -reset +read_verilog -icells <<EOT +module opt_expr_shift_1bit(input [2:0] a, input [1:0] b, output y); + \$shift #(.A_SIGNED(0), .B_SIGNED(0), .A_WIDTH(4), .B_WIDTH(2), .Y_WIDTH(1)) shift (.A({1'b0,a}), .B(b), .Y(y)); +endmodule +EOT +check + +equiv_opt -assert opt_expr +design -load postopt +select -assert-count 1 t:$shift r:A_WIDTH=3 %i + +########### + +design -reset +read_verilog -icells <<EOT +module opt_expr_shift_3bit(input [9:0] a, input [3:0] b, output [2:0] y); + \$shift #(.A_SIGNED(0), .B_SIGNED(0), .A_WIDTH(14), .B_WIDTH(4), .Y_WIDTH(3)) shift (.A({4'b0x0x,a}), .B(b), .Y(y)); +endmodule +EOT +check + +equiv_opt -assert opt_expr +design -load postopt +select -assert-count 1 t:$shift r:A_WIDTH=10 %i + +########### + +design -reset +read_verilog -icells <<EOT +module opt_expr_shift_3bit_keepdc(input [9:0] a, input [3:0] b, output [2:0] y); + \$shift #(.A_SIGNED(0), .B_SIGNED(0), .A_WIDTH(14), .B_WIDTH(4), .Y_WIDTH(3)) shift (.A({4'b0x0x,a}), .B(b), .Y(y)); +endmodule +EOT +check + +equiv_opt -assert opt_expr -keepdc +design -load postopt +select -assert-count 1 t:$shift r:A_WIDTH=13 %i diff --git a/tests/opt/opt_expr_cmp.v b/tests/opt/opt_expr_cmp.v new file mode 100644 index 000000000..5aff4b80f --- /dev/null +++ b/tests/opt/opt_expr_cmp.v @@ -0,0 +1,40 @@ +module top(...); + input [3:0] a; + + output o1_1 = 4'b0000 > a; + output o1_2 = 4'b0000 <= a; + output o1_3 = 4'b1111 < a; + output o1_4 = 4'b1111 >= a; + output o1_5 = a < 4'b0000; + output o1_6 = a >= 4'b0000; + output o1_7 = a > 4'b1111; + output o1_8 = a <= 4'b1111; + + output o2_1 = 4'sb0000 > $signed(a); + output o2_2 = 4'sb0000 <= $signed(a); + output o2_3 = $signed(a) < 4'sb0000; + output o2_4 = $signed(a) >= 4'sb0000; + + output o3_1 = 4'b0100 > a; + output o3_2 = 4'b0100 <= a; + output o3_3 = a < 4'b0100; + output o3_4 = a >= 4'b0100; + + output o4_1 = 5'b10000 > a; + output o4_2 = 5'b10000 >= a; + output o4_3 = 5'b10000 < a; + output o4_4 = 5'b10000 <= a; + output o4_5 = a < 5'b10000; + output o4_6 = a <= 5'b10000; + output o4_7 = a > 5'b10000; + output o4_8 = a >= 5'b10000; + + output o5_1 = 5'b10100 > a; + output o5_2 = 5'b10100 >= a; + output o5_3 = 5'b10100 < a; + output o5_4 = 5'b10100 <= a; + output o5_5 = a < 5'b10100; + output o5_6 = a <= 5'b10100; + output o5_7 = a > 5'b10100; + output o5_8 = a >= 5'b10100; +endmodule diff --git a/tests/opt/opt_expr_cmp.ys b/tests/opt/opt_expr_cmp.ys new file mode 100644 index 000000000..214ce8b11 --- /dev/null +++ b/tests/opt/opt_expr_cmp.ys @@ -0,0 +1,4 @@ +read_verilog opt_expr_cmp.v +equiv_opt -assert opt_expr -fine +design -load postopt +select -assert-count 0 t:$gt t:$ge t:$lt t:$le diff --git a/tests/opt/opt_lut.v b/tests/opt/opt_lut.v new file mode 100644 index 000000000..b13db367d --- /dev/null +++ b/tests/opt/opt_lut.v @@ -0,0 +1,18 @@ +module top( + input [8:0] a, + input [8:0] b, + output [8:0] o1, + output [2:0] o2, + input [2:0] c, + input [2:0] d, + output [2:0] o3, + output [2:0] o4, + input s +); + +assign o1 = (s ? 0 : a + b); +assign o2 = (s ? a : a - b); +assign o3 = (s ? 4'b1111 : d + c); +assign o4 = (s ? d : c - d); + +endmodule diff --git a/tests/opt/opt_lut.ys b/tests/opt/opt_lut.ys new file mode 100644 index 000000000..a9fccbb62 --- /dev/null +++ b/tests/opt/opt_lut.ys @@ -0,0 +1,2 @@ +read_verilog opt_lut.v +equiv_opt -map +/ice40/cells_sim.v -assert synth_ice40 diff --git a/tests/opt/opt_lut_elim.il b/tests/opt/opt_lut_elim.il new file mode 100644 index 000000000..75675d983 --- /dev/null +++ b/tests/opt/opt_lut_elim.il @@ -0,0 +1,19 @@ +module \test + wire input 1 \i + + wire output 2 \o1 + cell $lut $1 + parameter \LUT 16'0110100110010110 + parameter \WIDTH 4 + connect \A { \i 3'000 } + connect \Y \o1 + end + + wire output 2 \o2 + cell $lut $2 + parameter \LUT 16'0110100010010110 + parameter \WIDTH 4 + connect \A { \i 3'000 } + connect \Y \o2 + end +end diff --git a/tests/opt/opt_lut_elim.ys b/tests/opt/opt_lut_elim.ys new file mode 100644 index 000000000..8e5e23aea --- /dev/null +++ b/tests/opt/opt_lut_elim.ys @@ -0,0 +1,3 @@ +read_ilang opt_lut_elim.il +opt_lut +select -assert-count 0 t:$lut diff --git a/tests/opt/opt_lut_port.il b/tests/opt/opt_lut_port.il new file mode 100644 index 000000000..7eb71890f --- /dev/null +++ b/tests/opt/opt_lut_port.il @@ -0,0 +1,18 @@ +module $1 + wire width 4 input 2 \_0_ + wire output 4 \_1_ + wire input 3 \_2_ + wire output 1 \o + cell $lut \_3_ + parameter \LUT 16'0011000000000011 + parameter \WIDTH 4 + connect \A { \_0_ [3] \o 2'00 } + connect \Y \_1_ + end + cell $lut \_4_ + parameter \LUT 4'0001 + parameter \WIDTH 4 + connect \A { 3'000 \_2_ } + connect \Y \o + end +end diff --git a/tests/opt/opt_lut_port.ys b/tests/opt/opt_lut_port.ys new file mode 100644 index 000000000..3cb4ecb23 --- /dev/null +++ b/tests/opt/opt_lut_port.ys @@ -0,0 +1,3 @@ +read_ilang opt_lut_port.il +opt_lut +select -assert-count 2 t:$lut diff --git a/tests/opt/opt_rmdff.v b/tests/opt/opt_rmdff.v new file mode 100644 index 000000000..b1c06703c --- /dev/null +++ b/tests/opt/opt_rmdff.v @@ -0,0 +1,50 @@ +module opt_rmdff_test (input C, input D, input E, output [29:0] Q); +\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) remove0 (.CLK(C), .D(D), .EN(1'b0), .Q(Q[0])); // EN is never active +(* init = "1'b1" *) wire Q1; assign Q[1] = Q1; +\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) remove1 (.CLK(C), .D(D), .EN(1'b0), .Q(Q1)); // EN is never active +\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) remove2 (.CLK(C), .D(D), .EN(1'bx), .Q(Q[2])); // EN is don't care +\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) keep3 (.CLK(C), .D(D), .EN(1'b1), .Q(Q[3])); // EN is always active +(* init = "1'b0" *) wire Q4; assign Q[4] = Q4; +\$dffe #(.WIDTH(1), .CLK_POLARITY(0), .EN_POLARITY(1)) keep4 (.CLK(C), .D(D), .EN(1'b1), .Q(Q4)); // EN is always active +\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(0)) remove5 (.CLK(C), .D(D), .EN(1'b1), .Q(Q[5])); // EN is never active +\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(0)) remove6 (.CLK(C), .D(D), .EN(1'bx), .Q(Q[6])); // EN is don't care +(* init = "1'b0" *) wire Q7; assign Q[7] = Q7; +\$dffe #(.WIDTH(1), .CLK_POLARITY(0), .EN_POLARITY(0)) keep7 (.CLK(C), .D(D), .EN(E), .Q(Q7)); // EN is non constant + +\$_DFFE_PP_ remove8 (.C(C), .D(D), .E(1'b0), .Q(Q[8])); // EN is never active +(* init = "1'b1" *) wire Q9; assign Q[9] = Q9; +\$_DFFE_PP_ remove9 (.C(C), .D(D), .E(1'b0), .Q(Q9)); // EN is never active +\$_DFFE_PP_ remove10 (.C(C), .D(D), .E(1'bx), .Q(Q[10])); // EN is don't care +\$_DFFE_PP_ keep11 (.C(C), .D(D), .E(1'b1), .Q(Q[11])); // EN is always active +(* init = "1'b0" *) wire Q12; assign Q[12] = Q12; +\$_DFFE_PP_ keep12 (.C(C), .D(D), .E(1'b1), .Q(Q12)); // EN is always active + +\$_DFFE_NN_ remove13 (.C(C), .D(D), .E(1'b1), .Q(Q[13])); // EN is never active +(* init = "1'b1" *) wire Q14; assign Q[14] = Q14; +\$_DFFE_NN_ remove14 (.C(C), .D(D), .E(1'b1), .Q(Q14)); // EN is never active +\$_DFFE_NN_ remove15 (.C(C), .D(D), .E(1'bx), .Q(Q[15])); // EN is don't care +\$_DFFE_NN_ keep16 (.C(C), .D(D), .E(1'b0), .Q(Q[16])); // EN is always active +(* init = "1'b0" *) wire Q17; assign Q[17] = Q17; +\$_DFFE_NN_ keep17 (.C(C), .D(D), .E(1'b0), .Q(Q17)); // EN is always active + +\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) remove18 (.CLK(1'b0), .D(D), .EN(E), .Q(Q[18])); // CLK is constant +(* init = "1'b1" *) wire Q19; assign Q[19] = Q19; +\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) remove19 (.CLK(1'b1), .D(D), .EN(E), .Q(Q19)); // CLK is constant +\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) remove20 (.CLK(C), .D(1'bx), .EN(E), .Q(Q[20])); // D is undriven, Q has no initial value +(* init = "1'b0" *) wire Q21; assign Q[21] = Q21; +\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) keep21 (.CLK(C), .D(1'bx), .EN(E), .Q(Q21)); // D is undriven, Q has initial value +//\$dffe #(.WIDTH(1), .CLK_POLARITY(0), .EN_POLARITY(1)) remove22 (.CLK(C), .D(1'b0), .EN(1'b1), .Q(Q[22])); // D is constant, no initial Q value, EN is always active +// // (TODO, Q starts with 1'bx and becomes 1'b0) +(* init = "1'b0" *) wire Q23; assign Q[23] = Q23; +\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) noenable23 (.CLK(C), .D(1'b0), .EN(1'b1), .Q(Q23)); // D is constant, initial Q value same as D, EN is always active +(* init = "1'b1" *) wire Q24; assign Q[24] = Q24; +\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(0)) keep24 (.CLK(C), .D(1'b0), .EN(1'b0), .Q(Q24)); // D is constant, initial Q value NOT same as D, EN is always active +(* init = "1'b1" *) wire Q25; assign Q[25] = Q25; +\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(0)) remove25 (.CLK(C), .D(1'b0), .EN(1'b1), .Q(Q25)); // D is constant, EN is never active +\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) remove26 (.CLK(C), .D(Q[26]), .EN(1'b1), .Q(Q[26])); // D is Q, EN is always active +\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(0)) remove27 (.CLK(C), .D(Q[27]), .EN(1'b1), .Q(Q[27])); // D is Q, EN is never active, but no initial value +\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(0)) remove28 (.CLK(C), .D(Q[28]), .EN(E), .Q(Q[28])); // EN is nonconst, but no initial value +(* init = "1'b1" *) wire Q29; assign Q[29] = Q29; +\$dffe #(.WIDTH(1), .CLK_POLARITY(1), .EN_POLARITY(1)) keep29 (.CLK(C), .D(Q[29]), .EN(1'b1), .Q(Q29)); // EN is always active, but with initial value + +endmodule diff --git a/tests/opt/opt_rmdff.ys b/tests/opt/opt_rmdff.ys new file mode 100644 index 000000000..83a162f44 --- /dev/null +++ b/tests/opt/opt_rmdff.ys @@ -0,0 +1,26 @@ +read_verilog -icells opt_rmdff.v +prep +design -stash gold +read_verilog -icells opt_rmdff.v +proc +opt_rmdff + +select -assert-count 0 c:remove* +select -assert-min 7 c:keep* +select -assert-count 0 t:$dffe 7:$_DFFE_* %u c:noenable* %i + +design -stash gate + +design -import gold -as gold +design -import gate -as gate + +equiv_make gold gate equiv +hierarchy -top equiv +equiv_simple -undef +equiv_status -assert + +#design -load gold +#stat +# +#design -load gate +#stat diff --git a/tests/opt/opt_rmdff_sat.v b/tests/opt/opt_rmdff_sat.v new file mode 100644 index 000000000..5a0a6fe37 --- /dev/null +++ b/tests/opt/opt_rmdff_sat.v @@ -0,0 +1,12 @@ +module top ( + input clk, + output reg [7:0] cnt +); + initial cnt = 0; + always @(posedge clk) begin + if (cnt < 20) + cnt <= cnt + 1; + else + cnt <= 0; + end +endmodule diff --git a/tests/opt/opt_rmdff_sat.ys b/tests/opt/opt_rmdff_sat.ys new file mode 100644 index 000000000..1c3dd9c05 --- /dev/null +++ b/tests/opt/opt_rmdff_sat.ys @@ -0,0 +1,5 @@ +read_verilog opt_rmdff_sat.v +prep -flatten +opt_rmdff -sat +synth +select -assert-count 5 t:$_DFF_P_ diff --git a/tests/opt/opt_share_add_sub.v b/tests/opt/opt_share_add_sub.v new file mode 100644 index 000000000..d918f27cc --- /dev/null +++ b/tests/opt/opt_share_add_sub.v @@ -0,0 +1,10 @@ +module opt_share_test( + input [15:0] a, + input [15:0] b, + input sel, + output [15:0] res, + ); + + assign res = {sel ? a + b : a - b}; + +endmodule diff --git a/tests/opt/opt_share_add_sub.ys b/tests/opt/opt_share_add_sub.ys new file mode 100644 index 000000000..4a5406791 --- /dev/null +++ b/tests/opt/opt_share_add_sub.ys @@ -0,0 +1,13 @@ +read_verilog opt_share_add_sub.v +proc;; +copy opt_share_test merged + +alumacc merged +opt merged +opt_share merged +opt_clean merged + +miter -equiv -flatten -ignore_gold_x -make_outputs -make_outcmp opt_share_test merged miter +sat -set-def-inputs -verify -prove trigger 0 -show-inputs -show-outputs miter + +select -assert-count 1 -module merged t:$alu diff --git a/tests/opt/opt_share_cat.v b/tests/opt/opt_share_cat.v new file mode 100644 index 000000000..7fb97fef5 --- /dev/null +++ b/tests/opt/opt_share_cat.v @@ -0,0 +1,15 @@ +module opt_share_test( + input [15:0] a, + input [15:0] b, + input [15:0] c, + input [15:0] d, + input sel, + output [63:0] res, + ); + + reg [31: 0] cat1 = {a+b, c+d}; + reg [31: 0] cat2 = {a-b, c-d}; + + assign res = {b, sel ? cat1 : cat2, a}; + +endmodule diff --git a/tests/opt/opt_share_cat.ys b/tests/opt/opt_share_cat.ys new file mode 100644 index 000000000..7de69bfde --- /dev/null +++ b/tests/opt/opt_share_cat.ys @@ -0,0 +1,13 @@ +read_verilog opt_share_cat.v +proc;; +copy opt_share_test merged + +alumacc merged +opt merged +opt_share merged +opt_clean merged + +miter -equiv -flatten -ignore_gold_x -make_outputs -make_outcmp opt_share_test merged miter +sat -set-def-inputs -verify -prove trigger 0 -show-inputs -show-outputs miter + +select -assert-count 2 -module merged t:$alu diff --git a/tests/opt/opt_share_cat_multiuser.v b/tests/opt/opt_share_cat_multiuser.v new file mode 100644 index 000000000..b250689d9 --- /dev/null +++ b/tests/opt/opt_share_cat_multiuser.v @@ -0,0 +1,22 @@ +module opt_share_test( + input [15:0] a, + input [15:0] b, + input [15:0] c, + input [15:0] d, + input sel, + output reg [47:0] res, + ); + + wire [15:0] add_res = a+b; + wire [15:0] sub_res = a-b; + wire [31: 0] cat1 = {add_res, c+d}; + wire [31: 0] cat2 = {sub_res, c-d}; + + always @* begin + case(sel) + 0: res = {cat1, add_res}; + 1: res = {cat2, add_res}; + endcase + end + +endmodule diff --git a/tests/opt/opt_share_cat_multiuser.ys b/tests/opt/opt_share_cat_multiuser.ys new file mode 100644 index 000000000..6a82fbd79 --- /dev/null +++ b/tests/opt/opt_share_cat_multiuser.ys @@ -0,0 +1,13 @@ +read_verilog opt_share_cat_multiuser.v +proc;; +copy opt_share_test merged + +alumacc merged +opt merged +opt_share merged +opt_clean merged + +miter -equiv -flatten -ignore_gold_x -make_outputs -make_outcmp opt_share_test merged miter +sat -set-def-inputs -verify -prove trigger 0 -show-inputs -show-outputs miter + +select -assert-count 3 -module merged t:$alu diff --git a/tests/opt/opt_share_diff_port_widths.v b/tests/opt/opt_share_diff_port_widths.v new file mode 100644 index 000000000..1a37c80a6 --- /dev/null +++ b/tests/opt/opt_share_diff_port_widths.v @@ -0,0 +1,21 @@ +module opt_share_test( + input [15:0] a, + input [15:0] b, + input [15:0] c, + input [1:0] sel, + output reg [15:0] res + ); + + wire [15:0] add0_res = a+b; + wire [15:0] add1_res = a+c; + + always @* begin + case(sel) + 0: res = add0_res[10:0]; + 1: res = add1_res[10:0]; + 2: res = a - b; + default: res = 32'bx; + endcase + end + +endmodule diff --git a/tests/opt/opt_share_diff_port_widths.ys b/tests/opt/opt_share_diff_port_widths.ys new file mode 100644 index 000000000..ec5e9f7b0 --- /dev/null +++ b/tests/opt/opt_share_diff_port_widths.ys @@ -0,0 +1,13 @@ +read_verilog opt_share_diff_port_widths.v +proc;; +copy opt_share_test merged + +alumacc merged +opt merged +opt_share merged +opt_clean merged + +miter -equiv -flatten -ignore_gold_x -make_outputs -make_outcmp opt_share_test merged miter +sat -set-def-inputs -verify -prove trigger 0 -show-inputs -show-outputs miter + +select -assert-count 2 -module merged t:$alu diff --git a/tests/opt/opt_share_extend.v b/tests/opt/opt_share_extend.v new file mode 100644 index 000000000..d39f19069 --- /dev/null +++ b/tests/opt/opt_share_extend.v @@ -0,0 +1,18 @@ +module opt_share_test( + input signed [7:0] a, + input signed [10:0] b, + input signed [15:0] c, + input [1:0] sel, + output reg signed [15:0] res + ); + + always @* begin + case(sel) + 0: res = a + b; + 1: res = a - b; + 2: res = a + c; + default: res = 16'bx; + endcase + end + +endmodule diff --git a/tests/opt/opt_share_extend.ys b/tests/opt/opt_share_extend.ys new file mode 100644 index 000000000..c553ee0fb --- /dev/null +++ b/tests/opt/opt_share_extend.ys @@ -0,0 +1,13 @@ +read_verilog opt_share_extend.v +proc;; +copy opt_share_test merged + +alumacc merged +opt merged +opt_share merged +opt_clean merged + +miter -equiv -flatten -ignore_gold_x -make_outputs -make_outcmp opt_share_test merged miter +sat -set-def-inputs -verify -prove trigger 0 -show-inputs -show-outputs miter + +select -assert-count 1 -module merged t:$alu diff --git a/tests/opt/opt_share_large_pmux_cat.v b/tests/opt/opt_share_large_pmux_cat.v new file mode 100644 index 000000000..416ba3766 --- /dev/null +++ b/tests/opt/opt_share_large_pmux_cat.v @@ -0,0 +1,21 @@ +module opt_share_test( + input [15:0] a, + input [15:0] b, + input [15:0] c, + input [2:0] sel, + output reg [31:0] res + ); + + always @* begin + case(sel) + 0: res = {a + b, a}; + 1: res = {a - b, b}; + 2: res = {a + c, c}; + 3: res = {a - c, a}; + 4: res = {b, b}; + 5: res = {c, c}; + default: res = 32'bx; + endcase + end + +endmodule diff --git a/tests/opt/opt_share_large_pmux_cat.ys b/tests/opt/opt_share_large_pmux_cat.ys new file mode 100644 index 000000000..4186ca52e --- /dev/null +++ b/tests/opt/opt_share_large_pmux_cat.ys @@ -0,0 +1,13 @@ +read_verilog opt_share_large_pmux_cat.v +proc;; +copy opt_share_test merged + +alumacc merged +opt merged +opt_share merged +opt_clean merged + +miter -equiv -flatten -ignore_gold_x -make_outputs -make_outcmp opt_share_test merged miter +sat -set-def-inputs -verify -prove trigger 0 -show-inputs -show-outputs miter + +select -assert-count 1 -module merged t:$alu diff --git a/tests/opt/opt_share_large_pmux_cat_multipart.v b/tests/opt/opt_share_large_pmux_cat_multipart.v new file mode 100644 index 000000000..34d2bd9a8 --- /dev/null +++ b/tests/opt/opt_share_large_pmux_cat_multipart.v @@ -0,0 +1,25 @@ +module opt_share_test( + input [15:0] a, + input [15:0] b, + input [15:0] c, + input [15:0] d, + input [2:0] sel, + output reg [31:0] res + ); + + wire [15:0] add0_res = a+d; + + always @* begin + case(sel) + 0: res = {add0_res, a}; + 1: res = {a - b, add0_res[7], 15'b0}; + 2: res = {b-a, b}; + 3: res = {d, b - c}; + 4: res = {d, b - a}; + 5: res = {c, d}; + 6: res = {a - c, b-d}; + default: res = 32'bx; + endcase + end + +endmodule diff --git a/tests/opt/opt_share_large_pmux_cat_multipart.ys b/tests/opt/opt_share_large_pmux_cat_multipart.ys new file mode 100644 index 000000000..610bb8c6c --- /dev/null +++ b/tests/opt/opt_share_large_pmux_cat_multipart.ys @@ -0,0 +1,14 @@ +read_verilog opt_share_large_pmux_cat_multipart.v +proc;; +copy opt_share_test merged + +alumacc merged +opt merged + +opt_share merged +opt_clean merged + +miter -equiv -flatten -ignore_gold_x -make_outputs -make_outcmp opt_share_test merged miter +sat -set-def-inputs -verify -prove trigger 0 -show-inputs -show-outputs miter + +select -assert-count 4 -module merged t:$alu diff --git a/tests/opt/opt_share_large_pmux_multipart.v b/tests/opt/opt_share_large_pmux_multipart.v new file mode 100644 index 000000000..535adf96f --- /dev/null +++ b/tests/opt/opt_share_large_pmux_multipart.v @@ -0,0 +1,23 @@ +module opt_share_test( + input [15:0] a, + input [15:0] b, + input [15:0] c, + input [15:0] d, + input [2:0] sel, + output reg [15:0] res + ); + + always @* begin + case(sel) + 0: res = a + d; + 1: res = a - b; + 2: res = b; + 3: res = b - c; + 4: res = b - a; + 5: res = c; + 6: res = a - c; + default: res = 16'bx; + endcase + end + +endmodule diff --git a/tests/opt/opt_share_large_pmux_multipart.ys b/tests/opt/opt_share_large_pmux_multipart.ys new file mode 100644 index 000000000..11182df1a --- /dev/null +++ b/tests/opt/opt_share_large_pmux_multipart.ys @@ -0,0 +1,13 @@ +read_verilog opt_share_large_pmux_multipart.v +proc;; +copy opt_share_test merged + +alumacc merged +opt merged +opt_share merged +opt_clean merged + +miter -equiv -flatten -ignore_gold_x -make_outputs -make_outcmp opt_share_test merged miter +sat -set-def-inputs -verify -prove trigger 0 -show-inputs -show-outputs miter + +select -assert-count 2 -module merged t:$alu diff --git a/tests/opt/opt_share_large_pmux_part.v b/tests/opt/opt_share_large_pmux_part.v new file mode 100644 index 000000000..a9008fb5a --- /dev/null +++ b/tests/opt/opt_share_large_pmux_part.v @@ -0,0 +1,21 @@ +module opt_share_test( + input [15:0] a, + input [15:0] b, + input [15:0] c, + input [2:0] sel, + output reg [15:0] res + ); + + always @* begin + case(sel) + 0: res = a + b; + 1: res = a - b; + 2: res = a + c; + 3: res = a - c; + 4: res = b; + 5: res = c; + default: res = 16'bx; + endcase + end + +endmodule diff --git a/tests/opt/opt_share_large_pmux_part.ys b/tests/opt/opt_share_large_pmux_part.ys new file mode 100644 index 000000000..6b594a3d6 --- /dev/null +++ b/tests/opt/opt_share_large_pmux_part.ys @@ -0,0 +1,13 @@ +read_verilog opt_share_large_pmux_part.v +proc;; +copy opt_share_test merged + +alumacc merged +opt merged +opt_share merged +opt_clean merged + +miter -equiv -flatten -ignore_gold_x -make_outputs -make_outcmp opt_share_test merged miter +sat -set-def-inputs -verify -prove trigger 0 -show-inputs -show-outputs miter + +select -assert-count 1 -module merged t:$alu diff --git a/tests/opt/opt_share_mux_tree.v b/tests/opt/opt_share_mux_tree.v new file mode 100644 index 000000000..cc5ae4eb9 --- /dev/null +++ b/tests/opt/opt_share_mux_tree.v @@ -0,0 +1,18 @@ +module opt_share_test( + input [15:0] a, + input [15:0] b, + input [15:0] c, + input [1:0] sel, + output reg [15:0] res + ); + + always @* begin + case(sel) + 0: res = a + b; + 1: res = a - b; + 2: res = a + c; + default: res = 16'bx; + endcase + end + +endmodule diff --git a/tests/opt/opt_share_mux_tree.ys b/tests/opt/opt_share_mux_tree.ys new file mode 100644 index 000000000..58473039f --- /dev/null +++ b/tests/opt/opt_share_mux_tree.ys @@ -0,0 +1,13 @@ +read_verilog opt_share_mux_tree.v +proc;; +copy opt_share_test merged + +alumacc merged +opt merged +opt_share merged +opt_clean merged + +miter -equiv -flatten -ignore_gold_x -make_outputs -make_outcmp opt_share_test merged miter +sat -set-def-inputs -verify -prove trigger 0 -show-inputs -show-outputs miter + +select -assert-count 1 -module merged t:$alu diff --git a/tests/opt/run-test.sh b/tests/opt/run-test.sh new file mode 100755 index 000000000..44ce7e674 --- /dev/null +++ b/tests/opt/run-test.sh @@ -0,0 +1,6 @@ +#!/bin/bash +set -e +for x in *.ys; do + echo "Running $x.." + ../../yosys -ql ${x%.ys}.log $x +done diff --git a/tests/opt_share/.gitignore b/tests/opt_share/.gitignore new file mode 100644 index 000000000..9c595a6fb --- /dev/null +++ b/tests/opt_share/.gitignore @@ -0,0 +1 @@ +temp diff --git a/tests/opt_share/generate.py b/tests/opt_share/generate.py new file mode 100644 index 000000000..2ec92f7de --- /dev/null +++ b/tests/opt_share/generate.py @@ -0,0 +1,86 @@ +#!/usr/bin/env python3 + +import argparse +import sys +import random +from contextlib import contextmanager + + +@contextmanager +def redirect_stdout(new_target): + old_target, sys.stdout = sys.stdout, new_target + try: + yield new_target + finally: + sys.stdout = old_target + + +def random_plus_x(): + return "%s x" % random.choice(['+', '+', '+', '-', '-', '|', '&', '^']) + + +def maybe_plus_x(expr): + if random.randint(0, 4) == 0: + return "(%s %s)" % (expr, random_plus_x()) + else: + return expr + + +parser = argparse.ArgumentParser( + formatter_class=argparse.ArgumentDefaultsHelpFormatter) +parser.add_argument('-S', '--seed', type=int, help='seed for PRNG') +parser.add_argument('-c', + '--count', + type=int, + default=100, + help='number of test cases to generate') +args = parser.parse_args() + +if args.seed is not None: + print("PRNG seed: %d" % args.seed) + random.seed(args.seed) + +for idx in range(args.count): + with open('temp/uut_%05d.v' % idx, 'w') as f: + with redirect_stdout(f): + print('module uut_%05d(a, b, c, s, y);' % (idx)) + op = random.choice([ + random.choice(['+', '-', '*', '/', '%']), + random.choice(['<', '<=', '==', '!=', '===', '!==', '>=', + '>']), + random.choice(['<<', '>>', '<<<', '>>>']), + random.choice(['|', '&', '^', '~^', '||', '&&']), + ]) + print(' input%s [%d:0] a;' % (random.choice(['', ' signed']), 8)) + print(' input%s [%d:0] b;' % (random.choice(['', ' signed']), 8)) + print(' input%s [%d:0] c;' % (random.choice(['', ' signed']), 8)) + print(' input s;') + print(' output [%d:0] y;' % 8) + ops1 = ['a', 'b'] + ops2 = ['a', 'c'] + random.shuffle(ops1) + random.shuffle(ops2) + cast1 = random.choice(['', '$signed', '$unsigned']) + cast2 = random.choice(['', '$signed', '$unsigned']) + print(' assign y = (s ? %s(%s %s %s) : %s(%s %s %s));' % + (cast1, ops1[0], op, ops1[1], + cast2, ops2[0], op, ops2[1])) + print('endmodule') + + with open('temp/uut_%05d.ys' % idx, 'w') as f: + with redirect_stdout(f): + print('read_verilog temp/uut_%05d.v' % idx) + print('proc;;') + print('copy uut_%05d gold' % idx) + print('rename uut_%05d gate' % idx) + print('tee -a temp/all_share_log.txt log') + print('tee -a temp/all_share_log.txt log #job# uut_%05d' % idx) + print('tee -a temp/all_share_log.txt opt gate') + print('tee -a temp/all_share_log.txt opt_share gate') + print('tee -a temp/all_share_log.txt opt_clean gate') + print( + 'miter -equiv -flatten -ignore_gold_x -make_outputs -make_outcmp gold gate miter' + ) + print( + 'sat -set-def-inputs -verify -prove trigger 0 -show-inputs -show-outputs miter' + ) diff --git a/tests/opt_share/run-test.sh b/tests/opt_share/run-test.sh new file mode 100755 index 000000000..e01552646 --- /dev/null +++ b/tests/opt_share/run-test.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +# run this test many times: +# time bash -c 'for ((i=0; i<100; i++)); do echo "-- $i --"; bash run-test.sh || exit 1; done' + +set -e + +OPTIND=1 +count=100 +seed="" # default to no seed specified +while getopts "c:S:" opt +do + case "$opt" in + c) count="$OPTARG" ;; + S) seed="-S $OPTARG" ;; + esac +done +shift "$((OPTIND-1))" + +rm -rf temp +mkdir -p temp +echo "generating tests.." +python3 generate.py -c $count $seed + +echo "running tests.." +for i in $( ls temp/*.ys | sed 's,[^0-9],,g; s,^0*\(.\),\1,g;' ); do + echo -n "[$i]" + idx=$( printf "%05d" $i ) + ../../yosys -ql temp/uut_${idx}.log temp/uut_${idx}.ys +done +echo + +failed_share=$( echo $( gawk '/^#job#/ { j=$2; db[j]=0; } /^Removing [246] cells/ { delete db[j]; } END { for (j in db) print(j); }' temp/all_share_log.txt ) ) +if [ -n "$failed_share" ]; then + echo "Resource sharing failed for the following test cases: $failed_share" + false +fi + +exit 0 diff --git a/tests/proc/.gitignore b/tests/proc/.gitignore new file mode 100644 index 000000000..397b4a762 --- /dev/null +++ b/tests/proc/.gitignore @@ -0,0 +1 @@ +*.log diff --git a/tests/proc/bug_1268.v b/tests/proc/bug_1268.v new file mode 100644 index 000000000..698ac937a --- /dev/null +++ b/tests/proc/bug_1268.v @@ -0,0 +1,23 @@ +module gold (input clock, ctrl, din, output reg dout); + always @(posedge clock) begin + if (1'b1) begin + if (1'b0) begin end else begin + dout <= 0; + end + if (ctrl) + dout <= din; + end + end +endmodule + +module gate (input clock, ctrl, din, output reg dout); + always @(posedge clock) begin + if (1'b1) begin + if (1'b0) begin end else begin + dout <= 0; + end + end + if (ctrl) + dout <= din; + end +endmodule diff --git a/tests/proc/bug_1268.ys b/tests/proc/bug_1268.ys new file mode 100644 index 000000000..b73e94449 --- /dev/null +++ b/tests/proc/bug_1268.ys @@ -0,0 +1,5 @@ +read_verilog bug_1268.v +proc +equiv_make gold gate equiv +equiv_induct +equiv_status -assert diff --git a/tests/proc/run-test.sh b/tests/proc/run-test.sh new file mode 100755 index 000000000..44ce7e674 --- /dev/null +++ b/tests/proc/run-test.sh @@ -0,0 +1,6 @@ +#!/bin/bash +set -e +for x in *.ys; do + echo "Running $x.." + ../../yosys -ql ${x%.ys}.log $x +done diff --git a/tests/sat/counters-repeat.v b/tests/sat/counters-repeat.v new file mode 100644 index 000000000..2ea45499a --- /dev/null +++ b/tests/sat/counters-repeat.v @@ -0,0 +1,38 @@ +// coverage for repeat loops outside of constant functions + +module counter1(clk, rst, ping); + input clk, rst; + output ping; + reg [31:0] count; + + always @(posedge clk) begin + if (rst) + count <= 0; + else + count <= count + 1; + end + + assign ping = &count; +endmodule + +module counter2(clk, rst, ping); + input clk, rst; + output ping; + reg [31:0] count; + + integer i; + reg carry; + + always @(posedge clk) begin + carry = 1; + i = 0; + repeat (32) begin + count[i] <= !rst & (count[i] ^ carry); + carry = count[i] & carry; + i = i+1; + end + end + + assign ping = &count; +endmodule + diff --git a/tests/sat/counters-repeat.ys b/tests/sat/counters-repeat.ys new file mode 100644 index 000000000..b3dcfe08a --- /dev/null +++ b/tests/sat/counters-repeat.ys @@ -0,0 +1,10 @@ + +read_verilog counters-repeat.v +proc; opt + +expose -shared counter1 counter2 +miter -equiv -make_assert -make_outputs counter1 counter2 miter + +cd miter; flatten; opt +sat -verify -prove-asserts -tempinduct -set-at 1 in_rst 1 -seq 1 -show-inputs -show-outputs + diff --git a/tests/sat/initval.v b/tests/sat/initval.v index 5b661f8d6..81f71b5ba 100644 --- a/tests/sat/initval.v +++ b/tests/sat/initval.v @@ -1,6 +1,7 @@ -module test(input clk, input [3:0] bar, output [3:0] foo); +module test(input clk, input [3:0] bar, output [3:0] foo, asdf); reg [3:0] foo = 0; reg [3:0] last_bar = 0; + reg [3:0] asdf = 4'b1xxx; always @* foo[1:0] <= bar[1:0]; @@ -11,5 +12,10 @@ module test(input clk, input [3:0] bar, output [3:0] foo); always @(posedge clk) last_bar <= bar; + always @(posedge clk) + asdf[3] <= bar[3]; + always @* + asdf[2:0] = 3'b111; + assert property (foo == {last_bar[3:2], bar[1:0]}); endmodule diff --git a/tests/simple/arrays02.sv b/tests/simple/arrays02.sv new file mode 100644 index 000000000..76c2a7388 --- /dev/null +++ b/tests/simple/arrays02.sv @@ -0,0 +1,16 @@ +module uut_arrays02(clock, we, addr, wr_data, rd_data); + +input clock, we; +input [3:0] addr, wr_data; +output [3:0] rd_data; +reg [3:0] rd_data; + +reg [3:0] memory [16]; + +always @(posedge clock) begin + if (we) + memory[addr] <= wr_data; + rd_data <= memory[addr]; +end + +endmodule diff --git a/tests/simple/attrib01_module.v b/tests/simple/attrib01_module.v new file mode 100644 index 000000000..adef34f5b --- /dev/null +++ b/tests/simple/attrib01_module.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 (clk, rst, inp, out); +endmodule + diff --git a/tests/simple/attrib02_port_decl.v b/tests/simple/attrib02_port_decl.v new file mode 100644 index 000000000..3505e7265 --- /dev/null +++ b/tests/simple/attrib02_port_decl.v @@ -0,0 +1,25 @@ +module bar(clk, rst, inp, out); + (* this_is_clock = 1 *) + input wire clk; + (* this_is_reset = 1 *) + input wire rst; + input wire inp; + (* an_output_register = 1*) + output reg out; + + always @(posedge clk) + if (rst) out <= 1'd0; + else out <= ~inp; + +endmodule + +module foo(clk, rst, inp, out); + (* this_is_the_master_clock *) + input wire clk; + input wire rst; + input wire inp; + output wire out; + + bar bar_instance (clk, rst, inp, out); +endmodule + diff --git a/tests/simple/attrib03_parameter.v b/tests/simple/attrib03_parameter.v new file mode 100644 index 000000000..562d225cd --- /dev/null +++ b/tests/simple/attrib03_parameter.v @@ -0,0 +1,28 @@ +module bar(clk, rst, inp, out); + + (* bus_width *) + parameter WIDTH = 2; + + (* an_attribute_on_localparam = 55 *) + localparam INCREMENT = 5; + + input wire clk; + input wire rst; + input wire [WIDTH-1:0] inp; + output reg [WIDTH-1:0] out; + + always @(posedge clk) + if (rst) out <= 0; + else out <= inp + INCREMENT; + +endmodule + +module foo(clk, rst, inp, out); + input wire clk; + input wire rst; + input wire [7:0] inp; + output wire [7:0] out; + + bar # (.WIDTH(8)) bar_instance (clk, rst, inp, out); +endmodule + diff --git a/tests/simple/attrib04_net_var.v b/tests/simple/attrib04_net_var.v new file mode 100644 index 000000000..8b5523406 --- /dev/null +++ b/tests/simple/attrib04_net_var.v @@ -0,0 +1,32 @@ +module bar(clk, rst, inp, out); + input wire clk; + input wire rst; + input wire inp; + output reg out; + + (* this_is_a_prescaler *) + reg [7:0] counter; + + (* temp_wire *) + wire out_val; + + always @(posedge clk) + counter <= counter + 1; + + assign out_val = inp ^ counter[4]; + + always @(posedge clk) + if (rst) out <= 1'd0; + else out <= out_val; + +endmodule + +module foo(clk, rst, inp, out); + input wire clk; + input wire rst; + input wire inp; + output wire out; + + bar bar_instance (clk, rst, inp, out); +endmodule + diff --git a/tests/simple/attrib05_port_conn.v.DISABLED b/tests/simple/attrib05_port_conn.v.DISABLED new file mode 100644 index 000000000..e20e66319 --- /dev/null +++ b/tests/simple/attrib05_port_conn.v.DISABLED @@ -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/tests/simple/attrib06_operator_suffix.v b/tests/simple/attrib06_operator_suffix.v new file mode 100644 index 000000000..e21173c58 --- /dev/null +++ b/tests/simple/attrib06_operator_suffix.v @@ -0,0 +1,23 @@ +module bar(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 reg [7:0] out; + + always @(posedge clk) + if (rst) out <= 0; + else out <= inp_a + (* ripple_adder *) inp_b; + +endmodule + +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; + + bar bar_instance (clk, rst, inp_a, inp_b, out); +endmodule + diff --git a/tests/simple/attrib07_func_call.v.DISABLED b/tests/simple/attrib07_func_call.v.DISABLED new file mode 100644 index 000000000..f55ef2316 --- /dev/null +++ b/tests/simple/attrib07_func_call.v.DISABLED @@ -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/tests/simple/attrib08_mod_inst.v b/tests/simple/attrib08_mod_inst.v new file mode 100644 index 000000000..c5a32234e --- /dev/null +++ b/tests/simple/attrib08_mod_inst.v @@ -0,0 +1,22 @@ +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; + + (* my_module_instance = 99 *) + bar bar_instance (clk, rst, inp, out); +endmodule + diff --git a/tests/simple/attrib09_case.v b/tests/simple/attrib09_case.v new file mode 100644 index 000000000..8551bf9d0 --- /dev/null +++ b/tests/simple/attrib09_case.v @@ -0,0 +1,26 @@ +module bar(clk, rst, inp, out); + input wire clk; + input wire rst; + input wire [1:0] inp; + output reg [1:0] out; + + always @(inp) + (* full_case, parallel_case *) + case(inp) + 2'd0: out <= 2'd3; + 2'd1: out <= 2'd2; + 2'd2: out <= 2'd1; + 2'd3: out <= 2'd0; + endcase + +endmodule + +module foo(clk, rst, inp, out); + input wire clk; + input wire rst; + input wire [1:0] inp; + output wire [1:0] out; + + bar bar_instance (clk, rst, inp, out); +endmodule + diff --git a/tests/simple/defvalue.sv b/tests/simple/defvalue.sv new file mode 100644 index 000000000..b0a087ecb --- /dev/null +++ b/tests/simple/defvalue.sv @@ -0,0 +1,22 @@ +module top(input clock, input [3:0] delta, output [3:0] cnt1, cnt2); + cnt #(1) foo (.clock, .cnt(cnt1), .delta); + cnt #(2) bar (.clock, .cnt(cnt2)); +endmodule + +module cnt #( + parameter integer initval = 0 +) ( + input clock, + output logic [3:0] cnt = initval, +`ifdef __ICARUS__ + input [3:0] delta +`else + input [3:0] delta = 10 +`endif +); +`ifdef __ICARUS__ + assign (weak0, weak1) delta = 10; +`endif + always @(posedge clock) + cnt <= cnt + delta; +endmodule diff --git a/tests/simple/dff_init.v b/tests/simple/dff_init.v new file mode 100644 index 000000000..375ea5c4d --- /dev/null +++ b/tests/simple/dff_init.v @@ -0,0 +1,54 @@ +module dff0_test(n1, n1_inv, clk); + input clk; + output n1; + reg n1 = 32'd0; + output n1_inv; + always @(posedge clk) + n1 <= n1_inv; + assign n1_inv = ~n1; +endmodule + +module dff1_test(n1, n1_inv, clk); + input clk; + (* init = 32'd1 *) + output n1; + reg n1 = 32'd1; + output n1_inv; + always @(posedge clk) + n1 <= n1_inv; + assign n1_inv = ~n1; +endmodule + +module dff0a_test(n1, n1_inv, clk); + input clk; + (* init = 32'd0 *) // Must be consistent with reg initialiser below + output n1; + reg n1 = 32'd0; + output n1_inv; + always @(posedge clk) + n1 <= n1_inv; + assign n1_inv = ~n1; +endmodule + +module dff1a_test(n1, n1_inv, clk); + input clk; + (* init = 32'd1 *) // Must be consistent with reg initialiser below + output n1; + reg n1 = 32'd1; + output n1_inv; + always @(posedge clk) + n1 <= n1_inv; + assign n1_inv = ~n1; +endmodule + +module dff_test_997 (y, clk, wire4); +// https://github.com/YosysHQ/yosys/issues/997 + output wire [1:0] y; + input clk; + input signed wire4; + reg [1:0] reg10 = 0; + always @(posedge clk) begin + reg10 <= wire4; + end + assign y = reg10; +endmodule diff --git a/tests/simple/forloops.v b/tests/simple/forloops.v new file mode 100644 index 000000000..8665222d8 --- /dev/null +++ b/tests/simple/forloops.v @@ -0,0 +1,25 @@ +module forloops01 (input clk, a, b, output reg [3:0] p, q, x, y); + integer k; + always @(posedge clk) begin + for (k=0; k<2; k=k+1) + p[2*k +: 2] = {a, b} ^ {2{k}}; + x <= k + {a, b}; + end + always @* begin + for (k=0; k<4; k=k+1) + q[k] = {~a, ~b, a, b} >> k[1:0]; + y = k - {a, b}; + end +endmodule + +module forloops02 (input clk, a, b, output reg [3:0] q, x, output [3:0] y); + integer k; + always @* begin + for (k=0; k<4; k=k+1) + q[k] = {~a, ~b, a, b} >> k[1:0]; + end + always @* begin + x = k + {a, b}; + end + assign y = k - {a, b}; +endmodule diff --git a/tests/simple/generate.v b/tests/simple/generate.v index 24eb4462c..0e353ad9b 100644 --- a/tests/simple/generate.v +++ b/tests/simple/generate.v @@ -90,5 +90,72 @@ generate endcase end endgenerate +endmodule + +// ------------------------------------------ + +module gen_test4(a, b); + +input [3:0] a; +output [3:0] b; + +genvar i; +generate + for (i=0; i < 3; i=i+1) begin : foo + localparam PREV = i - 1; + wire temp; + if (i == 0) + assign temp = a[0]; + else + assign temp = foo[PREV].temp & a[i]; + assign b[i] = temp; + end +endgenerate +endmodule + +// ------------------------------------------ + +module gen_test5(input_bits, out); + +parameter WIDTH = 256; +parameter CHUNK = 4; + +input [WIDTH-1:0] input_bits; +output out; + +genvar step, i, j; +generate + for (step = 1; step <= WIDTH; step = step * CHUNK) begin : steps + localparam PREV = step / CHUNK; + localparam DIM = WIDTH / step; + for (i = 0; i < DIM; i = i + 1) begin : outer + localparam LAST_START = i * CHUNK; + for (j = 0; j < CHUNK; j = j + 1) begin : inner + wire temp; + if (step == 1) + assign temp = input_bits[i]; + else if (j == 0) + assign temp = steps[PREV].outer[LAST_START].val; + else + assign temp + = steps[step].outer[i].inner[j-1].temp + & steps[PREV].outer[LAST_START + j].val; + end + wire val; + assign val = steps[step].outer[i].inner[CHUNK - 1].temp; + end + end +endgenerate +assign out = steps[WIDTH].outer[0].val; +endmodule +// ------------------------------------------ + +module gen_test6(output [3:0] o); +generate + genvar i; + for (i = 3; i >= 0; i = i-1) begin + assign o[i] = 1'b0; + end +endgenerate endmodule diff --git a/tests/simple/hierdefparam.v b/tests/simple/hierdefparam.v index ff92c38bd..c9368ca7a 100644 --- a/tests/simple/hierdefparam.v +++ b/tests/simple/hierdefparam.v @@ -1,3 +1,5 @@ +`default_nettype none + module hierdefparam_top(input [7:0] A, output [7:0] Y); generate begin:foo hierdefparam_a mod_a(.A(A), .Y(Y)); diff --git a/tests/simple/implicit_ports.v b/tests/simple/implicit_ports.v new file mode 100644 index 000000000..8b0a6f386 --- /dev/null +++ b/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/tests/simple/localparam_attr.v b/tests/simple/localparam_attr.v new file mode 100644 index 000000000..2ef76c71c --- /dev/null +++ b/tests/simple/localparam_attr.v @@ -0,0 +1,11 @@ +module uut_localparam_attr (I, O); + +(* LOCALPARAM_ATTRIBUTE = "attribute_content" *) +localparam WIDTH = 1; + +input wire [WIDTH-1:0] I; +output wire [WIDTH-1:0] O; + +assign O = I; + +endmodule diff --git a/tests/simple/mem2reg.v b/tests/simple/mem2reg.v index 9839fd4a8..100426785 100644 --- a/tests/simple/mem2reg.v +++ b/tests/simple/mem2reg.v @@ -92,3 +92,25 @@ module mem2reg_test5(input ctrl, output out); assign out = bar[foo[0]]; endmodule +// ------------------------------------------------------ + +module mem2reg_test6 (din, dout); + input wire [3:0] din; + output reg [3:0] dout; + + reg [1:0] din_array [1:0]; + reg [1:0] dout_array [1:0]; + + always @* begin + din_array[0] = din[0 +: 2]; + din_array[1] = din[2 +: 2]; + + dout_array[0] = din_array[0]; + dout_array[1] = din_array[1]; + + {dout_array[0][1], dout_array[0][0]} = dout_array[0][0] + dout_array[1][0]; + + dout[0 +: 2] = dout_array[0]; + dout[2 +: 2] = dout_array[1]; + end +endmodule diff --git a/tests/simple/param_attr.v b/tests/simple/param_attr.v new file mode 100644 index 000000000..34d63a34e --- /dev/null +++ b/tests/simple/param_attr.v @@ -0,0 +1,11 @@ +module uut_param_attr (I, O); + +(* PARAMETER_ATTRIBUTE = "attribute_content" *) +parameter WIDTH = 1; + +input wire [WIDTH-1:0] I; +output wire [WIDTH-1:0] O; + +assign O = I; + +endmodule diff --git a/tests/simple/realexpr.v b/tests/simple/realexpr.v index 5b756e6be..74ed8faa5 100644 --- a/tests/simple/realexpr.v +++ b/tests/simple/realexpr.v @@ -1,4 +1,3 @@ - module demo_001(y1, y2, y3, y4); output [7:0] y1, y2, y3, y4; @@ -22,3 +21,13 @@ module demo_002(y0, y1, y2, y3); assign y3 = 1 ? -1 : 'd0; endmodule +module demo_003(output A, B); + parameter real p = 0; + assign A = (p==1.0); + assign B = (p!="1.000000"); +endmodule + +module demo_004(output A, B, C, D); + demo_003 #(1.0) demo_real (A, B); + demo_003 #(1) demo_int (C, D); +endmodule diff --git a/tests/simple/retime.v b/tests/simple/retime.v new file mode 100644 index 000000000..30b6087dc --- /dev/null +++ b/tests/simple/retime.v @@ -0,0 +1,6 @@ +module retime_test(input clk, input [7:0] a, output z); + reg [7:0] ff = 8'hF5; + always @(posedge clk) + ff <= {ff[6:0], ^a}; + assign z = ff[7]; +endmodule diff --git a/tests/simple/run-test.sh b/tests/simple/run-test.sh index aaa1cf940..f20fd0d30 100755 --- a/tests/simple/run-test.sh +++ b/tests/simple/run-test.sh @@ -12,9 +12,10 @@ done shift "$((OPTIND-1))" # check for Icarus Verilog -if ! which iverilog > /dev/null ; then +if ! command -v iverilog > /dev/null ; then echo "$0: Error: Icarus Verilog 'iverilog' not found." 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/tests/simple/task_func.v b/tests/simple/task_func.v index fa50c1d5c..f6e902f63 100644 --- a/tests/simple/task_func.v +++ b/tests/simple/task_func.v @@ -120,3 +120,22 @@ module task_func_test04(input [7:0] in, output [7:0] out1, out2, out3, out4); assign out3 = test3(in); assign out4 = test4(in); endmodule + +// ------------------------------------------------------------------- + +// https://github.com/YosysHQ/yosys/issues/857 +module task_func_test05(data_in,data_out,clk); + output reg data_out; + input data_in; + input clk; + + task myTask; + output out; + input in; + out = in; + endtask + + always @(posedge clk) begin + myTask(data_out,data_in); + end +endmodule diff --git a/tests/simple/wandwor.v b/tests/simple/wandwor.v new file mode 100644 index 000000000..34404aa26 --- /dev/null +++ b/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/tests/simple/xfirrtl b/tests/simple/xfirrtl new file mode 100644 index 000000000..10063d2c2 --- /dev/null +++ b/tests/simple/xfirrtl @@ -0,0 +1,29 @@ +# This file contains the names of verilog files to exclude from verilog to FIRRTL regression tests due to known failures. +arraycells.v inst id[0] of +defvalue.sv Initial value not supported +dff_different_styles.v +dff_init.v Initial value not supported +generate.v combinational loop +hierdefparam.v inst id[0] of +i2c_master_tests.v $adff +implicit_ports.v not fully initialized +macros.v drops modules +mem2reg.v drops modules +mem_arst.v $adff +memory.v $adff +multiplier.v inst id[0] of +muxtree.v drops modules +omsp_dbg_uart.v $adff +partsel.v drops modules +process.v drops modules +realexpr.v drops modules +retime.v Initial value (11110101) for (retime_test.ff) not supported +scopes.v original verilog issues ( -x where x isn't declared signed) +sincos.v $adff +specify.v no code (empty module generates error +subbytes.v $adff +task_func.v drops modules +values.v combinational loop +wandwor.v Invalid connect to an expression that is not a reference or a WritePort. +vloghammer.v combinational loop +wreduce.v original verilog issues ( -x where x isn't declared signed) diff --git a/tests/simple_abc9/.gitignore b/tests/simple_abc9/.gitignore new file mode 100644 index 000000000..2355aea29 --- /dev/null +++ b/tests/simple_abc9/.gitignore @@ -0,0 +1,4 @@ +*.v +*.sv +*.log +*.out diff --git a/tests/simple_abc9/abc.box b/tests/simple_abc9/abc.box new file mode 100644 index 000000000..a8801d807 --- /dev/null +++ b/tests/simple_abc9/abc.box @@ -0,0 +1,2 @@ +MUXF8 1 0 3 1 +1 1 1 diff --git a/tests/simple_abc9/abc9.v b/tests/simple_abc9/abc9.v new file mode 100644 index 000000000..64b625efe --- /dev/null +++ b/tests/simple_abc9/abc9.v @@ -0,0 +1,269 @@ +module abc9_test001(input a, output o); +assign o = a; +endmodule + +module abc9_test002(input [1:0] a, output o); +assign o = a[1]; +endmodule + +module abc9_test003(input [1:0] a, output [1:0] o); +assign o = a; +endmodule + +module abc9_test004(input [1:0] a, output o); +assign o = ^a; +endmodule + +module abc9_test005(input [1:0] a, output o, output p); +assign o = ^a; +assign p = ~o; +endmodule + +module abc9_test006(input [1:0] a, output [2:0] o); +assign o[0] = ^a; +assign o[1] = ~o[0]; +assign o[2] = o[1]; +endmodule + +module abc9_test007(input a, output o); +wire b, c; +assign c = ~a; +assign b = c; +abc9_test007_sub s(b, o); +endmodule + +module abc9_test007_sub(input a, output b); +assign b = a; +endmodule + +module abc9_test008(input a, output o); +wire b, c; +assign b = ~a; +assign c = b; +abc9_test008_sub s(b, o); +endmodule + +module abc9_test008_sub(input a, output b); +assign b = ~a; +endmodule + +module abc9_test009(inout io, input oe); +reg latch; +always @(io or oe) + if (!oe) + latch <= io; +assign io = oe ? ~latch : 1'bz; +endmodule + +module abc9_test010(inout [7:0] io, input oe); +reg [7:0] latch; +always @(io or oe) + if (!oe) + latch <= io; +assign io = oe ? ~latch : 8'bz; +endmodule + +module abc9_test011(inout io, input oe); +reg latch; +always @(io or oe) + if (!oe) + latch <= io; +//assign io = oe ? ~latch : 8'bz; +endmodule + +module abc9_test012(inout io, input oe); +reg latch; +//always @(io or oe) +// if (!oe) +// latch <= io; +assign io = oe ? ~latch : 8'bz; +endmodule + +module abc9_test013(inout [3:0] io, input oe); +reg [3:0] latch; +always @(io or oe) + if (!oe) + latch[3:0] <= io[3:0]; + else + latch[7:4] <= io; +assign io[3:0] = oe ? ~latch[3:0] : 4'bz; +assign io[7:4] = !oe ? {latch[4], latch[7:3]} : 4'bz; +endmodule + +module abc9_test014(inout [7:0] io, input oe); +abc9_test012_sub sub(io, oe); +endmodule + +module abc9_test012_sub(inout [7:0] io, input oe); +reg [7:0] latch; +always @(io or oe) + if (!oe) + latch[3:0] <= io; + else + latch[7:4] <= io; +assign io[3:0] = oe ? ~latch[3:0] : 4'bz; +assign io[7:4] = !oe ? {latch[4], latch[7:3]} : 4'bz; +endmodule + +module abc9_test015(input a, output b, input c); +assign b = ~a; +(* keep *) wire d; +assign d = ~c; +endmodule + +module abc9_test016(input a, output b); +assign b = ~a; +(* keep *) reg c; +always @* c <= ~a; +endmodule + +module abc9_test017(input a, output b); +assign b = ~a; +(* keep *) reg c; +always @* c = b; +endmodule + +module abc9_test018(input a, output b, output c); +assign b = ~a; +(* keep *) wire [1:0] d; +assign c = &d; +endmodule + +module abc9_test019(input a, output b); +assign b = ~a; +(* keep *) reg [1:0] c; +reg d; +always @* d <= &c; +endmodule + +module abc9_test020(input a, output b); +assign b = ~a; +(* keep *) reg [1:0] c; +(* keep *) reg d; +always @* d <= &c; +endmodule + +// Citation: https://github.com/alexforencich/verilog-ethernet +module abc9_test021(clk, rst, s_eth_hdr_valid, s_eth_hdr_ready, s_eth_dest_mac, s_eth_src_mac, s_eth_type, s_eth_payload_axis_tdata, s_eth_payload_axis_tkeep, s_eth_payload_axis_tvalid, s_eth_payload_axis_tready, s_eth_payload_axis_tlast, s_eth_payload_axis_tid, s_eth_payload_axis_tdest, s_eth_payload_axis_tuser, m_eth_hdr_valid, m_eth_hdr_ready, m_eth_dest_mac, m_eth_src_mac, m_eth_type, m_eth_payload_axis_tdata, m_eth_payload_axis_tkeep, m_eth_payload_axis_tvalid, m_eth_payload_axis_tready, m_eth_payload_axis_tlast, m_eth_payload_axis_tid, m_eth_payload_axis_tdest, m_eth_payload_axis_tuser); + input clk; + output [47:0] m_eth_dest_mac; + input m_eth_hdr_ready; + output m_eth_hdr_valid; + output [7:0] m_eth_payload_axis_tdata; + output [7:0] m_eth_payload_axis_tdest; + output [7:0] m_eth_payload_axis_tid; + output m_eth_payload_axis_tkeep; + output m_eth_payload_axis_tlast; + input m_eth_payload_axis_tready; + output m_eth_payload_axis_tuser; + output m_eth_payload_axis_tvalid; + output [47:0] m_eth_src_mac; + output [15:0] m_eth_type; + input rst; + input [191:0] s_eth_dest_mac; + output [3:0] s_eth_hdr_ready; + input [3:0] s_eth_hdr_valid; + input [31:0] s_eth_payload_axis_tdata; + input [31:0] s_eth_payload_axis_tdest; + input [31:0] s_eth_payload_axis_tid; + input [3:0] s_eth_payload_axis_tkeep; + input [3:0] s_eth_payload_axis_tlast; + output [3:0] s_eth_payload_axis_tready; + input [3:0] s_eth_payload_axis_tuser; + input [3:0] s_eth_payload_axis_tvalid; + input [191:0] s_eth_src_mac; + input [63:0] s_eth_type; + (* keep *) + wire [0:0] grant, request; + wire a; + not u0 ( + a, + grant[0] + ); + and u1 ( + request[0], + s_eth_hdr_valid[0], + a + ); + (* keep *) + MUXF8 u2 ( + .I0(1'bx), + .I1(1'bx), + .O(o), + .S(1'bx) + ); + arbiter arb_inst ( + .acknowledge(acknowledge), + .clk(clk), + .grant(grant), + .grant_encoded(grant_encoded), + .grant_valid(grant_valid), + .request(request), + .rst(rst) + ); +endmodule + +module arbiter (clk, rst, request, acknowledge, grant, grant_valid, grant_encoded); + input [3:0] acknowledge; + input clk; + output [3:0] grant; + output [1:0] grant_encoded; + output grant_valid; + input [3:0] request; + input rst; +endmodule + +(* abc_box_id=1 *) +module MUXF8(input I0, I1, S, output O); +endmodule + +// Citation: https://github.com/alexforencich/verilog-ethernet +// TODO: yosys -p "synth_xilinx -abc9 -top abc9_test022" abc9.v -q +// returns before b4321a31 +// Warning: Wire abc9_test022.\m_eth_payload_axis_tkeep [7] is used but has no +// driver. +// Warning: Wire abc9_test022.\m_eth_payload_axis_tkeep [3] is used but has no +// driver. +module abc9_test022 +( + input wire clk, + input wire i, + output wire [7:0] m_eth_payload_axis_tkeep +); + reg [7:0] m_eth_payload_axis_tkeep_reg = 8'd0; + assign m_eth_payload_axis_tkeep = m_eth_payload_axis_tkeep_reg; + always @(posedge clk) + m_eth_payload_axis_tkeep_reg <= i ? 8'hff : 8'h0f; +endmodule + +// Citation: https://github.com/riscv/riscv-bitmanip +// TODO: yosys -p "synth_xilinx -abc9 -top abc9_test023" abc9.v -q +// returns before 14233843 +// Warning: Wire abc9_test023.\dout [1] is used but has no driver. +module abc9_test023 #( + parameter integer N = 2, + parameter integer M = 2 +) ( + input [7:0] din, + output [M-1:0] dout +); + wire [2*M-1:0] mask = {M{1'b1}}; + assign dout = (mask << din[N-1:0]) >> M; +endmodule + +module abc9_test024(input [3:0] i, output [3:0] o); +abc9_test024_sub a(i[1:0], o[1:0]); +endmodule + +module abc9_test024_sub(input [1:0] i, output [1:0] o); +assign o = i; +endmodule + +module abc9_test025(input [3:0] i, output [3:0] o); +abc9_test024_sub a(i[2:1], o[2:1]); +endmodule + +module abc9_test026(output [3:0] o, p); +assign o = { 1'b1, 1'bx }; +assign p = { 1'b1, 1'bx, 1'b0 }; +endmodule diff --git a/tests/simple_abc9/run-test.sh b/tests/simple_abc9/run-test.sh new file mode 100755 index 000000000..0d4262005 --- /dev/null +++ b/tests/simple_abc9/run-test.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +OPTIND=1 +seed="" # default to no seed specified +while getopts "S:" opt +do + case "$opt" in + S) arg="${OPTARG#"${OPTARG%%[![:space:]]*}"}" # remove leading space + seed="SEED=$arg" ;; + esac +done +shift "$((OPTIND-1))" + +# check for Icarus Verilog +if ! command -v iverilog > /dev/null ; then + echo "$0: Error: Icarus Verilog 'iverilog' not found." + exit 1 +fi + +cp ../simple/*.v . +cp ../simple/*.sv . +DOLLAR='?' +exec ${MAKE:-make} -f ../tools/autotest.mk $seed *.v EXTRA_FLAGS="-n 300 -p '\ + hierarchy; \ + synth -run coarse; \ + opt -full; \ + techmap; abc9 -lut 4 -box ../abc.box; \ + check -assert; \ + select -assert-none t:${DOLLAR}_NOT_ t:${DOLLAR}_AND_ %%'" diff --git a/tests/sva/basic01.sv b/tests/sva/basic01.sv index 74ab93430..d5ad497dd 100644 --- a/tests/sva/basic01.sv +++ b/tests/sva/basic01.sv @@ -6,7 +6,7 @@ module top (input logic clock, ctrl); write <= ctrl; ready <= write; end - + a_rw: assert property ( @(posedge clock) !(read && write) ); `ifdef FAIL a_wr: assert property ( @(posedge clock) write |-> ready ); diff --git a/tests/sva/extnets.sv b/tests/sva/extnets.sv new file mode 100644 index 000000000..47312de7a --- /dev/null +++ b/tests/sva/extnets.sv @@ -0,0 +1,22 @@ +module top(input i, output o); + A A(); + B B(); + assign A.i = i; + assign o = B.o; + always @* assert(o == i); +endmodule + +module A; + wire i, y; +`ifdef FAIL + assign B.x = i; +`else + assign B.x = !i; +`endif + assign y = !B.y; +endmodule + +module B; + wire x, y, o; + assign y = x, o = A.y; +endmodule diff --git a/tests/svinterfaces/.gitignore b/tests/svinterfaces/.gitignore new file mode 100644 index 000000000..a5b7927d1 --- /dev/null +++ b/tests/svinterfaces/.gitignore @@ -0,0 +1,8 @@ +/a.out +/dut_result.txt +/reference_result.txt +/*.diff +/*.log_stderr +/*.log_stdout +/*_ref_syn.v +/*_syn.v diff --git a/tests/svinterfaces/run-test.sh b/tests/svinterfaces/run-test.sh new file mode 100755 index 000000000..86567d1c1 --- /dev/null +++ b/tests/svinterfaces/run-test.sh @@ -0,0 +1,6 @@ +#/bin/bash -e + + + +./runone.sh svinterface1 +./runone.sh svinterface_at_top diff --git a/tests/svinterfaces/runone.sh b/tests/svinterfaces/runone.sh new file mode 100755 index 000000000..54cf5f2ec --- /dev/null +++ b/tests/svinterfaces/runone.sh @@ -0,0 +1,44 @@ +#!/bin/bash + + +TESTNAME=$1 + +STDOUTFILE=${TESTNAME}.log_stdout +STDERRFILE=${TESTNAME}.log_stderr + +echo "" > $STDOUTFILE +echo "" > $STDERRFILE + +echo -n "Test: ${TESTNAME} -> " + +set -e + +$PWD/../../yosys -p "read_verilog -sv ${TESTNAME}.sv ; hierarchy -check -top TopModule ; synth ; write_verilog ${TESTNAME}_syn.v" >> $STDOUTFILE 2>> $STDERRFILE +$PWD/../../yosys -p "read_verilog -sv ${TESTNAME}_ref.v ; hierarchy -check -top TopModule ; synth ; write_verilog ${TESTNAME}_ref_syn.v" >> $STDOUTFILE 2>> $STDERRFILE + +rm -f a.out reference_result.txt dut_result.txt + +iverilog -g2012 ${TESTNAME}_syn.v +iverilog -g2012 ${TESTNAME}_ref_syn.v + +set +e +iverilog -g2012 ${TESTNAME}_tb.v ${TESTNAME}_ref_syn.v +./a.out +mv output.txt reference_result.txt +if [ -f ${TESTNAME}_wrapper.v ] ; then + iverilog -g2012 ${TESTNAME}_tb_wrapper.v ${TESTNAME}_syn.v +else + iverilog -g2012 ${TESTNAME}_tb.v ${TESTNAME}_syn.v +fi +./a.out +mv output.txt dut_result.txt + +diff reference_result.txt dut_result.txt > ${TESTNAME}.diff +RET=$? +if [ "$RET" != "0" ] ; then + echo "ERROR!" + exit -1 +fi + +echo "ok" +exit 0 diff --git a/tests/svinterfaces/svinterface1.sv b/tests/svinterfaces/svinterface1.sv new file mode 100644 index 000000000..6d60b4880 --- /dev/null +++ b/tests/svinterfaces/svinterface1.sv @@ -0,0 +1,117 @@ + + +module TopModule( + input logic clk, + input logic rst, + output logic [21:0] outOther, + input logic [1:0] sig, + input logic flip, + output logic [1:0] sig_out, + output logic [15:0] passThrough); + + MyInterface #(.WIDTH(4)) MyInterfaceInstance(); + + SubModule1 u_SubModule1 ( + .clk(clk), + .rst(rst), + .u_MyInterface(MyInterfaceInstance), + .outOther(outOther), + .sig (sig) + ); + + assign sig_out = MyInterfaceInstance.mysig_out; + + + assign MyInterfaceInstance.setting = flip; + + assign passThrough = MyInterfaceInstance.passThrough; + +endmodule + +interface MyInterface #( + parameter WIDTH = 3)( + ); + + logic setting; + logic [WIDTH-1:0] other_setting; + + logic [1:0] mysig_out; + + logic [15:0] passThrough; + + modport submodule1 ( + input setting, + output other_setting, + output mysig_out, + output passThrough + ); + + modport submodule2 ( + input setting, + output other_setting, + input mysig_out, + output passThrough + ); + +endinterface + + +module SubModule1( + input logic clk, + input logic rst, + MyInterface.submodule1 u_MyInterface, + input logic [1:0] sig, + output logic [21:0] outOther + + ); + + always_ff @(posedge clk or posedge rst) + if(rst) + u_MyInterface.mysig_out <= 0; + else begin + if(u_MyInterface.setting) + u_MyInterface.mysig_out <= sig; + else + u_MyInterface.mysig_out <= ~sig; + end + + MyInterface #(.WIDTH(22)) MyInterfaceInstanceInSub(); + + SubModule2 u_SubModule2 ( + .clk(clk), + .rst(rst), + .u_MyInterfaceInSub2(u_MyInterface), + .u_MyInterfaceInSub3(MyInterfaceInstanceInSub) + ); + + assign outOther = MyInterfaceInstanceInSub.other_setting; + + assign MyInterfaceInstanceInSub.setting = 0; + assign MyInterfaceInstanceInSub.mysig_out = sig; + +endmodule + +module SubModule2( + + input logic clk, + input logic rst, + MyInterface.submodule2 u_MyInterfaceInSub2, + MyInterface.submodule2 u_MyInterfaceInSub3 + + ); + + always_comb begin + if (u_MyInterfaceInSub3.mysig_out == 2'b00) + u_MyInterfaceInSub3.other_setting[21:0] = 1000; + else if (u_MyInterfaceInSub3.mysig_out == 2'b01) + u_MyInterfaceInSub3.other_setting[21:0] = 2000; + else if (u_MyInterfaceInSub3.mysig_out == 2'b10) + u_MyInterfaceInSub3.other_setting[21:0] = 3000; + else + u_MyInterfaceInSub3.other_setting[21:0] = 4000; + end + + assign u_MyInterfaceInSub2.passThrough[7:0] = 124; + assign u_MyInterfaceInSub2.passThrough[15:8] = 200; + +endmodule diff --git a/tests/svinterfaces/svinterface1_ref.v b/tests/svinterfaces/svinterface1_ref.v new file mode 100644 index 000000000..b119f4037 --- /dev/null +++ b/tests/svinterfaces/svinterface1_ref.v @@ -0,0 +1,107 @@ + +module TopModule( + input logic clk, + input logic rst, + input logic [1:0] sig, + input logic flip, + output logic [15:0] passThrough, + output logic [21:0] outOther, + output logic [1:0] sig_out); + + + logic MyInterfaceInstance_setting; + logic [3:0] MyInterfaceInstance_other_setting; + logic [1:0] MyInterfaceInstance_mysig_out; + + SubModule1 u_SubModule1 ( + .clk(clk), + .rst(rst), + .u_MyInterface_setting(MyInterfaceInstance_setting), + .u_MyInterface_mysig_out(MyInterfaceInstance_mysig_out), + .u_MyInterface_other_setting(MyInterfaceInstance_other_setting), + .outOther(outOther), + .passThrough (passThrough), + .sig (sig) + ); + + assign sig_out = MyInterfaceInstance_mysig_out; + + + assign MyInterfaceInstance_setting = flip; + +endmodule + + +module SubModule1( + input logic clk, + input logic rst, + input logic u_MyInterface_setting, + output logic [3:0] u_MyInterface_other_setting, + output logic [1:0] u_MyInterface_mysig_out, + output logic [21:0] outOther, + input logic [1:0] sig, + output logic [15:0] passThrough + ); + + always @(posedge clk or posedge rst) + if(rst) + u_MyInterface_mysig_out <= 0; + else begin + if(u_MyInterface_setting) + u_MyInterface_mysig_out <= sig; + else + u_MyInterface_mysig_out <= ~sig; + end + + logic MyInterfaceInstanceInSub_setting; + logic [21:0] MyInterfaceInstanceInSub_other_setting; + logic [1:0] MyInterfaceInstanceInSub_mysig_out; + + + SubModule2 u_SubModule2 ( + .clk(clk), + .rst(rst), + .u_MyInterfaceInSub2_setting(u_MyInterface_setting), + .u_MyInterfaceInSub2_mysig_out(u_MyInterface_mysig_out), + .u_MyInterfaceInSub2_other_setting(u_MyInterface_other_setting), + .u_MyInterfaceInSub3_setting(MyInterfaceInstanceInSub_setting), + .u_MyInterfaceInSub3_mysig_out(MyInterfaceInstanceInSub_mysig_out), + .u_MyInterfaceInSub3_other_setting(MyInterfaceInstanceInSub_other_setting), + .passThrough (passThrough) + ); + assign outOther = MyInterfaceInstanceInSub_other_setting; + + assign MyInterfaceInstanceInSub_setting = 0; + assign MyInterfaceInstanceInSub_mysig_out = sig; + +endmodule + +module SubModule2( + + input logic clk, + input logic rst, + input logic u_MyInterfaceInSub2_setting, + output logic [3:0] u_MyInterfaceInSub2_other_setting, + input logic [1:0] u_MyInterfaceInSub2_mysig_out, + input logic u_MyInterfaceInSub3_setting, + output logic [21:0] u_MyInterfaceInSub3_other_setting, + input logic [1:0] u_MyInterfaceInSub3_mysig_out, + output logic [15:0] passThrough + + ); + + always @(u_MyInterfaceInSub3_mysig_out) begin + if (u_MyInterfaceInSub3_mysig_out == 2'b00) + u_MyInterfaceInSub3_other_setting[21:0] = 1000; + else if (u_MyInterfaceInSub3_mysig_out == 2'b01) + u_MyInterfaceInSub3_other_setting[21:0] = 2000; + else if (u_MyInterfaceInSub3_mysig_out == 2'b10) + u_MyInterfaceInSub3_other_setting[21:0] = 3000; + else + u_MyInterfaceInSub3_other_setting[21:0] = 4000; + end + + assign passThrough[7:0] = 124; + assign passThrough[15:8] = 200; + +endmodule diff --git a/tests/svinterfaces/svinterface1_tb.v b/tests/svinterfaces/svinterface1_tb.v new file mode 100644 index 000000000..44c3b5f68 --- /dev/null +++ b/tests/svinterfaces/svinterface1_tb.v @@ -0,0 +1,57 @@ +`timescale 1ns/10ps + +module svinterface1_tb; + + + logic clk; + logic rst; + logic [21:0] outOther; + logic [1:0] sig; + logic [1:0] sig_out; + logic flip; + logic [15:0] passThrough; + integer outfile; + + TopModule u_dut ( + .clk(clk), + .rst(rst), + .outOther(outOther), + .sig(sig), + .flip(flip), + .passThrough(passThrough), + .sig_out(sig_out) + ); + + initial begin + clk = 0; + while(1) begin + clk = ~clk; + #50; + end + end + + initial begin + outfile = $fopen("output.txt"); + rst = 1; + sig = 0; + flip = 0; + @(posedge clk); + #(2); + rst = 0; + @(posedge clk); + for(int j=0;j<2;j++) begin + for(int i=0;i<20;i++) begin + #(2); + flip = j; + sig = i; + @(posedge clk); + end + end + $finish; + end + + always @(negedge clk) begin + $fdisplay(outfile, "%d %d %d", outOther, sig_out, passThrough); + end + +endmodule diff --git a/tests/svinterfaces/svinterface_at_top.sv b/tests/svinterfaces/svinterface_at_top.sv new file mode 100644 index 000000000..b5aa8c8f5 --- /dev/null +++ b/tests/svinterfaces/svinterface_at_top.sv @@ -0,0 +1,125 @@ + + +module TopModule( + input logic clk, + input logic rst, + output logic [21:0] outOther, + input logic [1:0] sig, + input logic flip, + output logic [1:0] sig_out, + MyInterface.submodule1 interfaceInstanceAtTop, + output logic [15:0] passThrough); + + MyInterface #(.WIDTH(4)) MyInterfaceInstance(); + + SubModule1 u_SubModule1 ( + .clk(clk), + .rst(rst), + .u_MyInterface(MyInterfaceInstance), + .u_MyInterfaceFromTop(interfaceInstanceAtTop), + .outOther(outOther), + .sig (sig) + ); + + assign sig_out = MyInterfaceInstance.mysig_out; + + + assign MyInterfaceInstance.setting = flip; + + assign passThrough = MyInterfaceInstance.passThrough; + +endmodule + +interface MyInterface #( + parameter WIDTH = 3)( + ); + + logic setting; + logic [WIDTH-1:0] other_setting; + + logic [1:0] mysig_out; + + logic [15:0] passThrough; + + modport submodule1 ( + input setting, + output other_setting, + output mysig_out, + output passThrough + ); + + modport submodule2 ( + input setting, + output other_setting, + input mysig_out, + output passThrough + ); + +endinterface + + +module SubModule1( + input logic clk, + input logic rst, + MyInterface.submodule1 u_MyInterface, + MyInterface.submodule1 u_MyInterfaceFromTop, + input logic [1:0] sig, + output logic [21:0] outOther + + ); + + + always_ff @(posedge clk or posedge rst) + if(rst) + u_MyInterface.mysig_out <= 0; + else begin + if(u_MyInterface.setting) + u_MyInterface.mysig_out <= sig; + else + u_MyInterface.mysig_out <= ~sig; + end + + MyInterface #(.WIDTH(22)) MyInterfaceInstanceInSub(); + + SubModule2 u_SubModule2 ( + .clk(clk), + .rst(rst), + .u_MyInterfaceFromTopDown(u_MyInterfaceFromTop), + .u_MyInterfaceInSub2(u_MyInterface), + .u_MyInterfaceInSub3(MyInterfaceInstanceInSub) + ); + + assign outOther = MyInterfaceInstanceInSub.other_setting; + + assign MyInterfaceInstanceInSub.setting = 0; + assign MyInterfaceInstanceInSub.mysig_out = sig; + +endmodule + +module SubModule2( + + input logic clk, + input logic rst, + MyInterface.submodule2 u_MyInterfaceInSub2, + MyInterface.submodule1 u_MyInterfaceFromTopDown, + MyInterface.submodule2 u_MyInterfaceInSub3 + + ); + + assign u_MyInterfaceFromTopDown.mysig_out = u_MyInterfaceFromTop.setting ? 10 : 20; + + always_comb begin + if (u_MyInterfaceInSub3.mysig_out == 2'b00) + u_MyInterfaceInSub3.other_setting[21:0] = 1000; + else if (u_MyInterfaceInSub3.mysig_out == 2'b01) + u_MyInterfaceInSub3.other_setting[21:0] = 2000; + else if (u_MyInterfaceInSub3.mysig_out == 2'b10) + u_MyInterfaceInSub3.other_setting[21:0] = 3000; + else + u_MyInterfaceInSub3.other_setting[21:0] = 4000; + end + + assign u_MyInterfaceInSub2.passThrough[7:0] = 124; + assign u_MyInterfaceInSub2.passThrough[15:8] = 200; + +endmodule diff --git a/tests/svinterfaces/svinterface_at_top_ref.v b/tests/svinterfaces/svinterface_at_top_ref.v new file mode 100644 index 000000000..7b54a26d6 --- /dev/null +++ b/tests/svinterfaces/svinterface_at_top_ref.v @@ -0,0 +1,120 @@ + +module TopModule( + input logic clk, + input logic rst, + input logic [1:0] sig, + input logic flip, + output logic [15:0] passThrough, + output logic [21:0] outOther, + input logic interfaceInstanceAtTop_setting, + output logic [2:0] interfaceInstanceAtTop_other_setting, + output logic [1:0] interfaceInstanceAtTop_mysig_out, + output logic [15:0] interfaceInstanceAtTop_passThrough, + output logic [1:0] sig_out); + + + logic MyInterfaceInstance_setting; + logic [3:0] MyInterfaceInstance_other_setting; + logic [1:0] MyInterfaceInstance_mysig_out; + + SubModule1 u_SubModule1 ( + .clk(clk), + .rst(rst), + .u_MyInterface_setting(MyInterfaceInstance_setting), + .u_MyInterface_mysig_out(MyInterfaceInstance_mysig_out), + .u_MyInterface_other_setting(MyInterfaceInstance_other_setting), + .u_MyInterfaceFromTop_setting(interfaceInstanceAtTop_setting), + .u_MyInterfaceFromTop_other_setting(interfaceInstanceAtTop_other_setting), + .u_MyInterfaceFromTop_mysig_out(interfaceInstanceAtTop_mysig_out), + .u_MyInterfaceFromTop_passThrough(interfaceInstanceAtTop_passThrough), + .outOther(outOther), + .passThrough (passThrough), + .sig (sig) + ); + + assign sig_out = MyInterfaceInstance_mysig_out; + + + assign MyInterfaceInstance_setting = flip; + +endmodule + + +module SubModule1( + input logic clk, + input logic rst, + input logic u_MyInterface_setting, + output logic [3:0] u_MyInterface_other_setting, + output logic [1:0] u_MyInterface_mysig_out, + output logic [21:0] outOther, + input logic [1:0] sig, + input logic u_MyInterfaceFromTop_setting, + output logic [2:0] u_MyInterfaceFromTop_other_setting, + output logic [1:0] u_MyInterfaceFromTop_mysig_out, + output logic [14:0] u_MyInterfaceFromTop_passThrough, + output logic [15:0] passThrough + ); + + always @(posedge clk or posedge rst) + if(rst) + u_MyInterface_mysig_out <= 0; + else begin + if(u_MyInterface_setting) + u_MyInterface_mysig_out <= sig; + else + u_MyInterface_mysig_out <= ~sig; + end + + logic MyInterfaceInstanceInSub_setting; + logic [21:0] MyInterfaceInstanceInSub_other_setting; + logic [1:0] MyInterfaceInstanceInSub_mysig_out; + + assign u_MyInterfaceFromTop_mysig_out = u_MyInterfaceFromTop_setting ? 10 : 20; + + SubModule2 u_SubModule2 ( + .clk(clk), + .rst(rst), + .u_MyInterfaceInSub2_setting(u_MyInterface_setting), + .u_MyInterfaceInSub2_mysig_out(u_MyInterface_mysig_out), + .u_MyInterfaceInSub2_other_setting(u_MyInterface_other_setting), + .u_MyInterfaceInSub3_setting(MyInterfaceInstanceInSub_setting), + .u_MyInterfaceInSub3_mysig_out(MyInterfaceInstanceInSub_mysig_out), + .u_MyInterfaceInSub3_other_setting(MyInterfaceInstanceInSub_other_setting), + .passThrough (passThrough) + ); + assign outOther = MyInterfaceInstanceInSub_other_setting; + + assign MyInterfaceInstanceInSub_setting = 0; + assign MyInterfaceInstanceInSub_mysig_out = sig; + +endmodule + +module SubModule2( + + input logic clk, + input logic rst, + input logic u_MyInterfaceInSub2_setting, + output logic [3:0] u_MyInterfaceInSub2_other_setting, + input logic [1:0] u_MyInterfaceInSub2_mysig_out, + input logic u_MyInterfaceInSub3_setting, + output logic [21:0] u_MyInterfaceInSub3_other_setting, + input logic [1:0] u_MyInterfaceInSub3_mysig_out, + output logic [15:0] passThrough + + ); + + always @(u_MyInterfaceInSub3_mysig_out) begin + if (u_MyInterfaceInSub3_mysig_out == 2'b00) + u_MyInterfaceInSub3_other_setting[21:0] = 1000; + else if (u_MyInterfaceInSub3_mysig_out == 2'b01) + u_MyInterfaceInSub3_other_setting[21:0] = 2000; + else if (u_MyInterfaceInSub3_mysig_out == 2'b10) + u_MyInterfaceInSub3_other_setting[21:0] = 3000; + else + u_MyInterfaceInSub3_other_setting[21:0] = 4000; + end + + assign passThrough[7:0] = 124; + assign passThrough[15:8] = 200; + +endmodule diff --git a/tests/svinterfaces/svinterface_at_top_tb.v b/tests/svinterfaces/svinterface_at_top_tb.v new file mode 100644 index 000000000..bf37a148d --- /dev/null +++ b/tests/svinterfaces/svinterface_at_top_tb.v @@ -0,0 +1,68 @@ +`timescale 1ns/10ps + +module svinterface_at_top_tb; + + + logic clk; + logic rst; + logic [21:0] outOther; + logic [1:0] sig; + logic [1:0] sig_out; + logic flip; + logic [15:0] passThrough; + integer outfile; + + logic interfaceInstanceAtTop_setting; + logic [2:0] interfaceInstanceAtTop_other_setting; + logic [1:0] interfaceInstanceAtTop_mysig_out; + logic [15:0] interfaceInstanceAtTop_passThrough; + + + TopModule u_dut ( + .clk(clk), + .rst(rst), + .outOther(outOther), + .sig(sig), + .flip(flip), + .passThrough(passThrough), + .interfaceInstanceAtTop_setting(interfaceInstanceAtTop_setting), + .interfaceInstanceAtTop_other_setting(interfaceInstanceAtTop_other_setting), + .interfaceInstanceAtTop_mysig_out(interfaceInstanceAtTop_mysig_out), + .interfaceInstanceAtTop_passThrough(interfaceInstanceAtTop_passThrough), + .sig_out(sig_out) + ); + + initial begin + clk = 0; + while(1) begin + clk = ~clk; + #50; + end + end + + initial begin + outfile = $fopen("output.txt"); + rst = 1; + interfaceInstanceAtTop_setting = 0; + sig = 0; + flip = 0; + @(posedge clk); + #(2); + rst = 0; + @(posedge clk); + for(int j=0;j<2;j++) begin + for(int i=0;i<20;i++) begin + #(2); + flip = j; + sig = i; + @(posedge clk); + end + end + $finish; + end + + always @(negedge clk) begin + $fdisplay(outfile, "%d %d %d %d", outOther, sig_out, passThrough, interfaceInstanceAtTop_mysig_out); + end + +endmodule diff --git a/tests/svinterfaces/svinterface_at_top_tb_wrapper.v b/tests/svinterfaces/svinterface_at_top_tb_wrapper.v new file mode 100644 index 000000000..b344a7b88 --- /dev/null +++ b/tests/svinterfaces/svinterface_at_top_tb_wrapper.v @@ -0,0 +1,68 @@ +`timescale 1ns/10ps + +module svinterface_at_top_tb_wrapper; + + + logic clk; + logic rst; + logic [21:0] outOther; + logic [1:0] sig; + logic [1:0] sig_out; + logic flip; + logic [15:0] passThrough; + integer outfile; + + logic interfaceInstanceAtTop_setting; + logic [2:0] interfaceInstanceAtTop_other_setting; + logic [1:0] interfaceInstanceAtTop_mysig_out; + logic [15:0] interfaceInstanceAtTop_passThrough; + + + TopModule u_dut ( + .clk(clk), + .rst(rst), + .outOther(outOther), + .sig(sig), + .flip(flip), + .passThrough(passThrough), + .\interfaceInstanceAtTop.setting (interfaceInstanceAtTop_setting), + .\interfaceInstanceAtTop.other_setting (interfaceInstanceAtTop_other_setting), + .\interfaceInstanceAtTop.mysig_out (interfaceInstanceAtTop_mysig_out), + .\interfaceInstanceAtTop.passThrough (interfaceInstanceAtTop_passThrough), + .sig_out(sig_out) + ); + + initial begin + clk = 0; + while(1) begin + clk = ~clk; + #50; + end + end + + initial begin + outfile = $fopen("output.txt"); + rst = 1; + sig = 0; + interfaceInstanceAtTop_setting = 0; + flip = 0; + @(posedge clk); + #(2); + rst = 0; + @(posedge clk); + for(int j=0;j<2;j++) begin + for(int i=0;i<20;i++) begin + #(2); + flip = j; + sig = i; + @(posedge clk); + end + end + $finish; + end + + always @(negedge clk) begin + $fdisplay(outfile, "%d %d %d %d", outOther, sig_out, passThrough, interfaceInstanceAtTop_mysig_out); + end + +endmodule diff --git a/tests/svinterfaces/svinterface_at_top_wrapper.v b/tests/svinterfaces/svinterface_at_top_wrapper.v new file mode 100644 index 000000000..64f906c07 --- /dev/null +++ b/tests/svinterfaces/svinterface_at_top_wrapper.v @@ -0,0 +1,33 @@ +`timescale 1ns/10ps + +module svinterface_at_top_wrapper( + input logic clk, + input logic rst, + output logic [21:0] outOther, + input logic [1:0] sig, + output logic [1:0] sig_out, + input logic flip, + output logic [15:0] passThrough, + + input logic interfaceInstanceAtTop_setting, + output logic [2:0] interfaceInstanceAtTop_other_setting, + output logic [1:0] interfaceInstanceAtTop_mysig_out, + output logic [15:0] interfaceInstanceAtTop_passThrough, + ); + + + TopModule u_dut ( + .clk(clk), + .rst(rst), + .outOther(outOther), + .sig(sig), + .flip(flip), + .passThrough(passThrough), + .\interfaceInstanceAtTop.setting(interfaceInstanceAtTop_setting), + .\interfaceInstanceAtTop.other_setting(interfaceInstanceAtTop_other_setting), + .\interfaceInstanceAtTop.mysig_out(interfaceInstanceAtTop_mysig_out), + .\interfaceInstanceAtTop.passThrough(interfaceInstanceAtTop_passThrough), + .sig_out(sig_out) + ); + +endmodule diff --git a/tests/techmap/.gitignore b/tests/techmap/.gitignore index 397b4a762..cfed22fc5 100644 --- a/tests/techmap/.gitignore +++ b/tests/techmap/.gitignore @@ -1 +1,2 @@ *.log +/*.mk diff --git a/tests/techmap/autopurge.ys b/tests/techmap/autopurge.ys new file mode 100644 index 000000000..1eb99ec37 --- /dev/null +++ b/tests/techmap/autopurge.ys @@ -0,0 +1,62 @@ +# https://github.com/YosysHQ/yosys/issues/1381 +read_verilog <<EOT +module sub(input i, output o, (* techmap_autopurge *) input j); +foobar f(i, o, j); +endmodule +EOT +design -stash techmap + +read_verilog <<EOT +(* blackbox *) +module sub(input i, output o, input j); +endmodule + +(* blackbox *) +module foobar(input i, output o, input j); +endmodule + +module top(input i, output o); +sub s0(i, o); +endmodule +EOT + +techmap -map %techmap +hierarchy +check -assert + +# https://github.com/YosysHQ/yosys/issues/1391 +design -reset +read_verilog <<EOT +module sub(input i, output o, (* techmap_autopurge *) input [1:0] j); +foobar f(i, o, j); +endmodule +EOT +design -stash techmap + +read_verilog <<EOT +(* blackbox *) +module sub(input i, output o, input j); +endmodule + +(* blackbox *) +module foobar(input i, output o, input j); +endmodule + +module top(input i, output o); +sub s0(i, o); +endmodule +EOT + +techmap -map %techmap +hierarchy +check -assert + +read_verilog -overwrite <<EOT +module top(input i, output o); +wire j; +sub s0(i, o, j); +endmodule +EOT + +techmap -map %techmap +hierarchy diff --git a/tests/techmap/clkbufmap.ys b/tests/techmap/clkbufmap.ys new file mode 100644 index 000000000..f1277864e --- /dev/null +++ b/tests/techmap/clkbufmap.ys @@ -0,0 +1,96 @@ +read_verilog <<EOT +module clkbuf (input i, (* clkbuf_driver *) output o); endmodule +module dff ((* clkbuf_sink *) input clk, input d, output q); endmodule +module dffe ((* clkbuf_sink *) input c, input d, e, output q); endmodule +module latch (input e, d, output q); endmodule +module clkgen (output o); endmodule + +module top(input clk1, clk2, clk3, d, e, output [4:0] q); +wire clk4, clk5, clk6; +dff s0 (.clk(clk1), .d(d), .q(q[0])); +dffe s1 (.c(clk2), .d(d), .e(e), .q(q[1])); +latch s2 (.e(clk3), .d(d), .q(q[2])); +sub s3 (.sclk4(clk4), .sclk5(clk5), .sclk6(clk6), .sd(d), .sq(q[3])); +dff s4 (.clk(clk4), .d(d), .q(q[4])); +dff s5 (.clk(clk5), .d(d), .q(q[4])); +dff s6 (.clk(clk6), .d(d), .q(q[4])); +endmodule + +module sub(output sclk4, output sclk5, output sclk6, input sd, output sq); +wire tmp; +clkgen s7(.o(sclk4)); +clkgen s8(.o(sclk5)); +clkgen s9(.o(tmp)); +clkbuf s10(.i(tmp), .o(sclk6)); +dff s11(.clk(sclk4), .d(sd), .q(sq)); +endmodule +EOT + +hierarchy -auto-top +design -save ref + +# ---------------------- + +design -load ref +clkbufmap -buf clkbuf o:i +select -assert-count 3 top/t:clkbuf +select -assert-count 2 sub/t:clkbuf +select -set clk1 w:clk1 %a %co t:clkbuf %i # Find 'clk1' fanouts that are 'clkbuf' +select -assert-count 1 @clk1 # Check there is one such fanout +select -assert-count 1 @clk1 %x:+[o] %co c:s* %i # Check that the 'o' of that clkbuf drives one fanout +select -assert-count 1 @clk1 %x:+[o] %co c:s0 %i # And that one fanout is 's0' +select -set clk2 w:clk2 %a %co t:clkbuf %i +select -assert-count 1 @clk2 +select -assert-count 1 @clk2 %x:+[o] %co c:s* %i +select -assert-count 1 @clk2 %x:+[o] %co c:s1 %i +select -set clk5 w:clk5 %a %ci t:clkbuf %i +select -assert-count 1 @clk5 +select -assert-count 1 @clk5 %x:+[o] %co c:s5 %i +select -assert-count 1 @clk5 %x:+[i] %ci c:s3 %i +select -set sclk4 w:sclk4 %a %ci t:clkbuf %i +select -assert-count 1 @sclk4 +select -assert-count 1 @sclk4 %x:+[o] %co c:s11 %i +select -assert-count 1 @sclk4 %x:+[i] %ci c:s7 %i + +# ---------------------- + +design -load ref +setattr -set clkbuf_inhibit 0 w:clk1 +setattr -set clkbuf_inhibit 1 w:clk2 +clkbufmap -buf clkbuf o:i +select -assert-count 2 top/t:clkbuf +select -set clk1 w:clk1 %a %co t:clkbuf %i # Find 'clk1' fanouts that are 'clkbuf' +select -assert-count 1 @clk1 # Check there is one such fanout +select -assert-count 1 @clk1 %x:+[o] %co c:s* %i # Check that the 'o' of that clkbuf drives one fanout +select -assert-count 1 @clk1 %x:+[o] %co c:s0 %i # And that one fanout is 's0' +select -assert-count 0 w:clk2 %a %co t:clkbuf %i + +# ---------------------- + +design -load ref +setattr -set clkbuf_inhibit 1 w:clk1 +setattr -set buffer_type "bufg" w:clk2 +clkbufmap -buf clkbuf o:i w:* a:buffer_type=none a:buffer_type=bufr %u %d +select -assert-count 3 top/t:clkbuf +select -assert-count 2 sub/t:clkbuf +select -set clk1 w:clk1 %a %co t:clkbuf %i # Find 'clk1' fanouts that are 'clkbuf' +select -assert-count 1 @clk1 # Check there is one such fanout +select -assert-count 1 @clk1 %x:+[o] %co c:s* %i # Check that the 'o' of that clkbuf drives one fanout +select -assert-count 1 @clk1 %x:+[o] %co c:s0 %i # And that one fanout is 's0' +select -set clk2 w:clk2 %a %co t:clkbuf %i # Find 'clk1' fanouts that are 'clkbuf' +select -assert-count 1 @clk2 # Check there is one such fanout +select -assert-count 1 @clk2 %x:+[o] %co c:s* %i # Check that the 'o' of that clkbuf drives one fanout +select -assert-count 1 @clk2 %x:+[o] %co c:s1 %i # And that one fanout is 's0' + +# ---------------------- + +design -load ref +setattr -set buffer_type "none" w:clk1 +setattr -set buffer_type "bufr" w:clk2 +setattr -set buffer_type "bufr" w:sclk4 +setattr -set buffer_type "bufr" w:sclk5 +clkbufmap -buf clkbuf o:i w:* a:buffer_type=none a:buffer_type=bufr %u %d +select -assert-count 0 w:clk1 %a %co t:clkbuf %i +select -assert-count 0 w:clk2 %a %co t:clkbuf %i +select -assert-count 0 top/t:clkbuf +select -assert-count 1 sub/t:clkbuf diff --git a/tests/techmap/dff2dffs.ys b/tests/techmap/dff2dffs.ys new file mode 100644 index 000000000..13f1a3cf3 --- /dev/null +++ b/tests/techmap/dff2dffs.ys @@ -0,0 +1,50 @@ +read_verilog << EOT +module top(...); +input clk; +input d; +input sr; +output reg q0, q1, q2, q3, q4, q5; + +initial q0 = 1'b0; +initial q1 = 1'b0; +initial q2 = 1'b1; +initial q3 = 1'b1; +initial q4 = 1'bx; +initial q5 = 1'bx; + +always @(posedge clk) begin + q0 <= sr ? 1'b0 : d; + q1 <= sr ? 1'b1 : d; + q2 <= sr ? 1'b0 : d; + q3 <= sr ? 1'b1 : d; + q4 <= sr ? 1'b0 : d; + q5 <= sr ? 1'b1 : d; +end + +endmodule +EOT + +proc +simplemap +design -save ref + +dff2dffs +clean + +select -assert-count 1 w:q0 %x t:$__DFFS_PP0_ %i +select -assert-count 1 w:q1 %x t:$__DFFS_PP1_ %i +select -assert-count 1 w:q2 %x t:$__DFFS_PP0_ %i +select -assert-count 1 w:q3 %x t:$__DFFS_PP1_ %i +select -assert-count 1 w:q4 %x t:$__DFFS_PP0_ %i +select -assert-count 1 w:q5 %x t:$__DFFS_PP1_ %i + +design -load ref +dff2dffs -match-init +clean + +select -assert-count 1 w:q0 %x t:$__DFFS_PP0_ %i +select -assert-count 0 w:q1 %x t:$__DFFS_PP1_ %i +select -assert-count 0 w:q2 %x t:$__DFFS_PP0_ %i +select -assert-count 1 w:q3 %x t:$__DFFS_PP1_ %i +select -assert-count 1 w:q4 %x t:$__DFFS_PP0_ %i +select -assert-count 1 w:q5 %x t:$__DFFS_PP1_ %i diff --git a/tests/techmap/extractinv.ys b/tests/techmap/extractinv.ys new file mode 100644 index 000000000..6146f829a --- /dev/null +++ b/tests/techmap/extractinv.ys @@ -0,0 +1,41 @@ +read_verilog << EOT + +module ff4(...); +parameter [0:0] CLK_INV = 1'b0; +parameter [3:0] DATA_INV = 4'b0000; +(* invertible_pin = "CLK_INV" *) +input clk; +(* invertible_pin = "DATA_INV" *) +input [3:0] d; +output [3:0] q; +endmodule + +module inv(...); +output o; +input i; +endmodule + +module top(...); +input d0, d1, d2, d3; +input clk; +output q; +ff4 #(.DATA_INV(4'h5)) ff_inst (.clk(clk), .d({d3, d2, d1, d0}), .q(q)); +endmodule + +EOT + +extractinv -inv inv o:i +clean + +select -assert-count 2 top/t:inv +select -assert-count 2 top/t:inv top/t:ff4 %ci:+[d] %ci:+[o] %i + +select -assert-count 1 top/t:inv top/w:d0 %co:+[i] %i +select -assert-count 0 top/t:inv top/w:d1 %co:+[i] %i +select -assert-count 1 top/t:inv top/w:d2 %co:+[i] %i +select -assert-count 0 top/t:inv top/w:d3 %co:+[i] %i + +select -assert-count 0 top/t:ff4 top/w:d0 %co:+[d] %i +select -assert-count 1 top/t:ff4 top/w:d1 %co:+[d] %i +select -assert-count 0 top/t:ff4 top/w:d2 %co:+[d] %i +select -assert-count 1 top/t:ff4 top/w:d3 %co:+[d] %i diff --git a/tests/techmap/recursive.v b/tests/techmap/recursive.v new file mode 100644 index 000000000..d281b21d8 --- /dev/null +++ b/tests/techmap/recursive.v @@ -0,0 +1,8 @@ +module top; +sub s0(); +foo f0(); +endmodule + +module foo; +sub s0(); +endmodule diff --git a/tests/techmap/recursive_map.v b/tests/techmap/recursive_map.v new file mode 100644 index 000000000..934256552 --- /dev/null +++ b/tests/techmap/recursive_map.v @@ -0,0 +1,4 @@ +module sub; + sub _TECHMAP_REPLACE_ (); + bar f0(); +endmodule diff --git a/tests/techmap/recursive_runtest.sh b/tests/techmap/recursive_runtest.sh new file mode 100644 index 000000000..30c79bf03 --- /dev/null +++ b/tests/techmap/recursive_runtest.sh @@ -0,0 +1,3 @@ +set -ev + +../../yosys -p 'hierarchy -top top; techmap -map recursive_map.v -max_iter 1; select -assert-count 2 t:sub; select -assert-count 2 t:bar' recursive.v diff --git a/tests/techmap/run-test.sh b/tests/techmap/run-test.sh index e2fc11e52..96489ff15 100755 --- a/tests/techmap/run-test.sh +++ b/tests/techmap/run-test.sh @@ -1,10 +1,20 @@ -#!/bin/bash +#!/usr/bin/env bash set -e -for x in *_runtest.sh; do - echo "Running $x.." - if ! bash $x &> ${x%.sh}.log; then - tail ${x%.sh}.log - echo ERROR - exit 1 +{ +echo "all::" +for x in *.ys; do + echo "all:: run-$x" + echo "run-$x:" + echo " @echo 'Running $x..'" + echo " @../../yosys -ql ${x%.ys}.log $x" +done +for s in *.sh; do + if [ "$s" != "run-test.sh" ]; then + echo "all:: run-$s" + echo "run-$s:" + echo " @echo 'Running $s..'" + echo " @bash $s > ${s%.sh}.log 2>&1" fi done +} > run-test.mk +exec ${MAKE:-make} -f run-test.mk diff --git a/tests/techmap/wireinit.ys b/tests/techmap/wireinit.ys new file mode 100644 index 000000000..1396839fe --- /dev/null +++ b/tests/techmap/wireinit.ys @@ -0,0 +1,98 @@ +read_verilog <<EOT +(* techmap_celltype = "$_DFF_P_" *) +module ffmap(...); +input D; +input C; +output Q; +parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; + +ffbb #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_(.D(D), .Q(Q), .C(C)); + +wire _TECHMAP_FAIL_ = _TECHMAP_WIREINIT_Q_ === 1'b1; + +wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; + +endmodule +EOT +design -stash map + +read_verilog <<EOT +(* techmap_celltype = "$_DFF_P_" *) +module ffmap(...); +input D; +input C; +output Q; +parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; + +ffbb #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_(.D(D), .Q(Q), .C(C)); + +wire _TECHMAP_FAIL_ = _TECHMAP_WIREINIT_Q_ === 1'b1; + +wire _TECHMAP_REMOVEINIT_Q_ = 1'b0; + +endmodule +EOT +design -stash map_noremove + +read_verilog <<EOT +module ffbb (...); +parameter [0:0] INIT = 1'bx; +input D, C; +output Q; +endmodule + +module top(...); +input clk; +input d; +output reg q0 = 0; +output reg q1 = 1; +output reg qx; + +always @(posedge clk) begin + q0 <= d; + q1 <= d; + qx <= d; +end +endmodule +EOT + +design -save ref + +hierarchy -auto-top +proc +simplemap +techmap -map %map +clean +# Make sure the parameter was used properly. +select -assert-count 2 top/t:ffbb +select -set ff0 top/w:q0 %ci t:ffbb %i +select -set ffx top/w:qx %ci t:ffbb %i +select -assert-count 1 @ff0 +select -assert-count 1 @ffx +select -assert-count 1 @ff0 r:INIT=1'b0 %i +select -assert-count 1 @ffx r:INIT=1'bx %i +select -assert-count 0 top/w:q1 %ci t:ffbb %i +# Make sure the init values are dropped from the wires iff mapping was performed. +select -assert-count 0 top/w:q0 a:init %i +select -assert-count 1 top/w:q1 a:init=1'b1 %i +select -assert-count 0 top/w:qx a:init %i + +design -load ref +hierarchy -auto-top +proc +simplemap +techmap -map %map_noremove +clean +# Make sure the parameter was used properly. +select -assert-count 2 top/t:ffbb +select -set ff0 top/w:q0 %ci t:ffbb %i +select -set ffx top/w:qx %ci t:ffbb %i +select -assert-count 1 @ff0 +select -assert-count 1 @ffx +select -assert-count 1 @ff0 r:INIT=1'b0 %i +select -assert-count 1 @ffx r:INIT=1'bx %i +select -assert-count 0 top/w:q1 %ci t:ffbb %i +# Make sure the init values are not dropped from the wires. +select -assert-count 1 top/w:q0 a:init=1'b0 %i +select -assert-count 1 top/w:q1 a:init=1'b1 %i +select -assert-count 0 top/w:qx a:init %i diff --git a/tests/tools/autotest.mk b/tests/tools/autotest.mk index c68678929..e0f2bcdc1 100644 --- a/tests/tools/autotest.mk +++ b/tests/tools/autotest.mk @@ -1,7 +1,7 @@ -EXTRA_FLAGS= -SEED= - +# Don't bother defining default values for SEED and EXTRA_FLAGS. +# Their "natural" default values should be sufficient, +# and they may be overridden in the environment. ifneq ($(strip $(SEED)),) SEEDOPT=-S$(SEED) endif diff --git a/tests/tools/autotest.sh b/tests/tools/autotest.sh index d6216244f..4d3478628 100755 --- a/tests/tools/autotest.sh +++ b/tests/tools/autotest.sh @@ -7,8 +7,8 @@ use_modelsim=false verbose=false keeprunning=false makejmode=false -frontend="verilog" -backend_opts="-noattr -noexpr" +frontend="verilog -noblackbox" +backend_opts="-noattr -noexpr -siminit" autotb_opts="" include_opts="" xinclude_opts="" @@ -17,12 +17,19 @@ scriptfiles="" scriptopt="" toolsdir="$(cd $(dirname $0); pwd)" warn_iverilog_git=false +# The following are used in verilog to firrtl regression tests. +# Typically these will be passed as environment variables: +#EXTRA_FLAGS="--firrtl2verilog 'java -cp /.../firrtl/utils/bin/firrtl.jar firrtl.Driver'" +# 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 ;; @@ -43,7 +50,7 @@ while getopts xmGl:wkjvref:s:p:n:S:I: opt; do r) backend_opts="$backend_opts -norename" ;; e) - backend_opts="$( echo " $backend_opts " | sed 's, -noexpr ,,; s,^ ,,; s, $,,;'; )" ;; + backend_opts="$( echo " $backend_opts " | sed 's, -noexpr , ,; s,^ ,,; s, $,,;'; )" ;; f) frontend="$OPTARG" ;; s) @@ -59,14 +66,38 @@ 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) + xfirrtl="${!OPTIND}" + OPTIND=$(( $OPTIND + 1 )) + ;; + firrtl2verilog) + firrtl2verilog="${!OPTIND}" + OPTIND=$(( $OPTIND + 1 )) + ;; + *) + if [ "$OPTERR" == 1 ] && [ "${optspec:0:1}" != ":" ]; then + echo "Unknown option --${OPTARG}" >&2 + fi + ;; + esac;; *) - echo "Usage: $0 [-x|-m] [-G] [-w] [-k] [-j] [-v] [-r] [-e] [-l libs] [-f frontend] [-s script] [-p cmdstring] [-n iters] [-S seed] [-I incdir] verilog-files\n" >&2 + echo "Usage: $0 [-x|-m] [-G] [-w] [-k] [-j] [-v] [-r] [-e] [-l libs] [-f frontend] [-s script] [-p cmdstring] [-n iters] [-S seed] [-I incdir] [--xfirrtl FIRRTL test exclude file] [--firrtl2verilog command to generate verilog from firrtl] verilog-files\n" >&2 exit 1 esac 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 @@ -77,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 } @@ -86,8 +117,9 @@ shift $((OPTIND - 1)) for fn do - bn=${fn%.v} - if [ "$bn" == "$fn" ]; then + bn=${fn%.*} + ext=${fn##*.} + if [[ "$ext" != "v" ]] && [[ "$ext" != "sv" ]] && [[ "$ext" != "aag" ]] && [[ "$ext" != "aig" ]]; then echo "Invalid argument: $fn" >&2 exit 1 fi @@ -100,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/* @@ -108,16 +144,27 @@ do cd ${bn}.out fn=$(basename $fn) bn=$(basename $bn) + refext=v - egrep -v '^\s*`timescale' ../$fn > ${bn}_ref.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 + 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 test_count=0 @@ -132,22 +179,29 @@ 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.${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 + fi fi touch ../${bn}.log } @@ -160,14 +214,18 @@ do ( set -ex; body; ) > ${bn}.err 2>&1 fi + did_firrtl="" + if [ -f ${bn}.out/${bn}_ref.fir ]; then + did_firrtl="+FIRRTL " + fi if [ -f ${bn}.log ]; then mv ${bn}.err ${bn}.log - echo "${status_prefix}-> ok" + echo "${status_prefix}${did_firrtl}-> ok" elif [ -f ${bn}.skip ]; then mv ${bn}.err ${bn}.skip echo "${status_prefix}-> skip" else - echo "${status_prefix}-> ERROR!" + echo "${status_prefix}${did_firrtl}-> ERROR!" if $warn_iverilog_git; then echo "Note: Make sure that 'iverilog' is an up-to-date git checkout of Icarus Verilog." fi diff --git a/tests/various/.gitignore b/tests/various/.gitignore index 397b4a762..4b286fd61 100644 --- a/tests/various/.gitignore +++ b/tests/various/.gitignore @@ -1 +1,5 @@ -*.log +/*.log +/*.out +/write_gzip.v +/write_gzip.v.gz +/run-test.mk diff --git a/tests/various/abc9.v b/tests/various/abc9.v new file mode 100644 index 000000000..30ebd4e26 --- /dev/null +++ b/tests/various/abc9.v @@ -0,0 +1,11 @@ +module abc9_test027(output reg o); +initial o = 1'b0; +always @* + o <= ~o; +endmodule + +module abc9_test028(input i, output o); +wire w; +unknown u(~i, w); +unknown2 u2(w, o); +endmodule diff --git a/tests/various/abc9.ys b/tests/various/abc9.ys new file mode 100644 index 000000000..5c9a4075d --- /dev/null +++ b/tests/various/abc9.ys @@ -0,0 +1,24 @@ +read_verilog abc9.v +design -save read +hierarchy -top abc9_test027 +proc +design -save gold + +abc9 -lut 4 +check +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 miter + +design -load read +hierarchy -top abc9_test028 +proc + +abc9 -lut 4 +select -assert-count 1 t:$lut r:LUT=2'b01 r:WIDTH=1 %i %i +select -assert-count 1 t:unknown +select -assert-none t:$lut t:unknown %% t: %D diff --git a/tests/various/async.sh b/tests/various/async.sh new file mode 100644 index 000000000..7c41d6d94 --- /dev/null +++ b/tests/various/async.sh @@ -0,0 +1,11 @@ +#!/bin/bash +set -ex +../../yosys -q -o async_syn.v -p 'synth; rename uut syn' async.v +../../yosys -q -o async_prp.v -p 'prep; rename uut prp' async.v +../../yosys -q -o async_a2s.v -p 'prep; async2sync; rename uut a2s' async.v +../../yosys -q -o async_ffl.v -p 'prep; clk2fflogic; rename uut ffl' async.v +iverilog -o async_sim -DTESTBENCH async.v async_???.v +vvp -N async_sim > async.out +tail async.out +grep PASS async.out +rm -f async_???.v async_sim async.out async.vcd diff --git a/tests/various/async.v b/tests/various/async.v new file mode 100644 index 000000000..c27e30c4b --- /dev/null +++ b/tests/various/async.v @@ -0,0 +1,108 @@ +`define MAXQ 2 +module uut ( + input clk, + input d, r, e, + output [`MAXQ:0] q +); + reg q0; + always @(posedge clk) begin + if (r) + q0 <= 0; + else if (e) + q0 <= d; + end + + reg q1; + always @(posedge clk, posedge r) begin + if (r) + q1 <= 0; + else if (e) + q1 <= d; + end + + reg q2; + always @(posedge clk, negedge r) begin + if (!r) + q2 <= 0; + else if (!e) + q2 <= d; + end + + assign q = {q2, q1, q0}; +endmodule + +`ifdef TESTBENCH +module \$ff #( + parameter integer WIDTH = 1 +) ( + input [WIDTH-1:0] D, + output reg [WIDTH-1:0] Q +); + wire sysclk = testbench.sysclk; + always @(posedge sysclk) + Q <= D; +endmodule + +module testbench; + reg sysclk; + always #5 sysclk = (sysclk === 1'b0); + + reg clk; + always @(posedge sysclk) clk = (clk === 1'b0); + + reg d, r, e; + + wire [`MAXQ:0] q_uut; + uut uut (.clk(clk), .d(d), .r(r), .e(e), .q(q_uut)); + + wire [`MAXQ:0] q_syn; + syn syn (.clk(clk), .d(d), .r(r), .e(e), .q(q_syn)); + + wire [`MAXQ:0] q_prp; + prp prp (.clk(clk), .d(d), .r(r), .e(e), .q(q_prp)); + + wire [`MAXQ:0] q_a2s; + a2s a2s (.clk(clk), .d(d), .r(r), .e(e), .q(q_a2s)); + + wire [`MAXQ:0] q_ffl; + ffl ffl (.clk(clk), .d(d), .r(r), .e(e), .q(q_ffl)); + + task printq; + reg [5*8-1:0] msg; + begin + msg = "OK"; + if (q_uut !== q_syn) msg = "SYN"; + if (q_uut !== q_prp) msg = "PRP"; + if (q_uut !== q_a2s) msg = "A2S"; + if (q_uut !== q_ffl) msg = "FFL"; + $display("%6t %b %b %b %b %b %s", $time, q_uut, q_syn, q_prp, q_a2s, q_ffl, msg); + if (msg != "OK") $finish; + end + endtask + + initial if(0) begin + $dumpfile("async.vcd"); + $dumpvars(0, testbench); + end + + initial begin + @(posedge clk); + d <= 0; + r <= 0; + e <= 0; + @(posedge clk); + e <= 1; + @(posedge clk); + e <= 0; + repeat (10000) begin + @(posedge clk); + printq; + d <= $random; + r <= $random; + e <= $random; + end + $display("PASS"); + $finish; + end +endmodule +`endif diff --git a/tests/various/attrib05_port_conn.v b/tests/various/attrib05_port_conn.v new file mode 100644 index 000000000..e20e66319 --- /dev/null +++ b/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/tests/various/attrib05_port_conn.ys b/tests/various/attrib05_port_conn.ys new file mode 100644 index 000000000..27a016733 --- /dev/null +++ b/tests/various/attrib05_port_conn.ys @@ -0,0 +1,2 @@ +# Read and parse Verilog file +read_verilog attrib05_port_conn.v diff --git a/tests/various/attrib07_func_call.v b/tests/various/attrib07_func_call.v new file mode 100644 index 000000000..f55ef2316 --- /dev/null +++ b/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/tests/various/attrib07_func_call.ys b/tests/various/attrib07_func_call.ys new file mode 100644 index 000000000..774827651 --- /dev/null +++ b/tests/various/attrib07_func_call.ys @@ -0,0 +1,2 @@ +# Read and parse Verilog file +read_verilog attrib07_func_call.v diff --git a/tests/various/chparam.sh b/tests/various/chparam.sh new file mode 100644 index 000000000..9bb8d81db --- /dev/null +++ b/tests/various/chparam.sh @@ -0,0 +1,52 @@ +#!/bin/bash + +trap 'echo "ERROR in chparam.sh" >&2; exit 1' ERR + +cat > chparam1.sv << "EOT" +module top #( + parameter [31:0] X = 0 +) ( + input [31:0] din, + output [31:0] dout +); + assign dout = X-din; +endmodule + +module top_props #( + parameter [31:0] X = 0 +) ( + input [31:0] dout +); + always @* assert (dout != X); +endmodule + +bind top top_props #(.X(123456789)) props (.*); +EOT + +cat > chparam2.sv << "EOT" +module top #( + parameter [31:0] X = 0 +) ( + input [31:0] din, + output [31:0] dout +); + assign dout = X-din; + always @* assert (dout != 123456789); +endmodule +EOT + +if ../../yosys -q -p 'verific -sv chparam1.sv'; then + ../../yosys -q -p 'verific -sv chparam1.sv; hierarchy -chparam X 123123123 -top top; prep -flatten' \ + -p 'sat -verify -prove-asserts -show-ports -set din[0] 1' \ + -p 'sat -falsify -prove-asserts -show-ports -set din[0] 0' + + ../../yosys -q -p 'verific -sv chparam2.sv; hierarchy -chparam X 123123123 -top top; prep -flatten' \ + -p 'sat -verify -prove-asserts -show-ports -set din[0] 1' \ + -p 'sat -falsify -prove-asserts -show-ports -set din[0] 0' +fi +../../yosys -q -p 'read_verilog -sv chparam2.sv; hierarchy -chparam X 123123123 -top top; prep -flatten' \ + -p 'sat -verify -prove-asserts -show-ports -set din[0] 1' \ + -p 'sat -falsify -prove-asserts -show-ports -set din[0] 0' + +rm chparam1.sv +rm chparam2.sv diff --git a/tests/various/elab_sys_tasks.sv b/tests/various/elab_sys_tasks.sv new file mode 100644 index 000000000..774d85b32 --- /dev/null +++ b/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/tests/various/elab_sys_tasks.ys b/tests/various/elab_sys_tasks.ys new file mode 100644 index 000000000..45bee3a60 --- /dev/null +++ b/tests/various/elab_sys_tasks.ys @@ -0,0 +1 @@ +read_verilog -sv elab_sys_tasks.sv diff --git a/tests/various/equiv_opt_multiclock.ys b/tests/various/equiv_opt_multiclock.ys new file mode 100644 index 000000000..81e36d018 --- /dev/null +++ b/tests/various/equiv_opt_multiclock.ys @@ -0,0 +1,12 @@ +read_verilog <<EOT +module top(input clk, pre, d, output reg q); + always @(posedge clk, posedge pre) + if (pre) + q <= 1'b1; + else + q <= d; +endmodule +EOT + +prep +equiv_opt -assert -multiclock -map +/simcells.v synth diff --git a/tests/various/gzip_verilog.v.gz b/tests/various/gzip_verilog.v.gz Binary files differnew file mode 100644 index 000000000..c52a95358 --- /dev/null +++ b/tests/various/gzip_verilog.v.gz diff --git a/tests/various/gzip_verilog.ys b/tests/various/gzip_verilog.ys new file mode 100644 index 000000000..870317e80 --- /dev/null +++ b/tests/various/gzip_verilog.ys @@ -0,0 +1,2 @@ +read_verilog gzip_verilog.v.gz +select -assert-any top diff --git a/tests/various/hierarchy.sh b/tests/various/hierarchy.sh new file mode 100644 index 000000000..9dbd1c89f --- /dev/null +++ b/tests/various/hierarchy.sh @@ -0,0 +1,60 @@ +#!/usr/bin/env bash +# Simple test of hierarchy -auto-top. + +set -e + +echo -n " TOP first - " +../../yosys -s - <<- EOY | grep "Automatically selected TOP as design top module" + read_verilog << EOV + module TOP(a, y); + input a; + output [31:0] y; + + aoi12 p [31:0] (a, y); + endmodule + + module aoi12(a, y); + input a; + output y; + assign y = ~a; + endmodule + EOV + hierarchy -auto-top +EOY + +echo -n " TOP last - " +../../yosys -s - <<- EOY | grep "Automatically selected TOP as design top module" + read_verilog << EOV + module aoi12(a, y); + input a; + output y; + assign y = ~a; + endmodule + + module TOP(a, y); + input a; + output [31:0] y; + + aoi12 foo (a, y); + endmodule + EOV + hierarchy -auto-top +EOY + +echo -n " no explicit top - " +../../yosys -s - <<- EOY | grep "Automatically selected noTop as design top module." + read_verilog << EOV + module aoi12(a, y); + input a; + output y; + assign y = ~a; + endmodule + + module noTop(a, y); + input a; + output [31:0] y; + assign y = a; + endmodule + EOV + hierarchy -auto-top +EOY diff --git a/tests/various/hierarchy_defer.ys b/tests/various/hierarchy_defer.ys new file mode 100644 index 000000000..70f5b70a3 --- /dev/null +++ b/tests/various/hierarchy_defer.ys @@ -0,0 +1,27 @@ +read -noverific +read -vlog2k <<EOT +module first; +endmodule + +(* top *) +module top(input i, output o); +sub s0(i, o); +endmodule + +(* constant_expression=1+1?2*2:3/3 *) +module sub(input i, output o); +assign o = ~i; +endmodule +EOT +design -save read + +hierarchy -auto-top +select -assert-any top +select -assert-any sub +select -assert-none foo + +design -load read +hierarchy +select -assert-any top +select -assert-any sub +select -assert-none foo diff --git a/tests/various/mem2reg.ys b/tests/various/mem2reg.ys new file mode 100644 index 000000000..85d6267c5 --- /dev/null +++ b/tests/various/mem2reg.ys @@ -0,0 +1,14 @@ +read_verilog <<EOT +module top; +parameter DATADEPTH=2; +parameter DATAWIDTH=1; +(* keep, nomem2reg *) reg [DATAWIDTH-1:0] data1 [DATADEPTH-1:0]; +(* keep, mem2reg *) reg [DATAWIDTH-1:0] data2 [DATADEPTH-1:0]; +endmodule +EOT + +proc +cd top +select -assert-count 1 m:data1 a:src=<<EOT:4 %i +select -assert-count 2 w:data2[*] a:src=<<EOT:5 %i +select -assert-none a:mem2reg diff --git a/tests/various/muxcover.ys b/tests/various/muxcover.ys index 7ac460f13..67e9625e6 100644 --- a/tests/various/muxcover.ys +++ b/tests/various/muxcover.ys @@ -13,7 +13,7 @@ read_verilog -formal <<EOT EOT -## Examle usage for "pmuxtree" and "muxcover" +## Example usage for "pmuxtree" and "muxcover" proc pmuxtree @@ -49,3 +49,462 @@ hierarchy -top equiv equiv_simple -undef equiv_status -assert +## Partial matching MUX4 + +design -reset +read_verilog -formal <<EOT +module mux_if_bal_3_1 #(parameter N=3, parameter W=1) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o); +always @* begin + o <= {{W{{1'bx}}}}; + if (s[0] == 1'b0) + if (s[1] == 1'b0) + o <= i[0*W+:W]; + else + o <= i[1*W+:W]; + else + if (s[1] == 1'b0) + o <= i[2*W+:W]; +end +endmodule +EOT +prep +design -save gold + +techmap +muxcover -mux4=150 +select -assert-count 0 t:$_MUX_ +select -assert-count 1 t:$_MUX4_ +select -assert-count 0 t:$_MUX8_ +select -assert-count 0 t:$_MUX16_ +techmap -map +/simcells.v t:$_MUX4_ +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 miter + +## Partial matching MUX8 + +design -reset +read_verilog -formal <<EOT +module mux_if_bal_5_1 #(parameter N=5, parameter W=1) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o); +always @* begin + o <= {{W{{1'bx}}}}; + if (s[0] == 1'b0) + if (s[1] == 1'b0) + if (s[2] == 1'b0) + o <= i[0*W+:W]; + else + o <= i[1*W+:W]; + else + if (s[2] == 1'b0) + o <= i[2*W+:W]; + else + o <= i[3*W+:W]; + else + if (s[1] == 1'b0) + if (s[2] == 1'b0) + o <= i[4*W+:W]; +end +endmodule +EOT +prep +design -save gold + +techmap +muxcover -mux4=150 -mux8=200 +clean +opt_expr -mux_bool +select -assert-count 0 t:$_MUX_ +select -assert-count 0 t:$_MUX4_ +select -assert-count 1 t:$_MUX8_ +select -assert-count 0 t:$_MUX16_ +techmap -map +/simcells.v t:$_MUX8_ +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 miter + +## Partial matching MUX16 + +design -reset +read_verilog -formal <<EOT +module mux_if_bal_9_1 #(parameter N=9, parameter W=1) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o); +always @* begin + o <= {{W{{1'bx}}}}; + if (s[0] == 1'b0) + if (s[1] == 1'b0) + if (s[2] == 1'b0) + if (s[3] == 1'b0) + o <= i[0*W+:W]; + else + o <= i[1*W+:W]; + else + if (s[3] == 1'b0) + o <= i[2*W+:W]; + else + o <= i[3*W+:W]; + else + if (s[2] == 1'b0) + if (s[3] == 1'b0) + o <= i[4*W+:W]; + else + o <= i[5*W+:W]; + else + if (s[3] == 1'b0) + o <= i[6*W+:W]; + else + o <= i[7*W+:W]; + else + if (s[1] == 1'b0) + if (s[2] == 1'b0) + if (s[3] == 1'b0) + o <= i[8*W+:W]; +end +endmodule +EOT +prep +design -save gold + +techmap +muxcover -mux4=150 -mux8=200 -mux16=250 +clean +opt_expr -mux_bool +select -assert-count 0 t:$_MUX_ +select -assert-count 0 t:$_MUX4_ +select -assert-count 0 t:$_MUX8_ +select -assert-count 1 t:$_MUX16_ +techmap -map +/simcells.v t:$_MUX16_ +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 miter + +## MUX2 in MUX4 :: https://github.com/YosysHQ/yosys/issues/1132 + +design -reset +read_verilog -formal <<EOT +module mux2in4(input [1:0] i, input s, output o); + assign o = s ? i[1] : i[0]; +endmodule +EOT +prep +design -save gold + +techmap +muxcover -mux4=99 -nodecode +clean +opt_expr -mux_bool +select -assert-count 0 t:$_MUX_ +select -assert-count 1 t:$_MUX4_ +select -assert-count 0 t:$_MUX8_ +select -assert-count 0 t:$_MUX16_ +techmap -map +/simcells.v t:$_MUX4_ +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 miter + +## MUX2 in MUX8 :: https://github.com/YosysHQ/yosys/issues/1132 + +design -reset +read_verilog -formal <<EOT +module mux2in8(input [1:0] i, input s, output o); + assign o = s ? i[1] : i[0]; +endmodule +EOT +prep +design -save gold + +techmap +muxcover -mux8=99 -nodecode +clean +opt_expr -mux_bool +select -assert-count 0 t:$_MUX_ +select -assert-count 0 t:$_MUX4_ +select -assert-count 1 t:$_MUX8_ +select -assert-count 0 t:$_MUX16_ +techmap -map +/simcells.v t:$_MUX8_ +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 miter + +## MUX4 in MUX8 :: https://github.com/YosysHQ/yosys/issues/1132 + +design -reset +read_verilog -formal <<EOT +module mux4in8(input [3:0] i, input [1:0] s, output o); + assign o = s[1] ? (s[0] ? i[3] : i[2]) : (s[0] ? i[1] : i[0]); +endmodule +EOT +prep +design -save gold + +techmap +muxcover -mux8=299 -nodecode +clean +opt_expr -mux_bool +select -assert-count 0 t:$_MUX_ +select -assert-count 0 t:$_MUX4_ +select -assert-count 1 t:$_MUX8_ +select -assert-count 0 t:$_MUX16_ +techmap -map +/simcells.v t:$_MUX8_ +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 miter + +## MUX2 in MUX16 :: https://github.com/YosysHQ/yosys/issues/1132 + +design -reset +read_verilog -formal <<EOT +module mux2in16(input [1:0] i, input s, output o); + assign o = s ? i[1] : i[0]; +endmodule +EOT +prep +design -save gold + +techmap +muxcover -mux16=99 -nodecode +clean +opt_expr -mux_bool +select -assert-count 0 t:$_MUX_ +select -assert-count 0 t:$_MUX4_ +select -assert-count 0 t:$_MUX8_ +select -assert-count 1 t:$_MUX16_ +techmap -map +/simcells.v t:$_MUX16_ +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 miter + +## MUX4 in MUX16 :: https://github.com/YosysHQ/yosys/issues/1132 + +design -reset +read_verilog -formal <<EOT +module mux4in16(input [3:0] i, input [1:0] s, output o); + assign o = s[1] ? (s[0] ? i[3] : i[2]) : (s[0] ? i[1] : i[0]); +endmodule +EOT +prep +design -save gold + +techmap +muxcover -mux16=299 -nodecode +clean +opt_expr -mux_bool +select -assert-count 0 t:$_MUX_ +select -assert-count 0 t:$_MUX4_ +select -assert-count 0 t:$_MUX8_ +select -assert-count 1 t:$_MUX16_ +techmap -map +/simcells.v t:$_MUX16_ +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 miter + +## MUX8 in MUX16 :: https://github.com/YosysHQ/yosys/issues/1132 + +design -reset +read_verilog -formal <<EOT +module mux4in16(input [7:0] i, input [2:0] s, output o); + assign o = s[2] ? s[1] ? (s[0] ? i[3] : i[2]) : (s[0] ? i[1] : i[0]) + : s[1] ? (s[0] ? i[7] : i[6]) : (s[0] ? i[5] : i[4]); +endmodule +EOT +prep +design -save gold + +techmap +muxcover -mux16=699 -nodecode +clean +opt_expr -mux_bool +select -assert-count 0 t:$_MUX_ +select -assert-count 0 t:$_MUX4_ +select -assert-count 0 t:$_MUX8_ +select -assert-count 1 t:$_MUX16_ +techmap -map +/simcells.v t:$_MUX16_ +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 miter + +## mux_if_bal_5_1 :: https://github.com/YosysHQ/yosys/issues/1132 + +design -reset +read_verilog -formal <<EOT +module mux_if_bal_5_1 #(parameter N=5, parameter W=1) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o); +always @* begin + o <= {{W{{1'bx}}}}; + if (s[0] == 1'b0) + if (s[1] == 1'b0) + if (s[2] == 1'b0) + o <= i[0*W+:W]; + else + o <= i[1*W+:W]; + else + if (s[2] == 1'b0) + o <= i[2*W+:W]; + else + o <= i[3*W+:W]; + else + if (s[1] == 1'b0) + if (s[2] == 1'b0) + o <= i[4*W+:W]; +end +endmodule +EOT +prep +design -save gold + +wreduce +opt -full +techmap +muxcover -mux8=350 +clean +opt_expr -mux_bool +select -assert-count 0 t:$_MUX_ +select -assert-count 0 t:$_MUX4_ +select -assert-count 1 t:$_MUX8_ +select -assert-count 0 t:$_MUX16_ +techmap -map +/simcells.v t:$_MUX8_ +design -stash gate + +design -import gold -as gold +design -import gate -as gate + +miter -equiv -flatten -make_assert -make_outputs -ignore_gold_x gold gate miter +sat -verify -prove-asserts -show-ports miter + +## mux_if_bal_5_1 (nodecode) :: https://github.com/YosysHQ/yosys/issues/1132 +design -load gold + +wreduce +opt -full +techmap +muxcover -mux8=350 -nodecode +clean +opt_expr -mux_bool +select -assert-count 0 t:$_MUX_ +select -assert-count 0 t:$_MUX4_ +select -assert-count 1 t:$_MUX8_ +select -assert-count 0 t:$_MUX16_ +techmap -map +/simcells.v t:$_MUX8_ +design -stash gate + +design -import gold -as gold +design -import gate -as gate + +miter -equiv -flatten -make_assert -make_outputs -ignore_gold_x gold gate miter +sat -verify -prove-asserts -show-ports miter + +## mux_if_bal_9_1 :: https://github.com/YosysHQ/yosys/issues/1132 + +design -reset +read_verilog -formal <<EOT +module mux_if_bal_9_1 #(parameter N=9, parameter W=1) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o); +always @* begin + o <= {{W{{1'bx}}}}; + if (s[3] == 1'b0) + if (s[2] == 1'b0) + if (s[1] == 1'b0) + if (s[0] == 1'b0) + o <= i[0*W+:W]; + else + o <= i[1*W+:W]; + else + if (s[0] == 1'b0) + o <= i[2*W+:W]; + else + o <= i[3*W+:W]; + else + if (s[1] == 1'b0) + if (s[0] == 1'b0) + o <= i[4*W+:W]; + else + o <= i[5*W+:W]; + else + if (s[0] == 1'b0) + o <= i[6*W+:W]; + else + o <= i[7*W+:W]; + else + if (s[2] == 1'b0) + if (s[1] == 1'b0) + if (s[0] == 1'b0) + o <= i[8*W+:W]; +end +endmodule +EOT +prep +design -save gold + +wreduce +opt -full +techmap +muxcover -mux16=750 +clean +opt_expr -mux_bool +select -assert-count 0 t:$_MUX_ +select -assert-count 0 t:$_MUX4_ +select -assert-count 0 t:$_MUX8_ +select -assert-count 1 t:$_MUX16_ +techmap -map +/simcells.v t:$_MUX16_ +design -stash gate + +design -import gold -as gold +design -import gate -as gate + +miter -equiv -flatten -make_assert -make_outputs -ignore_gold_x gold gate miter +sat -verify -prove-asserts -show-ports miter + +## mux_if_bal_9_1 (nodecode) :: https://github.com/YosysHQ/yosys/issues/1132 + +design -load gold + +wreduce +opt -full +techmap +muxcover -mux16=750 -nodecode +clean +opt_expr -mux_bool +select -assert-count 0 t:$_MUX_ +select -assert-count 0 t:$_MUX4_ +select -assert-count 0 t:$_MUX8_ +select -assert-count 1 t:$_MUX16_ +techmap -map +/simcells.v t:$_MUX16_ +design -stash gate + +design -import gold -as gold +design -import gate -as gate + +miter -equiv -flatten -make_assert -make_outputs -ignore_gold_x gold gate miter +sat -verify -prove-asserts -show-ports miter diff --git a/tests/various/muxpack.v b/tests/various/muxpack.v new file mode 100644 index 000000000..33ece1f16 --- /dev/null +++ b/tests/various/muxpack.v @@ -0,0 +1,259 @@ +module mux_if_unbal_4_1 #(parameter N=4, parameter W=1) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o); +always @* + if (s == 0) o <= i[0*W+:W]; + else if (s == 1) o <= i[1*W+:W]; + else if (s == 2) o <= i[2*W+:W]; + else if (s == 3) o <= i[3*W+:W]; + else o <= {W{1'bx}}; +endmodule + +module mux_if_unbal_5_3 #(parameter N=5, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o); +always @* begin + o <= {W{1'bx}}; + if (s == 0) o <= i[0*W+:W]; + if (s == 1) o <= i[1*W+:W]; + if (s == 2) o <= i[2*W+:W]; + if (s == 3) o <= i[3*W+:W]; + if (s == 4) o <= i[4*W+:W]; +end +endmodule + +module mux_if_unbal_5_3_invert #(parameter N=5, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o); +always @* + if (s != 0) + if (s != 1) + if (s != 2) + if (s != 3) + if (s != 4) o <= i[4*W+:W]; + else o <= i[0*W+:W]; + else o <= i[3*W+:W]; + else o <= i[2*W+:W]; + else o <= i[1*W+:W]; + else o <= {W{1'bx}}; +endmodule + +module mux_if_unbal_5_3_width_mismatch #(parameter N=5, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o); +always @* begin + o <= {W{1'bx}}; + if (s == 0) o <= i[0*W+:W]; + if (s == 1) o <= i[1*W+:W]; + if (s == 2) o[W-2:0] <= i[2*W+:W-1]; + if (s == 3) o <= i[3*W+:W]; + if (s == 4) o <= i[4*W+:W]; +end +endmodule + +module mux_if_unbal_4_1_missing #(parameter N=5, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o); +always @* begin + if (s == 0) o <= i[0*W+:W]; +// else if (s == 1) o <= i[1*W+:W]; +// else if (s == 2) o <= i[2*W+:W]; + else if (s == 3) o <= i[3*W+:W]; + else o <= {W{1'bx}}; +end +endmodule + +module mux_if_unbal_5_3_order #(parameter N=5, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o); +always @* begin + o <= {W{1'bx}}; + if (s == 3) o <= i[3*W+:W]; + if (s == 2) o <= i[2*W+:W]; + if (s == 1) o <= i[1*W+:W]; + if (s == 4) o <= i[4*W+:W]; + if (s == 0) o <= i[0*W+:W]; +end +endmodule + +module mux_if_unbal_4_1_nonexcl #(parameter N=4, parameter W=1) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o); +always @* + if (s == 0) o <= i[0*W+:W]; + else if (s == 1) o <= i[1*W+:W]; + else if (s == 2) o <= i[2*W+:W]; + else if (s == 3) o <= i[3*W+:W]; + else if (s == 0) o <= {W{1'b0}}; + else o <= {W{1'bx}}; +endmodule + +module mux_if_unbal_5_3_nonexcl #(parameter N=5, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o); +always @* begin + o <= {W{1'bx}}; + if (s == 0) o <= i[0*W+:W]; + if (s == 1) o <= i[1*W+:W]; + if (s == 2) o <= i[2*W+:W]; + if (s == 3) o <= i[3*W+:W]; + if (s == 4) o <= i[4*W+:W]; + if (s == 0) o <= i[2*W+:W]; +end +endmodule + +module mux_case_unbal_8_7#(parameter N=8, parameter W=7) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o); +always @* begin + o <= {W{1'bx}}; + case (s) + 0: o <= i[0*W+:W]; + default: + case (s) + 1: o <= i[1*W+:W]; + 2: o <= i[2*W+:W]; + default: + case (s) + 3: o <= i[3*W+:W]; + 4: o <= i[4*W+:W]; + 5: o <= i[5*W+:W]; + default: + case (s) + 6: o <= i[6*W+:W]; + default: o <= i[7*W+:W]; + endcase + endcase + endcase + endcase +end +endmodule + +module mux_if_bal_8_2 #(parameter N=8, parameter W=2) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o); +always @* + if (s[0] == 1'b0) + if (s[1] == 1'b0) + if (s[2] == 1'b0) + o <= i[0*W+:W]; + else + o <= i[1*W+:W]; + else + if (s[2] == 1'b0) + o <= i[2*W+:W]; + else + o <= i[3*W+:W]; + else + if (s[1] == 1'b0) + if (s[2] == 1'b0) + o <= i[4*W+:W]; + else + o <= i[5*W+:W]; + else + if (s[2] == 1'b0) + o <= i[6*W+:W]; + else + o <= i[7*W+:W]; +endmodule + +module mux_if_bal_5_1 #(parameter N=5, parameter W=1) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output reg [W-1:0] o); +always @* + if (s[0] == 1'b0) + if (s[1] == 1'b0) + if (s[2] == 1'b0) + o <= i[0*W+:W]; + else + o <= i[1*W+:W]; + else + if (s[2] == 1'b0) + o <= i[2*W+:W]; + else + o <= i[3*W+:W]; + else + o <= i[4*W+:W]; +endmodule + +module cliffordwolf_nonexclusive_select ( + input wire x, y, z, + input wire a, b, c, d, + output reg o +); + always @* begin + o = a; + if (x) o = b; + if (y) o = c; + if (z) o = d; + end +endmodule + +module cliffordwolf_freduce ( + input wire [1:0] s, + input wire a, b, c, d, + output reg [3:0] o +); + always @* begin + o = {4{a}}; + if (s == 0) o = {3{b}}; + if (s == 1) o = {2{c}}; + if (s == 2) o = d; + end +endmodule + +module case_nonexclusive_select ( + input wire [1:0] x, y, + input wire a, b, c, d, e, + output reg o +); + always @* begin + case (x) + 0: o = b; + 2: o = b; + 1: o = c; + default: begin + o = a; + if (y == 0) o = d; + if (y == 1) o = e; + end + endcase + end +endmodule + +module case_nonoverlap ( + input wire [2:0] x, + input wire a, b, c, d, e, + output reg o +); + always @* begin + case (x) + 0, 2: o = b; // Creates $reduce_or + 1: o = c; + default: + case (x) + 3: o = d; 4: o = d; // Creates $reduce_or + 5: o = e; + default: o = 1'b0; + endcase + endcase + end +endmodule + +module case_overlap ( + input wire [2:0] x, + input wire a, b, c, d, e, + output reg o +); + always @* begin + case (x) + 0, 2: o = b; // Creates $reduce_or + 1: o = c; + default: + case (x) + 0: o = 1'b1; // OVERLAP! + 3, 4: o = d; // Creates $reduce_or + 5: o = e; + default: o = 1'b0; + endcase + endcase + end +endmodule + +module case_overlap2 ( + input wire [2:0] x, + input wire a, b, c, d, e, + output reg o +); + always @* begin + case (x) + 0: o = b; 2: o = b; // Creates $reduce_or + 1: o = c; + default: + case (x) + 0: o = d; 2: o = d; // Creates $reduce_or + 3: o = d; 4: o = d; // Creates $reduce_or + 5: o = e; + default: o = 1'b0; + endcase + endcase + end +endmodule diff --git a/tests/various/muxpack.ys b/tests/various/muxpack.ys new file mode 100644 index 000000000..3e90419af --- /dev/null +++ b/tests/various/muxpack.ys @@ -0,0 +1,268 @@ +read_verilog muxpack.v +design -save read + +hierarchy -top mux_if_unbal_4_1 +prep +design -save gold +muxpack +opt +#stat +select -assert-count 0 t:$mux +select -assert-count 1 t:$pmux +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 miter + +design -load read +hierarchy -top mux_if_unbal_5_3 +prep +design -save gold +muxpack +opt +#stat +select -assert-count 0 t:$mux +select -assert-count 1 t:$pmux +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 miter + +# TODO: Currently ExclusiveDatabase only analyses $eq cells +#design -load read +#hierarchy -top mux_if_unbal_5_3_invert +#prep +#design -save gold +#muxpack +#opt +#stat +#select -assert-count 0 t:$mux +#select -assert-count 1 t:$pmux +#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 miter + +design -load read +hierarchy -top mux_if_unbal_5_3_width_mismatch +prep +design -save gold +muxpack +opt +#stat +select -assert-count 0 t:$mux +select -assert-count 2 t:$pmux +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 miter + +design -load read +hierarchy -top mux_if_unbal_4_1_missing +prep +design -save gold +muxpack +opt +#stat +select -assert-count 0 t:$mux +select -assert-count 1 t:$pmux +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 miter + +design -load read +hierarchy -top mux_if_unbal_5_3_order +prep +design -save gold +muxpack +opt +#stat +select -assert-count 0 t:$mux +select -assert-count 1 t:$pmux +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 miter + +design -load read +hierarchy -top mux_if_unbal_4_1_nonexcl +prep +design -save gold +muxpack +opt +#stat +select -assert-count 0 t:$mux +select -assert-count 1 t:$pmux +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 miter + +design -load read +hierarchy -top mux_if_unbal_5_3_nonexcl +prep +design -save gold +muxpack +opt +#stat +select -assert-count 0 t:$mux +select -assert-count 1 t:$pmux +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 miter + +design -load read +hierarchy -top mux_case_unbal_8_7 +prep +design -save gold +muxpack +opt +#stat +select -assert-count 0 t:$mux +select -assert-count 1 t:$pmux +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 miter + +design -load read +hierarchy -top mux_if_bal_8_2 +prep +design -save gold +muxpack +opt +#stat +select -assert-count 7 t:$mux +select -assert-count 0 t:$pmux +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 miter + +design -load read +hierarchy -top mux_if_bal_5_1 +prep +design -save gold +muxpack +opt +#stat +select -assert-count 4 t:$mux +select -assert-count 0 t:$pmux +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 miter + +design -load read +hierarchy -top cliffordwolf_nonexclusive_select +prep +design -save gold +muxpack +opt +#stat +select -assert-count 3 t:$mux +select -assert-count 0 t:$pmux +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 miter + +#design -load read +#hierarchy -top cliffordwolf_freduce +#prep +#design -save gold +#proc; opt; freduce; opt +#show +#muxpack +#opt +#stat +#select -assert-count 0 t:$mux +#select -assert-count 1 t:$pmux +#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 miter + +design -load read +hierarchy -top case_nonexclusive_select +prep +design -save gold +muxpack +opt +#stat +select -assert-count 0 t:$mux +select -assert-count 2 t:$pmux +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 miter + +design -load read +hierarchy -top case_nonoverlap +#prep # Do not prep otherwise $pmux's overlapping entry will get removed +proc +design -save gold +opt -fast -mux_undef +select -assert-count 2 t:$pmux +muxpack +opt +#stat +select -assert-count 0 t:$mux +select -assert-count 1 t:$pmux +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 miter + +design -load read +hierarchy -top case_overlap +#prep # Do not prep otherwise $pmux's overlapping entry will get removed +proc +design -save gold +opt -fast -mux_undef +select -assert-count 2 t:$pmux +muxpack +opt +#stat +select -assert-count 0 t:$mux +select -assert-count 2 t:$pmux +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 miter + +design -load read +hierarchy -top case_overlap2 +#prep # Do not prep otherwise $pmux's overlapping entry will get removed +proc +design -save gold +opt -fast -mux_undef +select -assert-count 2 t:$pmux +muxpack +opt +#stat +select -assert-count 0 t:$mux +select -assert-count 2 t:$pmux +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 miter diff --git a/tests/various/peepopt.ys b/tests/various/peepopt.ys new file mode 100644 index 000000000..6bca62e2b --- /dev/null +++ b/tests/various/peepopt.ys @@ -0,0 +1,175 @@ +read_verilog <<EOT +module peepopt_shiftmul_0 #(parameter N=3, parameter W=3) (input [N*W-1:0] i, input [$clog2(N)-1:0] s, output [W-1:0] o); +assign o = i[s*W+:W]; +endmodule +EOT + +prep -nokeepdc +equiv_opt -assert peepopt +design -load postopt +clean +select -assert-count 1 t:$shiftx +select -assert-count 0 t:$shiftx t:* %D + +#################### + +design -reset +read_verilog <<EOT +module peepopt_shiftmul_1 (output [7:0] y, input [2:0] w); +assign y = 1'b1 >> (w * (3'b110)); +endmodule +EOT + +prep -nokeepdc +equiv_opt -assert peepopt +design -load postopt +clean +select -assert-count 1 t:$shr +select -assert-count 1 t:$mul +select -assert-count 0 t:$shr t:$mul %% t:* %D + +#################### + +design -reset +read_verilog <<EOT +module peepopt_shiftmul_2 (input [11:0] D, input [1:0] S, output [11:0] Y); + assign Y = D >> (S*3); +endmodule +EOT + +prep +design -save gold +peepopt +design -stash gate + +design -import gold -as gold peepopt_shiftmul_2 +design -import gate -as gate peepopt_shiftmul_2 + +miter -equiv -make_assert -make_outputs -ignore_gold_x -flatten gold gate miter +sat -show-public -enable_undef -prove-asserts miter +cd gate +select -assert-count 1 t:$shr +select -assert-count 1 t:$mul +select -assert-count 0 t:$shr t:$mul %% t:* %D + +#################### + +design -reset +read_verilog <<EOT +module peepopt_muldiv_0(input [1:0] i, output [1:0] o); +wire [3:0] t; +assign t = i * 3; +assign o = t / 3; +endmodule +EOT + +prep -nokeepdc +equiv_opt -assert peepopt +design -load postopt +clean +select -assert-count 0 t:* + +#################### + +design -reset +read_verilog <<EOT +module peepopt_dffmuxext_unsigned(input clk, ce, input [1:0] i, output reg [3:0] o); + always @(posedge clk) if (ce) o <= i; +endmodule +EOT + +proc +equiv_opt -assert peepopt +design -load postopt +clean +select -assert-count 1 t:$dff r:WIDTH=2 %i +select -assert-count 1 t:$mux r:WIDTH=2 %i +select -assert-count 0 t:$dff t:$mux %% t:* %D + +#################### + +design -reset +read_verilog <<EOT +module peepopt_dffmuxext_signed(input clk, ce, input signed [1:0] i, output reg signed [3:0] o); + always @(posedge clk) if (ce) o <= i; +endmodule +EOT + +proc +equiv_opt -assert peepopt +design -load postopt +clean +select -assert-count 1 t:$dff r:WIDTH=2 %i +select -assert-count 1 t:$mux r:WIDTH=2 %i +select -assert-count 0 t:$dff t:$mux %% t:* %D + +################### + +design -reset +read_verilog <<EOT +module peepopt_dffmuxext_const(input clk, ce, input [1:0] i, output reg [5:0] o); + always @(posedge clk) if (ce) o <= {1'b0, i[1], 2'b1x, i[0], 1'bz}; +endmodule +EOT + +proc +equiv_opt -assert peepopt +design -load postopt +select -assert-count 1 t:$dff r:WIDTH=2 %i +select -assert-count 1 t:$mux r:WIDTH=2 %i +select -assert-count 0 t:$dff t:$mux %% t:* %D + +################### + +design -reset +read_verilog <<EOT +module peepopt_dffmuxext_const_init(input clk, ce, input [1:0] i, (* init=6'b0x00x1 *) output reg [5:0] o); + always @(posedge clk) if (ce) o <= {1'b0, i[1], 2'b1x, i[0], 1'bz}; +endmodule +EOT + +proc +equiv_opt -assert peepopt +design -load postopt +select -assert-count 1 t:$dff r:WIDTH=5 %i +select -assert-count 1 t:$mux r:WIDTH=5 %i +select -assert-count 0 t:$dff t:$mux %% t:* %D + +#################### + +design -reset +read_verilog <<EOT +module peepopt_dffmuxext_unsigned_rst(input clk, ce, rst, input [1:0] i, output reg [3:0] o); + always @(posedge clk) if (rst) o <= 0; else if (ce) o <= i; +endmodule +EOT + +proc +equiv_opt -assert peepopt +design -load postopt +wreduce +select -assert-count 1 t:$dff r:WIDTH=2 %i +select -assert-count 2 t:$mux +select -assert-count 2 t:$mux r:WIDTH=2 %i +select -assert-count 0 t:$dff t:$mux %% t:* %D + +#################### + +design -reset +read_verilog <<EOT +module peepopt_dffmuxext_signed_rst(input clk, ce, rstn, input signed [1:0] i, output reg signed [3:0] o); + always @(posedge clk) begin + if (ce) o <= i; + if (!rstn) o <= 4'b1111; + end +endmodule +EOT + +proc +equiv_opt -assert peepopt +design -load postopt +wreduce +select -assert-count 1 t:$dff r:WIDTH=2 %i +select -assert-count 2 t:$mux +select -assert-count 2 t:$mux r:WIDTH=2 %i +select -assert-count 0 t:$logic_not t:$dff t:$mux %% t:* %D diff --git a/tests/various/pmgen_reduce.ys b/tests/various/pmgen_reduce.ys new file mode 100644 index 000000000..c214d3f25 --- /dev/null +++ b/tests/various/pmgen_reduce.ys @@ -0,0 +1,21 @@ +test_pmgen -generate reduce +hierarchy -top pmtest_test_pmgen_pm_reduce +flatten; opt_clean + +design -save gold +test_pmgen -reduce_chain +design -stash gate + +design -copy-from gold -as gold pmtest_test_pmgen_pm_reduce +design -copy-from gate -as gate pmtest_test_pmgen_pm_reduce +miter -equiv -flatten -make_assert gold gate miter +sat -verify -prove-asserts miter + +design -load gold +test_pmgen -reduce_tree +design -stash gate + +design -copy-from gold -as gold pmtest_test_pmgen_pm_reduce +design -copy-from gate -as gate pmtest_test_pmgen_pm_reduce +miter -equiv -flatten -make_assert gold gate miter +sat -verify -prove-asserts miter diff --git a/tests/various/pmux2shiftx.v b/tests/various/pmux2shiftx.v new file mode 100644 index 000000000..563394080 --- /dev/null +++ b/tests/various/pmux2shiftx.v @@ -0,0 +1,44 @@ +module pmux2shiftx_test ( + input [2:0] S1, + input [5:0] S2, + input [1:0] S3, + input [9:0] A, B, C, D, D, E, F, G, H, + input [9:0] I, J, K, L, M, N, O, P, Q, + output reg [9:0] X +); + always @* begin + case (S1) + 3'd 0: X = A; + 3'd 1: X = B; + 3'd 2: X = C; + 3'd 3: X = D; + 3'd 4: X = E; + 3'd 5: X = F; + 3'd 6: X = G; + 3'd 7: X = H; + endcase + case (S2) + 6'd 45: X = I; + 6'd 47: X = J; + 6'd 49: X = K; + 6'd 55: X = L; + 6'd 57: X = M; + 6'd 59: X = N; + endcase + case (S3) + 2'd 1: X = O; + 2'd 2: X = P; + 2'd 3: X = Q; + endcase + end +endmodule + +module issue01135(input [7:0] i, output o); +always @* +case (i[6:3]) + 4: o <= i[0]; + 3: o <= i[2]; + 7: o <= i[3]; + default: o <= 1'b0; +endcase +endmodule diff --git a/tests/various/pmux2shiftx.ys b/tests/various/pmux2shiftx.ys new file mode 100644 index 000000000..51ee2f7be --- /dev/null +++ b/tests/various/pmux2shiftx.ys @@ -0,0 +1,39 @@ +read_verilog pmux2shiftx.v +design -save read + +hierarchy -top pmux2shiftx_test +prep +design -save gold + +pmux2shiftx -min_density 70 + +opt + +stat +# show -width +select -assert-count 1 t:$sub +select -assert-count 1 t:$mux +select -assert-count 1 t:$shift +select -assert-count 3 t:$shiftx + +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 miter + +#design -load gold +#stat +# +#design -load gate +#stat + +design -load read +hierarchy -top issue01135 +proc +pmux2shiftx -norange +opt -full +select -assert-count 0 t:$shift* +select -assert-count 1 t:$pmux diff --git a/tests/various/reg_wire_error.sv b/tests/various/reg_wire_error.sv new file mode 100644 index 000000000..fe5ff3abd --- /dev/null +++ b/tests/various/reg_wire_error.sv @@ -0,0 +1,74 @@ +module sub_mod(input i_in, output o_out); +assign o_out = i_in; +endmodule + +module test(i_clk, i, i_reg, o_reg, o_wire, o_mr, o_mw, o_ml); +input i_clk; +input i; +input i_reg; +output o_reg; +output o_wire; +output o_mr, o_mw, o_ml; + +// Enable this to see how it doesn't fail on yosys although it should +//reg o_wire; +// Enable this instead of the above to see how logic can be mapped to a wire +logic o_wire; +// Enable this to see how it doesn't fail on yosys although it should +//reg i_reg; +// Disable this to see how it doesn't fail on yosys although it should +//reg o_reg; + +logic l_reg; + +// Enable this to tst if logic-turne-reg will catch assignments even if done before it turned into a reg +assign l_reg = !o_reg; +initial o_reg = 1'b0; +always @(posedge i_clk) +begin + o_reg <= !o_reg; + l_reg <= !o_reg; +end + +assign o_wire = !o_reg; +// Uncomment this to see how a logic already turned intoa reg can be freely assigned on yosys +assign l_reg = !o_reg; + +sub_mod sm_inst ( + .i_in(1'b1), + .o_out(o_reg) +); + +wire mw1[0:1]; +wire mw2[0:1]; +wire mw3[0:1]; +reg mr1[0:1]; +reg mr2[0:1]; +reg mr3[0:1]; +logic ml1[0:1]; +logic ml2[0:1]; +logic ml3[0:1]; + +assign o_mw = mw1[i]; +assign o_mr = mr1[i]; +assign o_ml = ml1[i]; + +assign mw1[1] = 1'b1; +//assign mr1[1] = 1'b1; +assign ml1[1] = 1'b1; +always @(posedge i_clk) +begin + mr2[0] = 1'b0; + mw2[0] = 1'b0; + ml2[0] = 1'b0; +end + +always @(posedge i_clk) +begin + mr3[0] <= 1'b0; + mw3[0] <= 1'b0; + ml3[0] <= 1'b0; +end + +endmodule + diff --git a/tests/various/reg_wire_error.ys b/tests/various/reg_wire_error.ys new file mode 100644 index 000000000..b9d03155d --- /dev/null +++ b/tests/various/reg_wire_error.ys @@ -0,0 +1 @@ +read_verilog -sv reg_wire_error.sv diff --git a/tests/various/run-test.sh b/tests/various/run-test.sh index 67e1beb23..ea56b70f0 100755 --- a/tests/various/run-test.sh +++ b/tests/various/run-test.sh @@ -1,6 +1,20 @@ -#!/bin/bash +#!/usr/bin/env bash set -e +{ +echo "all::" for x in *.ys; do - echo "Running $x.." - ../../yosys -ql ${x%.ys}.log $x + echo "all:: run-$x" + echo "run-$x:" + echo " @echo 'Running $x..'" + echo " @../../yosys -ql ${x%.ys}.log $x" done +for s in *.sh; do + if [ "$s" != "run-test.sh" ]; then + echo "all:: run-$s" + echo "run-$s:" + echo " @echo 'Running $s..'" + echo " @bash $s" + fi +done +} > run-test.mk +exec ${MAKE:-make} -f run-test.mk diff --git a/tests/various/script.ys b/tests/various/script.ys new file mode 100644 index 000000000..66b7b5caa --- /dev/null +++ b/tests/various/script.ys @@ -0,0 +1,20 @@ +read_verilog -formal <<EOT + module top; + foo bar(); + foo asdf(); + winnie the_pooh(); + + wire [1023:0] _RUNME0 = "select -assert-count 2 t:foo"; + wire [1023:0] _RUNME1 = "select -assert-count 1 t:winnie"; + endmodule + + module other; + wire [1023:0] _DELETE = "cd; delete c:bar"; + endmodule +EOT + +script -scriptwire w:_RUNME* + +select w:_DELETE +script -scriptwire +select -assert-count 1 t:foo diff --git a/tests/various/shregmap.v b/tests/various/shregmap.v new file mode 100644 index 000000000..604c2c976 --- /dev/null +++ b/tests/various/shregmap.v @@ -0,0 +1,48 @@ +module shregmap_static_test(input i, clk, output [1:0] q); +reg head = 1'b0; +reg [3:0] shift1 = 4'b0000; +reg [3:0] shift2 = 4'b0000; + +always @(posedge clk) begin + head <= i; + shift1 <= {shift1[2:0], head}; + shift2 <= {shift2[2:0], head}; +end + +assign q = {shift2[3], shift1[3]}; +endmodule + +module $__SHREG_DFF_P_(input C, D, output Q); +parameter DEPTH = 1; +parameter [DEPTH-1:0] INIT = {DEPTH{1'b0}}; +reg [DEPTH-1:0] r = INIT; +always @(posedge C) + r <= { r[DEPTH-2:0], D }; +assign Q = r[DEPTH-1]; +endmodule + +module shregmap_variable_test(input i, clk, input [1:0] l1, l2, output [1:0] q); +reg head = 1'b0; +reg [3:0] shift1 = 4'b0000; +reg [3:0] shift2 = 4'b0000; + +always @(posedge clk) begin + head <= i; + shift1 <= {shift1[2:0], head}; + shift2 <= {shift2[2:0], head}; +end + +assign q = {shift2[l2], shift1[l1]}; +endmodule + +module $__XILINX_SHREG_(input C, D, input [1:0] L, output Q); +parameter CLKPOL = 1; +parameter ENPOL = 1; +parameter DEPTH = 1; +parameter [DEPTH-1:0] INIT = {DEPTH{1'b0}}; +reg [DEPTH-1:0] r = INIT; +wire clk = C ^ CLKPOL; +always @(posedge C) + r <= { r[DEPTH-2:0], D }; +assign Q = r[L]; +endmodule diff --git a/tests/various/shregmap.ys b/tests/various/shregmap.ys new file mode 100644 index 000000000..16e5f40e1 --- /dev/null +++ b/tests/various/shregmap.ys @@ -0,0 +1,33 @@ +read_verilog shregmap.v +design -save read + +design -copy-to model $__SHREG_DFF_P_ +hierarchy -top shregmap_static_test +prep +design -save gold + +techmap +shregmap -init + +opt + +# stat +# show -width +select -assert-count 1 t:$_DFF_P_ +select -assert-count 2 t:$__SHREG_DFF_P_ + +design -stash gate + +design -import gold -as gold +design -import gate -as gate +design -copy-from model -as $__SHREG_DFF_P_ \$__SHREG_DFF_P_ +prep + +miter -equiv -flatten -make_assert -make_outputs gold gate miter +sat -verify -prove-asserts -show-ports -seq 5 miter + +#design -load gold +#stat + +#design -load gate +#stat diff --git a/tests/various/signext.ys b/tests/various/signext.ys new file mode 100644 index 000000000..0c8d671e7 --- /dev/null +++ b/tests/various/signext.ys @@ -0,0 +1,33 @@ + +read_verilog -formal <<EOT +module gate(input clk, output [32:0] o, p, q, r, s, t, u); +assign o = 'bx; +assign p = 1'bx; +assign q = 'bz; +assign r = 1'bz; +assign s = 1'b0; +assign t = 'b1; +assign u = -'sb1; +endmodule +EOT + +proc + +## Equivalence checking + +read_verilog -formal <<EOT +module gold(input clk, output [32:0] o, p, q, r, s, t, u); +assign o = {33{1'bx}}; +assign p = {{32{1'b0}}, 1'bx}; +assign q = {33{1'bz}}; +assign r = {{32{1'b0}}, 1'bz}; +assign s = {33{1'b0}}; +assign t = {{32{1'b0}}, 1'b1}; +assign u = {33{1'b1}}; +endmodule +EOT + +proc + +miter -equiv -flatten -make_assert -make_outputs gold gate miter +sat -verify -prove-asserts -show-ports -enable_undef miter diff --git a/tests/various/specify.v b/tests/various/specify.v new file mode 100644 index 000000000..5d44d78f7 --- /dev/null +++ b/tests/various/specify.v @@ -0,0 +1,39 @@ +module test ( + input EN, CLK, + input [3:0] D, + output reg [3:0] Q +); + always @(posedge CLK) + if (EN) Q <= D; + + specify +`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 + +module test2 ( + input A, B, + output Q +); + xor (Q, A, B); + specify + //specparam T_rise = 1; + //specparam T_fall = 2; + `define T_rise 1 + `define T_fall 2 + (A => Q) = (`T_rise,`T_fall); + //(B => Q) = (`T_rise+`T_fall)/2.0; + (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/tests/various/specify.ys b/tests/various/specify.ys new file mode 100644 index 000000000..00597e1e2 --- /dev/null +++ b/tests/various/specify.ys @@ -0,0 +1,58 @@ +read_verilog -specify specify.v +prep +cd test +select t:$specify2 -assert-count 0 +select t:$specify3 -assert-count 1 +select t:$specrule -assert-count 2 +cd test2 +select t:$specify2 -assert-count 2 +select t:$specify3 -assert-count 0 +select t:$specrule -assert-count 0 +cd +write_verilog specify.out +design -stash gold + +read_verilog -specify specify.out +prep +cd test +select t:$specify2 -assert-count 0 +select t:$specify3 -assert-count 1 +select t:$specrule -assert-count 2 +cd test2 +select t:$specify2 -assert-count 2 +select t:$specify3 -assert-count 0 +select t:$specrule -assert-count 0 +cd +design -stash gate + +design -copy-from gold -as gold test +design -copy-from gate -as gate test +rename -hide +rename -enumerate -pattern A_% t:$specify3 +rename -enumerate -pattern B_% t:$specrule r:TYPE=$setup %i +rename -enumerate -pattern C_% t:$specrule r:TYPE=$hold %i +select n:A_* -assert-count 2 +select n:B_* -assert-count 2 +select n:C_* -assert-count 2 +equiv_make gold gate equiv +hierarchy -top equiv +equiv_struct +equiv_induct -seq 5 +equiv_status -assert +design -reset + +design -copy-from gold -as gold test2 +design -copy-from gate -as gate test2 +rename -hide +rename -enumerate -pattern A_% t:$specify2 r:T_RISE_TYP=1 %i +rename -enumerate -pattern B_% t:$specify2 n:A_* %d +select n:A_* -assert-count 2 +select n:B_* -assert-count 2 +equiv_make gold gate equiv +hierarchy -top equiv +equiv_struct +equiv_induct -seq 5 +equiv_status -assert +design -reset + +read_verilog -DSKIP_UNSUPPORTED_IGN_PARSER_CONSTRUCTS specify.v diff --git a/tests/various/wreduce.ys b/tests/various/wreduce.ys new file mode 100644 index 000000000..2e0812c48 --- /dev/null +++ b/tests/various/wreduce.ys @@ -0,0 +1,79 @@ +read_verilog <<EOT +module wreduce_sub_test(input [3:0] i, input [7:0] j, output [8:0] o); + assign o = (j >> 4) - i; +endmodule +EOT + +hierarchy -auto-top +proc +design -save gold + +opt_expr +wreduce + +select -assert-count 1 t:$sub r:A_WIDTH=4 r:B_WIDTH=4 r:Y_WIDTH=5 %i %i %i + +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 miter + +########## + +read_verilog <<EOT +module wreduce_sub_signed_test(input signed [3:0] i, input signed [7:0] j, output signed [8:0] o); + assign o = (j >>> 4) - i; +endmodule +EOT + +hierarchy -auto-top +proc +design -save gold + +opt_expr +wreduce + +select -assert-count 1 t:$sub r:A_WIDTH=4 r:B_WIDTH=4 r:Y_WIDTH=5 %i %i %i + +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 miter + +########## + +# Testcase from: https://github.com/YosysHQ/yosys/commit/25680f6a078bb32f157bd580705656496717bafb +design -reset +read_verilog <<EOT +module top( + input clk, + input rst, + input [2:0] a, + output [1:0] b +); + reg [2:0] b_reg; + initial begin + b_reg <= 3'b0; + end + + assign b = b_reg[1:0]; + always @(posedge clk or posedge rst) begin + if(rst) begin + b_reg <= 3'b0; + end else begin + b_reg <= a; + end + end +endmodule +EOT + +proc +wreduce + +select -assert-count 1 t:$adff r:ARST_VALUE=2'b00 %i diff --git a/tests/various/write_gzip.ys b/tests/various/write_gzip.ys new file mode 100644 index 000000000..524ecc33e --- /dev/null +++ b/tests/various/write_gzip.ys @@ -0,0 +1,16 @@ +read_verilog <<EOT +module top(input a, output y); +assign y = !a; +endmodule +EOT + +prep -top top +write_verilog write_gzip.v.gz +design -reset + +! rm -f write_gzip.v +! gunzip write_gzip.v.gz +read_verilog write_gzip.v +! rm -f write_gzip.v +hierarchy -top top +select -assert-any top diff --git a/tests/xilinx/.gitignore b/tests/xilinx/.gitignore new file mode 100644 index 000000000..b48f808a1 --- /dev/null +++ b/tests/xilinx/.gitignore @@ -0,0 +1,3 @@ +/*.log +/*.out +/run-test.mk diff --git a/tests/xilinx/pmgen_xilinx_srl.ys b/tests/xilinx/pmgen_xilinx_srl.ys new file mode 100644 index 000000000..ea2f20487 --- /dev/null +++ b/tests/xilinx/pmgen_xilinx_srl.ys @@ -0,0 +1,57 @@ +read_verilog -icells <<EOT +module \$__XILINX_SHREG_ (input C, input D, input [31:0] L, input E, output Q, output SO); + parameter DEPTH = 1; + parameter [DEPTH-1:0] INIT = 0; + parameter CLKPOL = 1; + parameter ENPOL = 2; + + wire pos_clk = C == CLKPOL; + reg pos_en; + always @(E) + if (ENPOL == 2) pos_en = 1'b1; + else pos_en = (E == ENPOL[0]); + + reg [DEPTH-1:0] r; + always @(posedge pos_clk) + if (pos_en) + r <= {r[DEPTH-2:0], D}; + + assign Q = r[L]; + assign SO = r[DEPTH-1]; +endmodule +EOT +read_verilog +/xilinx/cells_sim.v +proc +design -save model + +test_pmgen -generate xilinx_srl.fixed +hierarchy -top pmtest_xilinx_srl_pm_fixed +flatten; opt_clean + +design -save gold +xilinx_srl -fixed +techmap -autoproc -map %model +design -stash gate + +design -copy-from gold -as gold pmtest_xilinx_srl_pm_fixed +design -copy-from gate -as gate pmtest_xilinx_srl_pm_fixed +dff2dffe -unmap # sat does not support flops-with-enable yet +miter -equiv -flatten -make_assert gold gate miter +sat -set-init-zero -seq 5 -verify -prove-asserts miter + +design -load model + +test_pmgen -generate xilinx_srl.variable +hierarchy -top pmtest_xilinx_srl_pm_variable +flatten; opt_clean + +design -save gold +xilinx_srl -variable +techmap -autoproc -map %model +design -stash gate + +design -copy-from gold -as gold pmtest_xilinx_srl_pm_variable +design -copy-from gate -as gate pmtest_xilinx_srl_pm_variable +dff2dffe -unmap # sat does not support flops-with-enable yet +miter -equiv -flatten -make_assert gold gate miter +sat -set-init-zero -seq 5 -verify -prove-asserts miter diff --git a/tests/xilinx/run-test.sh b/tests/xilinx/run-test.sh new file mode 100755 index 000000000..ea56b70f0 --- /dev/null +++ b/tests/xilinx/run-test.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +set -e +{ +echo "all::" +for x in *.ys; do + echo "all:: run-$x" + echo "run-$x:" + echo " @echo 'Running $x..'" + echo " @../../yosys -ql ${x%.ys}.log $x" +done +for s in *.sh; do + if [ "$s" != "run-test.sh" ]; then + echo "all:: run-$s" + echo "run-$s:" + echo " @echo 'Running $s..'" + echo " @bash $s" + fi +done +} > run-test.mk +exec ${MAKE:-make} -f run-test.mk diff --git a/tests/xilinx/xilinx_srl.v b/tests/xilinx/xilinx_srl.v new file mode 100644 index 000000000..bc2a15ab2 --- /dev/null +++ b/tests/xilinx/xilinx_srl.v @@ -0,0 +1,40 @@ +module xilinx_srl_static_test(input i, clk, output [1:0] q); +reg head = 1'b0; +reg [3:0] shift1 = 4'b0000; +reg [3:0] shift2 = 4'b0000; + +always @(posedge clk) begin + head <= i; + shift1 <= {shift1[2:0], head}; + shift2 <= {shift2[2:0], head}; +end + +assign q = {shift2[3], shift1[3]}; +endmodule + +module xilinx_srl_variable_test(input i, clk, input [1:0] l1, l2, output [1:0] q); +reg head = 1'b0; +reg [3:0] shift1 = 4'b0000; +reg [3:0] shift2 = 4'b0000; + +always @(posedge clk) begin + head <= i; + shift1 <= {shift1[2:0], head}; + shift2 <= {shift2[2:0], head}; +end + +assign q = {shift2[l2], shift1[l1]}; +endmodule + +module $__XILINX_SHREG_(input C, D, E, input [1:0] L, output Q); +parameter CLKPOL = 1; +parameter ENPOL = 1; +parameter DEPTH = 1; +parameter [DEPTH-1:0] INIT = {DEPTH{1'b0}}; +reg [DEPTH-1:0] r = INIT; +wire clk = C ^ CLKPOL; +always @(posedge C) + if (E) + r <= { r[DEPTH-2:0], D }; +assign Q = r[L]; +endmodule diff --git a/tests/xilinx/xilinx_srl.ys b/tests/xilinx/xilinx_srl.ys new file mode 100644 index 000000000..b8df0e55a --- /dev/null +++ b/tests/xilinx/xilinx_srl.ys @@ -0,0 +1,67 @@ +read_verilog xilinx_srl.v +design -save read + +design -copy-to model $__XILINX_SHREG_ +hierarchy -top xilinx_srl_static_test +prep +design -save gold + +techmap +xilinx_srl -fixed +opt + +# stat +# show -width +select -assert-count 1 t:$_DFF_P_ +select -assert-count 2 t:$__XILINX_SHREG_ + +design -stash gate + +design -import gold -as gold +design -import gate -as gate +design -copy-from model -as $__XILINX_SHREG_ \$__XILINX_SHREG_ +prep + +miter -equiv -flatten -make_assert -make_outputs gold gate miter +dump gate +sat -verify -prove-asserts -show-ports -seq 5 miter + +#design -load gold +#stat + +#design -load gate +#stat + +########## + +design -load read +design -copy-to model $__XILINX_SHREG_ +hierarchy -top xilinx_srl_variable_test +prep +design -save gold + +xilinx_srl -variable +opt + +#stat +# show -width +# write_verilog -noexpr -norename +select -assert-count 1 t:$dff +select -assert-count 1 t:$dff r:WIDTH=1 %i +select -assert-count 2 t:$__XILINX_SHREG_ + +design -stash gate + +design -import gold -as gold +design -import gate -as gate +design -copy-from model -as $__XILINX_SHREG_ \$__XILINX_SHREG_ +prep + +miter -equiv -flatten -make_assert -make_outputs gold gate miter +sat -verify -prove-asserts -show-ports -seq 5 miter + +# design -load gold +# stat + +# design -load gate +# stat |