Merge pull request #7 from YosysHQ/master

Syncing with official repo
This commit is contained in:
Aman Goel 2019-09-27 12:30:27 -04:00 committed by GitHub
commit cb0dc6e68b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
679 changed files with 71913 additions and 8493 deletions

13
.clang-format Normal file
View File

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

13
.dockerignore Normal file
View File

@ -0,0 +1,13 @@
.editorconfig
.gitignore
.gitmodules
.github
.git
Dockerfile
README.md
manual
CodingReadme
CodeOfConduct
.travis
.travis.yml

7
.editorconfig Normal file
View File

@ -0,0 +1,7 @@
root = true
[*]
indent_style = tab
indent_size = tab
trim_trailing_whitespace = true
insert_final_newline = true

View File

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

10
.gitignore vendored
View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

57
Dockerfile Normal file
View File

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

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

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

View File

@ -1,3 +1,4 @@
OBJS += backends/aiger/aiger.o
OBJS += backends/aiger/xaiger.o

View File

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

879
backends/aiger/xaiger.cc Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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> &parameters, bool for_module=false)
{
bool first = true;
for (auto &param : 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()) {

View File

@ -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 &param : 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()) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

7
examples/anlogic/.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
demo.bit
demo_phy.area
full.v
*.log
*.h
*.tde
*.svf

12
examples/anlogic/README Normal file
View File

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

4
examples/anlogic/build.sh Executable file
View File

@ -0,0 +1,4 @@
#!/bin/bash
set -ex
yosys demo.ys
$TD_HOME/bin/td build.tcl

View File

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

View File

@ -0,0 +1,2 @@
set_pin_assignment {CLK_IN} { LOCATION = K14; } ##24MHZ
set_pin_assignment {R_LED} { LOCATION = R3; } ##R_LED

18
examples/anlogic/demo.v Normal file
View File

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

3
examples/anlogic/demo.ys Normal file
View File

@ -0,0 +1,3 @@
read_verilog demo.v
synth_anlogic -top demo
write_verilog full.v

View File

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

View File

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

View File

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

4
examples/igloo2/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
/netlist.edn
/netlist.vm
/example.stp
/proj

View File

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

View File

@ -0,0 +1,2 @@
# Add timing constraints here
create_clock -period 10.000 -waveform {0.000 5.000} [get_ports {clk}]

64
examples/igloo2/example.v Normal file
View File

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

View File

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

6
examples/igloo2/runme.sh Normal file
View File

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

8
examples/mimas2/README Normal file
View File

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

View File

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

14
examples/mimas2/example.v Normal file
View File

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

8
examples/mimas2/run.sh Normal file
View File

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

View File

@ -0,0 +1,3 @@
read_verilog example.v
synth_xilinx -top example -family xc6s -ise
write_edif -pvector bra example.edif

1
examples/python-api/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
out/**

32
examples/python-api/pass.py Executable file
View File

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

22
examples/python-api/script.py Executable file
View File

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

View File

@ -0,0 +1,3 @@
OBJS += frontends/aiger/aigerparse.o

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,4 +1,4 @@
ilang_lexer.cc
ilang_parser.output
ilang_parser.tab.cc
ilang_parser.tab.h
ilang_parser.tab.hh

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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> &parameters, 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

View File

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

View File

@ -1,4 +1,4 @@
verilog_lexer.cc
verilog_parser.output
verilog_parser.tab.cc
verilog_parser.tab.h
verilog_parser.tab.hh

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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> &parameters = 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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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