mirror of https://github.com/YosysHQ/yosys.git
commit
cb0dc6e68b
|
@ -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
|
|
@ -0,0 +1,13 @@
|
|||
.editorconfig
|
||||
.gitignore
|
||||
.gitmodules
|
||||
.github
|
||||
.git
|
||||
Dockerfile
|
||||
README.md
|
||||
manual
|
||||
CodingReadme
|
||||
CodeOfConduct
|
||||
.travis
|
||||
.travis.yml
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = tab
|
||||
indent_size = tab
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
69
.travis.yml
69
.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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
Brewfile
3
Brewfile
|
@ -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"
|
||||
|
|
270
CHANGELOG
270
CHANGELOG
|
@ -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
|
||||
|
|
2
COPYING
2
COPYING
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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"]
|
269
Makefile
269
Makefile
|
@ -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
|
||||
|
||||
|
|
227
README.md
227
README.md
|
@ -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 ``tri``, ``triand`` and ``trior`` net types
|
||||
|
||||
- The ``config`` keyword and library map files
|
||||
|
||||
- The ``disable``, ``primitive`` and ``specify`` statements
|
||||
|
||||
- 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`.
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
OBJS += backends/aiger/aiger.o
|
||||
OBJS += backends/aiger/xaiger.o
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
if (bit == State::Sx || bit == State::Sz)
|
||||
log_error("Design contains 'x' or 'z' bits. Use 'setundef' to replace those constants.\n");
|
||||
auto it = aig_map.find(bit);
|
||||
if (it != aig_map.end()) {
|
||||
log_assert(it->second >= 0);
|
||||
return it->second;
|
||||
}
|
||||
|
||||
log_assert(aig_map.at(bit) >= 0);
|
||||
return aig_map.at(bit);
|
||||
// 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_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())
|
||||
|
|
|
@ -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
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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()) {
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
demo.bit
|
||||
demo_phy.area
|
||||
full.v
|
||||
*.log
|
||||
*.h
|
||||
*.tde
|
||||
*.svf
|
|
@ -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.
|
|
@ -0,0 +1,4 @@
|
|||
#!/bin/bash
|
||||
set -ex
|
||||
yosys demo.ys
|
||||
$TD_HOME/bin/td 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
|
|
@ -0,0 +1,2 @@
|
|||
set_pin_assignment {CLK_IN} { LOCATION = K14; } ##24MHZ
|
||||
set_pin_assignment {R_LED} { LOCATION = R3; } ##R_LED
|
|
@ -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
|
|
@ -0,0 +1,3 @@
|
|||
read_verilog demo.v
|
||||
synth_anlogic -top demo
|
||||
write_verilog full.v
|
|
@ -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]
|
||||
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
/netlist.edn
|
||||
/netlist.vm
|
||||
/example.stp
|
||||
/proj
|
|
@ -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
|
|
@ -0,0 +1,2 @@
|
|||
# Add timing constraints here
|
||||
create_clock -period 10.000 -waveform {0.000 5.000} [get_ports {clk}]
|
|
@ -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
|
|
@ -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
|
|
@ -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 .
|
|
@ -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
|
|
@ -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 ;
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,3 @@
|
|||
read_verilog example.v
|
||||
synth_xilinx -top example -family xc6s -ise
|
||||
write_edif -pvector bra example.edif
|
|
@ -0,0 +1 @@
|
|||
out/**
|
|
@ -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()
|
|
@ -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()
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
OBJS += frontends/aiger/aigerparse.o
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
ilang_lexer.cc
|
||||
ilang_parser.output
|
||||
ilang_parser.tab.cc
|
||||
ilang_parser.tab.h
|
||||
ilang_parser.tab.hh
|
||||
|
|
|
@ -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 $@)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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)
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
verilog_lexer.cc
|
||||
verilog_parser.output
|
||||
verilog_parser.tab.cc
|
||||
verilog_parser.tab.h
|
||||
verilog_parser.tab.hh
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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_"))
|
||||
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("\\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);
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -81,23 +81,49 @@ 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(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);
|
||||
}
|
||||
|
||||
setup_type("$tribuf", {A, EN}, {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});
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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_internals_ff();
|
||||
|
||||
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});
|
||||
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("$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(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("$fsm", {CLK, ARST, CTRL_IN}, {CTRL_OUT});
|
||||
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_stdcells_eval();
|
||||
|
||||
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);
|
||||
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
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
134
kernel/cost.h
134
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))
|
||||
{
|
||||
RTLIL::Module *mod = design->module(type);
|
||||
|
||||
if (mod->attributes.count("\\cost"))
|
||||
return mod->attributes.at("\\cost").as_int();
|
||||
|
||||
dict<RTLIL::IdString, int> local_mod_cost_cache;
|
||||
if (mod_cost_cache == nullptr)
|
||||
mod_cost_cache = &local_mod_cost_cache;
|
||||
|
||||
if (mod_cost_cache->count(mod->name))
|
||||
return mod_cost_cache->at(mod->name);
|
||||
|
||||
int module_cost = 1;
|
||||
for (auto c : mod->cells())
|
||||
module_cost += get_cell_cost(c, mod_cost_cache);
|
||||
|
||||
(*mod_cost_cache)[mod->name] = module_cost;
|
||||
return module_cost;
|
||||
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;
|
||||
}
|
||||
|
||||
log_warning("Can't determine cost of %s cell (%d parameters).\n", log_id(type), GetSize(parameters));
|
||||
return 1;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
dict<RTLIL::IdString, int> mod_cost_cache;
|
||||
const dict<RTLIL::IdString, int> *gate_cost = nullptr;
|
||||
Design *design = nullptr;
|
||||
|
||||
int get(RTLIL::IdString type) const
|
||||
{
|
||||
if (gate_cost && gate_cost->count(type))
|
||||
return gate_cost->at(type);
|
||||
|
||||
log_warning("Can't determine cost of %s cell.\n", log_id(type));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int get(RTLIL::Cell *cell)
|
||||
{
|
||||
if (gate_cost && gate_cost->count(cell->type))
|
||||
return gate_cost->at(cell->type);
|
||||
|
||||
if (design && design->module(cell->type) && cell->parameters.empty())
|
||||
{
|
||||
RTLIL::Module *mod = design->module(cell->type);
|
||||
|
||||
if (mod->attributes.count(ID(cost)))
|
||||
return mod->attributes.at(ID(cost)).as_int();
|
||||
|
||||
if (mod_cost_cache.count(mod->name))
|
||||
return mod_cost_cache.at(mod->name);
|
||||
|
||||
int module_cost = 1;
|
||||
for (auto c : mod->cells())
|
||||
module_cost += get(c);
|
||||
|
||||
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
|
||||
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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(); }
|
||||
};
|
||||
|
||||
|
|
134
kernel/log.cc
134
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(const char *format, va_list ap)
|
||||
{
|
||||
logv_warning_with_prefix("Warning: ", format, ap);
|
||||
}
|
||||
|
||||
void logv_warning_noprefix(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();
|
||||
|
||||
if (log_errfile != NULL && !log_quiet_warnings)
|
||||
log_files.pop_back();
|
||||
|
||||
log_warnings.insert(message);
|
||||
}
|
||||
|
||||
log_warnings_count++;
|
||||
}
|
||||
logv_warning_with_prefix("", format, ap);
|
||||
}
|
||||
|
||||
void logv_error(const char *format, va_list ap)
|
||||
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);
|
||||
}
|
||||
|
||||
void log_file_info(const std::string &filename, int lineno,
|
||||
const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
std::string fmt = stringf("%s:%d: Info: %s",
|
||||
filename.c_str(), lineno, format);
|
||||
logv(fmt.c_str(), ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
YS_ATTRIBUTE(noreturn)
|
||||
static void logv_error_with_prefix(const char *prefix,
|
||||
const char *format, va_list ap)
|
||||
{
|
||||
#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
|
||||
|
||||
|
|
55
kernel/log.h
55
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
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue