Merge branch 'master' of https://github.com/cliffordwolf/yosys into btor

added case for memwr cell that is used in muxes (same cell is used more than one time)
corrected bug for xnor and logic_not
added pmux cell translation

Conflicts:
	backends/btor/btor.cc
This commit is contained in:
Ahmed Irfan 2014-09-22 11:35:04 +02:00
commit d3c67ad9b6
513 changed files with 34858 additions and 12079 deletions

2
.gitignore vendored
View file

@ -3,6 +3,7 @@
.*.swp
/.cproject
/.project
/.settings
/qtcreator.files
/qtcreator.includes
/qtcreator.config
@ -14,6 +15,5 @@
/yosys-abc
/yosys-config
/yosys-filterlib
/yosys-svgviewer
/kernel/version_*.cc
/share

149
CHANGELOG
View file

@ -1,45 +1,184 @@
List of incompatible changes and major milestones between releases
==================================================================
List of changes and major improvements between releases
=======================================================
Yosys 0.1.0 .. Yoys 0.1.0+
Yosys 0.3.0 .. Yoys 0.3.0+
--------------------------
... TBD ...
Yosys 0.2.0 .. Yoys 0.3.0
--------------------------
* Driver program and overall behavior:
- Added "design -push" and "design -pop"
- Added "tee" command for redirecting log output
* Changes in the internal cell library:
- Added $dlatchsr and $_DLATCHSR_???_ cell types
* Improvements in Verilog frontend:
- Improved support for const functions (case, always, repeat)
- The generate..endgenerate keywords are now optional
- Added support for arrays of module instances
- Added support for "`default_nettype" directive
- Added support for "`line" directive
* Other front- and back-ends:
- Various changes to "write_blif" options
- Various improvements in EDIF backend
- Added "vhdl2verilog" pseudo-front-end
- Added "verific" pseudo-front-end
* Improvements in technology mapping:
- Added support for recursive techmap
- Added CONSTMSK and CONSTVAL features to techmap
- Added _TECHMAP_CONNMAP_*_ feature to techmap
- Added _TECHMAP_REPLACE_ feature to techmap
- Added "connwrappers" command for wrap-extract-unwrap method
- Added "extract -map %<design_name>" feature
- Added "extract -ignore_param ..." and "extract -ignore_parameters"
- Added "techmap -max_iter" option
* Improvements to "eval" and "sat" framework:
- Now include a copy of Minisat (with build fixes applied)
- Switched to Minisat::SimpSolver as SAT back-end
- Added "sat -dump_vcd" feature
- Added "sat -dump_cnf" feature
- Added "sat -initsteps <N>" feature
- Added "freduce -stop <N>" feature
- Added "fredure -dump <prefix>" feature
* Integration with ABC:
- Updated ABC rev to 7600ffb9340c
* Improvements in the internal APIs:
- Added RTLIL::Module::add... helper methods
- Various build fixes for OSX (Darwin) and OpenBSD
Yosys 0.1.0 .. Yoys 0.2.0
-------------------------
* Changes to the driver program:
- Added "yosys -h" and "yosys -H"
- Added support for backslash line continuation in scripts
- Added support for #-comments in same line as command
- Added "echo" and "log" commands
* Improvements in Verilog frontend:
- Added support for local registers in named blocks
- Added support for "case" in "generate" blocks
- Added support for $clog2 system function
- Added support for basic SystemVerilog assert statements
- Added preprocessor support for macro arguments
- Added preprocessor support for `elsif statement
- Added "verilog_defaults" command
- Added read_verilog -icells option
- Added support for constant sizes from parameters
- Added "read_verilog -setattr"
- Added support for function returning 'integer'
- Added limited support for function calls in parameter values
- Added "read_verilog -defer" to suppress evaluation of modules with default parameters
* Other front- and back-ends:
- Added BTOR backend
- Added Liberty frontend
* Improvements in technology mapping:
- The "dfflibmap" command now strongly prefers solutions with
no inverters in clock paths
- The "dfflibmap" command now prefers cells with smaller area
- Added support for multiple -map options to techmap
- Added "dfflibmap" support for //-comments in liberty files
- Added "memory_unpack" command to revert "memory_collect"
- Added standard techmap rule "techmap -share_map pmux2mux.v"
- Added "iopadmap -bits"
- Added "setundef" command
- Added "hilomap" command
* Changes in the internal cell library:
- Major rewrite of simlib.v for better compatibility with other tools
- Added PRIORITY parameter to $memwr cells
- Added TRANSPARENT parameter to $memrd cells
- Added RD_TRANSPARENT parameter to $mem cells
- Added $bu0 cell (always 0-extend, even undef MSB)
- Added $assert cell type
- Added $slice and $concat cell types
* Integration with ABC:
- Updated ABC to hg rev 57517e81666b
- Updated ABC to hg rev 2058c8ccea68
- Tighter integration of ABC build with Yosys build. The make
targets 'make abc' and 'make install-abc' are now obsolete.
- Added support for passing FFs from one clock domain through ABC
- Now always use BLIF as exchange format with ABC
- Added support for "abc -script +<command_sequence>"
- Improved standard ABC recipe
- Added support for "keep" attribute to abc command
- Added "abc -dff / -clk / -keepff" options
* Improvements to "eval" and "sat" framework:
- Added support for "0" and "~0" in right-hand side -set expressions
- Added "eval -set-undef" and "eval -table"
- Added "sat -set-init" support for sequential problems
- Added "sat -set-init" and "sat -set-init-*" for sequential problems
- Added undef support to SAT solver, incl. various new "sat" options
- Added correct support for === and !== for "eval" and "sat"
- Added "sat -tempinduct" (default -seq is now non-induction sequential)
- Added "sat -prove-asserts"
- Complete rewrite of the 'freduce' command
- Added "miter" command
- Added "sat -show-inputs" and "sat -show-outputs"
- Added "sat -ignore_unknown_cells" (now produce an error by default)
- Added "sat -falsify"
- Now "sat -verify" and "sat -falsify" can also be used without "-prove"
- Added "expose" command
- Added support for @<sel_name> to sat and eval signal expressions
* Changes in the 'make test' framework and auxilary test tools:
- Added autotest.sh -p and -f options
- Replaced autotest.sh ISIM support with XSIM support
- Added test cases for SAT framework
* Added "abbreviated IDs":
- Now $<something>$foo can be abbriviated as $foo.
- Usually this last part is a unique id (from RTLIL::autoidx)
- This abbreviated IDs are now also used in "show" output
* Other changes to selection framework:
- Now */ is optional in */<mode>:<arg> expressions
- Added "select -assert-none" and "select -assert-any"
- Added support for matching modules by attribute (A:<expr>)
- Added "select -none"
- Added support for r:<expr> pattern for matching cell parameters
- Added support for !=, <, <=, >=, > for attribute and parameter matching
- Added support for %s for selecting sub-modules
- Added support for %m for expanding selections to whole modules
- Added support for i:*, o:* and x:* pattern for selecting module ports
- Added support for s:<expr> pattern for matching wire width
- Added support for %a operation to select wire aliases
* Various other changes to commands and options:
- The "ls" command now supports wildcards
- Added "show -pause" and "show -format dot"
- Added "show -color" support for cells
- Added "show -label" and "show -notitle"
- Added "dump -m" and "dump -n"
- Added "history" command
- Added "rename -hide"
- Added "connect" command
- Added "splitnets -driver"
- Added "opt_const -mux_undef"
- Added "opt_const -mux_bool"
- Added "opt_const -undriven"
- Added "opt -mux_undef -mux_bool -undriven -purge"
- Added "hierarchy -libdir"
- Added "hierarchy -purge_lib" (by default now do not remove lib cells)
- Added "delete" command
- Added "dump -append"
- Added "setattr" and "setparam" commands
- Added "design -stash/-copy-from/-copy-to"
- Added "copy" command
- Added "splice" command

194
CodingReadme Normal file
View file

@ -0,0 +1,194 @@
Getting Started
===============
Reading List
------------
To write Yosys C++ code you need to know at least the following classes in kernel/rtlil.h:
RTLIL::Wire
RTLIL::Cell
RTLIL::Module
RTLIL::SigSpec
The following yosys commands are a good starting point if you are looking for examples
of how to use the Yosys API:
passes/opt/wreduce.cc
passes/techmap/maccmap.cc
Notes on the existing codebase
------------------------------
For historical reasons not all parts of Yosys adhere to the current coding
styles. When adding code to existing parts of the system, adhere to this guide
for the new code instead of trying to mimic the style of the surrounding code.
Coding Style
============
Formatting of code
------------------
- Yosys code is using tabs for indentation. Tabs are 8 characters.
- A continuation of a statement in the following line is indented by
two additional tabs.
- Lines are as long as you want them to be. A good rule of thumb is
to break lines at about column 150.
- Opening braces can be put on the same or next line as the statement
opening the block (if, switch, for, while, do). Put the opening brace
on its own line for larger blocks, especially blocks that contains
blank lines.
- Otherwise stick to the Linux Kernel Coding Stlye:
https://www.kernel.org/doc/Documentation/CodingStyle
C++ Langugage
-------------
Yosys is written in C++11. At the moment only constructs supported by
gcc 4.6 is allowed in Yosys code. This will change in future releases.
In general Yosys uses "int" instead of "size_t". To avoid compiler
warnings for implicit type casts, always use "SIZE(foobar)" instead
of "foobar.size()". (the macro SIZE() is defined by kernel/yosys.h)
Use range-based for loops whenever applicable.
Checklist for adding internal cell types
========================================
Things to do right away:
- Add to kernel/celltypes.h (incl. eval() handling for non-mem cells)
- Add to InternalCellChecker::check() in kernel/rtlil.cc
- Add to techlibs/common/simlib.v
- Add to techlibs/common/techmap.v
Things to do after finalizing the cell interface:
- Add support to kernel/satgen.h for the new cell type
- Add to manual/CHAPTER_CellLib.tex (or just add a fixme to the bottom)
- Maybe add support to the verilog backend for dumping such cells as expression
Checklist for creating Yosys releases
=====================================
Update the CHANGELOG file:
cd ~yosys
gitk &
vi CHANGELOG
Run all tests with "make config-{clang-debug,gcc-debug,gcc-4.6,release}":
cd ~yosys
make clean
make test vloghtb
make install
cd ~yosys-bigsim
make clean
make full
cd ~vloghammer
make purge
make gen_issues gen_samples
make SYN_LIST="yosys" SIM_LIST="icarus yosim verilator" FULL=1 world
chromium-browser report.html
Then with default config setting:
cd ~yosys
./yosys -p 'proc; show' tests/simple/fiedler-cooley.v
./yosys -p 'proc; opt; show' tests/simple/fiedler-cooley.v
cd ~yosys
make manual
- sanity check the figures in the appnotes and presentation
- if there are any odd things -> investigate
- make cosmetic changes to the .tex files if necessary
Also with default config setting:
cd ~yosys/techlibs/cmos
bash testbench.sh
cd ~yosys/techlibs/xilinx/example_sim_counter
bash run_sim.sh
cd ~yosys/techlibs/xilinx/example_mojo_counter
bash example.sh
Finally if a current verific library is available:
cd ~yosys
cat frontends/verific/build_amd64.txt
- follow instructions
cd frontends/verific
../../yosys test_navre.ys
Release candiate:
- create branch yosys-x.y.z-rc and push to github
- contact the usual suspects per mail and ask them to test
- post on the reddit and ask people to test
- commit KISS fixes to the -rc branch if necessary
Release:
- set YOSYS_VER to x.y.z in Makefile
- update version string in CHANGELOG
git commit -am "Yosys x.y.z"
- push tag to github
- post changelog on github
- post short release note on reddit
- delete -rc branch from github
Updating the website:
cd ~yosys
make manual
make install
- update pdf files on the website
cd ~yosys-web
make update_cmd
make update_show
git commit -am update
make push
In master branch:
git merge {release-tag}
- set version to x.y.z+ in Makefile
- add section "Yosys x.y.z .. x.y.z+" to CHANGELOG
git commit --amend -am "Yosys x.y.z+"

261
Makefile
View file

@ -1,13 +1,15 @@
CONFIG := clang-debug
# CONFIG := gcc-debug
# CONFIG := release
CONFIG := clang
# CONFIG := gcc
# CONFIG := gcc-4.6
# CONFIG := emcc
# features (the more the better)
ENABLE_TCL := 1
ENABLE_QT4 := 1
ENABLE_MINISAT := 1
ENABLE_ABC := 1
ENABLE_PLUGINS := 1
ENABLE_READLINE := 1
ENABLE_VERIFIC := 0
# other configuration flags
ENABLE_GPROF := 0
@ -20,15 +22,30 @@ GENFILES =
EXTRA_TARGETS =
TARGETS = yosys yosys-config
PRETTY = 1
SMALL = 0
all: top-all
CXXFLAGS = -Wall -Wextra -ggdb -I"$(shell pwd)" -MD -D_YOSYS_ -fPIC
LDFLAGS = -rdynamic
LDLIBS = -lstdc++ -lreadline -lm -ldl -lrt
CXXFLAGS = -Wall -Wextra -ggdb -I"$(shell pwd)" -MD -DYOSYS_SRC='"$(shell pwd)"' -D_YOSYS_ -fPIC -I${DESTDIR}/include
LDFLAGS = -L${DESTDIR}/lib
LDLIBS = -lstdc++ -lm
QMAKE = qmake-qt4
SED = sed
YOSYS_VER := 0.1.0+
GIT_REV := $(shell git rev-parse --short HEAD || echo UNKOWN)
ifeq (Darwin,$(findstring Darwin,$(shell uname)))
# add macports include and library path to search directories, don't use '-rdynamic' and '-lrt':
CXXFLAGS += -I/opt/local/include
LDFLAGS += -L/opt/local/lib
QMAKE = qmake
SED = gsed
else
LDFLAGS += -rdynamic
LDLIBS += -lrt
endif
YOSYS_VER := 0.3.0+$(shell test -d .git && { git log --author=clifford@clifford.at --oneline ca125bf41.. | wc -l; })
GIT_REV := $(shell git rev-parse --short HEAD 2> /dev/null || echo UNKNOWN)
OBJS = kernel/version_$(GIT_REV).o
# set 'ABCREV = default' to use abc/ as it is
@ -37,108 +54,214 @@ OBJS = kernel/version_$(GIT_REV).o
# 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 = 10cc13a2a0f1
ABCREV = 4d547a5e065b
ABCPULL = 1
-include Makefile.conf
define newline
ifeq ($(CONFIG),clang-debug)
endef
ifneq ($(wildcard Makefile.conf),)
$(info $(subst $$--$$,$(newline),$(shell sed 's,^,[Makefile.conf] ,; s,$$,$$--$$,;' < Makefile.conf | tr -d '\n' | sed 's,\$$--\$$$$,,')))
include Makefile.conf
endif
ifeq ($(CONFIG),clang)
CXX = clang
CXXFLAGS += -std=c++11 -Os
endif
ifeq ($(CONFIG),gcc-debug)
else ifeq ($(CONFIG),gcc)
CXX = gcc
CXXFLAGS += -std=gnu++0x -Os
else ifeq ($(CONFIG),gcc-4.6)
CXX = gcc-4.6
CXXFLAGS += -std=gnu++0x -Os
else ifeq ($(CONFIG),emcc)
CXX = emcc
CXXFLAGS += -std=c++11 -Os -Wno-warn-absolute-paths
CXXFLAGS := $(filter-out -ggdb,$(CXXFLAGS))
else ifneq ($(CONFIG),none)
$(error Invalid CONFIG setting '$(CONFIG)'. Valid values: clang, gcc, gcc-4.6, emcc, none)
endif
ifeq ($(CONFIG),release)
CXX = gcc
CXXFLAGS += -std=gnu++0x -march=native -O3 -DNDEBUG
ifeq ($(ENABLE_READLINE),1)
CXXFLAGS += -DYOSYS_ENABLE_READLINE
LDLIBS += -lreadline
endif
ifeq ($(ENABLE_PLUGINS),1)
CXXFLAGS += -DYOSYS_ENABLE_PLUGINS $(shell pkg-config --silence-errors --cflags libffi)
LDLIBS += $(shell pkg-config --silence-errors --libs libffi || echo -lffi) -ldl
endif
ifeq ($(ENABLE_TCL),1)
CXXFLAGS += -I/usr/include/tcl8.5 -DYOSYS_ENABLE_TCL
LDLIBS += -ltcl8.5
TCL_VERSION ?= tcl8.5
TCL_INCLUDE ?= /usr/include/$(TCL_VERSION)
CXXFLAGS += -I$(TCL_INCLUDE) -DYOSYS_ENABLE_TCL
LDLIBS += -l$(TCL_VERSION)
endif
ifeq ($(ENABLE_GPROF),1)
CXXFLAGS += -pg -fno-inline
CXXFLAGS += -pg
LDFLAGS += -pg
endif
ifeq ($(ENABLE_QT4),1)
TARGETS += yosys-svgviewer
endif
ifeq ($(ENABLE_ABC),1)
CXXFLAGS += -DYOSYS_ENABLE_ABC
TARGETS += yosys-abc
endif
OBJS += kernel/driver.o kernel/register.o kernel/rtlil.o kernel/log.o kernel/calc.o
ifeq ($(ENABLE_VERIFIC),1)
VERIFIC_DIR ?= /usr/local/src/verific_lib_eval
VERIFIC_COMPONENTS ?= verilog vhdl database util containers
CXXFLAGS += $(patsubst %,-I$(VERIFIC_DIR)/%,$(VERIFIC_COMPONENTS)) -DYOSYS_ENABLE_VERIFIC
LDLIBS += $(patsubst %,$(VERIFIC_DIR)/%/*-linux.a,$(VERIFIC_COMPONENTS))
endif
ifeq ($(PRETTY), 1)
P_STATUS = 0
P_OFFSET = 0
P_UPDATE = $(eval P_STATUS=$(shell echo $(OBJS) yosys | gawk 'BEGIN { RS = " "; I = $(P_STATUS)+0; } $$1 == "$@" && NR > I { I = NR; } END { print I; }'))
P_SHOW = [$(shell gawk "BEGIN { N=$(words $(OBJS) yosys); 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
else
P_SHOW = ->
P =
Q =
S =
endif
OBJS += kernel/driver.o kernel/register.o kernel/rtlil.o kernel/log.o kernel/calc.o kernel/yosys.o
OBJS += libs/bigint/BigIntegerAlgorithms.o libs/bigint/BigInteger.o libs/bigint/BigIntegerUtils.o
OBJS += libs/bigint/BigUnsigned.o libs/bigint/BigUnsignedInABase.o
OBJS += libs/sha1/sha1.o
OBJS += libs/subcircuit/subcircuit.o
OBJS += libs/ezsat/ezsat.o
ifeq ($(ENABLE_MINISAT),1)
CXXFLAGS += -DYOSYS_ENABLE_MINISAT
ifneq ($(SMALL),1)
OBJS += libs/subcircuit/subcircuit.o
OBJS += libs/ezsat/ezsat.o
OBJS += libs/ezsat/ezminisat.o
LDLIBS += -lminisat
endif
OBJS += libs/minisat/Options.o
OBJS += libs/minisat/SimpSolver.o
OBJS += libs/minisat/Solver.o
OBJS += libs/minisat/System.o
include frontends/*/Makefile.inc
include passes/*/Makefile.inc
include backends/*/Makefile.inc
include techlibs/*/Makefile.inc
else
include frontends/verilog/Makefile.inc
include frontends/ilang/Makefile.inc
include frontends/ast/Makefile.inc
OBJS += passes/hierarchy/hierarchy.o
OBJS += passes/cmds/select.o
OBJS += passes/cmds/show.o
OBJS += passes/cmds/stat.o
OBJS += passes/cmds/cover.o
OBJS += passes/cmds/design.o
OBJS += passes/cmds/plugin.o
include passes/proc/Makefile.inc
include passes/opt/Makefile.inc
include passes/techmap/Makefile.inc
include passes/abc/Makefile.inc
include backends/verilog/Makefile.inc
include backends/ilang/Makefile.inc
include techlibs/common/Makefile.inc
endif
top-all: $(TARGETS) $(EXTRA_TARGETS)
@echo ""
@echo " Build successful."
@echo ""
yosys: $(OBJS)
$(CXX) -o yosys $(LDFLAGS) $(OBJS) $(LDLIBS)
$(P) $(CXX) -o yosys $(LDFLAGS) $(OBJS) $(LDLIBS)
%.o: %.cc
$(P) $(CXX) -o $@ -c $(CXXFLAGS) $<
%.o: %.cpp
$(P) $(CXX) -o $@ -c $(CXXFLAGS) $<
kernel/version_$(GIT_REV).cc: Makefile
rm -f kernel/version_*.o kernel/version_*.d kernel/version_*.cc
echo "extern const char *yosys_version_str; const char *yosys_version_str=\"Yosys $(YOSYS_VER) (git sha1 $(GIT_REV))\";" > kernel/version_$(GIT_REV).cc
$(P) rm -f kernel/version_*.o kernel/version_*.d kernel/version_*.cc
$(Q) echo "extern const char *yosys_version_str; const char *yosys_version_str=\"Yosys $(YOSYS_VER) (git sha1 $(GIT_REV), $(CXX) ` \
$(CXX) --version | tr ' ()' '\n' | grep '^[0-9]' | head -n1` $(filter -f% -m% -O% -DNDEBUG,$(CXXFLAGS)))\";" > kernel/version_$(GIT_REV).cc
yosys-config: yosys-config.in
sed -e 's,@CXX@,$(CXX),;' -e 's,@CXXFLAGS@,$(CXXFLAGS),;' -e 's,@LDFLAGS@,$(LDFLAGS),;' -e 's,@LDLIBS@,$(LDLIBS),;' \
$(P) $(SED) -e 's,@CXX@,$(CXX),;' -e 's,@CXXFLAGS@,$(CXXFLAGS),;' -e 's,@LDFLAGS@,$(LDFLAGS),;' -e 's,@LDLIBS@,$(LDLIBS),;' \
-e 's,@BINDIR@,$(DESTDIR)/bin,;' -e 's,@DATDIR@,$(DESTDIR)/share/yosys,;' < yosys-config.in > yosys-config
chmod +x yosys-config
yosys-svgviewer: libs/svgviewer/*.h libs/svgviewer/*.cpp
cd libs/svgviewer && $(QMAKE) && make
cp libs/svgviewer/svgviewer yosys-svgviewer
$(Q) chmod +x yosys-config
abc/abc-$(ABCREV):
$(P)
ifneq ($(ABCREV),default)
if ( cd abc && hg identify; ) | grep -q +; then \
$(Q) if ( cd abc 2> /dev/null && hg identify; ) | grep -q +; then \
echo 'REEBE: NOP pbagnvaf ybpny zbqvsvpngvbaf! Frg NOPERI=qrsnhyg va Lbflf Znxrsvyr!' | tr 'A-Za-z' 'N-ZA-Mn-za-m'; false; \
fi
if test "`cd abc && hg identify | cut -f1 -d' '`" != "$(ABCREV)"; then \
$(Q) if test "`cd abc 2> /dev/null && hg identify | cut -f1 -d' '`" != "$(ABCREV)"; then \
test $(ABCPULL) -ne 0 || { echo 'REEBE: NOP abg hc gb qngr naq NOPCHYY frg gb 0 va Znxrsvyr!' | tr 'A-Za-z' 'N-ZA-Mn-za-m'; exit 1; }; \
echo "Pulling ABC from bitbucket.org:"; \
test -d abc || hg clone https://bitbucket.org/alanmi/abc abc; \
cd abc && hg pull && hg update -r $(ABCREV); \
fi
endif
rm -f abc/abc-[0-9a-f]*
cd abc && $(MAKE) PROG="abc-$(ABCREV)" MSG_PREFIX="YOSYS-ABC: "
$(Q) rm -f abc/abc-[0-9a-f]*
$(Q) cd abc && $(MAKE) $(S) PROG="abc-$(ABCREV)" MSG_PREFIX="$(eval P_OFFSET = 5)$(call P_SHOW)$(eval P_OFFSET = 10) ABC: "
ifeq ($(ABCREV),default)
.PHONY: abc/abc-$(ABCREV)
endif
yosys-abc: abc/abc-$(ABCREV)
cp abc/abc-$(ABCREV) yosys-abc
$(P) cp abc/abc-$(ABCREV) yosys-abc
test: yosys
cd tests/simple && bash run-test.sh
cd tests/hana && bash run-test.sh
cd tests/asicworld && bash run-test.sh
cd tests/sat && bash run-test.sh
test: $(TARGETS) $(EXTRA_TARGETS)
+cd tests/simple && bash run-test.sh
+cd tests/hana && bash run-test.sh
+cd tests/asicworld && bash run-test.sh
+cd tests/realmath && bash run-test.sh
+cd tests/share && bash run-test.sh
+cd tests/fsm && bash run-test.sh
+cd tests/techmap && bash run-test.sh
+cd tests/memories && bash run-test.sh
+cd tests/various && bash run-test.sh
+cd tests/sat && bash run-test.sh
@echo ""
@echo " Passed \"make test\"."
@echo ""
VALGRIND ?= valgrind --error-exitcode=1 --leak-check=full --show-reachable=yes --errors-for-leak-kinds=all
vgtest: $(TARGETS) $(EXTRA_TARGETS)
$(VALGRIND) ./yosys -p 'setattr -mod -unset top; hierarchy; proc; opt; memory -nomap; opt -fine; techmap; opt' $$( ls tests/simple/*.v | grep -v repwhile.v )
@echo ""
@echo " Passed \"make vgtest\"."
@echo ""
vloghtb: $(TARGETS) $(EXTRA_TARGETS)
+cd tests/vloghtb && bash run-test.sh
@echo ""
@echo " Passed \"make vloghtb\"."
@echo ""
install: $(TARGETS) $(EXTRA_TARGETS)
$(INSTALL_SUDO) mkdir -p $(DESTDIR)/bin
@ -152,12 +275,15 @@ manual: $(TARGETS) $(EXTRA_TARGETS)
cd manual && bash manual.sh
clean:
rm -rvf share
rm -rf share
cd manual && bash clean.sh
rm -vf $(OBJS) $(GENFILES) $(TARGETS) $(EXTRA_TARGETS)
rm -vf kernel/version_*.o kernel/version_*.cc abc/abc-[0-9a-f]*
rm -vf libs/*/*.d frontends/*/*.d passes/*/*.d backends/*/*.d kernel/*.d techlibs/*/*.d
test ! -f libs/svgviewer/Makefile || make -C libs/svgviewer distclean
rm -f $(OBJS) $(GENFILES) $(TARGETS) $(EXTRA_TARGETS)
rm -f kernel/version_*.o kernel/version_*.cc abc/abc-[0-9a-f]*
rm -f libs/*/*.d frontends/*/*.d passes/*/*.d backends/*/*.d kernel/*.d techlibs/*/*.d
clean-abc:
make -C abc clean
rm -f yosys-abc abc/abc-[0-9a-f]*
mrproper: clean
git clean -xdf
@ -172,17 +298,24 @@ qtcreator:
config-clean: clean
rm -f Makefile.conf
config-clang-debug: clean
echo 'CONFIG := clang-debug' > Makefile.conf
config-clang: clean
echo 'CONFIG := clang' > Makefile.conf
config-gcc-debug: clean
echo 'CONFIG := gcc-debug' > Makefile.conf
config-gcc: clean
echo 'CONFIG := gcc' > Makefile.conf
config-release: clean
echo 'CONFIG := release' > Makefile.conf
config-gcc-4.6: clean
echo 'CONFIG := gcc-4.6' > Makefile.conf
config-emcc: clean
echo 'CONFIG := emcc' > Makefile.conf
echo 'ENABLE_TCL := 0' >> Makefile.conf
echo 'ENABLE_ABC := 0' >> Makefile.conf
echo 'ENABLE_PLUGINS := 0' >> Makefile.conf
echo 'ENABLE_READLINE := 0' >> Makefile.conf
config-gprof: clean
echo 'CONFIG := gcc-debug' > Makefile.conf
echo 'CONFIG := gcc' > Makefile.conf
echo 'ENABLE_GPROF := 1' >> Makefile.conf
config-sudo:
@ -196,5 +329,5 @@ config-sudo:
-include techlibs/*/*.d
.PHONY: all top-all abc test install install-abc manual clean mrproper qtcreator
.PHONY: config-clean config-clang-debug config-gcc-debug config-release
.PHONY: config-clean config-clang config-gcc config-gcc-4.6 config-gprof config-sudo

176
README
View file

@ -50,39 +50,31 @@ Getting Started
You need a C++ compiler with C++11 support (up-to-date CLANG or GCC is
recommended) and some standard tools such as GNU Flex, GNU Bison, and GNU Make.
The Qt4 library is needed for the yosys SVG viewer, that is used to display
schematics, the minisat library is required for the SAT features in yosys
and TCL for the scripting functionality. The extensive test suite requires
Icarus Verilog. For example on Ubuntu Linux 12.04 LTS the following commands
will install all prerequisites for building yosys:
TCL, readline and libffi are optional (see ENABLE_* settings in Makefile).
Xdot (graphviz) is used by the "show" command in yosys to display schematics.
For example on Ubuntu Linux 14.04 LTS the following commands will install all
prerequisites for building yosys:
$ sudo apt-get install git
$ sudo apt-get install g++
$ sudo apt-get install clang
$ sudo apt-get install make
$ sudo apt-get install bison
$ sudo apt-get install flex
$ sudo apt-get install libreadline-dev
$ sudo apt-get install tcl8.5-dev
$ sudo apt-get install minisat
$ sudo apt-get install zlib1g-dev
$ sudo apt-get install libqt4-dev
$ sudo apt-get install mercurial
$ sudo apt-get install iverilog
$ sudo apt-get install graphviz
$ yosys_deps="build-essential clang bison flex libreadline-dev
tcl8.5-dev libffi-dev git mercurial graphviz xdot"
$ sudo apt-get install $yosys_deps
To configure the build system to use a specific set of compiler and
build configuration, use one of
There are also pre-compiled packages for Yosys on Ubuntu. Visit the Yosys
download page to learn more about this:
$ make config-clang-debug
$ make config-gcc-debug
$ make config-release
http://www.clifford.at/yosys/download.html
To configure the build system to use a specific compiler, use one of
$ make config-clang
$ make config-gcc
For other compilers and build configurations it might be
necessary to make some changes to the config section of the
Makefile.
$ vi Makefile
$ vi Makefile ..or..
$ vi Makefile.conf
To build Yosys simply type 'make' in this directory.
@ -90,9 +82,6 @@ To build Yosys simply type 'make' in this directory.
$ make test
$ sudo make install
If you encounter any problems during build, make sure to check the section
"Workarounds for known build problems" at the end of this README file.
Note that this also downloads, builds and installs ABC (using yosys-abc
as executeable name).
@ -116,12 +105,16 @@ writing the design to the console in yosys's internal format:
yosys> write_ilang
elaborate design hierarchy:
yosys> hierarchy
convert processes ("always" blocks) to netlist elements and perform
some simple optimizations:
yosys> proc; opt
display design netlist using the yosys svg viewer:
display design netlist using xdot:
yosys> show
@ -139,13 +132,14 @@ write design netlist to a new verilog file:
a similar synthesis can be performed using yosys command line options only:
$ ./yosys -o synth.v -p proc -p opt -p techmap -p opt tests/simple/fiedler-cooley.v
$ ./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
proc; opt; techmap; opt
hierarchy; proc; opt; techmap; opt
write_verilog synth.v
$ ./yosys synth.ys
@ -154,21 +148,24 @@ It is also possible to only have the synthesis commands but not the read/write
commands in the synthesis script:
$ cat synth.ys
proc; opt; techmap; opt
hierarchy; proc; opt; techmap; opt
$ ./yosys -o synth.v tests/simple/fiedler-cooley.v synth.ys
The following synthesis script works reasonable for all designs:
The following very basic synthesis script should work well with all designs:
# check design hierarchy
hierarchy
# translate processes (always blocks) and memories (arrays)
proc; memory; opt
# translate processes (always blocks)
proc; opt
# detect and optimize FSM encodings
fsm; opt
# implement memories (arrays)
memory; opt
# convert to gate logic
techmap; opt
@ -177,7 +174,7 @@ in the liberty file mycells.lib, the following synthesis script will synthesize
for the given cell library:
# the high-level stuff
hierarchy; proc; memory; opt; fsm; opt
hierarchy; proc; fsm; opt; memory; opt
# mapping to internal cell library
techmap; opt
@ -194,6 +191,27 @@ for the given cell library:
If you do not have a liberty file but want to test this synthesis script,
you can use the file techlibs/cmos/cmos_cells.lib from the yosys sources.
Various more complex liberty files (for testing) can be found here:
http://vlsiarch.ecen.okstate.edu/flows/MOSIS_SCMOS/latest/..
../cadence/lib/tsmc025/signalstorm/osu025_stdcells.lib
../cadence/lib/ami035/signalstorm/osu035_stdcells.lib
../cadence/lib/tsmc018/signalstorm/osu018_stdcells.lib
../cadence/lib/ami05/signalstorm/osu05_stdcells.lib
The command "synth" provides a good default synthesis script (see "help synth").
If possible a synthesis script should borrow from "synth". For example:
# the high-level stuff
hierarchy
synth -run coarse
# mapping to internal cells
techmap; opt -fast
dfflibmap -liberty mycells.lib
abc -liberty mycells.lib
clean
Yosys is under construction. A more detailed documentation will follow.
@ -270,41 +288,83 @@ Verilog Attributes and non-standard features
for everything that comes after the {* ... *} statement. (Reset
by adding an empty {* *} statement.)
- 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
that is supported by the "sat" and "write_btor" commands.
- Modules can be declared with "module mod_name(...);" (with three dots
instead of a list of moudle ports). With this syntax it is sufficient
to simply declare a module port as 'input' or 'output' in the module
body.
- When defining a macro with `define, all text between tripple double quotes
is interpreted as macro body, even if it contains unescaped newlines. The
tripple double quotes are removed from the macro body. For example:
`define MY_MACRO(a, b) """
assign a = 23;
assign b = 42;
"""
- The attribute "via_celltype" can be used to implement a verilog task or
function by instantiating the specified cell type. The value is the name
of the cell type to use. For functions the name of the output port can
be specified by appending it to the cell type separated by a whitespace.
The body of the task or function is unused in this case and can be used
to specify a behavioral model of the cell type for simulation. For example:
module my_add3(A, B, C, Y);
parameter WIDTH = 8;
input [WIDTH-1:0] A, B, C;
output [WIDTH-1:0] Y;
...
endmodule
module top;
...
(* via_celltype = "my_add3 Y" *)
(* via_celltype_defparam_WIDTH = 32 *)
function [31:0] add3;
input [31:0] A, B, C;
begin
add3 = A + B + C;
end
endfunction
...
endmodule
- A limited subset of DPI-C functions is supported. The plugin mechanism
(see "help plugin") can be used load .so files with implementations of
DPI-C routines. As a non-standard extension it is possible to specify
a plugin alias using the "<alias>:" syntax. for example:
module dpitest;
import "DPI-C" function foo:round = real my_round (real);
parameter real r = my_round(12.345);
endmodule
$ yosys -p 'plugin -a foo -i /lib/libm.so; read_verilog dpitest.v'
- Sized constants (the syntax <size>'s?[bodh]<value>) support constant
expressions as <size>. If the expresion is not a simple identifier, it
must be put in parentheses. Examples: WIDTH'd42, (4+2)'b101010
Workarounds for known build problems
====================================
Supported features from SystemVerilog
=====================================
You might get an error message like this one during build when building with
a recent version of gcc:
When read_verilog is called with -sv, it accepts some language features
from SystemVerilog:
/usr/include/minisat/utils/Options.h:285:29: error:
unable to find string literal operator operator"" PRIi64
- 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
that is supported by the "sat" and "write_btor" commands.
This is a bug in the minisat header. It can be fixed by adding spaces before
and after each occurrence of PRIi64 in the header file:
sudo sed -i 's/PRIi64/ & /' /usr/include/minisat/utils/Options.h
- The keywords "always_comb", "always_ff" and "always_latch", "logic" and
"bit" are supported.
Roadmap / Large-scale TODOs
===========================
- Verification and Regression Tests
- VlogHammer: http://www.clifford.at/yosys/vloghammer.html
- yosys-bigsim: https://github.com/cliffordwolf/yosys-bigsim
- Technology mapping for real-world applications
- Add bit-wise const-folding via cell parameters to techmap pass
- Rewrite current stdcells.v techmap rules (modular and clean)
- Improve Xilinx FGPA synthesis (RAMB, CARRY4, SLR, etc.)
- Implement SAT-based formal equivialence checker
@ -321,7 +381,6 @@ Other Unsorted TODOs
- Implement missing Verilog 2005 features:
- Multi-dimensional arrays
- Support for real (float) const. expressions and parameters
- ROM modeling using $readmemh/$readmemb in "initial" blocks
- Ignore what needs to be ignored (e.g. drive and charge strengths)
@ -331,7 +390,4 @@ Other Unsorted TODOs
- Add brief source code documentation to most passes and kernel code
- Implement mux-to-tribuf pass and rebalance mixed mux/tribuf trees
- Add more commands for changing the design (delete, add, modify objects)
- Add full support for $lut cell type (const evaluation, sat solving, etc.)
- Smarter resource sharing pass (add MUXes and get rid of duplicated cells)

View file

@ -1,3 +0,0 @@
OBJS += backends/autotest/autotest.o

View file

@ -1,336 +0,0 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include "kernel/register.h"
#include "kernel/log.h"
#include <stdlib.h>
#include <stdio.h>
#define NUM_ITER 1000
static std::string id(std::string internal_id)
{
const char *str = internal_id.c_str();
bool do_escape = false;
if (*str == '\\')
str++;
if ('0' <= *str && *str <= '9')
do_escape = true;
for (int i = 0; str[i]; i++) {
if ('0' <= str[i] && str[i] <= '9')
continue;
if ('a' <= str[i] && str[i] <= 'z')
continue;
if ('A' <= str[i] && str[i] <= 'Z')
continue;
if (str[i] == '_')
continue;
do_escape = true;
break;
}
if (do_escape)
return "\\" + std::string(str) + " ";
return std::string(str);
}
static std::string idx(std::string str)
{
if (str[0] == '\\')
return str.substr(1);
return str;
}
static std::string idy(std::string str1, std::string str2 = std::string(), std::string str3 = std::string())
{
str1 = idx(str1);
if (!str2.empty())
str1 += "_" + idx(str2);
if (!str3.empty())
str1 += "_" + idx(str3);
return id(str1);
}
static void autotest(FILE *f, RTLIL::Design *design)
{
fprintf(f, "module testbench;\n\n");
fprintf(f, "integer i;\n\n");
fprintf(f, "reg [31:0] xorshift128_x = 123456789;\n");
fprintf(f, "reg [31:0] xorshift128_y = 362436069;\n");
fprintf(f, "reg [31:0] xorshift128_z = 521288629;\n");
fprintf(f, "reg [31:0] xorshift128_w = 88675123;\n");
fprintf(f, "reg [31:0] xorshift128_t;\n\n");
fprintf(f, "task xorshift128;\n");
fprintf(f, "begin\n");
fprintf(f, "\txorshift128_t = xorshift128_x ^ (xorshift128_x << 11);\n");
fprintf(f, "\txorshift128_x = xorshift128_y;\n");
fprintf(f, "\txorshift128_y = xorshift128_z;\n");
fprintf(f, "\txorshift128_z = xorshift128_w;\n");
fprintf(f, "\txorshift128_w = xorshift128_w ^ (xorshift128_w >> 19) ^ xorshift128_t ^ (xorshift128_t >> 8);\n");
fprintf(f, "end\n");
fprintf(f, "endtask\n\n");
for (auto it = design->modules.begin(); it != design->modules.end(); it++)
{
std::map<std::string, int> signal_in;
std::map<std::string, std::string> signal_const;
std::map<std::string, int> signal_clk;
std::map<std::string, int> signal_out;
RTLIL::Module *mod = it->second;
if (mod->get_bool_attribute("\\gentb_skip"))
continue;
int count_ports = 0;
log("Generating test bench for module `%s'.\n", it->first.c_str());
for (auto it2 = mod->wires.begin(); it2 != mod->wires.end(); it2++) {
RTLIL::Wire *wire = it2->second;
if (wire->port_output) {
count_ports++;
signal_out[idy("sig", mod->name, wire->name)] = wire->width;
fprintf(f, "wire [%d:0] %s;\n", wire->width-1, idy("sig", mod->name, wire->name).c_str());
} else if (wire->port_input) {
count_ports++;
bool is_clksignal = wire->get_bool_attribute("\\gentb_clock");
for (auto it3 = mod->processes.begin(); it3 != mod->processes.end(); it3++)
for (auto it4 = it3->second->syncs.begin(); it4 != it3->second->syncs.end(); it4++) {
if ((*it4)->type == RTLIL::ST0 || (*it4)->type == RTLIL::ST1)
continue;
RTLIL::SigSpec &signal = (*it4)->signal;
for (size_t i = 0; i < signal.chunks.size(); i++) {
if (signal.chunks[i].wire == wire)
is_clksignal = true;
}
}
if (is_clksignal && wire->attributes.count("\\gentb_constant") == 0) {
signal_clk[idy("sig", mod->name, wire->name)] = wire->width;
} else {
signal_in[idy("sig", mod->name, wire->name)] = wire->width;
if (wire->attributes.count("\\gentb_constant") != 0)
signal_const[idy("sig", mod->name, wire->name)] = wire->attributes["\\gentb_constant"].as_string();
}
fprintf(f, "reg [%d:0] %s;\n", wire->width-1, idy("sig", mod->name, wire->name).c_str());
}
}
fprintf(f, "%s %s(\n", id(mod->name).c_str(), idy("uut", mod->name).c_str());
for (auto it2 = mod->wires.begin(); it2 != mod->wires.end(); it2++) {
RTLIL::Wire *wire = it2->second;
if (wire->port_output || wire->port_input)
fprintf(f, "\t.%s(%s)%s\n", id(wire->name).c_str(),
idy("sig", mod->name, wire->name).c_str(), --count_ports ? "," : "");
}
fprintf(f, ");\n\n");
fprintf(f, "task %s;\n", idy(mod->name, "reset").c_str());
fprintf(f, "begin\n");
int delay_counter = 0;
for (auto it = signal_in.begin(); it != signal_in.end(); it++)
fprintf(f, "\t%s <= #%d 0;\n", it->first.c_str(), ++delay_counter*2);
for (auto it = signal_clk.begin(); it != signal_clk.end(); it++)
fprintf(f, "\t%s <= #%d 0;\n", it->first.c_str(), ++delay_counter*2);
for (auto it = signal_clk.begin(); it != signal_clk.end(); it++) {
fprintf(f, "\t#100; %s <= 1;\n", it->first.c_str());
fprintf(f, "\t#100; %s <= 0;\n", it->first.c_str());
}
delay_counter = 0;
for (auto it = signal_in.begin(); it != signal_in.end(); it++)
fprintf(f, "\t%s <= #%d ~0;\n", it->first.c_str(), ++delay_counter*2);
for (auto it = signal_clk.begin(); it != signal_clk.end(); it++) {
fprintf(f, "\t#100; %s <= 1;\n", it->first.c_str());
fprintf(f, "\t#100; %s <= 0;\n", it->first.c_str());
}
delay_counter = 0;
for (auto it = signal_in.begin(); it != signal_in.end(); it++) {
if (signal_const.count(it->first) == 0)
continue;
fprintf(f, "\t%s <= #%d 'b%s;\n", it->first.c_str(), ++delay_counter*2, signal_const[it->first].c_str());
}
fprintf(f, "end\n");
fprintf(f, "endtask\n\n");
fprintf(f, "task %s;\n", idy(mod->name, "update_data").c_str());
fprintf(f, "begin\n");
delay_counter = 0;
for (auto it = signal_in.begin(); it != signal_in.end(); it++) {
if (signal_const.count(it->first) > 0)
continue;
fprintf(f, "\txorshift128;\n");
fprintf(f, "\t%s <= #%d { xorshift128_x, xorshift128_y, xorshift128_z, xorshift128_w };\n", it->first.c_str(), ++delay_counter*2);
}
fprintf(f, "end\n");
fprintf(f, "endtask\n\n");
fprintf(f, "task %s;\n", idy(mod->name, "update_clock").c_str());
fprintf(f, "begin\n");
if (signal_clk.size()) {
fprintf(f, "\txorshift128;\n");
fprintf(f, "\t{");
int total_clock_bits = 0;
for (auto it = signal_clk.begin(); it != signal_clk.end(); it++) {
fprintf(f, "%s %s", it == signal_clk.begin() ? "" : ",", it->first.c_str());
total_clock_bits += it->second;
}
fprintf(f, " } = {");
for (auto it = signal_clk.begin(); it != signal_clk.end(); it++)
fprintf(f, "%s %s", it == signal_clk.begin() ? "" : ",", it->first.c_str());
fprintf(f, " } ^ (%d'b1 << (xorshift128_w %% %d));\n", total_clock_bits, total_clock_bits);
}
fprintf(f, "end\n");
fprintf(f, "endtask\n\n");
char shorthand = 'A';
std::vector<std::string> header1;
std::string header2 = "";
fprintf(f, "task %s;\n", idy(mod->name, "print_status").c_str());
fprintf(f, "begin\n");
fprintf(f, "\t$display(\"#OUT# %%b %%b %%b %%t %%d\", {");
if (signal_in.size())
for (auto it = signal_in.begin(); it != signal_in.end(); it++) {
fprintf(f, "%s %s", it == signal_in.begin() ? "" : ",", it->first.c_str());
int len = it->second;
if (len > 1)
header2 += "/", len--;
while (len > 1)
header2 += "-", len--;
if (len > 0)
header2 += shorthand, len--;
header1.push_back(" " + it->first);
header1.back()[0] = shorthand++;
}
else {
fprintf(f, " 1'bx");
header2 += "#";
}
fprintf(f, " }, {");
header2 += " ";
if (signal_clk.size()) {
for (auto it = signal_clk.begin(); it != signal_clk.end(); it++) {
fprintf(f, "%s %s", it == signal_clk.begin() ? "" : ",", it->first.c_str());
int len = it->second;
if (len > 1)
header2 += "/", len--;
while (len > 1)
header2 += "-", len--;
if (len > 0)
header2 += shorthand, len--;
header1.push_back(" " + it->first);
header1.back()[0] = shorthand++;
}
} else {
fprintf(f, " 1'bx");
header2 += "#";
}
fprintf(f, " }, {");
header2 += " ";
if (signal_out.size()) {
for (auto it = signal_out.begin(); it != signal_out.end(); it++) {
fprintf(f, "%s %s", it == signal_out.begin() ? "" : ",", it->first.c_str());
int len = it->second;
if (len > 1)
header2 += "/", len--;
while (len > 1)
header2 += "-", len--;
if (len > 0)
header2 += shorthand, len--;
header1.push_back(" " + it->first);
header1.back()[0] = shorthand++;
}
} else {
fprintf(f, " 1'bx");
header2 += "#";
}
fprintf(f, " }, $time, i);\n");
fprintf(f, "end\n");
fprintf(f, "endtask\n\n");
fprintf(f, "task %s;\n", idy(mod->name, "print_header").c_str());
fprintf(f, "begin\n");
fprintf(f, "\t$display(\"#OUT#\");\n");
for (auto &hdr : header1)
fprintf(f, "\t$display(\"#OUT# %s\");\n", hdr.c_str());
fprintf(f, "\t$display(\"#OUT#\");\n");
fprintf(f, "\t$display(\"#OUT# %s\");\n", header2.c_str());
fprintf(f, "end\n");
fprintf(f, "endtask\n\n");
fprintf(f, "task %s;\n", idy(mod->name, "test").c_str());
fprintf(f, "begin\n");
fprintf(f, "\t$display(\"#OUT#\\n#OUT# ==== %s ====\");\n", idy(mod->name).c_str());
fprintf(f, "\t%s;\n", idy(mod->name, "reset").c_str());
fprintf(f, "\tfor (i=0; i<%d; i=i+1) begin\n", NUM_ITER);
fprintf(f, "\t\tif (i %% 20 == 0) %s;\n", idy(mod->name, "print_header").c_str());
fprintf(f, "\t\t#100; %s;\n", idy(mod->name, "update_data").c_str());
fprintf(f, "\t\t#100; %s;\n", idy(mod->name, "update_clock").c_str());
fprintf(f, "\t\t#100; %s;\n", idy(mod->name, "print_status").c_str());
fprintf(f, "\tend\n");
fprintf(f, "end\n");
fprintf(f, "endtask\n\n");
}
fprintf(f, "initial begin\n");
fprintf(f, "\t// $dumpfile(\"testbench.vcd\");\n");
fprintf(f, "\t// $dumpvars(0, testbench);\n");
for (auto it = design->modules.begin(); it != design->modules.end(); it++)
if (!it->second->get_bool_attribute("\\gentb_skip"))
fprintf(f, "\t%s;\n", idy(it->first, "test").c_str());
fprintf(f, "\t$finish;\n");
fprintf(f, "end\n\n");
fprintf(f, "endmodule\n");
}
struct AutotestBackend : public Backend {
AutotestBackend() : Backend("autotest", "generate simple test benches") { }
virtual void help()
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" write_autotest [filename]\n");
log("\n");
log("Automatically create primitive verilog test benches for all modules in the\n");
log("design. The generated testbenches toggle the input pins of the module in\n");
log("a semi-random manner and dumps the resulting output signals.\n");
log("\n");
log("This can be used to check the synthesis results for simple circuits by\n");
log("comparing the testbench output for the input files and the synthesis results.\n");
log("\n");
log("The backend automatically detects clock signals. Additionally a signal can\n");
log("be forced to be interpreted as clock signal by setting the attribute\n");
log("'gentb_clock' on the signal.\n");
log("\n");
log("The attribute 'gentb_constant' can be used to force a signal to a constant\n");
log("value after initialization. This can e.g. be used to force a reset signal\n");
log("low in order to explore more inner states in a state machine.\n");
log("\n");
}
virtual void execute(FILE *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
{
log_header("Executing AUTOTEST backend (auto-generate pseudo-random test benches).\n");
extra_args(f, filename, args, 1);
autotest(f, design);
}
} AutotestBackend;

View file

@ -27,29 +27,30 @@
#include "kernel/celltypes.h"
#include "kernel/log.h"
#include <string>
#include <assert.h>
struct BlifDumperConfig
{
bool subckt_mode;
bool icells_mode;
bool conn_mode;
bool impltf_mode;
bool gates_mode;
bool param_mode;
std::string buf_type, buf_in, buf_out;
std::string true_type, true_out, false_type, false_out;
BlifDumperConfig() : subckt_mode(false), conn_mode(false), impltf_mode(false) { }
BlifDumperConfig() : icells_mode(false), conn_mode(false), impltf_mode(false), gates_mode(false), param_mode(false) { }
};
struct BlifDumper
{
FILE *f;
std::ostream &f;
RTLIL::Module *module;
RTLIL::Design *design;
BlifDumperConfig *config;
CellTypes ct;
BlifDumper(FILE *f, RTLIL::Module *module, RTLIL::Design *design, BlifDumperConfig *config) :
BlifDumper(std::ostream &f, RTLIL::Module *module, RTLIL::Design *design, BlifDumperConfig *config) :
f(f), module(module), design(design), config(config), ct(design)
{
}
@ -66,34 +67,42 @@ struct BlifDumper
return cstr_buf.back().c_str();
}
const char *cstr(RTLIL::SigSpec sig)
const char *cstr(RTLIL::SigBit sig)
{
sig.optimize();
log_assert(sig.width == 1);
if (sig.wire == NULL)
return sig == RTLIL::State::S1 ? "$true" : "$false";
if (sig.chunks.at(0).wire == NULL)
return sig.chunks.at(0).data.bits.at(0) == RTLIL::State::S1 ? "$true" : "$false";
std::string str = RTLIL::unescape_id(sig.chunks.at(0).wire->name);
std::string str = RTLIL::unescape_id(sig.wire->name);
for (size_t i = 0; i < str.size(); i++)
if (str[i] == '#' || str[i] == '=')
str[i] = '?';
if (sig.chunks.at(0).wire->width != 1)
str += stringf("[%d]", sig.chunks.at(0).offset);
if (sig.wire->width != 1)
str += stringf("[%d]", sig.offset);
cstr_buf.push_back(str);
return cstr_buf.back().c_str();
}
const char *subckt_or_gate(std::string cell_type)
{
if (!config->gates_mode)
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"))
return "gate";
return "subckt";
}
void dump()
{
fprintf(f, "\n");
fprintf(f, ".model %s\n", cstr(module->name));
f << stringf("\n");
f << stringf(".model %s\n", cstr(module->name));
std::map<int, RTLIL::Wire*> inputs, outputs;
for (auto &wire_it : module->wires) {
for (auto &wire_it : module->wires_) {
RTLIL::Wire *wire = wire_it.second;
if (wire->port_input)
inputs[wire->port_id] = wire;
@ -101,107 +110,150 @@ struct BlifDumper
outputs[wire->port_id] = wire;
}
fprintf(f, ".inputs");
f << stringf(".inputs");
for (auto &it : inputs) {
RTLIL::Wire *wire = it.second;
for (int i = 0; i < wire->width; i++)
fprintf(f, " %s", cstr(RTLIL::SigSpec(wire, 1, i)));
f << stringf(" %s", cstr(RTLIL::SigSpec(wire, i)));
}
fprintf(f, "\n");
f << stringf("\n");
fprintf(f, ".outputs");
f << stringf(".outputs");
for (auto &it : outputs) {
RTLIL::Wire *wire = it.second;
for (int i = 0; i < wire->width; i++)
fprintf(f, " %s", cstr(RTLIL::SigSpec(wire, 1, i)));
f << stringf(" %s", cstr(RTLIL::SigSpec(wire, i)));
}
fprintf(f, "\n");
f << stringf("\n");
if (!config->impltf_mode) {
if (!config->false_type.empty())
fprintf(f, ".subckt %s %s=$false\n", config->false_type.c_str(), config->false_out.c_str());
f << stringf(".%s %s %s=$false\n", subckt_or_gate(config->false_type),
config->false_type.c_str(), config->false_out.c_str());
else
fprintf(f, ".names $false\n");
f << stringf(".names $false\n");
if (!config->true_type.empty())
fprintf(f, ".subckt %s %s=$true\n", config->true_type.c_str(), config->true_out.c_str());
f << stringf(".%s %s %s=$true\n", subckt_or_gate(config->true_type),
config->true_type.c_str(), config->true_out.c_str());
else
fprintf(f, ".names $true\n1\n");
f << stringf(".names $true\n1\n");
}
for (auto &cell_it : module->cells)
for (auto &cell_it : module->cells_)
{
RTLIL::Cell *cell = cell_it.second;
if (!config->subckt_mode && cell->type == "$_INV_") {
fprintf(f, ".names %s %s\n0 1\n",
cstr(cell->connections.at("\\A")), cstr(cell->connections.at("\\Y")));
if (!config->icells_mode && cell->type == "$_NOT_") {
f << stringf(".names %s %s\n0 1\n",
cstr(cell->getPort("\\A")), cstr(cell->getPort("\\Y")));
continue;
}
if (!config->subckt_mode && cell->type == "$_AND_") {
fprintf(f, ".names %s %s %s\n11 1\n",
cstr(cell->connections.at("\\A")), cstr(cell->connections.at("\\B")), cstr(cell->connections.at("\\Y")));
if (!config->icells_mode && cell->type == "$_AND_") {
f << stringf(".names %s %s %s\n11 1\n",
cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), cstr(cell->getPort("\\Y")));
continue;
}
if (!config->subckt_mode && cell->type == "$_OR_") {
fprintf(f, ".names %s %s %s\n1- 1\n-1 1\n",
cstr(cell->connections.at("\\A")), cstr(cell->connections.at("\\B")), cstr(cell->connections.at("\\Y")));
if (!config->icells_mode && cell->type == "$_OR_") {
f << stringf(".names %s %s %s\n1- 1\n-1 1\n",
cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), cstr(cell->getPort("\\Y")));
continue;
}
if (!config->subckt_mode && cell->type == "$_XOR_") {
fprintf(f, ".names %s %s %s\n10 1\n01 1\n",
cstr(cell->connections.at("\\A")), cstr(cell->connections.at("\\B")), cstr(cell->connections.at("\\Y")));
if (!config->icells_mode && cell->type == "$_XOR_") {
f << stringf(".names %s %s %s\n10 1\n01 1\n",
cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), cstr(cell->getPort("\\Y")));
continue;
}
if (!config->subckt_mode && cell->type == "$_MUX_") {
fprintf(f, ".names %s %s %s %s\n1-0 1\n-11 1\n",
cstr(cell->connections.at("\\A")), cstr(cell->connections.at("\\B")),
cstr(cell->connections.at("\\S")), cstr(cell->connections.at("\\Y")));
if (!config->icells_mode && cell->type == "$_MUX_") {
f << stringf(".names %s %s %s %s\n1-0 1\n-11 1\n",
cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")),
cstr(cell->getPort("\\S")), cstr(cell->getPort("\\Y")));
continue;
}
if (!config->subckt_mode && cell->type == "$_DFF_N_") {
fprintf(f, ".latch %s %s fe %s\n",
cstr(cell->connections.at("\\D")), cstr(cell->connections.at("\\Q")), cstr(cell->connections.at("\\C")));
if (!config->icells_mode && cell->type == "$_DFF_N_") {
f << stringf(".latch %s %s fe %s\n",
cstr(cell->getPort("\\D")), cstr(cell->getPort("\\Q")), cstr(cell->getPort("\\C")));
continue;
}
if (!config->subckt_mode && cell->type == "$_DFF_P_") {
fprintf(f, ".latch %s %s re %s\n",
cstr(cell->connections.at("\\D")), cstr(cell->connections.at("\\Q")), cstr(cell->connections.at("\\C")));
if (!config->icells_mode && cell->type == "$_DFF_P_") {
f << stringf(".latch %s %s re %s\n",
cstr(cell->getPort("\\D")), cstr(cell->getPort("\\Q")), cstr(cell->getPort("\\C")));
continue;
}
fprintf(f, ".subckt %s", cstr(cell->type));
for (auto &conn : cell->connections)
for (int i = 0; i < conn.second.width; i++) {
if (conn.second.width == 1)
fprintf(f, " %s", cstr(conn.first));
if (!config->icells_mode && cell->type == "$lut") {
f << stringf(".names");
auto &inputs = cell->getPort("\\A");
auto width = cell->parameters.at("\\WIDTH").as_int();
log_assert(inputs.size() == width);
for (int i = 0; i < inputs.size(); i++) {
f << stringf(" %s", cstr(inputs.extract(i, 1)));
}
auto &output = cell->getPort("\\Y");
log_assert(output.size() == 1);
f << stringf(" %s", cstr(output));
f << stringf("\n");
auto mask = cell->parameters.at("\\LUT").as_string();
for (int i = 0; i < (1 << width); i++) {
if (mask[i] == '0') continue;
for (int j = width-1; j >= 0; j--) {
f << ((i>>j)&1 ? '1' : '0');
}
f << stringf(" %c\n", mask[i]);
}
continue;
}
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
fprintf(f, " %s[%d]", cstr(conn.first), i);
fprintf(f, "=%s", cstr(conn.second.extract(i, 1)));
f << stringf(" %s[%d]", cstr(conn.first), i);
f << stringf("=%s", cstr(conn.second.extract(i, 1)));
}
fprintf(f, "\n");
f << stringf("\n");
if (config->param_mode)
for (auto &param : cell->parameters) {
f << stringf(".param %s ", RTLIL::id2cstr(param.first));
if (param.second.flags & RTLIL::CONST_FLAG_STRING) {
std::string str = param.second.decode_string();
f << stringf("\"");
for (char ch : str)
if (ch == '"' || ch == '\\')
f << stringf("\\%c", ch);
else if (ch < 32 || ch >= 127)
f << stringf("\\%03o", ch);
else
f << stringf("%c", ch);
f << stringf("\"\n");
} else
f << stringf("%s\n", param.second.as_string().c_str());
}
}
for (auto &conn : module->connections)
for (int i = 0; i < conn.first.width; i++)
for (auto &conn : module->connections())
for (int i = 0; i < conn.first.size(); i++)
if (config->conn_mode)
fprintf(f, ".conn %s %s\n", cstr(conn.second.extract(i, 1)), cstr(conn.first.extract(i, 1)));
f << stringf(".conn %s %s\n", cstr(conn.second.extract(i, 1)), cstr(conn.first.extract(i, 1)));
else if (!config->buf_type.empty())
fprintf(f, ".subckt %s %s=%s %s=%s\n", config->buf_type.c_str(), config->buf_in.c_str(), cstr(conn.second.extract(i, 1)),
f << stringf(".%s %s %s=%s %s=%s\n", subckt_or_gate(config->buf_type), config->buf_type.c_str(), config->buf_in.c_str(), cstr(conn.second.extract(i, 1)),
config->buf_out.c_str(), cstr(conn.first.extract(i, 1)));
else
fprintf(f, ".names %s %s\n1 1\n", cstr(conn.second.extract(i, 1)), cstr(conn.first.extract(i, 1)));
f << stringf(".names %s %s\n1 1\n", cstr(conn.second.extract(i, 1)), cstr(conn.first.extract(i, 1)));
fprintf(f, ".end\n");
f << stringf(".end\n");
}
static void dump(FILE *f, RTLIL::Module *module, RTLIL::Design *design, BlifDumperConfig &config)
static void dump(std::ostream &f, RTLIL::Module *module, RTLIL::Design *design, BlifDumperConfig &config)
{
BlifDumper dumper(f, module, design, &config);
dumper.dump();
@ -228,23 +280,30 @@ struct BlifBackend : public Backend {
log(" -false <cell-type> <out-port>\n");
log(" use the specified cell types to drive nets that are constant 1 or 0\n");
log("\n");
log("The following options can be usefull when the generated file is not going to be\n");
log("The following options can be useful when the generated file is not going to be\n");
log("read by a BLIF parser but a custom tool. It is recommended to not name the output\n");
log("file *.blif when any of this options is used.\n");
log("\n");
log(" -subckt\n");
log(" -icells\n");
log(" do not translate Yosys's internal gates to generic BLIF logic\n");
log(" functions. Instead create .subckt lines for all cells.\n");
log(" functions. Instead create .subckt or .gate lines for all cells.\n");
log("\n");
log(" -gates\n");
log(" print .gate instead of .subckt lines for all cells that are not\n");
log(" instantiations of other modules from this design.\n");
log("\n");
log(" -conn\n");
log(" do not generate buffers for connected wires. instead use the\n");
log(" non-standard .conn statement.\n");
log("\n");
log(" -param\n");
log(" use the non-standard .param statement to write module parameters\n");
log("\n");
log(" -impltf\n");
log(" do not write definitions for the $true and $false wires.\n");
log("\n");
}
virtual void execute(FILE *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
{
std::string top_module_name;
std::string buf_type, buf_in, buf_out;
@ -277,14 +336,22 @@ struct BlifBackend : public Backend {
config.false_out = args[++argidx];
continue;
}
if (args[argidx] == "-subckt") {
config.subckt_mode = true;
if (args[argidx] == "-icells") {
config.icells_mode = true;
continue;
}
if (args[argidx] == "-gates") {
config.gates_mode = true;
continue;
}
if (args[argidx] == "-conn") {
config.conn_mode = true;
continue;
}
if (args[argidx] == "-param") {
config.param_mode = true;
continue;
}
if (args[argidx] == "-impltf") {
config.impltf_mode = true;
continue;
@ -294,15 +361,15 @@ struct BlifBackend : public Backend {
extra_args(f, filename, args, argidx);
if (top_module_name.empty())
for (auto & mod_it:design->modules)
for (auto & mod_it:design->modules_)
if (mod_it.second->get_bool_attribute("\\top"))
top_module_name = mod_it.first;
top_module_name = mod_it.first.str();
fprintf(f, "# Generated by %s\n", yosys_version_str);
*f << stringf("# Generated by %s\n", yosys_version_str);
std::vector<RTLIL::Module*> mod_list;
for (auto module_it : design->modules)
for (auto module_it : design->modules_)
{
RTLIL::Module *module = module_it.second;
if (module->get_bool_attribute("\\blackbox"))
@ -314,7 +381,7 @@ struct BlifBackend : public Backend {
log_error("Found munmapped emories in module %s: unmapped memories are not supported in BLIF backend!\n", RTLIL::id2cstr(module->name));
if (module->name == RTLIL::escape_id(top_module_name)) {
BlifDumper::dump(f, module, design, config);
BlifDumper::dump(*f, module, design, config);
top_module_name.clear();
continue;
}
@ -326,7 +393,7 @@ struct BlifBackend : public Backend {
log_error("Can't find top module `%s'!\n", top_module_name.c_str());
for (auto module : mod_list)
BlifDumper::dump(f, module, design, config);
BlifDumper::dump(*f, module, design, config);
}
} BlifBackend;

View file

@ -28,7 +28,6 @@
#include "kernel/celltypes.h"
#include "kernel/log.h"
#include <string>
#include <assert.h>
#include <math.h>
struct BtorDumperConfig
@ -46,9 +45,9 @@ struct BtorDumperConfig
struct WireInfo
{
RTLIL::IdString cell_name;
RTLIL::SigChunk *chunk;
const RTLIL::SigChunk *chunk;
WireInfo(RTLIL::IdString c, RTLIL::SigChunk* ch) : cell_name(c), chunk(ch) { }
WireInfo(RTLIL::IdString c, const RTLIL::SigChunk* ch) : cell_name(c), chunk(ch) { }
};
struct WireInfoOrder
@ -61,7 +60,7 @@ struct WireInfoOrder
struct BtorDumper
{
FILE *f;
std::ostream &f;
RTLIL::Module *module;
RTLIL::Design *design;
BtorDumperConfig *config;
@ -75,14 +74,14 @@ struct BtorDumper
std::string str;//temp string for writing file
std::map<RTLIL::IdString, bool> basic_wires;//input wires and registers
RTLIL::IdString curr_cell; //current cell being dumped
std::set<int> mem_next; //if memory (line_number) already has next
std::map<std::string, std::string> cell_type_translation, s_cell_type_translation; //RTLIL to BTOR translation
BtorDumper(FILE *f, RTLIL::Module *module, RTLIL::Design *design, BtorDumperConfig *config) :
f(f), module(module), design(design), config(config), ct(design), sigmap(module)
std::map<std::string, std::string> cell_type_translation, s_cell_type_translation; //RTLIL to BTOR translation
std::set<int> mem_next; //if memory (line_number) already has next
BtorDumper(std::ostream &f, RTLIL::Module *module, RTLIL::Design *design, BtorDumperConfig *config) :
f(f), module(module), design(design), config(config), ct(design), sigmap(module)
{
line_num=0;
str.clear();
for(auto it=module->wires.begin(); it!=module->wires.end(); ++it)
for(auto it=module->wires_.begin(); it!=module->wires_.end(); ++it)
{
if(it->second->port_input)
{
@ -113,6 +112,8 @@ struct BtorDumper
cell_type_translation["$shl"] = "sll";
cell_type_translation["$sshr"] = "sra";
cell_type_translation["$sshl"] = "sll";
cell_type_translation["$shift"] = "srl";
cell_type_translation["$shiftx"] = "srl";
cell_type_translation["$lt"] = "ult";
cell_type_translation["$le"] = "ulte";
cell_type_translation["$gt"] = "ugt";
@ -174,7 +175,7 @@ struct BtorDumper
++line_num;
line_ref[wire->name]=line_num;
str = stringf("%d var %d %s", line_num, wire->width, cstr(wire->name));
fprintf(f, "%s\n", str.c_str());
f << stringf("%s\n", str.c_str());
return line_num;
}
else return it->second;
@ -194,11 +195,11 @@ struct BtorDumper
if(cell_id == curr_cell)
break;
log(" -- found cell %s\n", cstr(cell_id));
RTLIL::Cell* cell = module->cells.at(cell_id);
RTLIL::SigSpec* cell_output = get_cell_output(cell);
RTLIL::Cell* cell = module->cells_.at(cell_id);
const RTLIL::SigSpec* cell_output = get_cell_output(cell);
int cell_line = dump_cell(cell);
if(dep_set.size()==1 && wire->width == cell_output->width)
if(dep_set.size()==1 && wire->width == cell_output->size())
{
wire_line = cell_line;
break;
@ -207,22 +208,22 @@ struct BtorDumper
{
int prev_wire_line=0; //previously dumped wire line
int start_bit=0;
for(unsigned j=0; j<cell_output->chunks.size(); ++j)
for(unsigned j=0; j<cell_output->chunks().size(); ++j)
{
start_bit+=cell_output->chunks[j].width;
if(cell_output->chunks[j].wire->name == wire->name)
start_bit+=cell_output->chunks().at(j).width;
if(cell_output->chunks().at(j).wire->name == wire->name)
{
prev_wire_line = wire_line;
wire_line = ++line_num;
str = stringf("%d slice %d %d %d %d;1", line_num, cell_output->chunks[j].width,
cell_line, start_bit-1, start_bit-cell_output->chunks[j].width);
fprintf(f, "%s\n", str.c_str());
wire_width += cell_output->chunks[j].width;
str = stringf("%d slice %d %d %d %d;1", line_num, cell_output->chunks().at(j).width,
cell_line, start_bit-1, start_bit-cell_output->chunks().at(j).width);
f << stringf("%s\n", str.c_str());
wire_width += cell_output->chunks().at(j).width;
if(prev_wire_line!=0)
{
++line_num;
str = stringf("%d concat %d %d %d", line_num, wire_width, wire_line, prev_wire_line);
fprintf(f, "%s\n", str.c_str());
f << stringf("%s\n", str.c_str());
wire_line = line_num;
}
}
@ -233,7 +234,7 @@ struct BtorDumper
{
log(" - checking sigmap\n");
RTLIL::SigSpec s = RTLIL::SigSpec(wire);
wire_line = dump_sigspec(&s, s.width);
wire_line = dump_sigspec(&s, s.size());
line_ref[wire->name]=wire_line;
}
line_ref[wire->name]=wire_line;
@ -245,7 +246,7 @@ struct BtorDumper
return it->second;
}
}
assert(false);
log_abort();
return -1;
}
@ -259,7 +260,7 @@ struct BtorDumper
int address_bits = ceil(log(memory->size)/log(2));
str = stringf("%d array %d %d", line_num, memory->width, address_bits);
line_ref[memory->name]=line_num;
fprintf(f, "%s\n", str.c_str());
f << stringf("%s\n", str.c_str());
return line_num;
}
else return it->second;
@ -279,12 +280,12 @@ struct BtorDumper
++line_num;
str = stringf("%d const %d %s", line_num, width, data_str.c_str());
fprintf(f, "%s\n", str.c_str());
f << stringf("%s\n", str.c_str());
return line_num;
}
else
log("writing const error\n");
assert(false);
log_abort();
return -1;
}
@ -294,7 +295,8 @@ struct BtorDumper
int l=-1;
if(chunk->wire == NULL)
{
l=dump_const(&chunk->data, chunk->width, chunk->offset);
RTLIL::Const data_const(chunk->data);
l=dump_const(&data_const, chunk->width, chunk->offset);
}
else
{
@ -303,11 +305,11 @@ struct BtorDumper
else
{
int wire_line_num = dump_wire(chunk->wire);
assert(wire_line_num>0);
log_assert(wire_line_num>0);
++line_num;
str = stringf("%d slice %d %d %d %d;2", line_num, chunk->width, wire_line_num,
chunk->width + chunk->offset - 1, chunk->offset);
fprintf(f, "%s\n", str.c_str());
f << stringf("%s\n", str.c_str());
l = line_num;
}
}
@ -322,24 +324,24 @@ struct BtorDumper
auto it = sig_ref.find(s);
if(it == std::end(sig_ref))
{
if (s.chunks.size() == 1)
if (s.is_chunk())
{
l = dump_sigchunk(&s.chunks[0]);
l = dump_sigchunk(&s.chunks().front());
}
else
{
int l1, l2, w1, w2;
l1 = dump_sigchunk(&s.chunks[0]);
assert(l1>0);
w1 = s.chunks[0].width;
for (unsigned i=1; i < s.chunks.size(); ++i)
l1 = dump_sigchunk(&s.chunks().front());
log_assert(l1>0);
w1 = s.chunks().front().width;
for (unsigned i=1; i < s.chunks().size(); ++i)
{
l2 = dump_sigchunk(&s.chunks[i]);
assert(l2>0);
w2 = s.chunks[i].width;
l2 = dump_sigchunk(&s.chunks().at(i));
log_assert(l2>0);
w2 = s.chunks().at(i).width;
++line_num;
str = stringf("%d concat %d %d %d", line_num, w1+w2, l2, l1);
fprintf(f, "%s\n", str.c_str());
f << stringf("%s\n", str.c_str());
l1=line_num;
w1+=w2;
}
@ -352,30 +354,30 @@ struct BtorDumper
l = it->second;
}
if (expected_width != s.width)
if (expected_width != s.size())
{
log(" - changing width of sigspec\n");
//TODO: this block may not be needed anymore, due to explicit type conversion by "splice" command
if(expected_width > s.width)
if(expected_width > s.size())
{
//TODO: case the signal is signed
++line_num;
str = stringf ("%d zero %d", line_num, expected_width - s.width);
fprintf(f, "%s\n", str.c_str());
str = stringf ("%d zero %d", line_num, expected_width - s.size());
f << stringf("%s\n", str.c_str());
++line_num;
str = stringf ("%d concat %d %d %d", line_num, expected_width, line_num-1, l);
fprintf(f, "%s\n", str.c_str());
f << stringf("%s\n", str.c_str());
l = line_num;
}
else if(expected_width < s.width)
else if(expected_width < s.size())
{
++line_num;
str = stringf ("%d slice %d %d %d %d;3", line_num, expected_width, l, expected_width-1, 0);
fprintf(f, "%s\n", str.c_str());
f << stringf("%s\n", str.c_str());
l = line_num;
}
}
assert(l>0);
log_assert(l>0);
return l;
}
@ -389,29 +391,29 @@ struct BtorDumper
if(cell->type == "$assert")
{
log("writing assert cell - %s\n", cstr(cell->type));
const RTLIL::SigSpec* expr = &cell->connections.at(RTLIL::IdString("\\A"));
const RTLIL::SigSpec* en = &cell->connections.at(RTLIL::IdString("\\EN"));
assert(expr->width == 1);
assert(en->width == 1);
const RTLIL::SigSpec* expr = &cell->getPort(RTLIL::IdString("\\A"));
const RTLIL::SigSpec* en = &cell->getPort(RTLIL::IdString("\\EN"));
log_assert(expr->size() == 1);
log_assert(en->size() == 1);
int expr_line = dump_sigspec(expr, 1);
int en_line = dump_sigspec(en, 1);
int one_line = ++line_num;
str = stringf("%d one 1", line_num);
fprintf(f, "%s\n", str.c_str());
f << stringf("%s\n", str.c_str());
++line_num;
str = stringf("%d %s %d %d %d", line_num, cell_type_translation.at("$eq").c_str(), 1, en_line, one_line);
fprintf(f, "%s\n", str.c_str());
f << stringf("%s\n", str.c_str());
++line_num;
str = stringf("%d %s %d %d %d %d", line_num, cell_type_translation.at("$mux").c_str(), 1, line_num-1,
expr_line, one_line);
fprintf(f, "%s\n", str.c_str());
f << stringf("%s\n", str.c_str());
int cell_line = ++line_num;
str = stringf("%d %s %d %d", line_num, cell_type_translation.at("$assert").c_str(), 1, -1*(line_num-1));
//multiplying the line number with -1, which means logical negation
//the reason for negative sign is that the properties in btor are given as "negation of the original property"
//bug identified by bobosoft
//http://www.reddit.com/r/yosys/comments/1w3xig/btor_backend_bug/
fprintf(f, "%s\n", str.c_str());
f << stringf("%s\n", str.c_str());
line_ref[cell->name]=cell_line;
}
//unary cells
@ -422,20 +424,20 @@ struct BtorDumper
int w = cell->parameters.at(RTLIL::IdString("\\A_WIDTH")).as_int();
int output_width = cell->parameters.at(RTLIL::IdString("\\Y_WIDTH")).as_int();
w = w>output_width ? w:output_width; //padding of w
int l = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\A")), w);
int l = dump_sigspec(&cell->getPort(RTLIL::IdString("\\A")), w);
int cell_line = l;
if(cell->type != "$pos")
{
cell_line = ++line_num;
bool reduced = (cell->type == "$not" || cell->type == "$neg") ? false : true;
str = stringf ("%d %s %d %d", cell_line, cell_type_translation.at(cell->type).c_str(), reduced?output_width:w, l);
fprintf(f, "%s\n", str.c_str());
str = stringf ("%d %s %d %d", cell_line, cell_type_translation.at(cell->type.str()).c_str(), reduced?output_width:w, l);
f << stringf("%s\n", str.c_str());
}
if(output_width < w && (cell->type == "$not" || cell->type == "$neg" || cell->type == "$pos"))
{
++line_num;
str = stringf ("%d slice %d %d %d %d;4", line_num, output_width, cell_line, output_width-1, 0);
fprintf(f, "%s\n", str.c_str());
f << stringf("%s\n", str.c_str());
cell_line = line_num;
}
line_ref[cell->name]=cell_line;
@ -445,25 +447,23 @@ struct BtorDumper
log("writing unary cell - %s\n", cstr(cell->type));
int w = cell->parameters.at(RTLIL::IdString("\\A_WIDTH")).as_int();
int output_width = cell->parameters.at(RTLIL::IdString("\\Y_WIDTH")).as_int();
assert(output_width == 1);
int l = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\A")), w);
log_assert(output_width == 1);
int l = dump_sigspec(&cell->getPort(RTLIL::IdString("\\A")), w);
if(cell->type == "$logic_not" && w > 1)
{
++line_num;
str = stringf ("%d %s %d %d", line_num, cell_type_translation.at("$reduce_or").c_str(), output_width, l);
fprintf(f, "%s\n", str.c_str());
l = line_num;
f << stringf("%s\n", str.c_str());
}
else if(cell->type == "$reduce_xnor")
{
++line_num;
str = stringf ("%d %s %d %d", line_num, cell_type_translation.at("$reduce_xor").c_str(), output_width, l);
fprintf(f, "%s\n", str.c_str());
l = line_num;
f << stringf("%s\n", str.c_str());
}
++line_num;
str = stringf ("%d %s %d %d", line_num, cell_type_translation.at("$not").c_str(), output_width, l);
fprintf(f, "%s\n", str.c_str());
f << stringf("%s\n", str.c_str());
line_ref[cell->name]=line_num;
}
//binary cells
@ -473,7 +473,7 @@ struct BtorDumper
{
log("writing binary cell - %s\n", cstr(cell->type));
int output_width = cell->parameters.at(RTLIL::IdString("\\Y_WIDTH")).as_int();
assert(!(cell->type == "$eq" || cell->type == "$ne" || cell->type == "$eqx" || cell->type == "$nex" ||
log_assert(!(cell->type == "$eq" || cell->type == "$ne" || cell->type == "$eqx" || cell->type == "$nex" ||
cell->type == "$ge" || cell->type == "$gt") || output_width == 1);
bool l1_signed = cell->parameters.at(RTLIL::IdString("\\A_SIGNED")).as_bool();
bool l2_signed = cell->parameters.at(RTLIL::IdString("\\B_SIGNED")).as_bool();
@ -485,21 +485,21 @@ struct BtorDumper
l1_width = l1_width > l2_width ? l1_width : l2_width;
l2_width = l2_width > l1_width ? l2_width : l1_width;
int l1 = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\A")), l1_width);
int l2 = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\B")), l2_width);
int l1 = dump_sigspec(&cell->getPort(RTLIL::IdString("\\A")), l1_width);
int l2 = dump_sigspec(&cell->getPort(RTLIL::IdString("\\B")), l2_width);
++line_num;
std::string op = cell_type_translation.at(cell->type);
std::string op = cell_type_translation.at(cell->type.str());
if(cell->type == "$lt" || cell->type == "$le" ||
cell->type == "$eq" || cell->type == "$ne" || cell->type == "$eqx" || cell->type == "$nex" ||
cell->type == "$ge" || cell->type == "$gt")
{
if(l1_signed)
op = s_cell_type_translation.at(cell->type);
op = s_cell_type_translation.at(cell->type.str());
}
str = stringf ("%d %s %d %d %d", line_num, op.c_str(), output_width, l1, l2);
fprintf(f, "%s\n", str.c_str());
f << stringf("%s\n", str.c_str());
line_ref[cell->name]=line_num;
}
@ -514,18 +514,18 @@ struct BtorDumper
int l1_width = cell->parameters.at(RTLIL::IdString("\\A_WIDTH")).as_int();
int l2_width = cell->parameters.at(RTLIL::IdString("\\B_WIDTH")).as_int();
assert(l1_signed == l2_signed);
log_assert(l1_signed == l2_signed);
l1_width = l1_width > output_width ? l1_width : output_width;
l1_width = l1_width > l2_width ? l1_width : l2_width;
l2_width = l2_width > l1_width ? l2_width : l1_width;
int l1 = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\A")), l1_width);
int l2 = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\B")), l2_width);
int l1 = dump_sigspec(&cell->getPort(RTLIL::IdString("\\A")), l1_width);
int l2 = dump_sigspec(&cell->getPort(RTLIL::IdString("\\B")), l2_width);
++line_num;
std::string op = cell_type_translation.at(cell->type);
std::string op = cell_type_translation.at(cell->type.str());
if(cell->type == "$div" && l1_signed)
op = s_cell_type_translation.at(cell->type);
op = s_cell_type_translation.at(cell->type.str());
else if(cell->type == "$mod")
{
if(l1_signed)
@ -534,17 +534,17 @@ struct BtorDumper
op = s_cell_type_translation.at("$mody");
}
str = stringf ("%d %s %d %d %d", line_num, op.c_str(), l1_width, l1, l2);
fprintf(f, "%s\n", str.c_str());
f << stringf("%s\n", str.c_str());
if(output_width < l1_width)
{
++line_num;
str = stringf ("%d slice %d %d %d %d;5", line_num, output_width, line_num-1, output_width-1, 0);
fprintf(f, "%s\n", str.c_str());
f << stringf("%s\n", str.c_str());
}
line_ref[cell->name]=line_num;
}
else if(cell->type == "$shr" || cell->type == "$shl" || cell->type == "$sshr" || cell->type == "$sshl")
else if(cell->type == "$shr" || cell->type == "$shl" || cell->type == "$sshr" || cell->type == "$sshl" || cell->type == "$shift" || cell->type == "$shiftx")
{
log("writing binary cell - %s\n", cstr(cell->type));
int output_width = cell->parameters.at(RTLIL::IdString("\\Y_WIDTH")).as_int();
@ -553,32 +553,32 @@ struct BtorDumper
int l1_width = cell->parameters.at(RTLIL::IdString("\\A_WIDTH")).as_int();
l1_width = pow(2, ceil(log(l1_width)/log(2)));
int l2_width = cell->parameters.at(RTLIL::IdString("\\B_WIDTH")).as_int();
//assert(l2_width <= ceil(log(l1_width)/log(2)) );
int l1 = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\A")), l1_width);
int l2 = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\B")), ceil(log(l1_width)/log(2)));
//log_assert(l2_width <= ceil(log(l1_width)/log(2)) );
int l1 = dump_sigspec(&cell->getPort(RTLIL::IdString("\\A")), l1_width);
int l2 = dump_sigspec(&cell->getPort(RTLIL::IdString("\\B")), ceil(log(l1_width)/log(2)));
int cell_output = ++line_num;
str = stringf ("%d %s %d %d %d", line_num, cell_type_translation.at(cell->type).c_str(), l1_width, l1, l2);
fprintf(f, "%s\n", str.c_str());
str = stringf ("%d %s %d %d %d", line_num, cell_type_translation.at(cell->type.str()).c_str(), l1_width, l1, l2);
f << stringf("%s\n", str.c_str());
if(l2_width > ceil(log(l1_width)/log(2)))
{
int extra_width = l2_width - ceil(log(l1_width)/log(2));
l2 = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\B")), l2_width);
l2 = dump_sigspec(&cell->getPort(RTLIL::IdString("\\B")), l2_width);
++line_num;
str = stringf ("%d slice %d %d %d %d;6", line_num, extra_width, l2, l2_width-1, l2_width-extra_width);
fprintf(f, "%s\n", str.c_str());
f << stringf("%s\n", str.c_str());
++line_num;
str = stringf ("%d one %d", line_num, extra_width);
fprintf(f, "%s\n", str.c_str());
f << stringf("%s\n", str.c_str());
int mux = ++line_num;
str = stringf ("%d %s %d %d %d", line_num, cell_type_translation.at("$gt").c_str(), 1, line_num-2, line_num-1);
fprintf(f, "%s\n", str.c_str());
f << stringf("%s\n", str.c_str());
++line_num;
str = stringf("%d %s %d", line_num, l1_signed && cell->type == "$sshr" ? "ones":"zero", l1_width);
fprintf(f, "%s\n", str.c_str());
f << stringf("%s\n", str.c_str());
++line_num;
str = stringf ("%d %s %d %d %d %d", line_num, cell_type_translation.at("$mux").c_str(), l1_width, mux, line_num-1, cell_output);
fprintf(f, "%s\n", str.c_str());
f << stringf("%s\n", str.c_str());
cell_output = line_num;
}
@ -586,7 +586,7 @@ struct BtorDumper
{
++line_num;
str = stringf ("%d slice %d %d %d %d;5", line_num, output_width, cell_output, output_width-1, 0);
fprintf(f, "%s\n", str.c_str());
f << stringf("%s\n", str.c_str());
cell_output = line_num;
}
line_ref[cell->name] = cell_output;
@ -595,23 +595,23 @@ struct BtorDumper
{
log("writing binary cell - %s\n", cstr(cell->type));
int output_width = cell->parameters.at(RTLIL::IdString("\\Y_WIDTH")).as_int();
assert(output_width == 1);
int l1 = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\A")), output_width);
int l2 = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\B")), output_width);
log_assert(output_width == 1);
int l1 = dump_sigspec(&cell->getPort(RTLIL::IdString("\\A")), output_width);
int l2 = dump_sigspec(&cell->getPort(RTLIL::IdString("\\B")), output_width);
int l1_width = cell->parameters.at(RTLIL::IdString("\\A_WIDTH")).as_int();
int l2_width = cell->parameters.at(RTLIL::IdString("\\B_WIDTH")).as_int();
if(l1_width >1)
{
++line_num;
str = stringf ("%d %s %d %d", line_num, cell_type_translation.at("$reduce_or").c_str(), output_width, l1);
fprintf(f, "%s\n", str.c_str());
f << stringf("%s\n", str.c_str());
l1 = line_num;
}
if(l2_width > 1)
{
++line_num;
str = stringf ("%d %s %d %d", line_num, cell_type_translation.at("$reduce_or").c_str(), output_width, l2);
fprintf(f, "%s\n", str.c_str());
f << stringf("%s\n", str.c_str());
l2 = line_num;
}
if(cell->type == "$logic_and")
@ -624,7 +624,7 @@ struct BtorDumper
++line_num;
str = stringf ("%d %s %d %d %d", line_num, cell_type_translation.at("$or").c_str(), output_width, l1, l2);
}
fprintf(f, "%s\n", str.c_str());
f << stringf("%s\n", str.c_str());
line_ref[cell->name]=line_num;
}
//multiplexers
@ -632,13 +632,14 @@ struct BtorDumper
{
log("writing mux cell\n");
int output_width = cell->parameters.at(RTLIL::IdString("\\WIDTH")).as_int();
int l1 = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\A")), output_width);
int l2 = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\B")), output_width);
int s = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\S")), 1);
int l1 = dump_sigspec(&cell->getPort(RTLIL::IdString("\\A")), output_width);
int l2 = dump_sigspec(&cell->getPort(RTLIL::IdString("\\B")), output_width);
int s = dump_sigspec(&cell->getPort(RTLIL::IdString("\\S")), 1);
++line_num;
str = stringf ("%d %s %d %d %d %d",
line_num, cell_type_translation.at(cell->type).c_str(), output_width, s, l2, l1);//if s is 0 then l1, if s is 1 then l2 //according to the implementation of mux cell
fprintf(f, "%s\n", str.c_str());
line_num, cell_type_translation.at(cell->type.str()).c_str(), output_width, s, l2, l1);
//if s is 0 then l1, if s is 1 then l2 //according to the implementation of mux cell
f << stringf("%s\n", str.c_str());
line_ref[cell->name]=line_num;
}
else if(cell->type == "$pmux")
@ -646,97 +647,97 @@ struct BtorDumper
log("writing pmux cell\n");
int output_width = cell->parameters.at(RTLIL::IdString("\\WIDTH")).as_int();
int select_width = cell->parameters.at(RTLIL::IdString("\\S_WIDTH")).as_int();
int default_case = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\A")), output_width);
int cases = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\B")), output_width*select_width);
int select = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\S")), select_width);
int default_case = dump_sigspec(&cell->getPort(RTLIL::IdString("\\A")), output_width);
int cases = dump_sigspec(&cell->getPort(RTLIL::IdString("\\B")), output_width*select_width);
int select = dump_sigspec(&cell->getPort(RTLIL::IdString("\\S")), select_width);
int *c = new int[select_width];
for (int i=0; i<select_width; ++i)
{
++line_num;
str = stringf ("%d slice 1 %d %d %d", line_num, select, i, i);
fprintf(f, "%s\n", str.c_str());
f << stringf("%s\n", str.c_str());
c[i] = line_num;
++line_num;
str = stringf ("%d slice %d %d %d %d", line_num, output_width, cases, i*output_width+output_width-1,
i*output_width);
fprintf(f, "%s\n", str.c_str());
f << stringf("%s\n", str.c_str());
}
++line_num;
str = stringf ("%d cond %d %d %d %d", line_num, output_width, c[select_width-1], c[select_width-1]+1, default_case);
fprintf(f, "%s\n", str.c_str());
f << stringf("%s\n", str.c_str());
for (int i=select_width-2; i>=0; --i)
{
++line_num;
str = stringf ("%d cond %d %d %d %d", line_num, output_width, c[i], c[i]+1, line_num-1);
fprintf(f, "%s\n", str.c_str());
f << stringf("%s\n", str.c_str());
}
line_ref[cell->name]=line_num;
}
//registers
//registers
else if(cell->type == "$dff" || cell->type == "$adff" || cell->type == "$dffsr")
{
//TODO: remodelling fo adff cells
log("writing cell - %s\n", cstr(cell->type));
int output_width = cell->parameters.at(RTLIL::IdString("\\WIDTH")).as_int();
log(" - width is %d\n", output_width);
int cond = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\CLK")), 1);
int cond = dump_sigspec(&cell->getPort(RTLIL::IdString("\\CLK")), 1);
bool polarity = cell->parameters.at(RTLIL::IdString("\\CLK_POLARITY")).as_bool();
const RTLIL::SigSpec* cell_output = &cell->connections.at(RTLIL::IdString("\\Q"));
int value = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\D")), output_width);
const RTLIL::SigSpec* cell_output = &cell->getPort(RTLIL::IdString("\\Q"));
int value = dump_sigspec(&cell->getPort(RTLIL::IdString("\\D")), output_width);
unsigned start_bit = 0;
for(unsigned i=0; i<cell_output->chunks.size(); ++i)
for(unsigned i=0; i<cell_output->chunks().size(); ++i)
{
output_width = cell_output->chunks[i].width;
assert( output_width == cell_output->chunks[i].wire->width);//full reg is given the next value
int reg = dump_wire(cell_output->chunks[i].wire);//register
output_width = cell_output->chunks().at(i).width;
log_assert( output_width == cell_output->chunks().at(i).wire->width);//full reg is given the next value
int reg = dump_wire(cell_output->chunks().at(i).wire);//register
int slice = value;
if(cell_output->chunks.size()>1)
if(cell_output->chunks().size()>1)
{
start_bit+=output_width;
slice = ++line_num;
str = stringf ("%d slice %d %d %d %d;", line_num, output_width, value, start_bit-1,
start_bit-output_width);
fprintf(f, "%s\n", str.c_str());
f << stringf("%s\n", str.c_str());
}
if(cell->type == "$dffsr")
{
int sync_reset = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\CLR")), 1);
int sync_reset = dump_sigspec(&cell->getPort(RTLIL::IdString("\\CLR")), 1);
bool sync_reset_pol = cell->parameters.at(RTLIL::IdString("\\CLR_POLARITY")).as_bool();
int sync_reset_value = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\SET")),
int sync_reset_value = dump_sigspec(&cell->getPort(RTLIL::IdString("\\SET")),
output_width);
bool sync_reset_value_pol = cell->parameters.at(RTLIL::IdString("\\SET_POLARITY")).as_bool();
++line_num;
str = stringf ("%d %s %d %s%d %s%d %d", line_num, cell_type_translation.at("$mux").c_str(),
output_width, sync_reset_pol ? "":"-", sync_reset, sync_reset_value_pol? "":"-",
sync_reset_value, slice);
fprintf(f, "%s\n", str.c_str());
f << stringf("%s\n", str.c_str());
slice = line_num;
}
++line_num;
str = stringf ("%d %s %d %s%d %d %d", line_num, cell_type_translation.at("$mux").c_str(),
output_width, polarity?"":"-", cond, slice, reg);
fprintf(f, "%s\n", str.c_str());
f << stringf("%s\n", str.c_str());
int next = line_num;
if(cell->type == "$adff")
{
int async_reset = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\ARST")), 1);
int async_reset = dump_sigspec(&cell->getPort(RTLIL::IdString("\\ARST")), 1);
bool async_reset_pol = cell->parameters.at(RTLIL::IdString("\\ARST_POLARITY")).as_bool();
int async_reset_value = dump_const(&cell->parameters.at(RTLIL::IdString("\\ARST_VALUE")),
output_width, 0);
++line_num;
str = stringf ("%d %s %d %s%d %d %d", line_num, cell_type_translation.at("$mux").c_str(),
output_width, async_reset_pol ? "":"-", async_reset, async_reset_value, next);
fprintf(f, "%s\n", str.c_str());
f << stringf("%s\n", str.c_str());
}
++line_num;
str = stringf ("%d %s %d %d %d", line_num, cell_type_translation.at(cell->type).c_str(),
str = stringf ("%d %s %d %d %d", line_num, cell_type_translation.at(cell->type.str()).c_str(),
output_width, reg, next);
fprintf(f, "%s\n", str.c_str());
f << stringf("%s\n", str.c_str());
}
line_ref[cell->name]=line_num;
}
@ -749,11 +750,11 @@ struct BtorDumper
str = cell->parameters.at(RTLIL::IdString("\\MEMID")).decode_string();
int mem = dump_memory(module->memories.at(RTLIL::IdString(str.c_str())));
int address_width = cell->parameters.at(RTLIL::IdString("\\ABITS")).as_int();
int address = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\ADDR")), address_width);
int address = dump_sigspec(&cell->getPort(RTLIL::IdString("\\ADDR")), address_width);
int data_width = cell->parameters.at(RTLIL::IdString("\\WIDTH")).as_int();
++line_num;
str = stringf("%d read %d %d %d", line_num, data_width, mem, address);
fprintf(f, "%s\n", str.c_str());
f << stringf("%s\n", str.c_str());
line_ref[cell->name]=line_num;
}
else if(cell->type == "$memwr")
@ -761,13 +762,13 @@ struct BtorDumper
log("writing memwr cell\n");
if (cell->parameters.at("\\CLK_ENABLE").as_bool() == false)
log_error("The btor backen does not support $memwr cells without built-in registers. Run memory_dff (but with -wr_only).\n");
int clk = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\CLK")), 1);
int clk = dump_sigspec(&cell->getPort(RTLIL::IdString("\\CLK")), 1);
bool polarity = cell->parameters.at(RTLIL::IdString("\\CLK_POLARITY")).as_bool();
int enable = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\EN")), 1);
int enable = dump_sigspec(&cell->getPort(RTLIL::IdString("\\EN")), 1);
int address_width = cell->parameters.at(RTLIL::IdString("\\ABITS")).as_int();
int address = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\ADDR")), address_width);
int data_width = cell->parameters.at(RTLIL::IdString("\\WIDTH")).as_int();
int data = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\DATA")), data_width);
int address = dump_sigspec(&cell->getPort(RTLIL::IdString("\\ADDR")), address_width);
int data_width = cell->parameters.at(RTLIL::IdString("\\WIDTH")).as_int();
int data = dump_sigspec(&cell->getPort(RTLIL::IdString("\\DATA")), data_width);
str = cell->parameters.at(RTLIL::IdString("\\MEMID")).decode_string();
int mem = dump_memory(module->memories.at(RTLIL::IdString(str.c_str())));
//check if the memory has already next
@ -779,68 +780,67 @@ struct BtorDumper
RTLIL::Memory *memory = module->memories.at(RTLIL::IdString(str.c_str()));
int address_bits = ceil(log(memory->size)/log(2));
str = stringf("%d array %d %d", line_num, memory->width, address_bits);
fprintf(f, "%s\n", str.c_str());
f << stringf("%s\n", str.c_str());
++line_num;
str = stringf("%d eq 1 %d %d", line_num, mem, line_num - 1);
fprintf(f, "%s\n", str.c_str());
f << stringf("%s\n", str.c_str());
mem = line_num - 1;
}
++line_num;
++line_num;
if(polarity)
str = stringf("%d one 1", line_num);
else
str = stringf("%d zero 1", line_num);
fprintf(f, "%s\n", str.c_str());
f << stringf("%s\n", str.c_str());
++line_num;
str = stringf("%d eq 1 %d %d", line_num, clk, line_num-1);
fprintf(f, "%s\n", str.c_str());
f << stringf("%s\n", str.c_str());
++line_num;
str = stringf("%d and 1 %d %d", line_num, line_num-1, enable);
fprintf(f, "%s\n", str.c_str());
f << stringf("%s\n", str.c_str());
++line_num;
str = stringf("%d write %d %d %d %d %d", line_num, data_width, address_width, mem, address, data);
fprintf(f, "%s\n", str.c_str());
f << stringf("%s\n", str.c_str());
++line_num;
str = stringf("%d acond %d %d %d %d %d", line_num, data_width, address_width, line_num-2/*enable*/, line_num-1, mem);
fprintf(f, "%s\n", str.c_str());
f << stringf("%s\n", str.c_str());
++line_num;
str = stringf("%d anext %d %d %d %d", line_num, data_width, address_width, mem, line_num-1);
fprintf(f, "%s\n", str.c_str());
f << stringf("%s\n", str.c_str());
mem_next.insert(mem);
line_ref[cell->name]=line_num;
line_ref[cell->name]=line_num;
}
else if(cell->type == "$slice")
{
log("writing slice cell\n");
const RTLIL::SigSpec* input = &cell->connections.at(RTLIL::IdString("\\A"));
const RTLIL::SigSpec* input = &cell->getPort(RTLIL::IdString("\\A"));
int input_width = cell->parameters.at(RTLIL::IdString("\\A_WIDTH")).as_int();
assert(input->width == input_width);
log_assert(input->size() == input_width);
int input_line = dump_sigspec(input, input_width);
const RTLIL::SigSpec* output = &cell->connections.at(RTLIL::IdString("\\Y"));
const RTLIL::SigSpec* output = &cell->getPort(RTLIL::IdString("\\Y"));
int output_width = cell->parameters.at(RTLIL::IdString("\\Y_WIDTH")).as_int();
assert(output->width == output_width);
log_assert(output->size() == output_width);
int offset = cell->parameters.at(RTLIL::IdString("\\OFFSET")).as_int();
++line_num;
str = stringf("%d %s %d %d %d %d", line_num, cell_type_translation.at(cell->type).c_str(),
output_width, input_line, output_width+offset-1, offset);
fprintf(f, "%s\n", str.c_str());
str = stringf("%d %s %d %d %d %d", line_num, cell_type_translation.at(cell->type.str()).c_str(), output_width, input_line, output_width+offset-1, offset);
f << stringf("%s\n", str.c_str());
line_ref[cell->name]=line_num;
}
else if(cell->type == "$concat")
{
log("writing concat cell\n");
const RTLIL::SigSpec* input_a = &cell->connections.at(RTLIL::IdString("\\A"));
const RTLIL::SigSpec* input_a = &cell->getPort(RTLIL::IdString("\\A"));
int input_a_width = cell->parameters.at(RTLIL::IdString("\\A_WIDTH")).as_int();
assert(input_a->width == input_a_width);
log_assert(input_a->size() == input_a_width);
int input_a_line = dump_sigspec(input_a, input_a_width);
const RTLIL::SigSpec* input_b = &cell->connections.at(RTLIL::IdString("\\B"));
const RTLIL::SigSpec* input_b = &cell->getPort(RTLIL::IdString("\\B"));
int input_b_width = cell->parameters.at(RTLIL::IdString("\\B_WIDTH")).as_int();
assert(input_b->width == input_b_width);
log_assert(input_b->size() == input_b_width);
int input_b_line = dump_sigspec(input_b, input_b_width);
++line_num;
str = stringf("%d %s %d %d %d", line_num, cell_type_translation.at(cell->type).c_str(), input_a_width+input_b_width,
str = stringf("%d %s %d %d %d", line_num, cell_type_translation.at(cell->type.str()).c_str(), input_a_width+input_b_width,
input_a_line, input_b_line);
fprintf(f, "%s\n", str.c_str());
f << stringf("%s\n", str.c_str());
line_ref[cell->name]=line_num;
}
curr_cell.clear();
@ -852,12 +852,12 @@ struct BtorDumper
}
}
RTLIL::SigSpec* get_cell_output(RTLIL::Cell* cell)
const RTLIL::SigSpec* get_cell_output(RTLIL::Cell* cell)
{
RTLIL::SigSpec *output_sig = nullptr;
const RTLIL::SigSpec *output_sig = nullptr;
if (cell->type == "$memrd")
{
output_sig = &cell->connections.at(RTLIL::IdString("\\DATA"));
output_sig = &cell->getPort(RTLIL::IdString("\\DATA"));
}
else if(cell->type == "$memwr" || cell->type == "$assert")
{
@ -865,11 +865,11 @@ struct BtorDumper
}
else if(cell->type == "$dff" || cell->type == "$adff" || cell->type == "$dffsr")
{
output_sig = &cell->connections.at(RTLIL::IdString("\\Q"));
output_sig = &cell->getPort(RTLIL::IdString("\\Q"));
}
else
{
output_sig = &cell->connections.at(RTLIL::IdString("\\Y"));
output_sig = &cell->getPort(RTLIL::IdString("\\Y"));
}
return output_sig;
}
@ -879,19 +879,19 @@ struct BtorDumper
int l = dump_wire(wire);
++line_num;
str = stringf("%d root 1 %d", line_num, l);
fprintf(f, "%s\n", str.c_str());
f << stringf("%s\n", str.c_str());
}
void dump()
{
fprintf(f, ";module %s\n", cstr(module->name));
f << stringf(";module %s\n", cstr(module->name));
log("creating intermediate wires map\n");
//creating map of intermediate wires as output of some cell
for (auto it = module->cells.begin(); it != module->cells.end(); ++it)
for (auto it = module->cells_.begin(); it != module->cells_.end(); ++it)
{
RTLIL::Cell *cell = it->second;
RTLIL::SigSpec* output_sig = get_cell_output(cell);
const RTLIL::SigSpec* output_sig = get_cell_output(cell);
if(output_sig==nullptr)
continue;
RTLIL::SigSpec s = sigmap(*output_sig);
@ -899,11 +899,11 @@ struct BtorDumper
log(" - %s\n", cstr(it->second->type));
if (cell->type == "$memrd")
{
for(unsigned i=0; i<output_sig->chunks.size(); ++i)
for(unsigned i=0; i<output_sig->chunks().size(); ++i)
{
RTLIL::Wire *w = output_sig->chunks[i].wire;
RTLIL::Wire *w = output_sig->chunks().at(i).wire;
RTLIL::IdString wire_id = w->name;
inter_wire_map[wire_id].insert(WireInfo(cell->name,&output_sig->chunks[i]));
inter_wire_map[wire_id].insert(WireInfo(cell->name,&output_sig->chunks().at(i)));
}
}
else if(cell->type == "$memwr")
@ -912,22 +912,22 @@ struct BtorDumper
}
else if(cell->type == "$dff" || cell->type == "$adff" || cell->type == "$dffsr")
{
RTLIL::IdString wire_id = output_sig->chunks[0].wire->name;
for(unsigned i=0; i<output_sig->chunks.size(); ++i)
RTLIL::IdString wire_id = output_sig->chunks().front().wire->name;
for(unsigned i=0; i<output_sig->chunks().size(); ++i)
{
RTLIL::Wire *w = output_sig->chunks[i].wire;
RTLIL::Wire *w = output_sig->chunks().at(i).wire;
RTLIL::IdString wire_id = w->name;
inter_wire_map[wire_id].insert(WireInfo(cell->name,&output_sig->chunks[i]));
inter_wire_map[wire_id].insert(WireInfo(cell->name,&output_sig->chunks().at(i)));
basic_wires[wire_id] = true;
}
}
else
{
for(unsigned i=0; i<output_sig->chunks.size(); ++i)
for(unsigned i=0; i<output_sig->chunks().size(); ++i)
{
RTLIL::Wire *w = output_sig->chunks[i].wire;
RTLIL::Wire *w = output_sig->chunks().at(i).wire;
RTLIL::IdString wire_id = w->name;
inter_wire_map[wire_id].insert(WireInfo(cell->name,&output_sig->chunks[i]));
inter_wire_map[wire_id].insert(WireInfo(cell->name,&output_sig->chunks().at(i)));
}
}
}
@ -936,23 +936,23 @@ struct BtorDumper
std::map<int, RTLIL::Wire*> inputs, outputs;
std::vector<RTLIL::Wire*> safety;
for (auto &wire_it : module->wires) {
for (auto &wire_it : module->wires_) {
RTLIL::Wire *wire = wire_it.second;
if (wire->port_input)
inputs[wire->port_id] = wire;
if (wire->port_output) {
outputs[wire->port_id] = wire;
if (wire->name.find("safety") != std::string::npos )
if (wire->name.str().find("safety") != std::string::npos )
safety.push_back(wire);
}
}
fprintf(f, ";inputs\n");
f << stringf(";inputs\n");
for (auto &it : inputs) {
RTLIL::Wire *wire = it.second;
dump_wire(wire);
}
fprintf(f, "\n");
f << stringf("\n");
log("writing memories\n");
for(auto mem_it = module->memories.begin(); mem_it != module->memories.end(); ++mem_it)
@ -967,7 +967,7 @@ struct BtorDumper
}
log("writing cells\n");
for(auto cell_it = module->cells.begin(); cell_it != module->cells.end(); ++cell_it)
for(auto cell_it = module->cells_.begin(); cell_it != module->cells_.end(); ++cell_it)
{
dump_cell(cell_it->second);
}
@ -975,19 +975,19 @@ struct BtorDumper
for(auto it: safety)
dump_property(it);
fprintf(f, "\n");
f << stringf("\n");
log("writing outputs info\n");
fprintf(f, ";outputs\n");
f << stringf(";outputs\n");
for (auto &it : outputs) {
RTLIL::Wire *wire = it.second;
int l = dump_wire(wire);
fprintf(f, ";%d %s", l, cstr(wire->name));
f << stringf(";%d %s", l, cstr(wire->name));
}
fprintf(f, "\n");
f << stringf("\n");
}
static void dump(FILE *f, RTLIL::Module *module, RTLIL::Design *design, BtorDumperConfig &config)
static void dump(std::ostream &f, RTLIL::Module *module, RTLIL::Design *design, BtorDumperConfig &config)
{
BtorDumper dumper(f, module, design, &config);
dumper.dump();
@ -1006,7 +1006,7 @@ struct BtorBackend : public Backend {
log("Write the current design to an BTOR file.\n");
}
virtual void execute(FILE *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
{
std::string top_module_name;
std::string buf_type, buf_in, buf_out;
@ -1020,18 +1020,18 @@ struct BtorBackend : public Backend {
extra_args(f, filename, args, argidx);
if (top_module_name.empty())
for (auto & mod_it:design->modules)
for (auto & mod_it:design->modules_)
if (mod_it.second->get_bool_attribute("\\top"))
top_module_name = mod_it.first;
top_module_name = mod_it.first.str();
fprintf(f, "; Generated by %s\n", yosys_version_str);
fprintf(f, "; %s developed and maintained by Clifford Wolf <clifford@clifford.at>\n", yosys_version_str);
fprintf(f, "; BTOR Backend developed by Ahmed Irfan <irfan@fbk.eu> - Fondazione Bruno Kessler, Trento, Italy\n");
fprintf(f, ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n");
*f << stringf("; Generated by %s\n", yosys_version_str);
*f << stringf("; %s developed and maintained by Clifford Wolf <clifford@clifford.at>\n", yosys_version_str);
*f << stringf("; BTOR Backend developed by Ahmed Irfan <irfan@fbk.eu> - Fondazione Bruno Kessler, Trento, Italy\n");
*f << stringf(";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n");
std::vector<RTLIL::Module*> mod_list;
for (auto module_it : design->modules)
for (auto module_it : design->modules_)
{
RTLIL::Module *module = module_it.second;
if (module->get_bool_attribute("\\blackbox"))
@ -1041,7 +1041,7 @@ struct BtorBackend : public Backend {
log_error("Found unmapped processes in module %s: unmapped processes are not supported in BTOR backend!\n", RTLIL::id2cstr(module->name));
if (module->name == RTLIL::escape_id(top_module_name)) {
BtorDumper::dump(f, module, design, config);
BtorDumper::dump(*f, module, design, config);
top_module_name.clear();
continue;
}
@ -1053,7 +1053,7 @@ struct BtorBackend : public Backend {
log_error("Can't find top module `%s'!\n", top_module_name.c_str());
for (auto module : mod_list)
BtorDumper::dump(f, module, design, config);
BtorDumper::dump(*f, module, design, config);
}
} BtorBackend;

View file

@ -17,14 +17,14 @@ FULL_PATH=$(readlink -f $1)
DIR=$(dirname $FULL_PATH)
./yosys -q -p "
read_verilog $1;
read_verilog -sv $1;
hierarchy -top $3;
hierarchy -libdir $DIR;
hierarchy -check;
proc;
opt; opt_const -mux_undef; opt;
rename -hide;;;
techmap -share_map pmux2mux.v;;
#techmap -share_map pmux2mux.v;;
splice; opt;
memory_dff -wr_only;
memory_collect;;

View file

@ -26,9 +26,9 @@
#include "kernel/celltypes.h"
#include "kernel/log.h"
#include <string>
#include <assert.h>
#define EDIF_NAME(_id) edif_names(RTLIL::unescape_id(_id)).c_str()
#define EDIF_DEF(_id) edif_names(RTLIL::unescape_id(_id), true).c_str()
#define EDIF_REF(_id) edif_names(RTLIL::unescape_id(_id), false).c_str()
namespace
{
@ -40,8 +40,13 @@ namespace
EdifNames() : counter(1) { }
std::string operator()(std::string id)
std::string operator()(std::string id, bool define)
{
if (define) {
std::string new_id = operator()(id, false);
return new_id != id ? stringf("(rename %s \"%s\")", new_id.c_str(), id.c_str()) : id;
}
if (name_map.count(id) > 0)
return name_map.at(id);
if (generated_names.count(id) > 0)
@ -74,7 +79,7 @@ namespace
}
generated_names.insert(gen_name);
name_map[id] = gen_name;
return stringf("(rename %s \"%s\")", gen_name.c_str(), id.c_str());
return gen_name;
}
};
}
@ -98,12 +103,12 @@ struct EdifBackend : public Backend {
log("is targeted.\n");
log("\n");
}
virtual void execute(FILE *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
{
log_header("Executing EDIF backend.\n");
std::string top_module_name;
std::map<std::string, std::set<std::string>> lib_cell_ports;
std::map<RTLIL::IdString, std::set<RTLIL::IdString>> lib_cell_ports;
CellTypes ct(design);
EdifNames edif_names;
@ -119,31 +124,31 @@ struct EdifBackend : public Backend {
extra_args(f, filename, args, argidx);
if (top_module_name.empty())
for (auto & mod_it:design->modules)
for (auto & mod_it:design->modules_)
if (mod_it.second->get_bool_attribute("\\top"))
top_module_name = mod_it.first;
top_module_name = mod_it.first.str();
for (auto module_it : design->modules)
for (auto module_it : design->modules_)
{
RTLIL::Module *module = module_it.second;
if (module->get_bool_attribute("\\blackbox"))
continue;
if (top_module_name.empty())
top_module_name = module->name;
top_module_name = module->name.str();
if (module->processes.size() != 0)
log_error("Found unmapped processes in module %s: unmapped processes are not supported in EDIF backend!\n", RTLIL::id2cstr(module->name));
if (module->memories.size() != 0)
log_error("Found munmapped emories in module %s: unmapped memories are not supported in EDIF backend!\n", RTLIL::id2cstr(module->name));
for (auto cell_it : module->cells)
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_bool_attribute("\\blackbox")) {
lib_cell_ports[cell->type];
for (auto p : cell->connections) {
if (p.second.width > 1)
for (auto p : cell->connections()) {
if (p.second.size() > 1)
log_error("Found multi-bit port %s on library cell %s.%s (%s): not supported in EDIF backend!\n",
RTLIL::id2cstr(p.first), RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type));
lib_cell_ports[cell->type].insert(p.first);
@ -155,38 +160,38 @@ struct EdifBackend : public Backend {
if (top_module_name.empty())
log_error("No module found in design!\n");
fprintf(f, "(edif %s\n", EDIF_NAME(top_module_name));
fprintf(f, " (edifVersion 2 0 0)\n");
fprintf(f, " (edifLevel 0)\n");
fprintf(f, " (keywordMap (keywordLevel 0))\n");
fprintf(f, " (comment \"Generated by %s\")\n", yosys_version_str);
*f << stringf("(edif %s\n", EDIF_DEF(top_module_name));
*f << stringf(" (edifVersion 2 0 0)\n");
*f << stringf(" (edifLevel 0)\n");
*f << stringf(" (keywordMap (keywordLevel 0))\n");
*f << stringf(" (comment \"Generated by %s\")\n", yosys_version_str);
fprintf(f, " (external LIB\n");
fprintf(f, " (edifLevel 0)\n");
fprintf(f, " (technology (numberDefinition))\n");
*f << stringf(" (external LIB\n");
*f << stringf(" (edifLevel 0)\n");
*f << stringf(" (technology (numberDefinition))\n");
fprintf(f, " (cell GND\n");
fprintf(f, " (cellType GENERIC)\n");
fprintf(f, " (view VIEW_NETLIST\n");
fprintf(f, " (viewType NETLIST)\n");
fprintf(f, " (interface (port G (direction OUTPUT)))\n");
fprintf(f, " )\n");
fprintf(f, " )\n");
*f << stringf(" (cell GND\n");
*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(" )\n");
*f << stringf(" )\n");
fprintf(f, " (cell VCC\n");
fprintf(f, " (cellType GENERIC)\n");
fprintf(f, " (view VIEW_NETLIST\n");
fprintf(f, " (viewType NETLIST)\n");
fprintf(f, " (interface (port P (direction OUTPUT)))\n");
fprintf(f, " )\n");
fprintf(f, " )\n");
*f << stringf(" (cell VCC\n");
*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(" )\n");
*f << stringf(" )\n");
for (auto &cell_it : lib_cell_ports) {
fprintf(f, " (cell %s\n", EDIF_NAME(cell_it.first));
fprintf(f, " (cellType GENERIC)\n");
fprintf(f, " (view VIEW_NETLIST\n");
fprintf(f, " (viewType NETLIST)\n");
fprintf(f, " (interface\n");
*f << stringf(" (cell %s\n", EDIF_DEF(cell_it.first));
*f << stringf(" (cellType GENERIC)\n");
*f << stringf(" (view VIEW_NETLIST\n");
*f << stringf(" (viewType NETLIST)\n");
*f << stringf(" (interface\n");
for (auto &port_it : cell_it.second) {
const char *dir = "INOUT";
if (ct.cell_known(cell_it.first)) {
@ -195,23 +200,23 @@ struct EdifBackend : public Backend {
else if (!ct.cell_input(cell_it.first, port_it))
dir = "OUTPUT";
}
fprintf(f, " (port %s (direction %s))\n", EDIF_NAME(port_it), dir);
*f << stringf(" (port %s (direction %s))\n", EDIF_DEF(port_it), dir);
}
fprintf(f, " )\n");
fprintf(f, " )\n");
fprintf(f, " )\n");
*f << stringf(" )\n");
*f << stringf(" )\n");
*f << stringf(" )\n");
}
fprintf(f, " )\n");
*f << stringf(" )\n");
std::vector<RTLIL::Module*> sorted_modules;
// extract module dependencies
std::map<RTLIL::Module*, std::set<RTLIL::Module*>> module_deps;
for (auto &mod_it : design->modules) {
for (auto &mod_it : design->modules_) {
module_deps[mod_it.second] = std::set<RTLIL::Module*>();
for (auto &cell_it : mod_it.second->cells)
if (design->modules.count(cell_it.second->type) > 0)
module_deps[mod_it.second].insert(design->modules.at(cell_it.second->type));
for (auto &cell_it : mod_it.second->cells_)
if (design->modules_.count(cell_it.second->type) > 0)
module_deps[mod_it.second].insert(design->modules_.at(cell_it.second->type));
}
// simple good-enough topological sort
@ -233,9 +238,9 @@ struct EdifBackend : public Backend {
}
fprintf(f, " (library DESIGN\n");
fprintf(f, " (edifLevel 0)\n");
fprintf(f, " (technology (numberDefinition))\n");
*f << stringf(" (library DESIGN\n");
*f << stringf(" (edifLevel 0)\n");
*f << stringf(" (technology (numberDefinition))\n");
for (auto module : sorted_modules)
{
if (module->get_bool_attribute("\\blackbox"))
@ -244,12 +249,12 @@ struct EdifBackend : public Backend {
SigMap sigmap(module);
std::map<RTLIL::SigSpec, std::set<std::string>> net_join_db;
fprintf(f, " (cell %s\n", EDIF_NAME(module->name));
fprintf(f, " (cellType GENERIC)\n");
fprintf(f, " (view VIEW_NETLIST\n");
fprintf(f, " (viewType NETLIST)\n");
fprintf(f, " (interface\n");
for (auto &wire_it : module->wires) {
*f << stringf(" (cell %s\n", EDIF_DEF(module->name));
*f << stringf(" (cellType GENERIC)\n");
*f << stringf(" (view VIEW_NETLIST\n");
*f << stringf(" (viewType NETLIST)\n");
*f << stringf(" (interface\n");
for (auto &wire_it : module->wires_) {
RTLIL::Wire *wire = wire_it.second;
if (wire->port_id == 0)
continue;
@ -259,31 +264,31 @@ struct EdifBackend : public Backend {
else if (!wire->port_input)
dir = "OUTPUT";
if (wire->width == 1) {
fprintf(f, " (port %s (direction %s))\n", EDIF_NAME(wire->name), dir);
*f << stringf(" (port %s (direction %s))\n", EDIF_DEF(wire->name), dir);
RTLIL::SigSpec sig = sigmap(RTLIL::SigSpec(wire));
net_join_db[sig].insert(stringf("(portRef %s)", EDIF_NAME(wire->name)));
net_join_db[sig].insert(stringf("(portRef %s)", EDIF_REF(wire->name)));
} else {
fprintf(f, " (port (array %s %d) (direction %s))\n", EDIF_NAME(wire->name), wire->width, dir);
*f << stringf(" (port (array %s %d) (direction %s))\n", EDIF_DEF(wire->name), wire->width, dir);
for (int i = 0; i < wire->width; i++) {
RTLIL::SigSpec sig = sigmap(RTLIL::SigSpec(wire, 1, i));
net_join_db[sig].insert(stringf("(portRef (member %s %d))", EDIF_NAME(wire->name), i));
RTLIL::SigSpec sig = sigmap(RTLIL::SigSpec(wire, i));
net_join_db[sig].insert(stringf("(portRef (member %s %d))", EDIF_REF(wire->name), i));
}
}
}
fprintf(f, " )\n");
fprintf(f, " (contents\n");
fprintf(f, " (instance GND (viewRef VIEW_NETLIST (cellRef GND (libraryRef LIB))))\n");
fprintf(f, " (instance VCC (viewRef VIEW_NETLIST (cellRef VCC (libraryRef LIB))))\n");
for (auto &cell_it : module->cells) {
*f << stringf(" )\n");
*f << stringf(" (contents\n");
*f << stringf(" (instance GND (viewRef VIEW_NETLIST (cellRef GND (libraryRef LIB))))\n");
*f << stringf(" (instance VCC (viewRef VIEW_NETLIST (cellRef VCC (libraryRef LIB))))\n");
for (auto &cell_it : module->cells_) {
RTLIL::Cell *cell = cell_it.second;
fprintf(f, " (instance %s\n", EDIF_NAME(cell->name));
fprintf(f, " (viewRef VIEW_NETLIST (cellRef %s%s))", EDIF_NAME(cell->type),
*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)
fprintf(f, "\n (property %s (string \"%s\"))", EDIF_NAME(p.first), p.second.decode_string().c_str());
*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())
fprintf(f, "\n (property %s (integer %u))", EDIF_NAME(p.first), p.second.as_int());
*f << stringf("\n (property %s (integer %u))", EDIF_DEF(p.first), p.second.as_int());
else {
std::string hex_string = "";
for (size_t i = 0; i < p.second.bits.size(); i += 4) {
@ -295,53 +300,48 @@ struct EdifBackend : public Backend {
char digit_str[2] = { "0123456789abcdef"[digit_value], 0 };
hex_string = std::string(digit_str) + hex_string;
}
fprintf(f, "\n (property %s (string \"%s\"))", EDIF_NAME(p.first), hex_string.c_str());
*f << stringf("\n (property %s (string \"%s\"))", EDIF_DEF(p.first), hex_string.c_str());
}
fprintf(f, ")\n");
for (auto &p : cell->connections) {
*f << stringf(")\n");
for (auto &p : cell->connections()) {
RTLIL::SigSpec sig = sigmap(p.second);
sig.expand();
for (int i = 0; i < sig.width; i++) {
RTLIL::SigSpec sigbit(sig.chunks.at(i));
std::string portname = sig.width > 1 ? stringf("%s[%d]", RTLIL::id2cstr(p.first), i) : RTLIL::id2cstr(p.first);
net_join_db[sigbit].insert(stringf("(portRef %s (instanceRef %s))", edif_names(portname).c_str(), EDIF_NAME(cell->name)));
}
for (int i = 0; i < SIZE(sig); i++)
if (sig.size() == 1)
net_join_db[sig[i]].insert(stringf("(portRef %s (instanceRef %s))", EDIF_REF(p.first), EDIF_REF(cell->name)));
else
net_join_db[sig[i]].insert(stringf("(portRef (member %s %d) (instanceRef %s))", EDIF_REF(p.first), i, EDIF_REF(cell->name)));
}
}
for (auto &it : net_join_db) {
RTLIL::SigSpec sig = it.first;
sig.optimize();
log_assert(sig.width == 1);
if (sig.chunks.at(0).wire == NULL) {
if (sig.chunks.at(0).data.bits.at(0) != RTLIL::State::S0 && sig.chunks.at(0).data.bits.at(0) != RTLIL::State::S1)
continue;
}
RTLIL::SigBit sig = it.first;
if (sig.wire == NULL && sig != RTLIL::State::S0 && sig != RTLIL::State::S1)
continue;
std::string netname = log_signal(sig);
for (size_t i = 0; i < netname.size(); i++)
if (netname[i] == ' ' || netname[i] == '\\')
netname.erase(netname.begin() + i--);
fprintf(f, " (net %s (joined\n", edif_names(netname).c_str());
*f << stringf(" (net %s (joined\n", EDIF_DEF(netname));
for (auto &ref : it.second)
fprintf(f, " %s\n", ref.c_str());
if (sig.chunks.at(0).wire == NULL) {
if (sig.chunks.at(0).data.bits.at(0) == RTLIL::State::S0)
fprintf(f, " (portRef G (instanceRef GND))\n");
if (sig.chunks.at(0).data.bits.at(0) == RTLIL::State::S1)
fprintf(f, " (portRef P (instanceRef VCC))\n");
*f << stringf(" %s\n", ref.c_str());
if (sig.wire == NULL) {
if (sig == RTLIL::State::S0)
*f << stringf(" (portRef G (instanceRef GND))\n");
if (sig == RTLIL::State::S1)
*f << stringf(" (portRef P (instanceRef VCC))\n");
}
fprintf(f, " ))\n");
*f << stringf(" ))\n");
}
fprintf(f, " )\n");
fprintf(f, " )\n");
fprintf(f, " )\n");
*f << stringf(" )\n");
*f << stringf(" )\n");
*f << stringf(" )\n");
}
fprintf(f, " )\n");
*f << stringf(" )\n");
fprintf(f, " (design %s\n", EDIF_NAME(top_module_name));
fprintf(f, " (cellRef %s (libraryRef DESIGN))\n", EDIF_NAME(top_module_name));
fprintf(f, " )\n");
*f << stringf(" (design %s\n", EDIF_DEF(top_module_name));
*f << stringf(" (cellRef %s (libraryRef DESIGN))\n", EDIF_REF(top_module_name));
*f << stringf(" )\n");
fprintf(f, ")\n");
*f << stringf(")\n");
}
} EdifBackend;

View file

@ -23,16 +23,12 @@
*/
#include "ilang_backend.h"
#include "kernel/register.h"
#include "kernel/log.h"
#include <string>
#include <assert.h>
#include <string.h>
#include "kernel/yosys.h"
#include <errno.h>
using namespace ILANG_BACKEND;
void ILANG_BACKEND::dump_const(FILE *f, const RTLIL::Const &data, int width, int offset, bool autoint)
void ILANG_BACKEND::dump_const(std::ostream &f, const RTLIL::Const &data, int width, int offset, bool autoint)
{
if (width < 0)
width = data.bits.size() - offset;
@ -40,7 +36,7 @@ void ILANG_BACKEND::dump_const(FILE *f, const RTLIL::Const &data, int width, int
if (width == 32 && autoint) {
int32_t val = 0;
for (int i = 0; i < width; i++) {
assert(offset+i < (int)data.bits.size());
log_assert(offset+i < (int)data.bits.size());
switch (data.bits[offset+i]) {
case RTLIL::S0: break;
case RTLIL::S1: val |= 1 << i; break;
@ -48,220 +44,230 @@ void ILANG_BACKEND::dump_const(FILE *f, const RTLIL::Const &data, int width, int
}
}
if (val >= 0) {
fprintf(f, "%d", val);
f << stringf("%d", val);
return;
}
}
fprintf(f, "%d'", width);
f << stringf("%d'", width);
for (int i = offset+width-1; i >= offset; i--) {
assert(i < (int)data.bits.size());
log_assert(i < (int)data.bits.size());
switch (data.bits[i]) {
case RTLIL::S0: fprintf(f, "0"); break;
case RTLIL::S1: fprintf(f, "1"); break;
case RTLIL::Sx: fprintf(f, "x"); break;
case RTLIL::Sz: fprintf(f, "z"); break;
case RTLIL::Sa: fprintf(f, "-"); break;
case RTLIL::Sm: fprintf(f, "m"); break;
case RTLIL::S0: f << stringf("0"); break;
case RTLIL::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;
case RTLIL::Sm: f << stringf("m"); break;
}
}
} else {
fprintf(f, "\"");
f << stringf("\"");
std::string str = data.decode_string();
for (size_t i = 0; i < str.size(); i++) {
if (str[i] == '\n')
fprintf(f, "\\n");
f << stringf("\\n");
else if (str[i] == '\t')
fprintf(f, "\\t");
f << stringf("\\t");
else if (str[i] < 32)
fprintf(f, "\\%03o", str[i]);
f << stringf("\\%03o", str[i]);
else if (str[i] == '"')
fprintf(f, "\\\"");
f << stringf("\\\"");
else if (str[i] == '\\')
fprintf(f, "\\\\");
f << stringf("\\\\");
else
fputc(str[i], f);
f << str[i];
}
fprintf(f, "\"");
f << stringf("\"");
}
}
void ILANG_BACKEND::dump_sigchunk(FILE *f, const RTLIL::SigChunk &chunk, bool autoint)
void ILANG_BACKEND::dump_sigchunk(std::ostream &f, const RTLIL::SigChunk &chunk, bool autoint)
{
if (chunk.wire == NULL) {
dump_const(f, chunk.data, chunk.width, chunk.offset, autoint);
} else {
if (chunk.width == chunk.wire->width && chunk.offset == 0)
fprintf(f, "%s", chunk.wire->name.c_str());
f << stringf("%s", chunk.wire->name.c_str());
else if (chunk.width == 1)
fprintf(f, "%s [%d]", chunk.wire->name.c_str(), chunk.offset);
f << stringf("%s [%d]", chunk.wire->name.c_str(), chunk.offset);
else
fprintf(f, "%s [%d:%d]", chunk.wire->name.c_str(), chunk.offset+chunk.width-1, chunk.offset);
f << stringf("%s [%d:%d]", chunk.wire->name.c_str(), chunk.offset+chunk.width-1, chunk.offset);
}
}
void ILANG_BACKEND::dump_sigspec(FILE *f, const RTLIL::SigSpec &sig, bool autoint)
void ILANG_BACKEND::dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig, bool autoint)
{
if (sig.chunks.size() == 1) {
dump_sigchunk(f, sig.chunks[0], autoint);
if (sig.is_chunk()) {
dump_sigchunk(f, sig.as_chunk(), autoint);
} else {
fprintf(f, "{ ");
for (auto it = sig.chunks.rbegin(); it != sig.chunks.rend(); it++) {
f << stringf("{ ");
for (auto it = sig.chunks().rbegin(); it != sig.chunks().rend(); it++) {
dump_sigchunk(f, *it, false);
fprintf(f, " ");
f << stringf(" ");
}
fprintf(f, "}");
f << stringf("}");
}
}
void ILANG_BACKEND::dump_wire(FILE *f, std::string indent, const RTLIL::Wire *wire)
void ILANG_BACKEND::dump_wire(std::ostream &f, std::string indent, const RTLIL::Wire *wire)
{
for (auto it = wire->attributes.begin(); it != wire->attributes.end(); it++) {
fprintf(f, "%s" "attribute %s ", indent.c_str(), it->first.c_str());
std::map<RTLIL::IdString, RTLIL::Const, RTLIL::sort_by_id_str> sorted_attributes(wire->attributes.begin(), wire->attributes.end());
for (auto it = sorted_attributes.begin(); it != sorted_attributes.end(); it++) {
f << stringf("%s" "attribute %s ", indent.c_str(), it->first.c_str());
dump_const(f, it->second);
fprintf(f, "\n");
f << stringf("\n");
}
fprintf(f, "%s" "wire ", indent.c_str());
f << stringf("%s" "wire ", indent.c_str());
if (wire->width != 1)
fprintf(f, "width %d ", wire->width);
f << stringf("width %d ", wire->width);
if (wire->upto)
f << stringf("upto ");
if (wire->start_offset != 0)
fprintf(f, "offset %d ", wire->start_offset);
f << stringf("offset %d ", wire->start_offset);
if (wire->port_input && !wire->port_output)
fprintf(f, "input %d ", wire->port_id);
f << stringf("input %d ", wire->port_id);
if (!wire->port_input && wire->port_output)
fprintf(f, "output %d ", wire->port_id);
f << stringf("output %d ", wire->port_id);
if (wire->port_input && wire->port_output)
fprintf(f, "inout %d ", wire->port_id);
fprintf(f, "%s\n", wire->name.c_str());
f << stringf("inout %d ", wire->port_id);
f << stringf("%s\n", wire->name.c_str());
}
void ILANG_BACKEND::dump_memory(FILE *f, std::string indent, const RTLIL::Memory *memory)
void ILANG_BACKEND::dump_memory(std::ostream &f, std::string indent, const RTLIL::Memory *memory)
{
for (auto it = memory->attributes.begin(); it != memory->attributes.end(); it++) {
fprintf(f, "%s" "attribute %s ", indent.c_str(), it->first.c_str());
std::map<RTLIL::IdString, RTLIL::Const, RTLIL::sort_by_id_str> sorted_attributes(memory->attributes.begin(), memory->attributes.end());
for (auto it = sorted_attributes.begin(); it != sorted_attributes.end(); it++) {
f << stringf("%s" "attribute %s ", indent.c_str(), it->first.c_str());
dump_const(f, it->second);
fprintf(f, "\n");
f << stringf("\n");
}
fprintf(f, "%s" "memory ", indent.c_str());
f << stringf("%s" "memory ", indent.c_str());
if (memory->width != 1)
fprintf(f, "width %d ", memory->width);
f << stringf("width %d ", memory->width);
if (memory->size != 0)
fprintf(f, "size %d ", memory->size);
fprintf(f, "%s\n", memory->name.c_str());
f << stringf("size %d ", memory->size);
f << stringf("%s\n", memory->name.c_str());
}
void ILANG_BACKEND::dump_cell(FILE *f, std::string indent, const RTLIL::Cell *cell)
void ILANG_BACKEND::dump_cell(std::ostream &f, std::string indent, const RTLIL::Cell *cell)
{
for (auto it = cell->attributes.begin(); it != cell->attributes.end(); it++) {
fprintf(f, "%s" "attribute %s ", indent.c_str(), it->first.c_str());
std::map<RTLIL::IdString, RTLIL::Const, RTLIL::sort_by_id_str> sorted_attributes(cell->attributes.begin(), cell->attributes.end());
std::map<RTLIL::IdString, RTLIL::Const, RTLIL::sort_by_id_str> sorted_parameters(cell->parameters.begin(), cell->parameters.end());
std::map<RTLIL::IdString, RTLIL::SigSpec, RTLIL::sort_by_id_str> sorted_connections(cell->connections().begin(), cell->connections().end());
for (auto it = sorted_attributes.begin(); it != sorted_attributes.end(); it++) {
f << stringf("%s" "attribute %s ", indent.c_str(), it->first.c_str());
dump_const(f, it->second);
fprintf(f, "\n");
f << stringf("\n");
}
fprintf(f, "%s" "cell %s %s\n", indent.c_str(), cell->type.c_str(), cell->name.c_str());
for (auto it = cell->parameters.begin(); it != cell->parameters.end(); it++) {
fprintf(f, "%s parameter%s %s ", indent.c_str(), (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0 ? " signed" : "", it->first.c_str());
f << stringf("%s" "cell %s %s\n", indent.c_str(), cell->type.c_str(), cell->name.c_str());
for (auto it = sorted_parameters.begin(); it != sorted_parameters.end(); it++) {
f << stringf("%s parameter%s %s ", indent.c_str(), (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0 ? " signed" : "", it->first.c_str());
dump_const(f, it->second);
fprintf(f, "\n");
f << stringf("\n");
}
for (auto it = cell->connections.begin(); it != cell->connections.end(); it++) {
fprintf(f, "%s connect %s ", indent.c_str(), it->first.c_str());
for (auto it = sorted_connections.begin(); it != sorted_connections.end(); it++) {
f << stringf("%s connect %s ", indent.c_str(), it->first.c_str());
dump_sigspec(f, it->second);
fprintf(f, "\n");
f << stringf("\n");
}
fprintf(f, "%s" "end\n", indent.c_str());
f << stringf("%s" "end\n", indent.c_str());
}
void ILANG_BACKEND::dump_proc_case_body(FILE *f, std::string indent, const RTLIL::CaseRule *cs)
void ILANG_BACKEND::dump_proc_case_body(std::ostream &f, std::string indent, const RTLIL::CaseRule *cs)
{
for (auto it = cs->actions.begin(); it != cs->actions.end(); it++)
{
fprintf(f, "%s" "assign ", indent.c_str());
f << stringf("%s" "assign ", indent.c_str());
dump_sigspec(f, it->first);
fprintf(f, " ");
f << stringf(" ");
dump_sigspec(f, it->second);
fprintf(f, "\n");
f << stringf("\n");
}
for (auto it = cs->switches.begin(); it != cs->switches.end(); it++)
dump_proc_switch(f, indent, *it);
}
void ILANG_BACKEND::dump_proc_switch(FILE *f, std::string indent, const RTLIL::SwitchRule *sw)
void ILANG_BACKEND::dump_proc_switch(std::ostream &f, std::string indent, const RTLIL::SwitchRule *sw)
{
for (auto it = sw->attributes.begin(); it != sw->attributes.end(); it++) {
fprintf(f, "%s" "attribute %s ", indent.c_str(), it->first.c_str());
f << stringf("%s" "attribute %s ", indent.c_str(), it->first.c_str());
dump_const(f, it->second);
fprintf(f, "\n");
f << stringf("\n");
}
fprintf(f, "%s" "switch ", indent.c_str());
f << stringf("%s" "switch ", indent.c_str());
dump_sigspec(f, sw->signal);
fprintf(f, "\n");
f << stringf("\n");
for (auto it = sw->cases.begin(); it != sw->cases.end(); it++)
{
fprintf(f, "%s case ", indent.c_str());
f << stringf("%s case ", indent.c_str());
for (size_t i = 0; i < (*it)->compare.size(); i++) {
if (i > 0)
fprintf(f, ", ");
f << stringf(", ");
dump_sigspec(f, (*it)->compare[i]);
}
fprintf(f, "\n");
f << stringf("\n");
dump_proc_case_body(f, indent + " ", *it);
}
fprintf(f, "%s" "end\n", indent.c_str());
f << stringf("%s" "end\n", indent.c_str());
}
void ILANG_BACKEND::dump_proc_sync(FILE *f, std::string indent, const RTLIL::SyncRule *sy)
void ILANG_BACKEND::dump_proc_sync(std::ostream &f, std::string indent, const RTLIL::SyncRule *sy)
{
fprintf(f, "%s" "sync ", indent.c_str());
f << stringf("%s" "sync ", indent.c_str());
switch (sy->type) {
if (0) case RTLIL::ST0: fprintf(f, "low ");
if (0) case RTLIL::ST1: fprintf(f, "high ");
if (0) case RTLIL::STp: fprintf(f, "posedge ");
if (0) case RTLIL::STn: fprintf(f, "negedge ");
if (0) case RTLIL::STe: fprintf(f, "edge ");
if (0) case RTLIL::ST0: f << stringf("low ");
if (0) case RTLIL::ST1: f << stringf("high ");
if (0) case RTLIL::STp: f << stringf("posedge ");
if (0) case RTLIL::STn: f << stringf("negedge ");
if (0) case RTLIL::STe: f << stringf("edge ");
dump_sigspec(f, sy->signal);
fprintf(f, "\n");
f << stringf("\n");
break;
case RTLIL::STa: fprintf(f, "always\n"); break;
case RTLIL::STi: fprintf(f, "init\n"); break;
case RTLIL::STa: f << stringf("always\n"); break;
case RTLIL::STi: f << stringf("init\n"); break;
}
for (auto it = sy->actions.begin(); it != sy->actions.end(); it++) {
fprintf(f, "%s update ", indent.c_str());
f << stringf("%s update ", indent.c_str());
dump_sigspec(f, it->first);
fprintf(f, " ");
f << stringf(" ");
dump_sigspec(f, it->second);
fprintf(f, "\n");
f << stringf("\n");
}
}
void ILANG_BACKEND::dump_proc(FILE *f, std::string indent, const RTLIL::Process *proc)
void ILANG_BACKEND::dump_proc(std::ostream &f, std::string indent, const RTLIL::Process *proc)
{
for (auto it = proc->attributes.begin(); it != proc->attributes.end(); it++) {
fprintf(f, "%s" "attribute %s ", indent.c_str(), it->first.c_str());
f << stringf("%s" "attribute %s ", indent.c_str(), it->first.c_str());
dump_const(f, it->second);
fprintf(f, "\n");
f << stringf("\n");
}
fprintf(f, "%s" "process %s\n", indent.c_str(), proc->name.c_str());
f << stringf("%s" "process %s\n", indent.c_str(), proc->name.c_str());
dump_proc_case_body(f, indent + " ", &proc->root_case);
for (auto it = proc->syncs.begin(); it != proc->syncs.end(); it++)
dump_proc_sync(f, indent + " ", *it);
fprintf(f, "%s" "end\n", indent.c_str());
f << stringf("%s" "end\n", indent.c_str());
}
void ILANG_BACKEND::dump_conn(FILE *f, std::string indent, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right)
void ILANG_BACKEND::dump_conn(std::ostream &f, std::string indent, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right)
{
fprintf(f, "%s" "connect ", indent.c_str());
f << stringf("%s" "connect ", indent.c_str());
dump_sigspec(f, left);
fprintf(f, " ");
f << stringf(" ");
dump_sigspec(f, right);
fprintf(f, "\n");
f << stringf("\n");
}
void ILANG_BACKEND::dump_module(FILE *f, std::string indent, const RTLIL::Module *module, const RTLIL::Design *design, bool only_selected, bool flag_m, bool flag_n)
void ILANG_BACKEND::dump_module(std::ostream &f, std::string indent, RTLIL::Module *module, RTLIL::Design *design, bool only_selected, bool flag_m, bool flag_n)
{
bool print_header = flag_m || design->selected_whole_module(module->name);
bool print_body = !flag_n || !design->selected_whole_module(module->name);
@ -269,51 +275,71 @@ void ILANG_BACKEND::dump_module(FILE *f, std::string indent, const RTLIL::Module
if (print_header)
{
for (auto it = module->attributes.begin(); it != module->attributes.end(); it++) {
fprintf(f, "%s" "attribute %s ", indent.c_str(), it->first.c_str());
f << stringf("%s" "attribute %s ", indent.c_str(), it->first.c_str());
dump_const(f, it->second);
fprintf(f, "\n");
f << stringf("\n");
}
fprintf(f, "%s" "module %s\n", indent.c_str(), module->name.c_str());
f << stringf("%s" "module %s\n", indent.c_str(), module->name.c_str());
}
if (print_body)
{
for (auto it = module->wires.begin(); it != module->wires.end(); it++)
if (!only_selected || design->selected(module, it->second)) {
std::vector<RTLIL::Wire*> sorted_wires;
for (auto it : module->wires())
sorted_wires.push_back(it);
std::sort(sorted_wires.begin(), sorted_wires.end(), RTLIL::sort_by_name_str<RTLIL::Wire>());
std::vector<RTLIL::Memory*> sorted_memories;
for (auto it : module->memories)
sorted_memories.push_back(it.second);
std::sort(sorted_memories.begin(), sorted_memories.end(), RTLIL::sort_by_name_str<RTLIL::Memory>());
std::vector<RTLIL::Cell*> sorted_cells;
for (auto it : module->cells())
sorted_cells.push_back(it);
std::sort(sorted_cells.begin(), sorted_cells.end(), RTLIL::sort_by_name_str<RTLIL::Cell>());
std::vector<RTLIL::Process*> sorted_processes;
for (auto it : module->processes)
sorted_processes.push_back(it.second);
std::sort(sorted_processes.begin(), sorted_processes.end(), RTLIL::sort_by_name_str<RTLIL::Process>());
for (auto it : sorted_wires)
if (!only_selected || design->selected(module, it)) {
if (only_selected)
fprintf(f, "\n");
dump_wire(f, indent + " ", it->second);
f << stringf("\n");
dump_wire(f, indent + " ", it);
}
for (auto it = module->memories.begin(); it != module->memories.end(); it++)
if (!only_selected || design->selected(module, it->second)) {
for (auto it : sorted_memories)
if (!only_selected || design->selected(module, it)) {
if (only_selected)
fprintf(f, "\n");
dump_memory(f, indent + " ", it->second);
f << stringf("\n");
dump_memory(f, indent + " ", it);
}
for (auto it = module->cells.begin(); it != module->cells.end(); it++)
if (!only_selected || design->selected(module, it->second)) {
for (auto it : sorted_cells)
if (!only_selected || design->selected(module, it)) {
if (only_selected)
fprintf(f, "\n");
dump_cell(f, indent + " ", it->second);
f << stringf("\n");
dump_cell(f, indent + " ", it);
}
for (auto it = module->processes.begin(); it != module->processes.end(); it++)
if (!only_selected || design->selected(module, it->second)) {
for (auto it : sorted_processes)
if (!only_selected || design->selected(module, it)) {
if (only_selected)
fprintf(f, "\n");
dump_proc(f, indent + " ", it->second);
f << stringf("\n");
dump_proc(f, indent + " ", it);
}
bool first_conn_line = true;
for (auto it = module->connections.begin(); it != module->connections.end(); it++) {
for (auto it = module->connections().begin(); it != module->connections().end(); it++) {
bool show_conn = !only_selected;
if (only_selected) {
RTLIL::SigSpec sigs = it->first;
sigs.append(it->second);
for (auto &c : sigs.chunks) {
for (auto &c : sigs.chunks()) {
if (c.wire == NULL || !design->selected(module, c.wire))
continue;
show_conn = true;
@ -321,7 +347,7 @@ void ILANG_BACKEND::dump_module(FILE *f, std::string indent, const RTLIL::Module
}
if (show_conn) {
if (only_selected && first_conn_line)
fprintf(f, "\n");
f << stringf("\n");
dump_conn(f, indent + " ", it->first, it->second);
first_conn_line = false;
}
@ -329,27 +355,40 @@ void ILANG_BACKEND::dump_module(FILE *f, std::string indent, const RTLIL::Module
}
if (print_header)
fprintf(f, "%s" "end\n", indent.c_str());
f << stringf("%s" "end\n", indent.c_str());
}
void ILANG_BACKEND::dump_design(FILE *f, const RTLIL::Design *design, bool only_selected, bool flag_m, bool flag_n)
void ILANG_BACKEND::dump_design(std::ostream &f, RTLIL::Design *design, bool only_selected, bool flag_m, bool flag_n)
{
int init_autoidx = autoidx;
if (!flag_m) {
int count_selected_mods = 0;
for (auto it = design->modules.begin(); it != design->modules.end(); it++)
for (auto it = design->modules_.begin(); it != design->modules_.end(); it++) {
if (design->selected_whole_module(it->first))
flag_m = true;
if (design->selected(it->second))
count_selected_mods++;
}
if (count_selected_mods > 1)
flag_m = true;
}
for (auto it = design->modules.begin(); it != design->modules.end(); it++) {
if (!only_selected || flag_m) {
if (only_selected)
f << stringf("\n");
f << stringf("autoidx %d\n", autoidx);
}
for (auto it = design->modules_.begin(); it != design->modules_.end(); it++) {
if (!only_selected || design->selected(it->second)) {
if (only_selected)
fprintf(f, "\n");
f << stringf("\n");
dump_module(f, "", it->second, design, only_selected, flag_m, flag_n);
}
}
log_assert(init_autoidx == autoidx);
}
struct IlangBackend : public Backend {
@ -367,7 +406,7 @@ struct IlangBackend : public Backend {
log(" only write selected parts of the design.\n");
log("\n");
}
virtual void execute(FILE *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
{
bool selected = false;
@ -385,8 +424,8 @@ struct IlangBackend : public Backend {
extra_args(f, filename, args, argidx);
log("Output filename: %s\n", filename.c_str());
fprintf(f, "# Generated by %s\n", yosys_version_str);
ILANG_BACKEND::dump_design(f, design, selected, true, false);
*f << stringf("# Generated by %s\n", yosys_version_str);
ILANG_BACKEND::dump_design(*f, design, selected, true, false);
}
} IlangBackend;
@ -446,25 +485,27 @@ struct DumpPass : public Pass {
}
extra_args(args, argidx, design);
FILE *f = NULL;
char *buf_ptr;
size_t buf_size;
std::ostream *f;
std::stringstream buf;
if (!filename.empty()) {
f = fopen(filename.c_str(), append ? "a" : "w");
if (f == NULL)
std::ofstream *ff = new std::ofstream;
ff->open(filename.c_str(), append ? std::ofstream::app : std::ofstream::trunc);
if (ff->fail()) {
delete ff;
log_error("Can't open file `%s' for writing: %s\n", filename.c_str(), strerror(errno));
}
f = ff;
} else {
f = open_memstream(&buf_ptr, &buf_size);
f = &buf;
}
ILANG_BACKEND::dump_design(f, design, true, flag_m, flag_n);
ILANG_BACKEND::dump_design(*f, design, true, flag_m, flag_n);
fclose(f);
if (filename.empty()) {
log("%s", buf_ptr);
free(buf_ptr);
if (!filename.empty()) {
delete f;
} else {
log("%s", buf.str().c_str());
}
}
} DumpPass;

View file

@ -25,23 +25,27 @@
#ifndef ILANG_BACKEND_H
#define ILANG_BACKEND_H
#include "kernel/rtlil.h"
#include "kernel/yosys.h"
#include <stdio.h>
YOSYS_NAMESPACE_BEGIN
namespace ILANG_BACKEND {
void dump_const(FILE *f, const RTLIL::Const &data, int width = -1, int offset = 0, bool autoint = true);
void dump_sigchunk(FILE *f, const RTLIL::SigChunk &chunk, bool autoint = true);
void dump_sigspec(FILE *f, const RTLIL::SigSpec &sig, bool autoint = true);
void dump_wire(FILE *f, std::string indent, const RTLIL::Wire *wire);
void dump_memory(FILE *f, std::string indent, const RTLIL::Memory *memory);
void dump_cell(FILE *f, std::string indent, const RTLIL::Cell *cell);
void dump_proc_case_body(FILE *f, std::string indent, const RTLIL::CaseRule *cs);
void dump_proc_switch(FILE *f, std::string indent, const RTLIL::SwitchRule *sw);
void dump_proc_sync(FILE *f, std::string indent, const RTLIL::SyncRule *sy);
void dump_proc(FILE *f, std::string indent, const RTLIL::Process *proc);
void dump_conn(FILE *f, std::string indent, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right);
void dump_module(FILE *f, std::string indent, const RTLIL::Module *module, const RTLIL::Design *design, bool only_selected, bool flag_m = true, bool flag_n = false);
void dump_design(FILE *f, const RTLIL::Design *design, bool only_selected, bool flag_m = true, bool flag_n = false);
void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int offset = 0, bool autoint = true);
void dump_sigchunk(std::ostream &f, const RTLIL::SigChunk &chunk, bool autoint = true);
void dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig, bool autoint = true);
void dump_wire(std::ostream &f, std::string indent, const RTLIL::Wire *wire);
void dump_memory(std::ostream &f, std::string indent, const RTLIL::Memory *memory);
void dump_cell(std::ostream &f, std::string indent, const RTLIL::Cell *cell);
void dump_proc_case_body(std::ostream &f, std::string indent, const RTLIL::CaseRule *cs);
void dump_proc_switch(std::ostream &f, std::string indent, const RTLIL::SwitchRule *sw);
void dump_proc_sync(std::ostream &f, std::string indent, const RTLIL::SyncRule *sy);
void dump_proc(std::ostream &f, std::string indent, const RTLIL::Process *proc);
void dump_conn(std::ostream &f, std::string indent, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right);
void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module, RTLIL::Design *design, bool only_selected, bool flag_m = true, bool flag_n = false);
void dump_design(std::ostream &f, RTLIL::Design *design, bool only_selected, bool flag_m = true, bool flag_n = false);
}
YOSYS_NAMESPACE_END
#endif

View file

@ -23,30 +23,23 @@
#include "kernel/celltypes.h"
#include "kernel/log.h"
#include <string>
#include <assert.h>
static std::string netname(std::set<std::string> &conntypes_code, std::set<std::string> &celltypes_code, std::set<std::string> &constcells_code, RTLIL::SigSpec sig)
{
sig.optimize();
if (sig.chunks.size() != 1)
error:
if (!sig.is_fully_const() && !sig.is_wire())
log_error("Can't export composite or non-word-wide signal %s.\n", log_signal(sig));
conntypes_code.insert(stringf("conntype b%d %d 2 %d\n", sig.width, sig.width, sig.width));
conntypes_code.insert(stringf("conntype b%d %d 2 %d\n", sig.size(), sig.size(), sig.size()));
if (sig.chunks[0].wire == NULL) {
celltypes_code.insert(stringf("celltype CONST_%d b%d *CONST cfg:%d VALUE\n", sig.width, sig.width, sig.width));
constcells_code.insert(stringf("node CONST_%d_0x%x CONST_%d CONST CONST_%d_0x%x VALUE 0x%x\n", sig.width, sig.chunks[0].data.as_int(),
sig.width, sig.width, sig.chunks[0].data.as_int(), sig.chunks[0].data.as_int()));
return stringf("CONST_%d_0x%x", sig.width, sig.chunks[0].data.as_int());
if (sig.is_fully_const()) {
celltypes_code.insert(stringf("celltype CONST_%d b%d *CONST cfg:%d VALUE\n", sig.size(), sig.size(), sig.size()));
constcells_code.insert(stringf("node CONST_%d_0x%x CONST_%d CONST CONST_%d_0x%x VALUE 0x%x\n",
sig.size(), sig.as_int(), sig.size(), sig.size(), sig.as_int(), sig.as_int()));
return stringf("CONST_%d_0x%x", sig.size(), sig.as_int());
}
if (sig.chunks[0].offset != 0 || sig.width != sig.chunks[0].wire->width)
goto error;
return RTLIL::unescape_id(sig.chunks[0].wire->name);
return RTLIL::unescape_id(sig.as_wire()->name);
}
struct IntersynthBackend : public Backend {
@ -76,7 +69,7 @@ struct IntersynthBackend : public Backend {
log("http://www.clifford.at/intersynth/\n");
log("\n");
}
virtual void execute(FILE *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
{
log_header("Executing INTERSYNTH backend.\n");
log_push();
@ -108,13 +101,13 @@ struct IntersynthBackend : public Backend {
log("Output filename: %s\n", filename.c_str());
for (auto filename : libfiles) {
FILE *f = fopen(filename.c_str(), "rt");
if (f == NULL)
std::ifstream f;
f.open(filename.c_str());
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.substr(filename.size()-3) == ".il") ? "ilang" : "verilog");
libs.push_back(lib);
fclose(f);
}
if (libs.size() > 0)
@ -127,14 +120,14 @@ struct IntersynthBackend : public Backend {
for (auto lib : libs)
ct.setup_design(lib);
for (auto module_it : design->modules)
for (auto module_it : design->modules_)
{
RTLIL::Module *module = module_it.second;
SigMap sigmap(module);
if (module->get_bool_attribute("\\blackbox"))
continue;
if (module->memories.size() == 0 && module->processes.size() == 0 && module->cells.size() == 0)
if (module->memories.size() == 0 && module->processes.size() == 0 && module->cells_.size() == 0)
continue;
if (selected && !design->selected_whole_module(module->name)) {
@ -153,7 +146,7 @@ struct IntersynthBackend : public Backend {
netlists_code += stringf("netlist %s\n", RTLIL::id2cstr(module->name));
// Module Ports: "std::set<string> celltypes_code" prevents duplicate top level ports
for (auto wire_it : module->wires) {
for (auto wire_it : module->wires_) {
RTLIL::Wire *wire = wire_it.second;
if (wire->port_input || wire->port_output) {
celltypes_code.insert(stringf("celltype !%s b%d %sPORT\n" "%s %s %d %s PORT\n",
@ -165,7 +158,7 @@ struct IntersynthBackend : public Backend {
}
// Submodules: "std::set<string> celltypes_code" prevents duplicate cell types
for (auto cell_it : module->cells)
for (auto cell_it : module->cells_)
{
RTLIL::Cell *cell = cell_it.second;
std::string celltype_code, node_code;
@ -175,11 +168,11 @@ struct IntersynthBackend : public Backend {
celltype_code = stringf("celltype %s", RTLIL::id2cstr(cell->type));
node_code = stringf("node %s %s", RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type));
for (auto &port : cell->connections) {
for (auto &port : cell->connections()) {
RTLIL::SigSpec sig = sigmap(port.second);
if (sig.width != 0) {
conntypes_code.insert(stringf("conntype b%d %d 2 %d\n", sig.width, sig.width, sig.width));
celltype_code += stringf(" b%d %s%s", sig.width, ct.cell_output(cell->type, port.first) ? "*" : "", RTLIL::id2cstr(port.first));
if (sig.size() != 0) {
conntypes_code.insert(stringf("conntype b%d %d 2 %d\n", sig.size(), sig.size(), sig.size()));
celltype_code += stringf(" b%d %s%s", sig.size(), ct.cell_output(cell->type, port.first) ? "*" : "", RTLIL::id2cstr(port.first));
node_code += stringf(" %s %s", RTLIL::id2cstr(port.first), netname(conntypes_code, celltypes_code, constcells_code, sig).c_str());
}
}
@ -205,15 +198,15 @@ struct IntersynthBackend : public Backend {
}
if (!flag_notypes) {
fprintf(f, "### Connection Types\n");
*f << stringf("### Connection Types\n");
for (auto code : conntypes_code)
fprintf(f, "%s", code.c_str());
fprintf(f, "\n### Cell Types\n");
*f << stringf("%s", code.c_str());
*f << stringf("\n### Cell Types\n");
for (auto code : celltypes_code)
fprintf(f, "%s", code.c_str());
*f << stringf("%s", code.c_str());
}
fprintf(f, "\n### Netlists\n");
fprintf(f, "%s", netlists_code.c_str());
*f << stringf("\n### Netlists\n");
*f << stringf("%s", netlists_code.c_str());
for (auto lib : libs)
delete lib;

View file

@ -23,53 +23,51 @@
#include "kernel/celltypes.h"
#include "kernel/log.h"
#include <string>
#include <assert.h>
static void print_spice_net(FILE *f, RTLIL::SigSpec s, std::string &neg, std::string &pos, std::string &ncpf, int &nc_counter)
static void print_spice_net(std::ostream &f, RTLIL::SigBit s, std::string &neg, std::string &pos, std::string &ncpf, int &nc_counter)
{
log_assert(s.chunks.size() == 1 && s.chunks[0].width == 1);
if (s.chunks[0].wire) {
if (s.chunks[0].wire->width > 1)
fprintf(f, " %s[%d]", RTLIL::id2cstr(s.chunks[0].wire->name), s.chunks[0].offset);
if (s.wire) {
if (s.wire->width > 1)
f << stringf(" %s[%d]", RTLIL::id2cstr(s.wire->name), s.offset);
else
fprintf(f, " %s", RTLIL::id2cstr(s.chunks[0].wire->name));
f << stringf(" %s", RTLIL::id2cstr(s.wire->name));
} else {
if (s.chunks[0].data.bits.at(0) == RTLIL::State::S0)
fprintf(f, " %s", neg.c_str());
else if (s.chunks[0].data.bits.at(0) == RTLIL::State::S1)
fprintf(f, " %s", pos.c_str());
if (s == RTLIL::State::S0)
f << stringf(" %s", neg.c_str());
else if (s == RTLIL::State::S1)
f << stringf(" %s", pos.c_str());
else
fprintf(f, " %s%d", ncpf.c_str(), nc_counter++);
f << stringf(" %s%d", ncpf.c_str(), nc_counter++);
}
}
static void print_spice_module(FILE *f, RTLIL::Module *module, RTLIL::Design *design, std::string &neg, std::string &pos, std::string &ncpf, bool big_endian)
static void print_spice_module(std::ostream &f, RTLIL::Module *module, RTLIL::Design *design, std::string &neg, std::string &pos, std::string &ncpf, bool big_endian)
{
SigMap sigmap(module);
int cell_counter = 0, conn_counter = 0, nc_counter = 0;
for (auto &cell_it : module->cells)
for (auto &cell_it : module->cells_)
{
RTLIL::Cell *cell = cell_it.second;
fprintf(f, "X%d", cell_counter++);
f << stringf("X%d", cell_counter++);
std::vector<RTLIL::SigSpec> port_sigs;
if (design->modules.count(cell->type) == 0)
if (design->modules_.count(cell->type) == 0)
{
log("Warning: no (blackbox) module for cell type `%s' (%s.%s) found! Guessing order of ports.\n",
RTLIL::id2cstr(cell->type), RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name));
for (auto &conn : cell->connections) {
for (auto &conn : cell->connections()) {
RTLIL::SigSpec sig = sigmap(conn.second);
port_sigs.push_back(sig);
}
}
else
{
RTLIL::Module *mod = design->modules.at(cell->type);
RTLIL::Module *mod = design->modules_.at(cell->type);
std::vector<RTLIL::Wire*> ports;
for (auto wire_it : mod->wires) {
for (auto wire_it : mod->wires_) {
RTLIL::Wire *wire = wire_it.second;
if (wire->port_id == 0)
continue;
@ -81,8 +79,8 @@ static void print_spice_module(FILE *f, RTLIL::Module *module, RTLIL::Design *de
for (RTLIL::Wire *wire : ports) {
log_assert(wire != NULL);
RTLIL::SigSpec sig(RTLIL::State::Sz, wire->width);
if (cell->connections.count(wire->name) > 0) {
sig = sigmap(cell->connections.at(wire->name));
if (cell->hasPort(wire->name)) {
sig = sigmap(cell->getPort(wire->name));
sig.extend(wire->width, false);
}
port_sigs.push_back(sig);
@ -90,22 +88,21 @@ static void print_spice_module(FILE *f, RTLIL::Module *module, RTLIL::Design *de
}
for (auto &sig : port_sigs) {
for (int i = 0; i < sig.width; i++) {
RTLIL::SigSpec s = sig.extract(big_endian ? sig.width - 1 - i : i, 1);
log_assert(s.chunks.size() == 1 && s.chunks[0].width == 1);
for (int i = 0; i < sig.size(); i++) {
RTLIL::SigSpec s = sig.extract(big_endian ? sig.size() - 1 - i : i, 1);
print_spice_net(f, s, neg, pos, ncpf, nc_counter);
}
}
fprintf(f, " %s\n", RTLIL::id2cstr(cell->type));
f << stringf(" %s\n", RTLIL::id2cstr(cell->type));
}
for (auto &conn : module->connections)
for (int i = 0; i < conn.first.width; i++) {
fprintf(f, "V%d", conn_counter++);
for (auto &conn : module->connections())
for (int i = 0; i < conn.first.size(); i++) {
f << stringf("V%d", conn_counter++);
print_spice_net(f, conn.first.extract(i, 1), neg, pos, ncpf, nc_counter);
print_spice_net(f, conn.second.extract(i, 1), neg, pos, ncpf, nc_counter);
fprintf(f, " DC 0\n");
f << stringf(" DC 0\n");
}
}
@ -136,7 +133,7 @@ struct SpiceBackend : public Backend {
log(" set the specified module as design top module\n");
log("\n");
}
virtual void execute(FILE *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
{
std::string top_module_name;
RTLIL::Module *top_module = NULL;
@ -173,14 +170,14 @@ struct SpiceBackend : public Backend {
extra_args(f, filename, args, argidx);
if (top_module_name.empty())
for (auto & mod_it:design->modules)
for (auto & mod_it:design->modules_)
if (mod_it.second->get_bool_attribute("\\top"))
top_module_name = mod_it.first;
top_module_name = mod_it.first.str();
fprintf(f, "* SPICE netlist generated by %s\n", yosys_version_str);
fprintf(f, "\n");
*f << stringf("* SPICE netlist generated by %s\n", yosys_version_str);
*f << stringf("\n");
for (auto module_it : design->modules)
for (auto module_it : design->modules_)
{
RTLIL::Module *module = module_it.second;
if (module->get_bool_attribute("\\blackbox"))
@ -197,7 +194,7 @@ struct SpiceBackend : public Backend {
}
std::vector<RTLIL::Wire*> ports;
for (auto wire_it : module->wires) {
for (auto wire_it : module->wires_) {
RTLIL::Wire *wire = wire_it.second;
if (wire->port_id == 0)
continue;
@ -206,31 +203,31 @@ struct SpiceBackend : public Backend {
ports.at(wire->port_id-1) = wire;
}
fprintf(f, ".SUBCKT %s", RTLIL::id2cstr(module->name));
*f << stringf(".SUBCKT %s", RTLIL::id2cstr(module->name));
for (RTLIL::Wire *wire : ports) {
log_assert(wire != NULL);
if (wire->width > 1) {
for (int i = 0; i < wire->width; i++)
fprintf(f, " %s[%d]", RTLIL::id2cstr(wire->name), big_endian ? wire->width - 1 - i : i);
*f << stringf(" %s[%d]", RTLIL::id2cstr(wire->name), big_endian ? wire->width - 1 - i : i);
} else
fprintf(f, " %s", RTLIL::id2cstr(wire->name));
*f << stringf(" %s", RTLIL::id2cstr(wire->name));
}
fprintf(f, "\n");
print_spice_module(f, module, design, neg, pos, ncpf, big_endian);
fprintf(f, ".ENDS %s\n\n", RTLIL::id2cstr(module->name));
*f << stringf("\n");
print_spice_module(*f, module, design, neg, pos, ncpf, big_endian);
*f << stringf(".ENDS %s\n\n", RTLIL::id2cstr(module->name));
}
if (!top_module_name.empty()) {
if (top_module == NULL)
log_error("Can't find top module `%s'!\n", top_module_name.c_str());
print_spice_module(f, top_module, design, neg, pos, ncpf, big_endian);
fprintf(f, "\n");
print_spice_module(*f, top_module, design, neg, pos, ncpf, big_endian);
*f << stringf("\n");
}
fprintf(f, "************************\n");
fprintf(f, "* end of SPICE netlist *\n");
fprintf(f, "************************\n");
fprintf(f, "\n");
*f << stringf("************************\n");
*f << stringf("* end of SPICE netlist *\n");
*f << stringf("************************\n");
*f << stringf("\n");
}
} SpiceBackend;

File diff suppressed because it is too large Load diff

View file

@ -29,11 +29,10 @@
#ifndef VERILOG_BACKEND_H
#define VERILOG_BACKEND_H
#include "kernel/rtlil.h"
#include <stdio.h>
#include "kernel/yosys.h"
namespace VERILOG_BACKEND {
void verilog_backend(FILE *f, std::vector<std::string> args, RTLIL::Design *design);
void verilog_backend(std::ostream &f, std::vector<std::string> args, RTLIL::Design *design);
}
#endif

View file

@ -2,4 +2,5 @@
OBJS += frontends/ast/ast.o
OBJS += frontends/ast/simplify.o
OBJS += frontends/ast/genrtlil.o
OBJS += frontends/ast/dpicall.o

View file

@ -32,7 +32,9 @@
#include <sstream>
#include <stdarg.h>
#include <assert.h>
#include <math.h>
YOSYS_NAMESPACE_BEGIN
using namespace AST;
using namespace AST_INTERNAL;
@ -46,11 +48,10 @@ namespace AST {
// instanciate global variables (private API)
namespace AST_INTERNAL {
bool flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, flag_nolatches, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells;
bool flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, flag_nolatches, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire;
AstNode *current_ast, *current_ast_mod;
std::map<std::string, AstNode*> current_scope;
RTLIL::SigSpec *genRTLIL_subst_from = NULL;
RTLIL::SigSpec *genRTLIL_subst_to = NULL;
const std::map<RTLIL::SigBit, RTLIL::SigBit> *genRTLIL_subst_ptr = NULL;
RTLIL::SigSpec ignoreThisSignalsInInitial;
AstNode *current_top_block, *current_block, *current_block_child;
AstModule *current_module;
@ -67,6 +68,7 @@ std::string AST::type2str(AstNodeType type)
X(AST_MODULE)
X(AST_TASK)
X(AST_FUNCTION)
X(AST_DPI_FUNCTION)
X(AST_WIRE)
X(AST_MEMORY)
X(AST_AUTOWIRE)
@ -76,7 +78,9 @@ std::string AST::type2str(AstNodeType type)
X(AST_PARASET)
X(AST_ARGUMENT)
X(AST_RANGE)
X(AST_MULTIRANGE)
X(AST_CONSTANT)
X(AST_REALVALUE)
X(AST_CELLTYPE)
X(AST_IDENTIFIER)
X(AST_PREFIX)
@ -127,6 +131,7 @@ std::string AST::type2str(AstNodeType type)
X(AST_ASSIGN)
X(AST_CELL)
X(AST_PRIMITIVE)
X(AST_CELLARRAY)
X(AST_ALWAYS)
X(AST_INITIAL)
X(AST_BLOCK)
@ -136,6 +141,8 @@ std::string AST::type2str(AstNodeType type)
X(AST_COND)
X(AST_DEFAULT)
X(AST_FOR)
X(AST_WHILE)
X(AST_REPEAT)
X(AST_GENVAR)
X(AST_GENFOR)
X(AST_GENIF)
@ -177,10 +184,12 @@ AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2)
is_signed = false;
is_string = false;
range_valid = false;
range_swapped = false;
port_id = 0;
range_left = -1;
range_right = 0;
integer = 0;
realvalue = 0;
id2ast = NULL;
basic_prep = false;
@ -243,6 +252,12 @@ void AstNode::dumpAst(FILE *f, std::string indent)
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 (!str.empty())
fprintf(f, " str='%s'", str.c_str());
if (!bits.empty()) {
@ -265,9 +280,17 @@ void AstNode::dumpAst(FILE *f, std::string indent)
if (port_id > 0)
fprintf(f, " port=%d", port_id);
if (range_valid || range_left != -1 || range_right != 0)
fprintf(f, " range=[%d:%d]%s", range_left, range_right, range_valid ? "" : "!");
fprintf(f, " %srange=[%d:%d]%s", range_swapped ? "swapped_" : "", range_left, range_right, range_valid ? "" : "!");
if (integer != 0)
fprintf(f, " int=%u", (int)integer);
if (realvalue != 0)
fprintf(f, " real=%e", realvalue);
if (!multirange_dimensions.empty()) {
fprintf(f, " multirange=[");
for (int v : multirange_dimensions)
fprintf(f, " %d", v);
fprintf(f, " ]");
}
fprintf(f, "\n");
for (auto &it : attributes) {
@ -309,7 +332,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent)
}
for (auto &it : attributes) {
fprintf(f, "%s" "(* %s = ", indent.c_str(), id2vl(it.first).c_str());
fprintf(f, "%s" "(* %s = ", indent.c_str(), id2vl(it.first.str()).c_str());
it.second->dumpVlog(f, "");
fprintf(f, " *)%s", indent.empty() ? "" : "\n");
}
@ -451,6 +474,10 @@ void AstNode::dumpVlog(FILE *f, std::string indent)
fprintf(f, "%zd'b %s", bits.size(), RTLIL::Const(bits).as_string().c_str());
break;
case AST_REALVALUE:
fprintf(f, "%e", realvalue);
break;
case AST_BLOCK:
if (children.size() == 1) {
children[0]->dumpVlog(f, indent);
@ -603,6 +630,8 @@ bool AstNode::operator==(const AstNode &other) const
return false;
if (range_valid != other.range_valid)
return false;
if (range_swapped != other.range_swapped)
return false;
if (port_id != other.port_id)
return false;
if (range_left != other.range_left)
@ -694,6 +723,14 @@ AstNode *AstNode::mkconst_str(const std::string &str)
return node;
}
bool AstNode::bits_only_01()
{
for (auto bit : bits)
if (bit != RTLIL::S0 && bit != RTLIL::S1)
return false;
return true;
}
RTLIL::Const AstNode::bitsAsConst(int width, bool is_signed)
{
std::vector<RTLIL::State> bits = this->bits;
@ -746,11 +783,94 @@ bool AstNode::asBool()
return false;
}
// create a new AstModule from an AST_MODULE AST node
static AstModule* process_module(AstNode *ast)
int AstNode::isConst()
{
assert(ast->type == AST_MODULE);
log("Generating RTLIL representation for module `%s'.\n", ast->str.c_str());
if (type == AST_CONSTANT)
return 1;
if (type == AST_REALVALUE)
return 2;
return 0;
}
uint64_t AstNode::asInt(bool is_signed)
{
if (type == AST_CONSTANT)
{
RTLIL::Const v = bitsAsConst(64, is_signed);
uint64_t ret = 0;
for (int i = 0; i < 64; i++)
if (v.bits.at(i) == RTLIL::State::S1)
ret |= uint64_t(1) << i;
return ret;
}
if (type == AST_REALVALUE)
return realvalue;
log_abort();
}
double AstNode::asReal(bool is_signed)
{
if (type == AST_CONSTANT)
{
RTLIL::Const val(bits);
bool is_negative = is_signed && val.bits.back() == RTLIL::State::S1;
if (is_negative)
val = const_neg(val, val, false, false, val.bits.size());
double v = 0;
for (size_t i = 0; i < val.bits.size(); i++)
// IEEE Std 1800-2012 Par 6.12.2: Individual bits that are x or z in
// the net or the variable shall be treated as zero upon conversion.
if (val.bits.at(i) == RTLIL::State::S1)
v += exp2(i);
if (is_negative)
v *= -1;
return v;
}
if (type == AST_REALVALUE)
return realvalue;
log_abort();
}
RTLIL::Const AstNode::realAsConst(int width)
{
double v = round(realvalue);
RTLIL::Const result;
#ifdef EMSCRIPTEN
if (!isfinite(v)) {
#else
if (!std::isfinite(v)) {
#endif
result.bits = std::vector<RTLIL::State>(width, RTLIL::State::Sx);
} else {
bool is_negative = v < 0;
if (is_negative)
v *= -1;
for (int i = 0; i < width; i++, v /= 2)
result.bits.push_back((fmod(floor(v), 2) != 0) ? RTLIL::State::S1 : RTLIL::State::S0);
if (is_negative)
result = const_neg(result, result, false, false, result.bits.size());
}
return result;
}
// create a new AstModule from an AST_MODULE AST node
static AstModule* process_module(AstNode *ast, bool defer)
{
log_assert(ast->type == AST_MODULE);
if (defer)
log("Storing AST representation for module `%s'.\n", ast->str.c_str());
else
log("Generating RTLIL representation for module `%s'.\n", ast->str.c_str());
current_module = new AstModule;
current_module->ast = NULL;
@ -766,61 +886,64 @@ static AstModule* process_module(AstNode *ast)
log("--- END OF AST DUMP ---\n");
}
while (ast->simplify(!flag_noopt, false, false, 0, -1, false)) { }
if (!defer)
{
while (ast->simplify(!flag_noopt, false, false, 0, -1, false, false)) { }
if (flag_dump_ast2) {
log("Dumping verilog 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");
ast->dumpVlog(NULL, " ");
log("--- END OF AST DUMP ---\n");
}
if (flag_lib) {
std::vector<AstNode*> new_children;
for (auto child : ast->children) {
if (child->type == AST_WIRE && (child->is_input || child->is_output))
new_children.push_back(child);
else
delete child;
if (flag_dump_ast2) {
log("Dumping verilog AST after simplification:\n");
ast->dumpAst(NULL, " ");
log("--- END OF AST DUMP ---\n");
}
ast->children.swap(new_children);
ast->attributes["\\blackbox"] = AstNode::mkconst_int(1, false);
}
ignoreThisSignalsInInitial = RTLIL::SigSpec();
if (flag_dump_vlog) {
log("Dumping verilog AST (as requested by dump_vlog option):\n");
ast->dumpVlog(NULL, " ");
log("--- END OF AST DUMP ---\n");
}
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);
current_module->attributes[attr.first] = attr.second->asAttrConst();
}
for (size_t i = 0; i < ast->children.size(); i++) {
AstNode *node = ast->children[i];
if (node->type == AST_WIRE || node->type == AST_MEMORY)
node->genRTLIL();
}
for (size_t i = 0; i < ast->children.size(); i++) {
AstNode *node = ast->children[i];
if (node->type != AST_WIRE && node->type != AST_MEMORY && node->type != AST_INITIAL)
node->genRTLIL();
}
if (flag_lib) {
std::vector<AstNode*> new_children;
for (auto child : ast->children) {
if (child->type == AST_WIRE && (child->is_input || child->is_output))
new_children.push_back(child);
else
delete child;
}
ast->children.swap(new_children);
ast->attributes["\\blackbox"] = AstNode::mkconst_int(1, false);
}
ignoreThisSignalsInInitial.sort_and_unify();
ignoreThisSignalsInInitial = RTLIL::SigSpec();
for (size_t i = 0; i < ast->children.size(); i++) {
AstNode *node = ast->children[i];
if (node->type == AST_INITIAL)
node->genRTLIL();
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);
current_module->attributes[attr.first] = attr.second->asAttrConst();
}
for (size_t i = 0; i < ast->children.size(); i++) {
AstNode *node = ast->children[i];
if (node->type == AST_WIRE || node->type == AST_MEMORY)
node->genRTLIL();
}
for (size_t i = 0; i < ast->children.size(); i++) {
AstNode *node = ast->children[i];
if (node->type != AST_WIRE && node->type != AST_MEMORY && node->type != AST_INITIAL)
node->genRTLIL();
}
ignoreThisSignalsInInitial.sort_and_unify();
for (size_t i = 0; i < ast->children.size(); i++) {
AstNode *node = ast->children[i];
if (node->type == AST_INITIAL)
node->genRTLIL();
}
ignoreThisSignalsInInitial = RTLIL::SigSpec();
}
ignoreThisSignalsInInitial = RTLIL::SigSpec();
current_module->ast = ast_before_simplify;
current_module->nolatches = flag_nolatches;
current_module->nomem2reg = flag_nomem2reg;
@ -828,11 +951,13 @@ static AstModule* process_module(AstNode *ast)
current_module->lib = flag_lib;
current_module->noopt = flag_noopt;
current_module->icells = flag_icells;
current_module->autowire = flag_autowire;
current_module->fixup_ports();
return current_module;
}
// 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 nolatches, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool ignore_redef)
void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool dump_vlog, bool nolatches, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool ignore_redef, bool defer, bool autowire)
{
current_ast = ast;
flag_dump_ast1 = dump_ast1;
@ -844,18 +969,37 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump
flag_lib = lib;
flag_noopt = noopt;
flag_icells = icells;
flag_autowire = autowire;
assert(current_ast->type == AST_DESIGN);
for (auto it = current_ast->children.begin(); it != current_ast->children.end(); it++) {
if (design->modules.count((*it)->str) != 0) {
if (!ignore_redef)
log_error("Re-definition of module `%s' at %s:%d!\n",
std::vector<AstNode*> global_decls;
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)
{
for (auto n : global_decls)
(*it)->children.push_back(n->clone());
if (flag_icells && (*it)->str.substr(0, 2) == "\\$")
(*it)->str = (*it)->str.substr(1);
if (defer)
(*it)->str = "$abstract" + (*it)->str;
if (design->has((*it)->str)) {
if (!ignore_redef)
log_error("Re-definition of module `%s' at %s:%d!\n",
(*it)->str.c_str(), (*it)->filename.c_str(), (*it)->linenum);
log("Ignoring re-definition of module `%s' at %s:%d!\n",
(*it)->str.c_str(), (*it)->filename.c_str(), (*it)->linenum);
log_error("Ignoring re-definition of module `%s' at %s:%d!\n",
(*it)->str.c_str(), (*it)->filename.c_str(), (*it)->linenum);
continue;
continue;
}
design->add(process_module(*it, defer));
}
design->modules[(*it)->str] = process_module(*it);
else
global_decls.push_back(*it);
}
}
@ -869,7 +1013,12 @@ AstModule::~AstModule()
// create a new parametric module (when needed) and return the name of the generated module
RTLIL::IdString AstModule::derive(RTLIL::Design *design, std::map<RTLIL::IdString, RTLIL::Const> parameters)
{
log_header("Executing AST frontend in derive mode using pre-parsed AST for module `%s'.\n", name.c_str());
std::string stripped_name = name.str();
if (stripped_name.substr(0, 9) == "$abstract")
stripped_name = stripped_name.substr(9);
log_header("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;
@ -881,16 +1030,14 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, std::map<RTLIL::IdStrin
flag_lib = lib;
flag_noopt = noopt;
flag_icells = icells;
flag_autowire = autowire;
use_internal_line_num();
std::string para_info;
std::vector<unsigned char> hash_data;
hash_data.insert(hash_data.end(), name.begin(), name.end());
hash_data.push_back(0);
AstNode *new_ast = ast->clone();
int para_counter = 0;
int orig_parameters_n = parameters.size();
for (auto it = new_ast->children.begin(); it != new_ast->children.end(); it++) {
AstNode *child = *it;
if (child->type != AST_PARAMETER)
@ -903,10 +1050,6 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, std::map<RTLIL::IdStrin
para_info += stringf("%s=%s", child->str.c_str(), log_signal(RTLIL::SigSpec(parameters[para_id])));
delete child->children.at(0);
child->children[0] = AstNode::mkconst_bits(parameters[para_id].bits, (parameters[para_id].flags & RTLIL::CONST_FLAG_SIGNED) != 0);
hash_data.insert(hash_data.end(), child->str.begin(), child->str.end());
hash_data.push_back(0);
hash_data.insert(hash_data.end(), parameters[para_id].bits.begin(), parameters[para_id].bits.end());
hash_data.push_back(0xff);
parameters.erase(para_id);
continue;
}
@ -917,33 +1060,21 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, std::map<RTLIL::IdStrin
}
}
if (parameters.size() > 0)
log_error("Requested parameter `%s' does not exist in module `%s'!\n", parameters.begin()->first.c_str(), name.c_str());
log_error("Requested parameter `%s' does not exist in module `%s'!\n", parameters.begin()->first.c_str(), stripped_name.c_str());
std::string modname;
if (para_info.size() > 60)
{
unsigned char hash[20];
unsigned char *hash_data2 = new unsigned char[hash_data.size()];
for (size_t i = 0; i < hash_data.size(); i++)
hash_data2[i] = hash_data[i];
sha1::calc(hash_data2, hash_data.size(), hash);
delete[] hash_data2;
char hexstring[41];
sha1::toHexString(hash, hexstring);
modname = "$paramod$" + std::string(hexstring) + name;
}
if (orig_parameters_n == 0)
modname = stripped_name;
else if (para_info.size() > 60)
modname = "$paramod$" + sha1(para_info) + stripped_name;
else
{
modname = "$paramod" + name + para_info;
}
modname = "$paramod" + stripped_name + para_info;
if (design->modules.count(modname) == 0) {
if (!design->has(modname)) {
new_ast->str = modname;
design->modules[modname] = process_module(new_ast);
design->modules[modname]->check();
design->add(process_module(new_ast, false));
design->module(modname)->check();
} else {
log("Found cached RTLIL representation for module `%s'.\n", modname.c_str());
}
@ -955,6 +1086,7 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, std::map<RTLIL::IdStrin
RTLIL::Module *AstModule::clone() const
{
AstModule *new_mod = new AstModule;
new_mod->name = name;
cloneInto(new_mod);
new_mod->ast = ast->clone();
@ -964,6 +1096,7 @@ RTLIL::Module *AstModule::clone() const
new_mod->lib = lib;
new_mod->noopt = noopt;
new_mod->icells = icells;
new_mod->autowire = autowire;
return new_mod;
}
@ -986,3 +1119,5 @@ void AST::use_internal_line_num()
get_line_num = &internal_get_line_num;
}
YOSYS_NAMESPACE_END

View file

@ -33,6 +33,8 @@
#include <stdint.h>
#include <set>
YOSYS_NAMESPACE_BEGIN
namespace AST
{
// all node types, type2str() must be extended
@ -44,6 +46,7 @@ namespace AST
AST_MODULE,
AST_TASK,
AST_FUNCTION,
AST_DPI_FUNCTION,
AST_WIRE,
AST_MEMORY,
@ -54,7 +57,9 @@ namespace AST
AST_PARASET,
AST_ARGUMENT,
AST_RANGE,
AST_MULTIRANGE,
AST_CONSTANT,
AST_REALVALUE,
AST_CELLTYPE,
AST_IDENTIFIER,
AST_PREFIX,
@ -107,6 +112,7 @@ namespace AST
AST_ASSIGN,
AST_CELL,
AST_PRIMITIVE,
AST_CELLARRAY,
AST_ALWAYS,
AST_INITIAL,
AST_BLOCK,
@ -116,6 +122,8 @@ namespace AST
AST_COND,
AST_DEFAULT,
AST_FOR,
AST_WHILE,
AST_REPEAT,
AST_GENVAR,
AST_GENFOR,
@ -147,9 +155,13 @@ 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;
bool is_input, is_output, is_reg, is_signed, is_string, range_valid, range_swapped;
int port_id, range_left, range_right;
uint32_t integer;
double realvalue;
// if this is a multirange memory then this vector contains offset and length of each dimension
std::vector<int> multirange_dimensions;
// this is set by simplify and used during RTLIL generation
AstNode *id2ast;
@ -183,6 +195,7 @@ namespace AST
MEM2REG_FL_SET_ELSE = 0x00000400,
MEM2REG_FL_SET_ASYNC = 0x00000800,
MEM2REG_FL_EQ2 = 0x00001000,
MEM2REG_FL_CMPLX_LHS = 0x00002000,
/* proc flags */
MEM2REG_FL_EQ1 = 0x01000000,
@ -190,27 +203,33 @@ namespace AST
// simplify() creates a simpler AST by unrolling for-loops, expanding generate blocks, etc.
// it also sets the id2ast pointers so that identifier lookups are fast in genRTLIL()
bool simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, int width_hint, bool sign_hint);
bool simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, int width_hint, bool sign_hint, bool in_param);
void expand_genblock(std::string index_var, std::string prefix, std::map<std::string, std::string> &name_map);
void replace_ids(std::map<std::string, std::string> &rules);
void replace_ids(const std::string &prefix, const std::map<std::string, std::string> &rules);
void mem2reg_as_needed_pass1(std::map<AstNode*, std::set<std::string>> &mem2reg_places,
std::map<AstNode*, uint32_t> &mem2reg_flags, std::map<AstNode*, uint32_t> &proc_flags, uint32_t &status_flags);
void mem2reg_as_needed_pass2(std::set<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block);
void meminfo(int &mem_width, int &mem_size, int &addr_bits);
// additional functionality for evaluating constant functions
struct varinfo_t { RTLIL::Const val; int offset; bool is_signed; };
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);
// create a human-readable text representation of the AST (for debugging)
void dumpAst(FILE *f, std::string indent);
void dumpVlog(FILE *f, std::string indent);
// used by genRTLIL() for detecting expression width and sign
void detectSignWidthWorker(int &width_hint, bool &sign_hint);
void detectSignWidth(int &width_hint, bool &sign_hint);
void detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *found_real = NULL);
void detectSignWidth(int &width_hint, bool &sign_hint, bool *found_real = NULL);
// create RTLIL code for this AST node
// for expressions the resulting signal vector is returned
// all generated cell instances, etc. are written to the RTLIL::Module pointed to by AST_INTERNAL::current_module
RTLIL::SigSpec genRTLIL(int width_hint = -1, bool sign_hint = false);
RTLIL::SigSpec genWidthRTLIL(int width, RTLIL::SigSpec *subst_from = NULL, RTLIL::SigSpec *subst_to = NULL);
RTLIL::SigSpec genWidthRTLIL(int width, const std::map<RTLIL::SigBit, RTLIL::SigBit> *new_subst_ptr = NULL);
// compare AST nodes
bool operator==(const AstNode &other) const;
@ -228,17 +247,24 @@ namespace AST
RTLIL::Const bitsAsConst(int width = -1);
RTLIL::Const asAttrConst();
RTLIL::Const asParaConst();
uint64_t asInt(bool is_signed);
bool bits_only_01();
bool asBool();
// helper functions for real valued const eval
int isConst(); // return '1' for AST_CONSTANT and '2' for AST_REALVALUE
double asReal(bool is_signed);
RTLIL::Const realAsConst(int width);
};
// 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 = false, bool dump_ast2 = false, bool dump_vlog = false, bool nolatches = false, bool nomem2reg = false, bool mem2reg = false, bool lib = false, bool noopt = false, bool icells = false, bool ignore_redef = false);
void process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool dump_vlog, bool nolatches, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool ignore_redef, bool defer, bool autowire);
// parametric modules are supported directly by the AST library
// therfore we need our own derivate of RTLIL::Module with overloaded virtual functions
struct AstModule : RTLIL::Module {
AstNode *ast;
bool nolatches, nomem2reg, mem2reg, lib, noopt, icells;
bool nolatches, nomem2reg, mem2reg, lib, noopt, icells, autowire;
virtual ~AstModule();
virtual RTLIL::IdString derive(RTLIL::Design *design, std::map<RTLIL::IdString, RTLIL::Const> parameters);
virtual RTLIL::Module *clone() const;
@ -254,18 +280,24 @@ namespace AST
// set set_line_num and get_line_num to internal dummy functions (done by simplify() and AstModule::derive
// to control the filename and linenum properties of new nodes not generated by a frontend parser)
void use_internal_line_num();
// 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);
}
namespace AST_INTERNAL
{
// internal state variables
extern bool flag_dump_ast1, flag_dump_ast2, flag_nolatches, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells;
extern bool flag_dump_ast1, flag_dump_ast2, flag_nolatches, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire;
extern AST::AstNode *current_ast, *current_ast_mod;
extern std::map<std::string, AST::AstNode*> current_scope;
extern RTLIL::SigSpec *genRTLIL_subst_from, *genRTLIL_subst_to, ignoreThisSignalsInInitial;
extern const std::map<RTLIL::SigBit, RTLIL::SigBit> *genRTLIL_subst_ptr;
extern RTLIL::SigSpec ignoreThisSignalsInInitial;
extern AST::AstNode *current_top_block, *current_block, *current_block_child;
extern AST::AstModule *current_module;
struct ProcessGenerator;
}
YOSYS_NAMESPACE_END
#endif

140
frontends/ast/dpicall.cc Normal file
View file

@ -0,0 +1,140 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include "ast.h"
#ifdef YOSYS_ENABLE_PLUGINS
#include <dlfcn.h>
#include <ffi.h>
typedef void (*ffi_fptr) ();
static ffi_fptr resolve_fn (std::string symbol_name)
{
if (symbol_name.find(':') != std::string::npos)
{
int pos = symbol_name.find(':');
std::string plugin_name = symbol_name.substr(0, pos);
std::string real_symbol_name = symbol_name.substr(pos+1);
while (loaded_plugin_aliases.count(plugin_name))
plugin_name = loaded_plugin_aliases.at(plugin_name);
if (loaded_plugins.count(plugin_name) == 0)
log_error("unable to resolve '%s': can't find plugin `%s'\n", symbol_name.c_str(), plugin_name.c_str());
void *symbol = dlsym(loaded_plugins.at(plugin_name), real_symbol_name.c_str());
if (symbol == nullptr)
log_error("unable to resolve '%s': can't find symbol `%s' in plugin `%s'\n",
symbol_name.c_str(), real_symbol_name.c_str(), plugin_name.c_str());
return (ffi_fptr) symbol;
}
for (auto &it : loaded_plugins) {
void *symbol = dlsym(it.second, symbol_name.c_str());
if (symbol != nullptr)
return (ffi_fptr) symbol;
}
void *symbol = dlsym(RTLD_DEFAULT, symbol_name.c_str());
if (symbol != nullptr)
return (ffi_fptr) symbol;
log_error("unable to resolve '%s'.\n", symbol_name.c_str());
}
AST::AstNode *AST::dpi_call(const std::string &rtype, const std::string &fname, const std::vector<std::string> &argtypes, const std::vector<AstNode*> &args)
{
AST::AstNode *newNode = nullptr;
union { double f64; float f32; int32_t i32; } value_store [args.size() + 1];
ffi_type *types [args.size() + 1];
void *values [args.size() + 1];
ffi_cif cif;
int status;
log("Calling DPI function `%s' and returning `%s':\n", fname.c_str(), rtype.c_str());
log_assert(SIZE(args) == SIZE(argtypes));
for (int i = 0; i < SIZE(args); i++) {
if (argtypes[i] == "real") {
log(" arg %d (%s): %f\n", i, argtypes[i].c_str(), args[i]->asReal(args[i]->is_signed));
value_store[i].f64 = args[i]->asReal(args[i]->is_signed);
values[i] = &value_store[i].f64;
types[i] = &ffi_type_double;
} else if (argtypes[i] == "shortreal") {
log(" arg %d (%s): %f\n", i, argtypes[i].c_str(), args[i]->asReal(args[i]->is_signed));
value_store[i].f32 = args[i]->asReal(args[i]->is_signed);
values[i] = &value_store[i].f32;
types[i] = &ffi_type_double;
} else if (argtypes[i] == "integer") {
log(" arg %d (%s): %lld\n", i, argtypes[i].c_str(), (long long)args[i]->asInt(args[i]->is_signed));
value_store[i].i32 = args[i]->asInt(args[i]->is_signed);
values[i] = &value_store[i].i32;
types[i] = &ffi_type_sint32;
} else {
log_error("invalid argtype '%s' for argument %d.\n", argtypes[i].c_str(), i);
}
}
if (rtype == "integer") {
types[args.size()] = &ffi_type_slong;
values[args.size()] = &value_store[args.size()].i32;
} else if (rtype == "shortreal") {
types[args.size()] = &ffi_type_float;
values[args.size()] = &value_store[args.size()].f32;
} else if (rtype == "real") {
types[args.size()] = &ffi_type_double;
values[args.size()] = &value_store[args.size()].f64;
} else {
log_error("invalid rtype '%s'.\n", rtype.c_str());
}
if ((status = ffi_prep_cif(&cif, FFI_DEFAULT_ABI, args.size(), types[args.size()], types)) != FFI_OK)
log_error("ffi_prep_cif failed: status %d.\n", status);
ffi_call(&cif, resolve_fn(fname.c_str()), values[args.size()], values);
if (rtype == "real") {
newNode = new AstNode(AST_REALVALUE);
newNode->realvalue = value_store[args.size()].f64;
log(" return realvalue: %g\n", newNode->asReal(true));
} else if (rtype == "shortreal") {
newNode = new AstNode(AST_REALVALUE);
newNode->realvalue = value_store[args.size()].f32;
log(" return realvalue: %g\n", newNode->asReal(true));
} else {
newNode = AstNode::mkconst_int(value_store[args.size()].i32, false);
log(" return integer: %lld\n", (long long)newNode->asInt(true));
}
return newNode;
}
#else /* YOSYS_ENABLE_PLUGINS */
AST::AstNode *AST::dpi_call(const std::string&, const std::string &fname, const std::vector<std::string>&, const std::vector<AstNode*>&)
{
log_error("Can't call DPI function `%s': this version of yosys is built without plugin support\n", fname.c_str());
}
#endif /* YOSYS_ENABLE_PLUGINS */

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -4,12 +4,14 @@ GENFILES += frontends/ilang/parser.tab.h
GENFILES += frontends/ilang/parser.output
GENFILES += frontends/ilang/lexer.cc
frontends/ilang/parser.tab.cc frontends/ilang/parser.tab.h: frontends/ilang/parser.y
bison -d -r all -b frontends/ilang/parser frontends/ilang/parser.y
mv frontends/ilang/parser.tab.c frontends/ilang/parser.tab.cc
frontends/ilang/parser.tab.cc: frontends/ilang/parser.y
$(P) bison -d -r all -b frontends/ilang/parser frontends/ilang/parser.y
$(Q) mv frontends/ilang/parser.tab.c frontends/ilang/parser.tab.cc
frontends/ilang/parser.tab.h: frontends/ilang/parser.tab.cc
frontends/ilang/lexer.cc: frontends/ilang/lexer.l
flex -o frontends/ilang/lexer.cc frontends/ilang/lexer.l
$(P) flex -o frontends/ilang/lexer.cc frontends/ilang/lexer.l
OBJS += frontends/ilang/parser.tab.o frontends/ilang/lexer.o
OBJS += frontends/ilang/ilang_frontend.o

View file

@ -26,6 +26,8 @@
#include "kernel/register.h"
#include "kernel/log.h"
YOSYS_NAMESPACE_BEGIN
void rtlil_frontend_ilang_yyerror(char const *s)
{
log_error("Parser error in line %d: %s\n", rtlil_frontend_ilang_yyget_lineno(), s);
@ -43,17 +45,20 @@ struct IlangFrontend : public Frontend {
log("representation of a design in yosys's internal format.)\n");
log("\n");
}
virtual void execute(FILE *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
{
log_header("Executing ILANG frontend.\n");
extra_args(f, filename, args, 1);
log("Input filename: %s\n", filename.c_str());
ILANG_FRONTEND::lexin = f;
ILANG_FRONTEND::current_design = design;
rtlil_frontend_ilang_yydebug = false;
rtlil_frontend_ilang_yyrestart(f);
rtlil_frontend_ilang_yyrestart(NULL);
rtlil_frontend_ilang_yyparse();
rtlil_frontend_ilang_yylex_destroy();
}
} IlangFrontend;
YOSYS_NAMESPACE_END

View file

@ -25,20 +25,23 @@
#ifndef ILANG_FRONTEND_H
#define ILANG_FRONTEND_H
#include "kernel/rtlil.h"
#include <stdio.h>
#include "kernel/yosys.h"
YOSYS_NAMESPACE_BEGIN
namespace ILANG_FRONTEND {
void ilang_frontend(FILE *f, RTLIL::Design *design);
extern std::istream *lexin;
extern RTLIL::Design *current_design;
}
YOSYS_NAMESPACE_END
extern int rtlil_frontend_ilang_yydebug;
int rtlil_frontend_ilang_yylex(void);
void rtlil_frontend_ilang_yyerror(char const *s);
void rtlil_frontend_ilang_yyrestart(FILE *f);
int rtlil_frontend_ilang_yyparse(void);
void rtlil_frontend_ilang_yylex_destroy(void);
int rtlil_frontend_ilang_yylex_destroy(void);
int rtlil_frontend_ilang_yyget_lineno(void);
#endif

View file

@ -23,9 +23,18 @@
*/
%{
#include "kernel/rtlil.h"
#ifdef __clang__
// bison generates code using the 'register' storage class specifier
#pragma clang diagnostic ignored "-Wdeprecated-register"
#endif
#include "ilang_frontend.h"
#include "parser.tab.h"
void update_autoidx(const char *p);
#define YY_INPUT(buf,result,max_size) \
result = ILANG_FRONTEND::lexin->readsome(buf, max_size);
%}
%option yylineno
@ -37,6 +46,7 @@ void update_autoidx(const char *p);
%%
"autoidx" { return TOK_AUTOIDX; }
"module" { return TOK_MODULE; }
"attribute" { return TOK_ATTRIBUTE; }
"parameter" { return TOK_PARAMETER; }
@ -44,6 +54,7 @@ void update_autoidx(const char *p);
"wire" { return TOK_WIRE; }
"memory" { return TOK_MEMORY; }
"width" { return TOK_WIDTH; }
"upto" { return TOK_UPTO; }
"offset" { return TOK_OFFSET; }
"size" { return TOK_SIZE; }
"input" { return TOK_INPUT; }
@ -69,11 +80,11 @@ void update_autoidx(const char *p);
[a-z]+ { return TOK_INVALID; }
"\\"[^ \t\r\n]+ { rtlil_frontend_ilang_yylval.string = strdup(yytext); return TOK_ID; }
"$"[^ \t\r\n]+ { rtlil_frontend_ilang_yylval.string = strdup(yytext); update_autoidx(yytext); return TOK_ID; }
"$"[^ \t\r\n]+ { rtlil_frontend_ilang_yylval.string = strdup(yytext); return TOK_ID; }
"."[0-9]+ { rtlil_frontend_ilang_yylval.string = strdup(yytext); return TOK_ID; }
[0-9]+'[01xzm-]* { rtlil_frontend_ilang_yylval.string = strdup(yytext); return TOK_VALUE; }
[0-9]+ { rtlil_frontend_ilang_yylval.integer = atoi(yytext); return TOK_INT; }
-?[0-9]+ { rtlil_frontend_ilang_yylval.integer = atoi(yytext); return TOK_INT; }
\" { BEGIN(STRING); }
<STRING>\\. { yymore(); }
@ -117,27 +128,6 @@ void update_autoidx(const char *p);
%%
void update_autoidx(const char *p)
{
if (*p != '$')
return;
while (*p) {
if (*(p++) != '$')
continue;
if ('0' <= *p && *p <= '9') {
const char *q = p;
while ('0' <= *q && *q <= '9')
q++;
if ((q - p) < 10) {
int idx = atoi(p);
if (idx > RTLIL::autoidx)
RTLIL::autoidx = idx;
}
}
}
}
// this is a hack to avoid the 'yyinput defined but not used' error msgs
void *rtlil_frontend_ilang_avoid_input_warnings() {
return (void*)&yyinput;

View file

@ -25,7 +25,9 @@
%{
#include <list>
#include "ilang_frontend.h"
YOSYS_NAMESPACE_BEGIN
namespace ILANG_FRONTEND {
std::istream *lexin;
RTLIL::Design *current_design;
RTLIL::Module *current_module;
RTLIL::Wire *current_wire;
@ -37,24 +39,26 @@ namespace ILANG_FRONTEND {
std::map<RTLIL::IdString, RTLIL::Const> attrbuf;
}
using namespace ILANG_FRONTEND;
YOSYS_NAMESPACE_END
USING_YOSYS_NAMESPACE
%}
%name-prefix="rtlil_frontend_ilang_yy"
%name-prefix "rtlil_frontend_ilang_yy"
%union {
char *string;
int integer;
RTLIL::Const *data;
RTLIL::SigSpec *sigspec;
YOSYS_NAMESPACE_PREFIX RTLIL::Const *data;
YOSYS_NAMESPACE_PREFIX RTLIL::SigSpec *sigspec;
}
%token <string> TOK_ID TOK_VALUE TOK_STRING
%token <integer> TOK_INT
%token TOK_MODULE TOK_WIRE TOK_WIDTH TOK_INPUT TOK_OUTPUT TOK_INOUT
%token TOK_AUTOIDX TOK_MODULE TOK_WIRE TOK_WIDTH TOK_INPUT TOK_OUTPUT TOK_INOUT
%token TOK_CELL TOK_CONNECT TOK_SWITCH TOK_CASE TOK_ASSIGN TOK_SYNC
%token TOK_LOW TOK_HIGH TOK_POSEDGE TOK_NEGEDGE TOK_EDGE TOK_ALWAYS TOK_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
%token TOK_PARAMETER TOK_ATTRIBUTE TOK_MEMORY TOK_SIZE TOK_SIGNED TOK_UPTO
%type <sigspec> sigspec sigspec_list
%type <integer> sync_type
@ -82,21 +86,23 @@ optional_eol:
design:
design module |
design attr_stmt |
design autoidx_stmt |
/* empty */;
module:
TOK_MODULE TOK_ID EOL {
if (current_design->modules.count($2) != 0)
rtlil_frontend_ilang_yyerror(stringf("scope error: redefinition of module %s.", $2).c_str());
if (current_design->has($2))
rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of module %s.", $2).c_str());
current_module = new RTLIL::Module;
current_module->name = $2;
current_module->attributes = attrbuf;
current_design->modules[$2] = 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();
} EOL;
module_body:
@ -113,16 +119,20 @@ attr_stmt:
free($2);
};
autoidx_stmt:
TOK_AUTOIDX TOK_INT EOL {
autoidx = std::max(autoidx, $2);
};
wire_stmt:
TOK_WIRE {
current_wire = new RTLIL::Wire;
current_wire = current_module->addWire("$__ilang_frontend_tmp__");
current_wire->attributes = attrbuf;
attrbuf.clear();
} wire_options TOK_ID EOL {
if (current_module->wires.count($4) != 0)
rtlil_frontend_ilang_yyerror(stringf("scope error: redefinition of wire %s.", $4).c_str());
current_wire->name = $4;
current_module->wires[$4] = current_wire;
if (current_module->wires_.count($4) != 0)
rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of wire %s.", $4).c_str());
current_module->rename(current_wire, $4);
free($4);
};
@ -130,6 +140,9 @@ wire_options:
wire_options TOK_WIDTH TOK_INT {
current_wire->width = $3;
} |
wire_options TOK_UPTO {
current_wire->upto = true;
} |
wire_options TOK_OFFSET TOK_INT {
current_wire->start_offset = $3;
} |
@ -157,7 +170,7 @@ memory_stmt:
attrbuf.clear();
} memory_options TOK_ID EOL {
if (current_module->memories.count($4) != 0)
rtlil_frontend_ilang_yyerror(stringf("scope error: redefinition of memory %s.", $4).c_str());
rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of memory %s.", $4).c_str());
current_memory->name = $4;
current_module->memories[$4] = current_memory;
free($4);
@ -174,13 +187,10 @@ memory_options:
cell_stmt:
TOK_CELL TOK_ID TOK_ID EOL {
if (current_module->cells.count($3) != 0)
rtlil_frontend_ilang_yyerror(stringf("scope error: redefinition of cell %s.", $3).c_str());
current_cell = new RTLIL::Cell;
current_cell->type = $2;
current_cell->name = $3;
if (current_module->cells_.count($3) != 0)
rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of cell %s.", $3).c_str());
current_cell = current_module->addCell($3, $2);
current_cell->attributes = attrbuf;
current_module->cells[$3] = current_cell;
attrbuf.clear();
free($2);
free($3);
@ -199,9 +209,9 @@ cell_body:
delete $5;
} |
cell_body TOK_CONNECT TOK_ID sigspec EOL {
if (current_cell->connections.count($3) != 0)
rtlil_frontend_ilang_yyerror(stringf("scope error: redefinition of cell port %s.", $3).c_str());
current_cell->connections[$3] = *$4;
if (current_cell->hasPort($3))
rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of cell port %s.", $3).c_str());
current_cell->setPort($3, *$4);
delete $4;
free($3);
} |
@ -210,7 +220,7 @@ cell_body:
proc_stmt:
TOK_PROCESS TOK_ID EOL {
if (current_module->processes.count($2) != 0)
rtlil_frontend_ilang_yyerror(stringf("scope error: redefinition of process %s.", $2).c_str());
rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of process %s.", $2).c_str());
current_process = new RTLIL::Process;
current_process->name = $2;
current_process->attributes = attrbuf;
@ -219,6 +229,7 @@ proc_stmt:
switch_stack.push_back(&current_process->root_case.switches);
case_stack.clear();
case_stack.push_back(&current_process->root_case);
attrbuf.clear();
free($2);
} case_body sync_list TOK_END EOL;
@ -350,50 +361,25 @@ constant:
sigspec:
constant {
RTLIL::SigChunk chunk;
chunk.wire = NULL;
chunk.width = $1->bits.size();
chunk.offset = 0;
chunk.data = *$1;
$$ = new RTLIL::SigSpec;
$$->chunks.push_back(chunk);
$$->width = chunk.width;
$$ = new RTLIL::SigSpec(*$1);
delete $1;
} |
TOK_ID {
if (current_module->wires.count($1) == 0)
rtlil_frontend_ilang_yyerror(stringf("scope error: wire %s not found", $1).c_str());
RTLIL::SigChunk chunk;
chunk.wire = current_module->wires[$1];
chunk.width = current_module->wires[$1]->width;
chunk.offset = 0;
$$ = new RTLIL::SigSpec;
$$->chunks.push_back(chunk);
$$->width = chunk.width;
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]);
free($1);
} |
TOK_ID '[' TOK_INT ']' {
if (current_module->wires.count($1) == 0)
rtlil_frontend_ilang_yyerror(stringf("scope error: wire %s not found", $1).c_str());
RTLIL::SigChunk chunk;
chunk.wire = current_module->wires[$1];
chunk.offset = $3;
chunk.width = 1;
$$ = new RTLIL::SigSpec;
$$->chunks.push_back(chunk);
$$->width = 1;
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);
} |
TOK_ID '[' TOK_INT ':' TOK_INT ']' {
if (current_module->wires.count($1) == 0)
rtlil_frontend_ilang_yyerror(stringf("scope error: wire %s not found", $1).c_str());
RTLIL::SigChunk chunk;
chunk.wire = current_module->wires[$1];
chunk.width = $3 - $5 + 1;
chunk.offset = $5;
$$ = new RTLIL::SigSpec;
$$->chunks.push_back(chunk);
$$->width = chunk.width;
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_list '}' {
@ -403,14 +389,8 @@ sigspec:
sigspec_list:
sigspec_list sigspec {
$$ = new RTLIL::SigSpec;
for (auto it = $2->chunks.begin(); it != $2->chunks.end(); it++) {
$$->chunks.push_back(*it);
$$->width += it->width;
}
for (auto it = $1->chunks.begin(); it != $1->chunks.end(); it++) {
$$->chunks.push_back(*it);
$$->width += it->width;
}
$$->append(*$2);
$$->append(*$1);
delete $1;
delete $2;
} |
@ -422,7 +402,7 @@ conn_stmt:
TOK_CONNECT sigspec sigspec EOL {
if (attrbuf.size() != 0)
rtlil_frontend_ilang_yyerror("dangling attribute");
current_module->connections.push_back(RTLIL::SigSig(*$2, *$3));
current_module->connect(*$2, *$3);
delete $2;
delete $3;
};

View file

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

View file

@ -0,0 +1,578 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include "passes/techmap/libparse.h"
#include "kernel/register.h"
#include "kernel/log.h"
YOSYS_NAMESPACE_BEGIN
using namespace PASS_DFFLIBMAP;
struct token_t {
char type;
RTLIL::SigSpec sig;
token_t (char t) : type(t) { }
token_t (char t, RTLIL::SigSpec s) : type(t), sig(s) { }
};
static RTLIL::SigSpec parse_func_identifier(RTLIL::Module *module, const char *&expr)
{
log_assert(*expr != 0);
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++;
if (id_len == 0)
log_error("Expected identifier at `%s'.\n", expr);
if (id_len == 1 && (*expr == '0' || *expr == '1'))
return *(expr++) == '0' ? RTLIL::State::S0 : RTLIL::State::S1;
std::string id = RTLIL::escape_id(std::string(expr, id_len));
if (!module->wires_.count(id))
log_error("Can't resolve wire name %s.\n", RTLIL::unescape_id(id).c_str());
expr += id_len;
return module->wires_.at(id);
}
static RTLIL::SigSpec create_inv_cell(RTLIL::Module *module, RTLIL::SigSpec A)
{
RTLIL::Cell *cell = module->addCell(NEW_ID, "$_NOT_");
cell->setPort("\\A", A);
cell->setPort("\\Y", module->addWire(NEW_ID));
return cell->getPort("\\Y");
}
static RTLIL::SigSpec create_xor_cell(RTLIL::Module *module, RTLIL::SigSpec A, RTLIL::SigSpec B)
{
RTLIL::Cell *cell = module->addCell(NEW_ID, "$_XOR_");
cell->setPort("\\A", A);
cell->setPort("\\B", B);
cell->setPort("\\Y", module->addWire(NEW_ID));
return cell->getPort("\\Y");
}
static RTLIL::SigSpec create_and_cell(RTLIL::Module *module, RTLIL::SigSpec A, RTLIL::SigSpec B)
{
RTLIL::Cell *cell = module->addCell(NEW_ID, "$_AND_");
cell->setPort("\\A", A);
cell->setPort("\\B", B);
cell->setPort("\\Y", module->addWire(NEW_ID));
return cell->getPort("\\Y");
}
static RTLIL::SigSpec create_or_cell(RTLIL::Module *module, RTLIL::SigSpec A, RTLIL::SigSpec B)
{
RTLIL::Cell *cell = module->addCell(NEW_ID, "$_OR_");
cell->setPort("\\A", A);
cell->setPort("\\B", B);
cell->setPort("\\Y", module->addWire(NEW_ID));
return cell->getPort("\\Y");
}
static bool parse_func_reduce(RTLIL::Module *module, std::vector<token_t> &stack, token_t next_token)
{
int top = int(stack.size())-1;
if (0 <= top-1 && stack[top].type == 0 && stack[top-1].type == '!') {
token_t t = token_t(0, create_inv_cell(module, stack[top].sig));
stack.pop_back();
stack.pop_back();
stack.push_back(t);
return true;
}
if (0 <= top-1 && stack[top].type == '\'' && stack[top-1].type == 0) {
token_t t = token_t(0, create_inv_cell(module, stack[top-1].sig));
stack.pop_back();
stack.pop_back();
stack.push_back(t);
return true;
}
if (0 <= top && stack[top].type == 0) {
if (next_token.type == '\'')
return false;
stack[top].type = 1;
return true;
}
if (0 <= top-2 && stack[top-2].type == 1 && stack[top-1].type == '^' && stack[top].type == 1) {
token_t t = token_t(1, create_xor_cell(module, stack[top-2].sig, stack[top].sig));
stack.pop_back();
stack.pop_back();
stack.pop_back();
stack.push_back(t);
return true;
}
if (0 <= top && stack[top].type == 1) {
if (next_token.type == '^')
return false;
stack[top].type = 2;
return true;
}
if (0 <= top-1 && stack[top-1].type == 2 && stack[top].type == 2) {
token_t t = token_t(2, create_and_cell(module, stack[top-1].sig, stack[top].sig));
stack.pop_back();
stack.pop_back();
stack.push_back(t);
return true;
}
if (0 <= top-2 && stack[top-2].type == 2 && (stack[top-1].type == '*' || stack[top-1].type == '&') && stack[top].type == 2) {
token_t t = token_t(2, create_and_cell(module, stack[top-2].sig, stack[top].sig));
stack.pop_back();
stack.pop_back();
stack.pop_back();
stack.push_back(t);
return true;
}
if (0 <= top && stack[top].type == 2) {
if (next_token.type == '*' || next_token.type == '&' || next_token.type == 0 || next_token.type == '(')
return false;
stack[top].type = 3;
return true;
}
if (0 <= top-2 && stack[top-2].type == 3 && (stack[top-1].type == '+' || stack[top-1].type == '|') && stack[top].type == 3) {
token_t t = token_t(3, create_or_cell(module, stack[top-2].sig, stack[top].sig));
stack.pop_back();
stack.pop_back();
stack.pop_back();
stack.push_back(t);
return true;
}
if (0 <= top-2 && stack[top-2].type == '(' && stack[top-1].type == 3 && stack[top].type == ')') {
token_t t = token_t(0, stack[top-1].sig);
stack.pop_back();
stack.pop_back();
stack.pop_back();
stack.push_back(t);
return true;
}
return false;
}
static RTLIL::SigSpec parse_func_expr(RTLIL::Module *module, const char *expr)
{
const char *orig_expr = expr;
std::vector<token_t> stack;
while (*expr)
{
if (*expr == ' ' || *expr == '\t' || *expr == '\r' || *expr == '\n' || *expr == '"') {
expr++;
continue;
}
token_t next_token(0);
if (*expr == '(' || *expr == ')' || *expr == '\'' || *expr == '!' || *expr == '^' || *expr == '*' || *expr == '+' || *expr == '|')
next_token = token_t(*(expr++));
else
next_token = token_t(0, parse_func_identifier(module, expr));
while (parse_func_reduce(module, stack, next_token)) {}
stack.push_back(next_token);
}
while (parse_func_reduce(module, stack, token_t('.'))) {}
#if 0
for (size_t i = 0; i < stack.size(); i++)
if (stack[i].type < 16)
log("%3d: %d %s\n", int(i), stack[i].type, log_signal(stack[i].sig));
else
log("%3d: %c\n", int(i), stack[i].type);
#endif
if (stack.size() != 1 || stack.back().type != 3)
log_error("Parser error in function expr `%s'.\n", orig_expr);
return stack.back().sig;
}
static void create_ff(RTLIL::Module *module, LibertyAst *node)
{
RTLIL::SigSpec iq_sig(module->addWire(RTLIL::escape_id(node->args.at(0))));
RTLIL::SigSpec iqn_sig(module->addWire(RTLIL::escape_id(node->args.at(1))));
RTLIL::SigSpec clk_sig, data_sig, clear_sig, preset_sig;
bool clk_polarity = true, clear_polarity = true, preset_polarity = true;
for (auto child : node->children) {
if (child->id == "clocked_on")
clk_sig = parse_func_expr(module, child->value.c_str());
if (child->id == "next_state")
data_sig = parse_func_expr(module, child->value.c_str());
if (child->id == "clear")
clear_sig = parse_func_expr(module, child->value.c_str());
if (child->id == "preset")
preset_sig = parse_func_expr(module, child->value.c_str());
}
if (clk_sig.size() == 0 || data_sig.size() == 0)
log_error("FF cell %s has no next_state and/or clocked_on attribute.\n", log_id(module->name));
for (bool rerun_invert_rollback = true; rerun_invert_rollback;)
{
rerun_invert_rollback = false;
for (auto &it : module->cells_) {
if (it.second->type == "$_NOT_" && it.second->getPort("\\Y") == clk_sig) {
clk_sig = it.second->getPort("\\A");
clk_polarity = !clk_polarity;
rerun_invert_rollback = true;
}
if (it.second->type == "$_NOT_" && it.second->getPort("\\Y") == clear_sig) {
clear_sig = it.second->getPort("\\A");
clear_polarity = !clear_polarity;
rerun_invert_rollback = true;
}
if (it.second->type == "$_NOT_" && it.second->getPort("\\Y") == preset_sig) {
preset_sig = it.second->getPort("\\A");
preset_polarity = !preset_polarity;
rerun_invert_rollback = true;
}
}
}
RTLIL::Cell *cell = module->addCell(NEW_ID, "$_NOT_");
cell->setPort("\\A", iq_sig);
cell->setPort("\\Y", iqn_sig);
cell = module->addCell(NEW_ID, "");
cell->setPort("\\D", data_sig);
cell->setPort("\\Q", iq_sig);
cell->setPort("\\C", clk_sig);
if (clear_sig.size() == 0 && preset_sig.size() == 0) {
cell->type = stringf("$_DFF_%c_", clk_polarity ? 'P' : 'N');
}
if (clear_sig.size() == 1 && preset_sig.size() == 0) {
cell->type = stringf("$_DFF_%c%c0_", clk_polarity ? 'P' : 'N', clear_polarity ? 'P' : 'N');
cell->setPort("\\R", clear_sig);
}
if (clear_sig.size() == 0 && preset_sig.size() == 1) {
cell->type = stringf("$_DFF_%c%c1_", clk_polarity ? 'P' : 'N', preset_polarity ? 'P' : 'N');
cell->setPort("\\R", preset_sig);
}
if (clear_sig.size() == 1 && preset_sig.size() == 1) {
cell->type = stringf("$_DFFSR_%c%c%c_", clk_polarity ? 'P' : 'N', preset_polarity ? 'P' : 'N', clear_polarity ? 'P' : 'N');
cell->setPort("\\S", preset_sig);
cell->setPort("\\R", clear_sig);
}
log_assert(!cell->type.empty());
}
static void create_latch(RTLIL::Module *module, LibertyAst *node)
{
RTLIL::SigSpec iq_sig(module->addWire(RTLIL::escape_id(node->args.at(0))));
RTLIL::SigSpec iqn_sig(module->addWire(RTLIL::escape_id(node->args.at(1))));
RTLIL::SigSpec enable_sig, data_sig, clear_sig, preset_sig;
bool enable_polarity = true, clear_polarity = true, preset_polarity = true;
for (auto child : node->children) {
if (child->id == "enable")
enable_sig = parse_func_expr(module, child->value.c_str());
if (child->id == "data_in")
data_sig = parse_func_expr(module, child->value.c_str());
if (child->id == "clear")
clear_sig = parse_func_expr(module, child->value.c_str());
if (child->id == "preset")
preset_sig = parse_func_expr(module, child->value.c_str());
}
if (enable_sig.size() == 0 || data_sig.size() == 0)
log_error("Latch cell %s has no data_in and/or enable attribute.\n", log_id(module->name));
for (bool rerun_invert_rollback = true; rerun_invert_rollback;)
{
rerun_invert_rollback = false;
for (auto &it : module->cells_) {
if (it.second->type == "$_NOT_" && it.second->getPort("\\Y") == enable_sig) {
enable_sig = it.second->getPort("\\A");
enable_polarity = !enable_polarity;
rerun_invert_rollback = true;
}
if (it.second->type == "$_NOT_" && it.second->getPort("\\Y") == clear_sig) {
clear_sig = it.second->getPort("\\A");
clear_polarity = !clear_polarity;
rerun_invert_rollback = true;
}
if (it.second->type == "$_NOT_" && it.second->getPort("\\Y") == preset_sig) {
preset_sig = it.second->getPort("\\A");
preset_polarity = !preset_polarity;
rerun_invert_rollback = true;
}
}
}
RTLIL::Cell *cell = module->addCell(NEW_ID, "$_NOT_");
cell->setPort("\\A", iq_sig);
cell->setPort("\\Y", iqn_sig);
if (clear_sig.size() == 1)
{
RTLIL::SigSpec clear_negative = clear_sig;
RTLIL::SigSpec clear_enable = clear_sig;
if (clear_polarity == true || clear_polarity != enable_polarity)
{
RTLIL::Cell *inv = module->addCell(NEW_ID, "$_NOT_");
inv->setPort("\\A", clear_sig);
inv->setPort("\\Y", module->addWire(NEW_ID));
if (clear_polarity == true)
clear_negative = inv->getPort("\\Y");
if (clear_polarity != enable_polarity)
clear_enable = inv->getPort("\\Y");
}
RTLIL::Cell *data_gate = module->addCell(NEW_ID, "$_AND_");
data_gate->setPort("\\A", data_sig);
data_gate->setPort("\\B", clear_negative);
data_gate->setPort("\\Y", data_sig = module->addWire(NEW_ID));
RTLIL::Cell *enable_gate = module->addCell(NEW_ID, enable_polarity ? "$_OR_" : "$_AND_");
enable_gate->setPort("\\A", enable_sig);
enable_gate->setPort("\\B", clear_enable);
enable_gate->setPort("\\Y", data_sig = module->addWire(NEW_ID));
}
if (preset_sig.size() == 1)
{
RTLIL::SigSpec preset_positive = preset_sig;
RTLIL::SigSpec preset_enable = preset_sig;
if (preset_polarity == false || preset_polarity != enable_polarity)
{
RTLIL::Cell *inv = module->addCell(NEW_ID, "$_NOT_");
inv->setPort("\\A", preset_sig);
inv->setPort("\\Y", module->addWire(NEW_ID));
if (preset_polarity == false)
preset_positive = inv->getPort("\\Y");
if (preset_polarity != enable_polarity)
preset_enable = inv->getPort("\\Y");
}
RTLIL::Cell *data_gate = module->addCell(NEW_ID, "$_OR_");
data_gate->setPort("\\A", data_sig);
data_gate->setPort("\\B", preset_positive);
data_gate->setPort("\\Y", data_sig = module->addWire(NEW_ID));
RTLIL::Cell *enable_gate = module->addCell(NEW_ID, enable_polarity ? "$_OR_" : "$_AND_");
enable_gate->setPort("\\A", enable_sig);
enable_gate->setPort("\\B", preset_enable);
enable_gate->setPort("\\Y", data_sig = module->addWire(NEW_ID));
}
cell = module->addCell(NEW_ID, stringf("$_DLATCH_%c_", enable_polarity ? 'P' : 'N'));
cell->setPort("\\D", data_sig);
cell->setPort("\\Q", iq_sig);
cell->setPort("\\E", enable_sig);
}
struct LibertyFrontend : public Frontend {
LibertyFrontend() : Frontend("liberty", "read cells from liberty file") { }
virtual void help()
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" read_liberty [filename]\n");
log("\n");
log("Read cells from liberty file as modules into current design.\n");
log("\n");
log(" -lib\n");
log(" only create empty blackbox modules\n");
log("\n");
log(" -ignore_redef\n");
log(" ignore re-definitions of modules. (the default behavior is to\n");
log(" create an error message.)\n");
log("\n");
log(" -ignore_miss_func\n");
log(" ignore cells with missing function specification of outputs\n");
log("\n");
log(" -ignore_miss_dir\n");
log(" ignore cells with a missing or invalid direction\n");
log(" specification on a pin\n");
log("\n");
log(" -setattr <attribute_name>\n");
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)
{
bool flag_lib = false;
bool flag_ignore_redef = false;
bool flag_ignore_miss_func = false;
bool flag_ignore_miss_dir = false;
std::vector<std::string> attributes;
log_header("Executing Liberty frontend.\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
std::string arg = args[argidx];
if (arg == "-lib") {
flag_lib = true;
continue;
}
if (arg == "-ignore_redef") {
flag_ignore_redef = true;
continue;
}
if (arg == "-ignore_miss_func") {
flag_ignore_miss_func = true;
continue;
}
if (arg == "-ignore_miss_dir") {
flag_ignore_miss_dir = true;
continue;
}
if (arg == "-setattr" && argidx+1 < args.size()) {
attributes.push_back(RTLIL::escape_id(args[++argidx]));
continue;
}
break;
}
extra_args(f, filename, args, argidx);
LibertyParser parser(*f);
int cell_count = 0;
for (auto cell : parser.ast->children)
{
if (cell->id != "cell" || cell->args.size() != 1)
continue;
std::string cell_name = RTLIL::escape_id(cell->args.at(0));
if (design->has(cell_name)) {
if (flag_ignore_redef)
continue;
log_error("Duplicate definition of cell/module %s.\n", RTLIL::unescape_id(cell_name).c_str());
}
// log("Processing cell type %s.\n", RTLIL::unescape_id(cell_name).c_str());
RTLIL::Module *module = new RTLIL::Module;
module->name = cell_name;
if (flag_lib)
module->set_bool_attribute("\\blackbox");
for (auto &attr : attributes)
module->attributes[attr] = 1;
for (auto node : cell->children)
if (node->id == "pin" && node->args.size() == 1) {
LibertyAst *dir = node->find("direction");
if (!dir || (dir->value != "input" && dir->value != "output" && dir->value != "inout" && dir->value != "internal"))
{
if (!flag_ignore_miss_dir)
{
log_error("Missing or invalid direction for pin %s of cell %s.\n", node->args.at(0).c_str(), log_id(module->name));
} else {
log("Ignoring cell %s with missing or invalid direction for pin %s.\n", log_id(module->name), node->args.at(0).c_str());
delete module;
goto skip_cell;
}
}
if (!flag_lib || dir->value != "internal")
module->addWire(RTLIL::escape_id(node->args.at(0)));
}
for (auto node : cell->children)
{
if (!flag_lib) {
if (node->id == "ff" && node->args.size() == 2)
create_ff(module, node);
if (node->id == "latch" && node->args.size() == 2)
create_latch(module, node);
}
if (node->id == "pin" && node->args.size() == 1)
{
LibertyAst *dir = node->find("direction");
if (flag_lib && dir->value == "internal")
continue;
RTLIL::Wire *wire = module->wires_.at(RTLIL::escape_id(node->args.at(0)));
if (dir && dir->value == "inout") {
wire->port_input = true;
wire->port_output = true;
}
if (dir && dir->value == "input") {
wire->port_input = true;
continue;
}
if (dir && dir->value == "output")
wire->port_output = true;
if (flag_lib)
continue;
LibertyAst *func = node->find("function");
if (func == NULL)
{
if (!flag_ignore_miss_func)
{
log_error("Missing function on output %s of cell %s.\n", log_id(wire->name), log_id(module->name));
} else {
log("Ignoring cell %s with missing function on output %s.\n", log_id(module->name), log_id(wire->name));
delete module;
goto skip_cell;
}
}
RTLIL::SigSpec out_sig = parse_func_expr(module, func->value.c_str());
module->connect(RTLIL::SigSig(wire, out_sig));
}
}
module->fixup_ports();
design->add(module);
cell_count++;
skip_cell:;
}
log("Imported %d cell types from liberty file.\n", cell_count);
}
} LibertyFrontend;
YOSYS_NAMESPACE_END

View file

@ -0,0 +1,16 @@
OBJS += frontends/verific/verific.o
ifeq ($(ENABLE_VERIFIC),1)
EXTRA_TARGETS += share/verific
share/verific:
$(P) rm -rf share/verific.new
$(Q) mkdir -p share/verific.new
$(Q) cp -r $(VERIFIC_DIR)/vhdl_packages/vdbs share/verific.new/vhdl_vdbs_1993
$(Q) cp -r $(VERIFIC_DIR)/vhdl_packages/vdbs_2008 share/verific.new/vhdl_vdbs_2008
$(Q) mv share/verific.new share/verific
endif

View file

@ -0,0 +1,31 @@
Notes on building yosys with verific support on amd64 when you
only have the i386 eval version of Verific:
1.) Use a Makefile.conf like the following one:
--snip--
CONFIG := clang
ENABLE_TCL := 0
ENABLE_QT4 := 0
ENABLE_ABC := 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:amd64 or lib32readline6-dev, depending on the
exact version of debian/ubuntu you are working with.
3.) Build and test
make -j8
./yosys frontends/verific/test_navre.ys

View file

@ -0,0 +1,18 @@
verific -vlog2k ../yosys-bigsim/softusb_navre/rtl/softusb_navre.v
verific -import softusb_navre
memory softusb_navre
flatten softusb_navre
rename softusb_navre gate
read_verilog ../yosys-bigsim/softusb_navre/rtl/softusb_navre.v
cd softusb_navre; proc; opt; memory; opt; cd ..
rename softusb_navre gold
expose -dff -shared gold gate
miter -equiv -ignore_gold_x -make_assert -make_outputs -make_outcmp gold gate miter
cd miter
flatten; opt -undriven
sat -verify -maxsteps 5 -set-init-undef -set-def-inputs -prove-asserts -tempinduct-def \
-seq 1 -set-at 1 in_rst 1 # -show-inputs -show-outputs

View file

@ -0,0 +1,949 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
#include "kernel/log.h"
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <dirent.h>
USING_YOSYS_NAMESPACE
#ifdef YOSYS_ENABLE_VERIFIC
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Woverloaded-virtual"
#include "veri_file.h"
#include "vhdl_file.h"
#include "VeriModule.h"
#include "VhdlUnits.h"
#include "DataBase.h"
#include "Message.h"
#pragma clang diagnostic pop
#ifdef VERIFIC_NAMESPACE
using namespace Verific ;
#endif
static void msg_func(msg_type_t msg_type, const char *message_id, linefile_type linefile, const char *msg, va_list args)
{
log("VERIFIC-%s [%s] ",
msg_type == VERIFIC_NONE ? "NONE" :
msg_type == VERIFIC_ERROR ? "ERROR" :
msg_type == VERIFIC_WARNING ? "WARNING" :
msg_type == VERIFIC_IGNORE ? "IGNORE" :
msg_type == VERIFIC_INFO ? "INFO" :
msg_type == VERIFIC_COMMENT ? "COMMENT" :
msg_type == VERIFIC_PROGRAM_ERROR ? "PROGRAM_ERROR" : "UNKNOWN", message_id);
if (linefile)
log("%s:%d: ", LineFile::GetFileName(linefile), LineFile::GetLineNo(linefile));
logv(msg, args);
log("\n");
}
static void import_attributes(std::map<RTLIL::IdString, RTLIL::Const> &attributes, DesignObj *obj)
{
MapIter mi;
Att *attr;
if (obj->Linefile())
attributes["\\src"] = stringf("%s:%d", LineFile::GetFileName(obj->Linefile()), LineFile::GetLineNo(obj->Linefile()));
// FIXME: Parse numeric attributes
FOREACH_ATTRIBUTE(obj, mi, attr)
attributes[RTLIL::escape_id(attr->Key())] = RTLIL::Const(std::string(attr->Value()));
}
static RTLIL::SigSpec operatorInput(Instance *inst, std::map<Net*, RTLIL::SigBit> &net_map)
{
RTLIL::SigSpec sig;
for (int i = int(inst->InputSize())-1; i >= 0; i--)
if (inst->GetInputBit(i))
sig.append(net_map.at(inst->GetInputBit(i)));
else
sig.append(RTLIL::State::Sz);
return sig;
}
static RTLIL::SigSpec operatorInput1(Instance *inst, std::map<Net*, RTLIL::SigBit> &net_map)
{
RTLIL::SigSpec sig;
for (int i = int(inst->Input1Size())-1; i >= 0; i--)
if (inst->GetInput1Bit(i))
sig.append(net_map.at(inst->GetInput1Bit(i)));
else
sig.append(RTLIL::State::Sz);
return sig;
}
static RTLIL::SigSpec operatorInput2(Instance *inst, std::map<Net*, RTLIL::SigBit> &net_map)
{
RTLIL::SigSpec sig;
for (int i = int(inst->Input2Size())-1; i >= 0; i--)
if (inst->GetInput2Bit(i))
sig.append(net_map.at(inst->GetInput2Bit(i)));
else
sig.append(RTLIL::State::Sz);
return sig;
}
static RTLIL::SigSpec operatorInport(Instance *inst, const char *portname, std::map<Net*, RTLIL::SigBit> &net_map)
{
PortBus *portbus = inst->View()->GetPortBus(portname);
if (portbus) {
RTLIL::SigSpec sig;
for (unsigned i = 0; i < portbus->Size(); i++) {
Net *net = inst->GetNet(portbus->ElementAtIndex(i));
if (net) {
if (net->IsGnd())
sig.append(RTLIL::State::S0);
else if (net->IsPwr())
sig.append(RTLIL::State::S1);
else
sig.append(net_map.at(net));
} else
sig.append(RTLIL::State::Sz);
}
return sig;
} else {
Port *port = inst->View()->GetPort(portname);
log_assert(port != NULL);
Net *net = inst->GetNet(port);
return net_map.at(net);
}
}
static RTLIL::SigSpec operatorOutput(Instance *inst, std::map<Net*, RTLIL::SigBit> &net_map, RTLIL::Module *module)
{
RTLIL::SigSpec sig;
RTLIL::Wire *dummy_wire = NULL;
for (int i = int(inst->OutputSize())-1; i >= 0; i--)
if (inst->GetOutputBit(i)) {
sig.append(net_map.at(inst->GetOutputBit(i)));
dummy_wire = NULL;
} else {
if (dummy_wire == NULL)
dummy_wire = module->addWire(NEW_ID);
else
dummy_wire->width++;
sig.append(RTLIL::SigSpec(dummy_wire, dummy_wire->width - 1));
}
return sig;
}
static bool import_netlist_instance_gates(RTLIL::Module *module, std::map<Net*, RTLIL::SigBit> &net_map, Instance *inst)
{
if (inst->Type() == PRIM_AND) {
module->addAndGate(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetInput1()), net_map.at(inst->GetInput2()), net_map.at(inst->GetOutput()));
return true;
}
if (inst->Type() == PRIM_NAND) {
RTLIL::SigSpec tmp = module->addWire(NEW_ID);
module->addAndGate(NEW_ID, net_map.at(inst->GetInput1()), net_map.at(inst->GetInput2()), tmp);
module->addNotGate(RTLIL::escape_id(inst->Name()), tmp, net_map.at(inst->GetOutput()));
return true;
}
if (inst->Type() == PRIM_OR) {
module->addOrGate(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetInput1()), net_map.at(inst->GetInput2()), net_map.at(inst->GetOutput()));
return true;
}
if (inst->Type() == PRIM_NOR) {
RTLIL::SigSpec tmp = module->addWire(NEW_ID);
module->addOrGate(NEW_ID, net_map.at(inst->GetInput1()), net_map.at(inst->GetInput2()), tmp);
module->addNotGate(RTLIL::escape_id(inst->Name()), tmp, net_map.at(inst->GetOutput()));
return true;
}
if (inst->Type() == PRIM_XOR) {
module->addXorGate(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetInput1()), net_map.at(inst->GetInput2()), net_map.at(inst->GetOutput()));
return true;
}
if (inst->Type() == PRIM_INV) {
module->addNotGate(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetInput()), net_map.at(inst->GetOutput()));
return true;
}
if (inst->Type() == PRIM_MUX) {
module->addMuxGate(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetInput1()), net_map.at(inst->GetInput2()), net_map.at(inst->GetControl()), net_map.at(inst->GetOutput()));
return true;
}
if (inst->Type() == PRIM_TRI) {
module->addMuxGate(RTLIL::escape_id(inst->Name()), RTLIL::State::Sz, net_map.at(inst->GetInput()), net_map.at(inst->GetControl()), net_map.at(inst->GetOutput()));
return true;
}
if (inst->Type() == PRIM_FADD)
{
RTLIL::SigSpec a = net_map.at(inst->GetInput1()), b = net_map.at(inst->GetInput2()), c = net_map.at(inst->GetCin());
RTLIL::SigSpec x = inst->GetCout() ? net_map.at(inst->GetCout()) : module->addWire(NEW_ID);
RTLIL::SigSpec y = inst->GetOutput() ? net_map.at(inst->GetOutput()) : module->addWire(NEW_ID);
RTLIL::SigSpec tmp1 = module->addWire(NEW_ID);
RTLIL::SigSpec tmp2 = module->addWire(NEW_ID);
RTLIL::SigSpec tmp3 = module->addWire(NEW_ID);
module->addXorGate(NEW_ID, a, b, tmp1);
module->addXorGate(RTLIL::escape_id(inst->Name()), tmp1, c, y);
module->addAndGate(NEW_ID, tmp1, c, tmp2);
module->addAndGate(NEW_ID, a, b, tmp3);
module->addOrGate(NEW_ID, tmp2, tmp3, x);
return true;
}
if (inst->Type() == PRIM_DFFRS)
{
if (inst->GetSet()->IsGnd() && inst->GetReset()->IsGnd())
module->addDffGate(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetClock()), net_map.at(inst->GetInput()), net_map.at(inst->GetOutput()));
else if (inst->GetSet()->IsGnd())
module->addAdffGate(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetClock()), net_map.at(inst->GetReset()),
net_map.at(inst->GetInput()), net_map.at(inst->GetOutput()), false);
else if (inst->GetReset()->IsGnd())
module->addAdffGate(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetClock()), net_map.at(inst->GetSet()),
net_map.at(inst->GetInput()), net_map.at(inst->GetOutput()), true);
else
module->addDffsrGate(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetClock()), net_map.at(inst->GetSet()), net_map.at(inst->GetReset()),
net_map.at(inst->GetInput()), net_map.at(inst->GetOutput()));
return true;
}
return false;
}
static bool import_netlist_instance_cells(RTLIL::Module *module, std::map<Net*, RTLIL::SigBit> &net_map, Instance *inst)
{
if (inst->Type() == PRIM_AND) {
module->addAnd(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetInput1()), net_map.at(inst->GetInput2()), net_map.at(inst->GetOutput()));
return true;
}
if (inst->Type() == PRIM_NAND) {
RTLIL::SigSpec tmp = module->addWire(NEW_ID);
module->addAnd(NEW_ID, net_map.at(inst->GetInput1()), net_map.at(inst->GetInput2()), tmp);
module->addNot(RTLIL::escape_id(inst->Name()), tmp, net_map.at(inst->GetOutput()));
return true;
}
if (inst->Type() == PRIM_OR) {
module->addOr(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetInput1()), net_map.at(inst->GetInput2()), net_map.at(inst->GetOutput()));
return true;
}
if (inst->Type() == PRIM_NOR) {
RTLIL::SigSpec tmp = module->addWire(NEW_ID);
module->addOr(NEW_ID, net_map.at(inst->GetInput1()), net_map.at(inst->GetInput2()), tmp);
module->addNot(RTLIL::escape_id(inst->Name()), tmp, net_map.at(inst->GetOutput()));
return true;
}
if (inst->Type() == PRIM_XOR) {
module->addXor(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetInput1()), net_map.at(inst->GetInput2()), net_map.at(inst->GetOutput()));
return true;
}
if (inst->Type() == PRIM_XNOR) {
module->addXnor(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetInput1()), net_map.at(inst->GetInput2()), net_map.at(inst->GetOutput()));
return true;
}
if (inst->Type() == PRIM_INV) {
module->addNot(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetInput()), net_map.at(inst->GetOutput()));
return true;
}
if (inst->Type() == PRIM_MUX) {
module->addMux(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetInput1()), net_map.at(inst->GetInput2()), net_map.at(inst->GetControl()), net_map.at(inst->GetOutput()));
return true;
}
if (inst->Type() == PRIM_TRI) {
module->addMux(RTLIL::escape_id(inst->Name()), RTLIL::State::Sz, net_map.at(inst->GetInput()), net_map.at(inst->GetControl()), net_map.at(inst->GetOutput()));
return true;
}
if (inst->Type() == PRIM_FADD)
{
RTLIL::SigSpec a_plus_b = module->addWire(NEW_ID, 2);
RTLIL::SigSpec y = inst->GetOutput() ? net_map.at(inst->GetOutput()) : module->addWire(NEW_ID);
if (inst->GetCout())
y.append(net_map.at(inst->GetCout()));
module->addAdd(NEW_ID, net_map.at(inst->GetInput1()), net_map.at(inst->GetInput2()), a_plus_b);
module->addAdd(RTLIL::escape_id(inst->Name()), a_plus_b, net_map.at(inst->GetCin()), y);
return true;
}
if (inst->Type() == PRIM_DFFRS)
{
if (inst->GetSet()->IsGnd() && inst->GetReset()->IsGnd())
module->addDff(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetClock()), net_map.at(inst->GetInput()), net_map.at(inst->GetOutput()));
else if (inst->GetSet()->IsGnd())
module->addAdff(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetClock()), net_map.at(inst->GetReset()),
net_map.at(inst->GetInput()), net_map.at(inst->GetOutput()), RTLIL::State::S0);
else if (inst->GetReset()->IsGnd())
module->addAdff(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetClock()), net_map.at(inst->GetSet()),
net_map.at(inst->GetInput()), net_map.at(inst->GetOutput()), RTLIL::State::S1);
else
module->addDffsr(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetClock()), net_map.at(inst->GetSet()), net_map.at(inst->GetReset()),
net_map.at(inst->GetInput()), net_map.at(inst->GetOutput()));
return true;
}
#define IN operatorInput(inst, net_map)
#define IN1 operatorInput1(inst, net_map)
#define IN2 operatorInput2(inst, net_map)
#define OUT operatorOutput(inst, net_map, module)
#define SIGNED inst->View()->IsSigned()
if (inst->Type() == OPER_ADDER) {
RTLIL::SigSpec out = OUT;
if (inst->GetCout() != NULL)
out.append(net_map.at(inst->GetCout()));
if (inst->GetCin()->IsGnd()) {
module->addAdd(RTLIL::escape_id(inst->Name()), IN1, IN2, out, SIGNED);
} else {
RTLIL::SigSpec tmp = module->addWire(NEW_ID, SIZE(out));
module->addAdd(NEW_ID, IN1, IN2, tmp, SIGNED);
module->addAdd(RTLIL::escape_id(inst->Name()), tmp, net_map.at(inst->GetCin()), out, false);
}
return true;
}
if (inst->Type() == OPER_MULTIPLIER) {
module->addMul(RTLIL::escape_id(inst->Name()), IN1, IN2, OUT, SIGNED);
return true;
}
if (inst->Type() == OPER_DIVIDER) {
module->addDiv(RTLIL::escape_id(inst->Name()), IN1, IN2, OUT, SIGNED);
return true;
}
if (inst->Type() == OPER_MODULO) {
module->addMod(RTLIL::escape_id(inst->Name()), IN1, IN2, OUT, SIGNED);
return true;
}
if (inst->Type() == OPER_REMAINDER) {
module->addMod(RTLIL::escape_id(inst->Name()), IN1, IN2, OUT, SIGNED);
return true;
}
if (inst->Type() == OPER_SHIFT_LEFT) {
module->addShl(RTLIL::escape_id(inst->Name()), IN1, IN2, OUT, false);
return true;
}
if (inst->Type() == OPER_SHIFT_RIGHT) {
Net *net_cin = inst->GetCin();
Net *net_a_msb = inst->GetInput1Bit(0);
if (net_cin->IsGnd())
module->addShr(RTLIL::escape_id(inst->Name()), IN1, IN2, OUT, false);
else if (net_cin == net_a_msb)
module->addSshr(RTLIL::escape_id(inst->Name()), IN1, IN2, OUT, true);
else
log_error("Can't import Verific OPER_SHIFT_RIGHT instance %s: carry_in is neither 0 nor msb of left input\n", inst->Name());
return true;
}
if (inst->Type() == OPER_REDUCE_AND) {
module->addReduceAnd(RTLIL::escape_id(inst->Name()), IN, net_map.at(inst->GetOutput()), SIGNED);
return true;
}
if (inst->Type() == OPER_REDUCE_OR) {
module->addReduceOr(RTLIL::escape_id(inst->Name()), IN, net_map.at(inst->GetOutput()), SIGNED);
return true;
}
if (inst->Type() == OPER_REDUCE_XOR) {
module->addReduceXor(RTLIL::escape_id(inst->Name()), IN, net_map.at(inst->GetOutput()), SIGNED);
return true;
}
if (inst->Type() == OPER_REDUCE_XNOR) {
module->addReduceXnor(RTLIL::escape_id(inst->Name()), IN, net_map.at(inst->GetOutput()), SIGNED);
return true;
}
if (inst->Type() == OPER_LESSTHAN) {
Net *net_cin = inst->GetCin();
if (net_cin->IsGnd())
module->addLt(RTLIL::escape_id(inst->Name()), IN1, IN2, net_map.at(inst->GetOutput()), SIGNED);
else if (net_cin->IsPwr())
module->addLe(RTLIL::escape_id(inst->Name()), IN1, IN2, net_map.at(inst->GetOutput()), SIGNED);
else
log_error("Can't import Verific OPER_LESSTHAN instance %s: carry_in is neither 0 nor 1\n", inst->Name());
return true;
}
if (inst->Type() == OPER_WIDE_AND) {
module->addAnd(RTLIL::escape_id(inst->Name()), IN1, IN2, OUT, SIGNED);
return true;
}
if (inst->Type() == OPER_WIDE_OR) {
module->addOr(RTLIL::escape_id(inst->Name()), IN1, IN2, OUT, SIGNED);
return true;
}
if (inst->Type() == OPER_WIDE_XOR) {
module->addXor(RTLIL::escape_id(inst->Name()), IN1, IN2, OUT, SIGNED);
return true;
}
if (inst->Type() == OPER_WIDE_XNOR) {
module->addXnor(RTLIL::escape_id(inst->Name()), IN1, IN2, OUT, SIGNED);
return true;
}
if (inst->Type() == OPER_WIDE_BUF) {
module->addPos(RTLIL::escape_id(inst->Name()), IN, OUT, SIGNED);
return true;
}
if (inst->Type() == OPER_WIDE_INV) {
module->addNot(RTLIL::escape_id(inst->Name()), IN, OUT, SIGNED);
return true;
}
if (inst->Type() == OPER_MINUS) {
module->addSub(RTLIL::escape_id(inst->Name()), IN1, IN2, OUT, SIGNED);
return true;
}
if (inst->Type() == OPER_UMINUS) {
module->addNeg(RTLIL::escape_id(inst->Name()), IN, OUT, SIGNED);
return true;
}
if (inst->Type() == OPER_EQUAL) {
module->addEq(RTLIL::escape_id(inst->Name()), IN1, IN2, net_map.at(inst->GetOutput()), SIGNED);
return true;
}
if (inst->Type() == OPER_NEQUAL) {
module->addNe(RTLIL::escape_id(inst->Name()), IN1, IN2, net_map.at(inst->GetOutput()), SIGNED);
return true;
}
if (inst->Type() == OPER_WIDE_MUX) {
module->addMux(RTLIL::escape_id(inst->Name()), IN1, IN2, net_map.at(inst->GetControl()), OUT);
return true;
}
if (inst->Type() == OPER_WIDE_TRI) {
module->addMux(RTLIL::escape_id(inst->Name()), RTLIL::SigSpec(RTLIL::State::Sz, inst->OutputSize()), IN, net_map.at(inst->GetControl()), OUT);
return true;
}
if (inst->Type() == OPER_WIDE_DFFRS) {
RTLIL::SigSpec sig_set = operatorInport(inst, "set", net_map);
RTLIL::SigSpec sig_reset = operatorInport(inst, "reset", net_map);
if (sig_set.is_fully_const() && !sig_set.as_bool() && sig_reset.is_fully_const() && !sig_reset.as_bool())
module->addDff(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetClock()), IN, OUT);
else
module->addDffsr(RTLIL::escape_id(inst->Name()), net_map.at(inst->GetClock()), sig_set, sig_reset, IN, OUT);
return true;
}
#undef IN
#undef IN1
#undef IN2
#undef OUT
#undef SIGNED
return false;
}
static void import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*> &nl_todo, bool mode_gates)
{
std::string module_name = nl->IsOperator() ? std::string("$verific$") + nl->Owner()->Name() : RTLIL::escape_id(nl->Owner()->Name());
if (design->has(module_name)) {
if (!nl->IsOperator())
log_cmd_error("Re-definition of module `%s'.\n", nl->Owner()->Name());
return;
}
RTLIL::Module *module = new RTLIL::Module;
module->name = module_name;
design->add(module);
log("Importing module %s.\n", RTLIL::id2cstr(module->name));
std::map<Net*, RTLIL::SigBit> net_map;
SetIter si;
MapIter mi, mi2;
Port *port;
PortBus *portbus;
Net *net;
NetBus *netbus;
Instance *inst;
PortRef *pr;
FOREACH_PORT_OF_NETLIST(nl, mi, port)
{
if (port->Bus())
continue;
// log(" importing port %s.\n", port->Name());
RTLIL::Wire *wire = module->addWire(RTLIL::escape_id(port->Name()));
import_attributes(wire->attributes, port);
wire->port_id = nl->IndexOf(port) + 1;
if (port->GetDir() == DIR_INOUT || port->GetDir() == DIR_IN)
wire->port_input = true;
if (port->GetDir() == DIR_INOUT || port->GetDir() == DIR_OUT)
wire->port_output = true;
if (port->GetNet()) {
net = port->GetNet();
if (net_map.count(net) == 0)
net_map[net] = wire;
else if (wire->port_input)
module->connect(net_map.at(net), wire);
else
module->connect(wire, net_map.at(net));
}
}
FOREACH_PORTBUS_OF_NETLIST(nl, mi, portbus)
{
// log(" importing portbus %s.\n", portbus->Name());
RTLIL::Wire *wire = module->addWire(RTLIL::escape_id(portbus->Name()), portbus->Size());
wire->start_offset = std::min(portbus->LeftIndex(), portbus->RightIndex());
import_attributes(wire->attributes, portbus);
if (portbus->GetDir() == DIR_INOUT || portbus->GetDir() == DIR_IN)
wire->port_input = true;
if (portbus->GetDir() == DIR_INOUT || portbus->GetDir() == DIR_OUT)
wire->port_output = true;
for (int i = portbus->LeftIndex();; i += portbus->IsUp() ? +1 : -1) {
if (portbus->ElementAtIndex(i) && portbus->ElementAtIndex(i)->GetNet()) {
net = portbus->ElementAtIndex(i)->GetNet();
RTLIL::SigBit bit(wire, i - wire->start_offset);
if (net_map.count(net) == 0)
net_map[net] = bit;
else if (wire->port_input)
module->connect(net_map.at(net), bit);
else
module->connect(bit, net_map.at(net));
}
if (i == portbus->RightIndex())
break;
}
}
module->fixup_ports();
FOREACH_NET_OF_NETLIST(nl, mi, net)
{
if (net->IsRamNet())
{
RTLIL::Memory *memory = new RTLIL::Memory;
memory->name = RTLIL::escape_id(net->Name());
log_assert(module->count_id(memory->name) == 0);
module->memories[memory->name] = memory;
int number_of_bits = net->Size();
int bits_in_word = number_of_bits;
FOREACH_PORTREF_OF_NET(net, si, pr) {
if (pr->GetInst()->Type() == OPER_READ_PORT) {
bits_in_word = std::min<int>(bits_in_word, pr->GetInst()->OutputSize());
continue;
}
if (pr->GetInst()->Type() == OPER_WRITE_PORT || pr->GetInst()->Type() == OPER_CLOCKED_WRITE_PORT) {
bits_in_word = std::min<int>(bits_in_word, pr->GetInst()->Input2Size());
continue;
}
log_error("Verific RamNet %s is connected to unsupported instance type %s (%s).\n",
net->Name(), pr->GetInst()->View()->Owner()->Name(), pr->GetInst()->Name());
}
memory->width = bits_in_word;
memory->size = number_of_bits / bits_in_word;
continue;
}
if (net_map.count(net)) {
// log(" skipping net %s.\n", net->Name());
continue;
}
if (net->Bus())
continue;
// log(" importing net %s.\n", net->Name());
RTLIL::IdString wire_name = module->uniquify(RTLIL::escape_id(net->Name()));
RTLIL::Wire *wire = module->addWire(wire_name);
import_attributes(wire->attributes, net);
net_map[net] = wire;
}
FOREACH_NETBUS_OF_NETLIST(nl, mi, netbus)
{
bool found_new_net = false;
for (int i = netbus->LeftIndex();; i += netbus->IsUp() ? +1 : -1) {
net = netbus->ElementAtIndex(i);
if (net_map.count(net) == 0)
found_new_net = true;
if (i == netbus->RightIndex())
break;
}
if (found_new_net)
{
// log(" importing netbus %s.\n", netbus->Name());
RTLIL::IdString wire_name = module->uniquify(RTLIL::escape_id(netbus->Name()));
RTLIL::Wire *wire = module->addWire(wire_name, netbus->Size());
wire->start_offset = std::min(netbus->LeftIndex(), netbus->RightIndex());
import_attributes(wire->attributes, netbus);
for (int i = netbus->LeftIndex();; i += netbus->IsUp() ? +1 : -1) {
if (netbus->ElementAtIndex(i)) {
net = netbus->ElementAtIndex(i);
RTLIL::SigBit bit(wire, i - wire->start_offset);
if (net_map.count(net) == 0)
net_map[net] = bit;
else
module->connect(bit, net_map.at(net));
}
if (i == netbus->RightIndex())
break;
}
}
else
{
// log(" skipping netbus %s.\n", netbus->Name());
}
}
FOREACH_INSTANCE_OF_NETLIST(nl, mi, inst)
{
// log(" importing cell %s (%s).\n", inst->Name(), inst->View()->Owner()->Name());
if (inst->Type() == PRIM_PWR) {
module->connect(net_map.at(inst->GetOutput()), RTLIL::State::S1);
continue;
}
if (inst->Type() == PRIM_GND) {
module->connect(net_map.at(inst->GetOutput()), RTLIL::State::S0);
continue;
}
if (inst->Type() == PRIM_X) {
module->connect(net_map.at(inst->GetOutput()), RTLIL::State::Sx);
continue;
}
if (inst->Type() == PRIM_Z) {
module->connect(net_map.at(inst->GetOutput()), RTLIL::State::Sz);
continue;
}
if (inst->Type() == OPER_READ_PORT)
{
RTLIL::Memory *memory = module->memories.at(RTLIL::escape_id(inst->GetInput()->Name()));
if (memory->width != int(inst->OutputSize()))
log_error("Import of asymetric memories from Verific is not supported yet: %s %s\n", inst->Name(), inst->GetInput()->Name());
RTLIL::SigSpec addr = operatorInput1(inst, net_map);
RTLIL::SigSpec data = operatorOutput(inst, net_map, module);
RTLIL::Cell *cell = module->addCell(RTLIL::escape_id(inst->Name()), "$memrd");
cell->parameters["\\MEMID"] = memory->name.str();
cell->parameters["\\CLK_ENABLE"] = false;
cell->parameters["\\CLK_POLARITY"] = true;
cell->parameters["\\TRANSPARENT"] = false;
cell->parameters["\\ABITS"] = SIZE(addr);
cell->parameters["\\WIDTH"] = SIZE(data);
cell->setPort("\\CLK", RTLIL::State::S0);
cell->setPort("\\ADDR", addr);
cell->setPort("\\DATA", data);
continue;
}
if (inst->Type() == OPER_WRITE_PORT || inst->Type() == OPER_CLOCKED_WRITE_PORT)
{
RTLIL::Memory *memory = module->memories.at(RTLIL::escape_id(inst->GetOutput()->Name()));
if (memory->width != int(inst->Input2Size()))
log_error("Import of asymetric memories from Verific is not supported yet: %s %s\n", inst->Name(), inst->GetInput()->Name());
RTLIL::SigSpec addr = operatorInput1(inst, net_map);
RTLIL::SigSpec data = operatorInput2(inst, net_map);
RTLIL::Cell *cell = module->addCell(RTLIL::escape_id(inst->Name()), "$memwr");
cell->parameters["\\MEMID"] = memory->name.str();
cell->parameters["\\CLK_ENABLE"] = false;
cell->parameters["\\CLK_POLARITY"] = true;
cell->parameters["\\PRIORITY"] = 0;
cell->parameters["\\ABITS"] = SIZE(addr);
cell->parameters["\\WIDTH"] = SIZE(data);
cell->setPort("\\EN", RTLIL::SigSpec(net_map.at(inst->GetControl())).repeat(SIZE(data)));
cell->setPort("\\CLK", RTLIL::State::S0);
cell->setPort("\\ADDR", addr);
cell->setPort("\\DATA", data);
if (inst->Type() == OPER_CLOCKED_WRITE_PORT) {
cell->parameters["\\CLK_ENABLE"] = true;
cell->setPort("\\CLK", net_map.at(inst->GetClock()));
}
continue;
}
if (!mode_gates) {
if (import_netlist_instance_cells(module, net_map, inst))
continue;
if (inst->IsOperator())
log("Warning: Unsupported Verific operator: %s (fallback to gate level implementation provided by verific)\n", inst->View()->Owner()->Name());
} else {
if (import_netlist_instance_gates(module, net_map, inst))
continue;
}
if (inst->IsPrimitive())
log_error("Unsupported Verific primitive: %s\n", inst->View()->Owner()->Name());
nl_todo.insert(inst->View());
RTLIL::Cell *cell = module->addCell(RTLIL::escape_id(inst->Name()), inst->IsOperator() ?
std::string("$verific$") + inst->View()->Owner()->Name() : RTLIL::escape_id(inst->View()->Owner()->Name()));
FOREACH_PORTREF_OF_INST(inst, mi2, pr) {
// log(" .%s(%s)\n", pr->GetPort()->Name(), pr->GetNet()->Name());
const char *port_name = pr->GetPort()->Name();
int port_offset = 0;
if (pr->GetPort()->Bus()) {
port_name = pr->GetPort()->Bus()->Name();
port_offset = pr->GetPort()->Bus()->IndexOf(pr->GetPort()) -
std::min(pr->GetPort()->Bus()->LeftIndex(), pr->GetPort()->Bus()->RightIndex());
}
RTLIL::SigSpec conn;
if (cell->hasPort(RTLIL::escape_id(port_name)))
conn = cell->getPort(RTLIL::escape_id(port_name));
while (SIZE(conn) <= port_offset) {
if (pr->GetPort()->GetDir() != DIR_IN)
conn.append(module->addWire(NEW_ID, port_offset - SIZE(conn)));
conn.append(RTLIL::State::Sz);
}
conn.replace(port_offset, net_map.at(pr->GetNet()));
cell->setPort(RTLIL::escape_id(port_name), conn);
}
}
}
#endif /* YOSYS_ENABLE_VERIFIC */
YOSYS_NAMESPACE_BEGIN
struct VerificPass : public Pass {
VerificPass() : Pass("verific", "load Verilog and VHDL designs using Verific") { }
virtual void help()
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" verific {-vlog95|-vlog2k|-sv2005|-sv2009|-sv} <verilog-file>..\n");
log("\n");
log("Load the specified Verilog/SystemVerilog files into Verific.\n");
log("\n");
log("\n");
log(" verific {-vhdl87|-vhdl93|-vhdl2k|-vhdl2008} <vhdl-file>..\n");
log("\n");
log("Load the specified VHDL files into Verific.\n");
log("\n");
log("\n");
log(" verific -import [-gates] {-all | <top-module>..}\n");
log("\n");
log("Elaborate the design for the sepcified top modules, import to Yosys and\n");
log("reset the internal state of Verific. A gate-level netlist is created\n");
log("when called with -gates.\n");
log("\n");
log("Visit http://verific.com/ for more information on Verific.\n");
log("\n");
}
#ifdef YOSYS_ENABLE_VERIFIC
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
log_header("Executing VERIFIC (loading Verilog and VHDL designs using Verific).\n");
Message::SetConsoleOutput(0);
Message::RegisterCallBackMsg(msg_func);
if (args.size() > 1 && args[1] == "-vlog95") {
for (size_t argidx = 2; argidx < args.size(); argidx++)
if (!veri_file::Analyze(args[argidx].c_str(), veri_file::VERILOG_95))
log_cmd_error("Reading `%s' in VERILOG_95 mode failed.\n", args[argidx].c_str());
return;
}
if (args.size() > 1 && args[1] == "-vlog2k") {
for (size_t argidx = 2; argidx < args.size(); argidx++)
if (!veri_file::Analyze(args[argidx].c_str(), veri_file::VERILOG_2K))
log_cmd_error("Reading `%s' in VERILOG_2K mode failed.\n", args[argidx].c_str());
return;
}
if (args.size() > 1 && args[1] == "-sv2005") {
for (size_t argidx = 2; argidx < args.size(); argidx++)
if (!veri_file::Analyze(args[argidx].c_str(), veri_file::SYSTEM_VERILOG_2005))
log_cmd_error("Reading `%s' in SYSTEM_VERILOG_2005 mode failed.\n", args[argidx].c_str());
return;
}
if (args.size() > 1 && args[1] == "-sv2009") {
for (size_t argidx = 2; argidx < args.size(); argidx++)
if (!veri_file::Analyze(args[argidx].c_str(), veri_file::SYSTEM_VERILOG_2009))
log_cmd_error("Reading `%s' in SYSTEM_VERILOG_2009 mode failed.\n", args[argidx].c_str());
return;
}
if (args.size() > 1 && args[1] == "-sv") {
for (size_t argidx = 2; argidx < args.size(); argidx++)
if (!veri_file::Analyze(args[argidx].c_str(), veri_file::SYSTEM_VERILOG))
log_cmd_error("Reading `%s' in SYSTEM_VERILOG mode failed.\n", args[argidx].c_str());
return;
}
if (args.size() > 1 && args[1] == "-vhdl87") {
vhdl_file::SetDefaultLibraryPath((proc_share_dirname() + "verific/vhdl_vdbs_1993").c_str());
for (size_t argidx = 2; argidx < args.size(); argidx++)
if (!vhdl_file::Analyze(args[argidx].c_str(), "work", vhdl_file::VHDL_87))
log_cmd_error("Reading `%s' in VHDL_87 mode failed.\n", args[argidx].c_str());
return;
}
if (args.size() > 1 && args[1] == "-vhdl93") {
vhdl_file::SetDefaultLibraryPath((proc_share_dirname() + "verific/vhdl_vdbs_1993").c_str());
for (size_t argidx = 2; argidx < args.size(); argidx++)
if (!vhdl_file::Analyze(args[argidx].c_str(), "work", vhdl_file::VHDL_93))
log_cmd_error("Reading `%s' in VHDL_93 mode failed.\n", args[argidx].c_str());
return;
}
if (args.size() > 1 && args[1] == "-vhdl2k") {
vhdl_file::SetDefaultLibraryPath((proc_share_dirname() + "verific/vhdl_vdbs_1993").c_str());
for (size_t argidx = 2; argidx < args.size(); argidx++)
if (!vhdl_file::Analyze(args[argidx].c_str(), "work", vhdl_file::VHDL_2K))
log_cmd_error("Reading `%s' in VHDL_2K mode failed.\n", args[argidx].c_str());
return;
}
if (args.size() > 1 && args[1] == "-vhdl2008") {
vhdl_file::SetDefaultLibraryPath((proc_share_dirname() + "verific/vhdl_vdbs_2008").c_str());
for (size_t argidx = 2; argidx < args.size(); argidx++)
if (!vhdl_file::Analyze(args[argidx].c_str(), "work", vhdl_file::VHDL_2008))
log_cmd_error("Reading `%s' in VHDL_2008 mode failed.\n", args[argidx].c_str());
return;
}
if (args.size() > 1 && args[1] == "-import")
{
std::set<Netlist*> nl_todo, nl_done;
bool mode_all = false, mode_gates = false;
size_t argidx = 2;
for (; argidx < args.size(); argidx++) {
if (args[argidx] == "-all") {
mode_all = true;
continue;
}
if (args[argidx] == "-gates") {
mode_gates = true;
continue;
}
break;
}
if (argidx > args.size() && args[argidx].substr(0, 1) == "-")
cmd_error(args, argidx, "unknown option");
if (mode_all)
{
if (argidx != args.size())
log_cmd_error("Got -all and an explicit list of top modules.\n");
MapIter m1, m2, m3;
VeriModule *mod;
FOREACH_VERILOG_MODULE(m1, mod)
args.push_back(mod->Name());
VhdlLibrary *lib;
VhdlPrimaryUnit *primunit;
FOREACH_VHDL_LIBRARY(m1, lib)
FOREACH_VHDL_PRIMARY_UNIT(lib, m2, primunit) {
if (primunit->IsPackageDecl())
continue;
args.push_back(primunit->Name());
}
}
else
if (argidx == args.size())
log_cmd_error("No top module specified.\n");
for (; argidx < args.size(); argidx++) {
if (veri_file::GetModule(args[argidx].c_str())) {
if (!veri_file::Elaborate(args[argidx].c_str()))
log_cmd_error("Elaboration of top module `%s' failed.\n", args[argidx].c_str());
nl_todo.insert(Netlist::PresentDesign());
} else {
if (!vhdl_file::Elaborate(args[argidx].c_str()))
log_cmd_error("Elaboration of top module `%s' failed.\n", args[argidx].c_str());
nl_todo.insert(Netlist::PresentDesign());
}
}
while (!nl_todo.empty()) {
Netlist *nl = *nl_todo.begin();
if (nl_done.count(nl) == 0)
import_netlist(design, nl, nl_todo, mode_gates);
nl_todo.erase(nl);
nl_done.insert(nl);
}
Libset::Reset();
return;
}
log_cmd_error("Missing or unsupported mode parameter.\n");
}
#else /* YOSYS_ENABLE_VERIFIC */
virtual void execute(std::vector<std::string>, RTLIL::Design *) {
log_cmd_error("This version of Yosys is built without Verific support.\n");
}
#endif
} VerificPass;
YOSYS_NAMESPACE_END

View file

@ -5,13 +5,13 @@ GENFILES += frontends/verilog/parser.output
GENFILES += frontends/verilog/lexer.cc
frontends/verilog/parser.tab.cc: frontends/verilog/parser.y
bison -d -r all -b frontends/verilog/parser frontends/verilog/parser.y
mv frontends/verilog/parser.tab.c frontends/verilog/parser.tab.cc
$(P) bison -d -r all -b frontends/verilog/parser frontends/verilog/parser.y
$(Q) mv frontends/verilog/parser.tab.c frontends/verilog/parser.tab.cc
frontends/verilog/parser.tab.h: frontends/verilog/parser.tab.cc
frontends/verilog/lexer.cc: frontends/verilog/lexer.l
flex -o frontends/verilog/lexer.cc frontends/verilog/lexer.l
$(P) flex -o frontends/verilog/lexer.cc frontends/verilog/lexer.l
OBJS += frontends/verilog/parser.tab.o
OBJS += frontends/verilog/lexer.o

View file

@ -36,10 +36,11 @@
#include "verilog_frontend.h"
#include "kernel/log.h"
#include <assert.h>
#include <string.h>
#include <math.h>
YOSYS_NAMESPACE_BEGIN
using namespace AST;
// divide an arbitrary length decimal number by two and return the rest
@ -47,11 +48,13 @@ static int my_decimal_div_by_two(std::vector<uint8_t> &digits)
{
int carry = 0;
for (size_t i = 0; i < digits.size(); i++) {
assert(digits[i] < 10);
log_assert(digits[i] < 10);
digits[i] += carry * 10;
carry = digits[i] % 2;
digits[i] /= 2;
}
while (!digits.empty() && !digits.front())
digits.erase(digits.begin());
return carry;
}
@ -90,10 +93,15 @@ static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int le
if (base == 10) {
data.clear();
if (len_in_bits < 0)
len_in_bits = ceil(digits.size()/log10(2));
for (int i = 0; i < len_in_bits; i++)
data.push_back(my_decimal_div_by_two(digits) ? RTLIL::S1 : RTLIL::S0);
if (len_in_bits < 0) {
while (!digits.empty())
data.push_back(my_decimal_div_by_two(digits) ? RTLIL::S1 : RTLIL::S0);
while (data.size() < 32)
data.push_back(RTLIL::S0);
} else {
for (int i = 0; i < len_in_bits; i++)
data.push_back(my_decimal_div_by_two(digits) ? RTLIL::S1 : RTLIL::S0);
}
return;
}
@ -151,20 +159,24 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type)
str = code.c_str();
char *endptr;
long intval = strtol(str, &endptr, 10);
long len_in_bits = strtol(str, &endptr, 10);
// 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);
return AstNode::mkconst_bits(data, true);
}
// Simple 32 bit integer
if (*endptr == 0)
return AstNode::mkconst_int(intval, true);
// unsized constant
if (str == endptr)
intval = -1;
len_in_bits = -1;
// The "<bits>'s?[bodh]<digits>" syntax
if (*endptr == '\'')
{
int len_in_bits = intval;
std::vector<RTLIL::State> data;
bool is_signed = false;
if (*(endptr+1) == 's') {
@ -188,9 +200,17 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type)
default:
return NULL;
}
if (len_in_bits < 0) {
if (is_signed && data.back() == RTLIL::S1)
data.push_back(RTLIL::S0);
while (data.size() < 32)
data.push_back(RTLIL::S0);
}
return AstNode::mkconst_bits(data, is_signed);
}
return NULL;
}
YOSYS_NAMESPACE_END

View file

@ -34,18 +34,37 @@
%{
#ifdef __clang__
// bison generates code using the 'register' storage class specifier
#pragma clang diagnostic ignored "-Wdeprecated-register"
#endif
#include "kernel/log.h"
#include "verilog_frontend.h"
#include "frontends/ast/ast.h"
#include "parser.tab.h"
USING_YOSYS_NAMESPACE
using namespace AST;
using namespace VERILOG_FRONTEND;
YOSYS_NAMESPACE_BEGIN
namespace VERILOG_FRONTEND {
std::vector<std::string> fn_stack;
std::vector<int> ln_stack;
}
YOSYS_NAMESPACE_END
#define SV_KEYWORD(_tok) \
if (sv_mode) return _tok; \
log("Lexer warning: The SystemVerilog keyword `%s' (at %s:%d) is not "\
"recognized unless read_verilog is called with -sv!\n", yytext, \
AST::current_filename.c_str(), frontend_verilog_yyget_lineno()); \
frontend_verilog_yylval.string = new std::string(std::string("\\") + yytext); \
return TOK_ID;
#define YY_INPUT(buf,result,max_size) \
result = lexin->readsome(buf, max_size);
%}
@ -58,29 +77,53 @@ namespace VERILOG_FRONTEND {
%x STRING
%x SYNOPSYS_TRANSLATE_OFF
%x SYNOPSYS_FLAGS
%x IMPORT_DPI
%%
"`file_push "[^\n]* {
<INITIAL,SYNOPSYS_TRANSLATE_OFF>"`file_push "[^\n]* {
fn_stack.push_back(current_filename);
ln_stack.push_back(frontend_verilog_yyget_lineno());
current_filename = yytext+11;
frontend_verilog_yyset_lineno(0);
}
"`file_pop"[^\n]*\n {
<INITIAL,SYNOPSYS_TRANSLATE_OFF>"`file_pop"[^\n]*\n {
current_filename = fn_stack.back();
fn_stack.pop_back();
frontend_verilog_yyset_lineno(ln_stack.back());
ln_stack.pop_back();
}
<INITIAL,SYNOPSYS_TRANSLATE_OFF>"`line"[ \t]+[^ \t\r\n]+[ \t]+\"[^ \r\n]+\"[^\r\n]*\n {
char *p = yytext + 5;
while (*p == ' ' || *p == '\t') p++;
frontend_verilog_yyset_lineno(atoi(p));
while (*p && *p != ' ' && *p != '\t') p++;
while (*p == ' ' || *p == '\t') p++;
char *q = *p ? p + 1 : p;
while (*q && *q != '"') q++;
current_filename = std::string(p).substr(1, q-p-1);
}
"`file_notfound "[^\n]* {
log_error("Can't open include file `%s'!\n", yytext + 15);
}
"`timescale"[ \t]+[^ \t\r\n/]+[ \t]*"/"[ \t]*[^ \t\r\n]* /* ignore timescale directive */
"`default_nettype"[ \t]+[^ \t\r\n/]+ {
char *p = yytext;
while (*p != 0 && *p != ' ' && *p != '\t') p++;
while (*p == ' ' || *p == '\t') p++;
if (!strcmp(p, "none"))
VERILOG_FRONTEND::default_nettype_wire = false;
else if (!strcmp(p, "wire"))
VERILOG_FRONTEND::default_nettype_wire = true;
else
frontend_verilog_yyerror("Unsupported default nettype: %s", p);
}
"`"[a-zA-Z_$][a-zA-Z0-9_$]* {
frontend_verilog_yyerror("Unimplemented compiler directive or undefined macro %s.", yytext);
}
@ -112,8 +155,17 @@ namespace VERILOG_FRONTEND {
"default" { return TOK_DEFAULT; }
"generate" { return TOK_GENERATE; }
"endgenerate" { return TOK_ENDGENERATE; }
"while" { return TOK_WHILE; }
"repeat" { return TOK_REPEAT; }
"assert"([ \t\r\n]+"property")? { return TOK_ASSERT; }
"always_comb" { SV_KEYWORD(TOK_ALWAYS); }
"always_ff" { SV_KEYWORD(TOK_ALWAYS); }
"always_latch" { SV_KEYWORD(TOK_ALWAYS); }
"assert" { SV_KEYWORD(TOK_ASSERT); }
"property" { SV_KEYWORD(TOK_PROPERTY); }
"logic" { SV_KEYWORD(TOK_REG); }
"bit" { SV_KEYWORD(TOK_REG); }
"input" { return TOK_INPUT; }
"output" { return TOK_OUTPUT; }
@ -123,6 +175,7 @@ namespace VERILOG_FRONTEND {
"integer" { return TOK_INTEGER; }
"signed" { return TOK_SIGNED; }
"genvar" { return TOK_GENVAR; }
"real" { return TOK_REAL; }
[0-9]+ {
frontend_verilog_yylval.string = new std::string(yytext);
@ -134,6 +187,16 @@ namespace VERILOG_FRONTEND {
return TOK_CONST;
}
[0-9][0-9_]*\.[0-9][0-9_]*([eE][-+]?[0-9_]+)? {
frontend_verilog_yylval.string = new std::string(yytext);
return TOK_REALVAL;
}
[0-9][0-9_]*[eE][-+]?[0-9_]+ {
frontend_verilog_yylval.string = new std::string(yytext);
return TOK_REALVAL;
}
\" { BEGIN(STRING); }
<STRING>\\. { yymore(); }
<STRING>\" {
@ -215,6 +278,27 @@ supply1 { return TOK_SUPPLY1; }
<SYNOPSYS_FLAGS>. /* ignore everything else */
<SYNOPSYS_FLAGS>"*/" { BEGIN(0); }
import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ {
BEGIN(IMPORT_DPI);
return TOK_DPI_FUNCTION;
}
<IMPORT_DPI>[a-zA-Z_$][a-zA-Z0-9_$]* {
frontend_verilog_yylval.string = new std::string(std::string("\\") + yytext);
return TOK_ID;
}
<IMPORT_DPI>[ \t\r\n] /* ignore whitespaces */
<IMPORT_DPI>";" {
BEGIN(0);
return *yytext;
}
<IMPORT_DPI>. {
return *yytext;
}
"\\"[^ \t\r\n]+ {
frontend_verilog_yylval.string = new std::string(yytext);
return TOK_ID;

View file

@ -35,13 +35,15 @@
%{
#include <list>
#include <assert.h>
#include <string.h>
#include "verilog_frontend.h"
#include "kernel/log.h"
USING_YOSYS_NAMESPACE
using namespace AST;
using namespace VERILOG_FRONTEND;
YOSYS_NAMESPACE_BEGIN
namespace VERILOG_FRONTEND {
int port_counter;
std::map<std::string, int> port_stubs;
@ -53,7 +55,12 @@ namespace VERILOG_FRONTEND {
struct AstNode *current_ast, *current_ast_mod;
int current_function_or_task_port_id;
std::vector<char> case_type_stack;
bool do_not_require_port_stubs;
bool default_nettype_wire;
bool sv_mode;
std::istream *lexin;
}
YOSYS_NAMESPACE_END
static void append_attr(AstNode *ast, std::map<std::string, AstNode*> *al)
{
@ -83,30 +90,31 @@ static void free_attr(std::map<std::string, AstNode*> *al)
%}
%name-prefix="frontend_verilog_yy"
%name-prefix "frontend_verilog_yy"
%union {
std::string *string;
struct AstNode *ast;
std::map<std::string, AstNode*> *al;
struct YOSYS_NAMESPACE_PREFIX AST::AstNode *ast;
std::map<std::string, YOSYS_NAMESPACE_PREFIX AST::AstNode*> *al;
bool boolean;
}
%token <string> TOK_STRING TOK_ID TOK_CONST TOK_PRIMITIVE
%token <string> TOK_STRING TOK_ID TOK_CONST TOK_REALVAL TOK_PRIMITIVE
%token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END
%token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM
%token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_REG
%token TOK_INTEGER TOK_SIGNED TOK_ASSIGN TOK_ALWAYS TOK_INITIAL
%token TOK_BEGIN TOK_END TOK_IF TOK_ELSE TOK_FOR
%token TOK_POSEDGE TOK_NEGEDGE TOK_OR
%token TOK_BEGIN TOK_END TOK_IF TOK_ELSE TOK_FOR TOK_WHILE TOK_REPEAT
%token TOK_DPI_FUNCTION TOK_POSEDGE TOK_NEGEDGE TOK_OR
%token TOK_CASE TOK_CASEX TOK_CASEZ TOK_ENDCASE TOK_DEFAULT
%token TOK_FUNCTION TOK_ENDFUNCTION TOK_TASK TOK_ENDTASK
%token TOK_GENERATE TOK_ENDGENERATE TOK_GENVAR
%token TOK_GENERATE TOK_ENDGENERATE TOK_GENVAR TOK_REAL
%token TOK_SYNOPSYS_FULL_CASE TOK_SYNOPSYS_PARALLEL_CASE
%token TOK_SUPPLY0 TOK_SUPPLY1 TOK_TO_SIGNED TOK_TO_UNSIGNED
%token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_ASSERT
%token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_ASSERT TOK_PROPERTY
%type <ast> wire_type range non_opt_range expr basic_expr concat_list rvalue lvalue lvalue_concat_list
%type <ast> range range_or_multirange non_opt_range non_opt_multirange range_or_signed_int
%type <ast> wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list
%type <string> opt_label tok_prim_wrapper hierarchical_id
%type <boolean> opt_signed
%type <al> attr
@ -130,14 +138,21 @@ static void free_attr(std::map<std::string, AstNode*> *al)
%%
input:
module input |
defattr input |
/* empty */ {
for (auto &it : default_attr_list)
delete it.second;
default_attr_list.clear();
};
input: {
ast_stack.push_back(current_ast);
} design {
ast_stack.pop_back();
log_assert(SIZE(ast_stack) == 0);
for (auto &it : default_attr_list)
delete it.second;
default_attr_list.clear();
};
design:
module design |
defattr design |
task_func_decl design |
/* empty */;
attr:
{
@ -205,10 +220,11 @@ hierarchical_id:
module:
attr TOK_MODULE TOK_ID {
do_not_require_port_stubs = false;
AstNode *mod = new AstNode(AST_MODULE);
current_ast->children.push_back(mod);
current_ast_mod = mod;
ast_stack.back()->children.push_back(mod);
ast_stack.push_back(mod);
current_ast_mod = mod;
port_stubs.clear();
port_counter = 0;
mod->str = *$3;
@ -219,7 +235,8 @@ module:
frontend_verilog_yyerror("Missing details for module port `%s'.",
port_stubs.begin()->first.c_str());
ast_stack.pop_back();
assert(ast_stack.size() == 0);
log_assert(ast_stack.size() == 1);
current_ast_mod = NULL;
};
module_para_opt:
@ -288,7 +305,10 @@ module_arg:
ast_stack.back()->children.push_back(node);
append_attr(node, $1);
delete $4;
} module_arg_opt_assignment;
} module_arg_opt_assignment |
'.' '.' '.' {
do_not_require_port_stubs = true;
};
wire_type:
{
@ -320,6 +340,7 @@ wire_type_token:
astbuf3->is_reg = true;
astbuf3->range_left = 31;
astbuf3->range_right = 0;
astbuf3->is_signed = true;
} |
TOK_GENVAR {
astbuf3->type = AST_GENVAR;
@ -352,6 +373,15 @@ non_opt_range:
$$->children.push_back($2);
};
non_opt_multirange:
non_opt_range non_opt_range {
$$ = new AstNode(AST_MULTIRANGE, $1, $2);
} |
non_opt_multirange non_opt_range {
$$ = $1;
$$->children.push_back($2);
};
range:
non_opt_range {
$$ = $1;
@ -360,44 +390,120 @@ range:
$$ = NULL;
};
range_or_multirange:
range { $$ = $1; } |
non_opt_multirange { $$ = $1; };
range_or_signed_int:
range {
$$ = $1;
} |
TOK_INTEGER {
$$ = new AstNode(AST_RANGE);
$$->children.push_back(AstNode::mkconst_int(31, true));
$$->children.push_back(AstNode::mkconst_int(0, true));
$$->is_signed = true;
};
module_body:
module_body module_body_stmt |
/* the following line makes the generate..endgenrate keywords optional */
module_body gen_stmt |
/* empty */;
module_body_stmt:
task_func_decl | param_decl | localparam_decl | defparam_decl | wire_decl | assign_stmt | cell_stmt |
always_stmt | TOK_GENERATE module_gen_body TOK_ENDGENERATE | defattr | assert;
always_stmt | TOK_GENERATE module_gen_body TOK_ENDGENERATE | defattr | assert_property;
task_func_decl:
TOK_TASK TOK_ID ';' {
attr TOK_DPI_FUNCTION TOK_ID TOK_ID {
current_function_or_task = new AstNode(AST_DPI_FUNCTION, AstNode::mkconst_str(*$3), AstNode::mkconst_str(*$4));
current_function_or_task->str = *$4;
append_attr(current_function_or_task, $1);
ast_stack.back()->children.push_back(current_function_or_task);
delete $3;
delete $4;
} opt_dpi_function_args ';' {
current_function_or_task = NULL;
} |
attr TOK_DPI_FUNCTION TOK_ID '=' TOK_ID TOK_ID {
current_function_or_task = new AstNode(AST_DPI_FUNCTION, AstNode::mkconst_str(*$5), AstNode::mkconst_str(*$3));
current_function_or_task->str = *$6;
append_attr(current_function_or_task, $1);
ast_stack.back()->children.push_back(current_function_or_task);
delete $3;
delete $5;
delete $6;
} opt_dpi_function_args ';' {
current_function_or_task = NULL;
} |
attr TOK_DPI_FUNCTION TOK_ID ':' TOK_ID '=' TOK_ID TOK_ID {
current_function_or_task = new AstNode(AST_DPI_FUNCTION, AstNode::mkconst_str(*$7), AstNode::mkconst_str(*$3 + ":" + RTLIL::unescape_id(*$5)));
current_function_or_task->str = *$8;
append_attr(current_function_or_task, $1);
ast_stack.back()->children.push_back(current_function_or_task);
delete $3;
delete $5;
delete $7;
delete $8;
} opt_dpi_function_args ';' {
current_function_or_task = NULL;
} |
attr TOK_TASK TOK_ID ';' {
current_function_or_task = new AstNode(AST_TASK);
current_function_or_task->str = *$2;
current_function_or_task->str = *$3;
append_attr(current_function_or_task, $1);
ast_stack.back()->children.push_back(current_function_or_task);
ast_stack.push_back(current_function_or_task);
current_function_or_task_port_id = 1;
delete $2;
delete $3;
} task_func_body TOK_ENDTASK {
current_function_or_task = NULL;
ast_stack.pop_back();
} |
TOK_FUNCTION opt_signed range TOK_ID ';' {
attr TOK_FUNCTION opt_signed range_or_signed_int TOK_ID ';' {
current_function_or_task = new AstNode(AST_FUNCTION);
current_function_or_task->str = *$4;
current_function_or_task->str = *$5;
append_attr(current_function_or_task, $1);
ast_stack.back()->children.push_back(current_function_or_task);
ast_stack.push_back(current_function_or_task);
AstNode *outreg = new AstNode(AST_WIRE);
if ($3 != NULL)
outreg->children.push_back($3);
outreg->str = *$4;
outreg->is_signed = $2;
outreg->str = *$5;
outreg->is_signed = $3;
if ($4 != NULL) {
outreg->children.push_back($4);
outreg->is_signed = $3 || $4->is_signed;
$4->is_signed = false;
}
current_function_or_task->children.push_back(outreg);
current_function_or_task_port_id = 1;
delete $4;
delete $5;
} task_func_body TOK_ENDFUNCTION {
current_function_or_task = NULL;
ast_stack.pop_back();
};
dpi_function_arg:
TOK_ID TOK_ID {
current_function_or_task->children.push_back(AstNode::mkconst_str(*$1));
delete $1;
delete $2;
} |
TOK_ID {
current_function_or_task->children.push_back(AstNode::mkconst_str(*$1));
delete $1;
};
opt_dpi_function_args:
'(' dpi_function_args ')' |
/* empty */;
dpi_function_args:
dpi_function_args ',' dpi_function_arg |
dpi_function_args ',' |
dpi_function_arg |
/* empty */;
opt_signed:
TOK_SIGNED {
$$ = true;
@ -422,6 +528,14 @@ param_integer:
astbuf1->children.push_back(new AstNode(AST_RANGE));
astbuf1->children.back()->children.push_back(AstNode::mkconst_int(31, true));
astbuf1->children.back()->children.push_back(AstNode::mkconst_int(0, true));
astbuf1->is_signed = true;
} | /* empty */;
param_real:
TOK_REAL {
if (astbuf1->children.size() != 1)
frontend_verilog_yyerror("Syntax error.");
astbuf1->children.push_back(new AstNode(AST_REALVALUE));
} | /* empty */;
param_range:
@ -437,7 +551,7 @@ param_decl:
TOK_PARAMETER {
astbuf1 = new AstNode(AST_PARAMETER);
astbuf1->children.push_back(AstNode::mkconst_int(0, true));
} param_signed param_integer param_range param_decl_list ';' {
} param_signed param_integer param_real param_range param_decl_list ';' {
delete astbuf1;
};
@ -445,7 +559,7 @@ localparam_decl:
TOK_LOCALPARAM {
astbuf1 = new AstNode(AST_LOCALPARAM);
astbuf1->children.push_back(AstNode::mkconst_int(0, true));
} param_signed param_integer param_range param_decl_list ';' {
} param_signed param_integer param_real param_range param_decl_list ';' {
delete astbuf1;
};
@ -533,7 +647,7 @@ wire_name_and_opt_assign:
};
wire_name:
TOK_ID range {
TOK_ID range_or_multirange {
AstNode *node = astbuf1->clone();
node->str = *$1;
append_attr_clone(node, albuf);
@ -552,6 +666,9 @@ wire_name:
node->children.push_back($2);
}
if (current_function_or_task == NULL) {
if (do_not_require_port_stubs && (node->is_input || node->is_output) && port_stubs.count(*$1) == 0) {
port_stubs[*$1] = ++port_counter;
}
if (port_stubs.count(*$1) != 0) {
if (!node->is_input && !node->is_output)
frontend_verilog_yyerror("Module port `%s' is neither input nor output.", $1->c_str());
@ -563,12 +680,11 @@ wire_name:
if (node->is_input || node->is_output)
frontend_verilog_yyerror("Module port `%s' is not declared in module header.", $1->c_str());
}
ast_stack.back()->children.push_back(node);
} else {
if (node->is_input || node->is_output)
node->port_id = current_function_or_task_port_id++;
current_function_or_task->children.push_back(node);
}
ast_stack.back()->children.push_back(node);
delete $1;
};
@ -621,6 +737,13 @@ single_cell:
astbuf2->str = *$1;
delete $1;
ast_stack.back()->children.push_back(astbuf2);
} '(' cell_port_list ')' |
TOK_ID non_opt_range {
astbuf2 = astbuf1->clone();
if (astbuf2->type != AST_PRIMITIVE)
astbuf2->str = *$1;
delete $1;
ast_stack.back()->children.push_back(new AstNode(AST_CELLARRAY, $2, astbuf2));
} '(' cell_port_list ')';
prim_list:
@ -753,6 +876,11 @@ assert:
ast_stack.back()->children.push_back(new AstNode(AST_ASSERT, $3));
};
assert_property:
TOK_ASSERT TOK_PROPERTY '(' expr ')' ';' {
ast_stack.back()->children.push_back(new AstNode(AST_ASSERT, $4));
};
simple_behavioral_stmt:
lvalue '=' expr {
AstNode *node = new AstNode(AST_ASSIGN_EQ, $1, $3);
@ -808,6 +936,32 @@ behavioral_stmt:
ast_stack.pop_back();
ast_stack.pop_back();
} |
attr TOK_WHILE '(' expr ')' {
AstNode *node = new AstNode(AST_WHILE);
ast_stack.back()->children.push_back(node);
ast_stack.push_back(node);
append_attr(node, $1);
AstNode *block = new AstNode(AST_BLOCK);
ast_stack.back()->children.push_back($4);
ast_stack.back()->children.push_back(block);
ast_stack.push_back(block);
} behavioral_stmt {
ast_stack.pop_back();
ast_stack.pop_back();
} |
attr TOK_REPEAT '(' expr ')' {
AstNode *node = new AstNode(AST_REPEAT);
ast_stack.back()->children.push_back(node);
ast_stack.push_back(node);
append_attr(node, $1);
AstNode *block = new AstNode(AST_BLOCK);
ast_stack.back()->children.push_back($4);
ast_stack.back()->children.push_back(block);
ast_stack.push_back(block);
} behavioral_stmt {
ast_stack.pop_back();
ast_stack.pop_back();
} |
attr TOK_IF '(' expr ')' {
AstNode *node = new AstNode(AST_CASE);
AstNode *block = new AstNode(AST_BLOCK);
@ -934,8 +1088,8 @@ rvalue:
$$->str = *$1;
delete $1;
} |
hierarchical_id non_opt_range non_opt_range {
$$ = new AstNode(AST_IDENTIFIER, $2, $3);
hierarchical_id non_opt_multirange {
$$ = new AstNode(AST_IDENTIFIER, $2);
$$->str = *$1;
delete $1;
};
@ -976,9 +1130,12 @@ single_arg:
};
module_gen_body:
module_gen_body gen_stmt |
module_gen_body gen_stmt_or_module_body_stmt |
/* empty */;
gen_stmt_or_module_body_stmt:
gen_stmt | module_body_stmt;
// this production creates the obligatory if-else shift/reduce conflict
gen_stmt:
TOK_FOR '(' {
@ -1017,15 +1174,14 @@ gen_stmt:
if ($6 != NULL)
delete $6;
ast_stack.pop_back();
} |
module_body_stmt;
};
gen_stmt_block:
{
AstNode *node = new AstNode(AST_GENBLOCK);
ast_stack.back()->children.push_back(node);
ast_stack.push_back(node);
} gen_stmt {
} gen_stmt_or_module_body_stmt {
ast_stack.pop_back();
};
@ -1073,12 +1229,30 @@ basic_expr:
delete $1;
delete $2;
} |
TOK_CONST TOK_CONST {
$$ = const2ast(*$1 + *$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back());
if ($$ == NULL || (*$2)[0] != '\'')
log_error("Value conversion failed: `%s%s'\n", $1->c_str(), $2->c_str());
delete $1;
delete $2;
} |
TOK_CONST {
$$ = const2ast(*$1, case_type_stack.size() == 0 ? 0 : case_type_stack.back());
if ($$ == NULL)
log_error("Value conversion failed: `%s'\n", $1->c_str());
delete $1;
} |
TOK_REALVAL {
$$ = new AstNode(AST_REALVALUE);
char *p = strdup($1->c_str()), *q;
for (int i = 0, j = 0; !p[j]; j++)
if (p[j] != '_')
p[i++] = p[j], p[i] = 0;
$$->realvalue = strtod(p, &q);
log_assert(*q == 0);
delete $1;
free(p);
} |
TOK_STRING {
$$ = AstNode::mkconst_str(*$1);
delete $1;

View file

@ -37,7 +37,8 @@
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
YOSYS_NAMESPACE_BEGIN
static std::list<std::string> output_code;
static std::list<std::string> input_buffer;
@ -65,7 +66,7 @@ static char next_char()
if (input_buffer.empty())
return 0;
assert(input_buffer_charp <= input_buffer.front().size());
log_assert(input_buffer_charp <= input_buffer.front().size());
if (input_buffer_charp == input_buffer.front().size()) {
input_buffer_charp = 0;
input_buffer.pop_front();
@ -130,6 +131,12 @@ static std::string next_token(bool pass_newline = false)
token += ch;
}
}
if (token == "\"\"" && (ch = next_char()) != 0) {
if (ch == '"')
token += ch;
else
return_char(ch);
}
}
else if (ch == '/')
{
@ -186,7 +193,7 @@ static std::string next_token(bool pass_newline = false)
return token;
}
static void input_file(FILE *f, std::string filename)
static void input_file(std::istream &f, std::string filename)
{
char buffer[513];
int rc;
@ -195,14 +202,14 @@ static void input_file(FILE *f, std::string filename)
auto it = input_buffer.begin();
input_buffer.insert(it, "`file_push " + filename + "\n");
while ((rc = fread(buffer, 1, sizeof(buffer)-1, f)) > 0) {
while ((rc = f.readsome(buffer, sizeof(buffer)-1)) > 0) {
buffer[rc] = 0;
input_buffer.insert(it, buffer);
}
input_buffer.insert(it, "`file_pop\n");
input_buffer.insert(it, "\n`file_pop\n");
}
std::string frontend_verilog_preproc(FILE *f, std::string filename, const std::map<std::string, std::string> pre_defines_map, const std::list<std::string> include_dirs)
std::string frontend_verilog_preproc(std::istream &f, std::string filename, const std::map<std::string, std::string> pre_defines_map, const std::list<std::string> include_dirs)
{
std::set<std::string> defines_with_args;
std::map<std::string, std::string> defines_map(pre_defines_map);
@ -281,27 +288,28 @@ std::string frontend_verilog_preproc(FILE *f, std::string filename, const std::m
else
fn = fn.substr(0, pos) + fn.substr(pos+1);
}
FILE *fp = fopen(fn.c_str(), "r");
if (fp == NULL && fn.size() > 0 && fn[0] != '/' && filename.find('/') != std::string::npos) {
std::ifstream ff;
ff.clear();
ff.open(fn.c_str());
if (ff.fail() && fn.size() > 0 && fn[0] != '/' && filename.find('/') != std::string::npos) {
// if the include file was not found, it is not given with an absolute path, and the
// currently read file is given with a path, then try again relative to its directory
std::string fn2 = filename.substr(0, filename.rfind('/')+1) + fn;
fp = fopen(fn2.c_str(), "r");
ff.clear();
ff.open(filename.substr(0, filename.rfind('/')+1) + fn);
}
if (fp == NULL && fn.size() > 0 && fn[0] != '/') {
if (ff.fail() && fn.size() > 0 && fn[0] != '/') {
// if the include file was not found and it is not given with an absolute path, then
// search it in the include path
for (auto incdir : include_dirs) {
std::string fn2 = incdir + '/' + fn;
fp = fopen(fn2.c_str(), "r");
if (fp != NULL) break;
ff.clear();
ff.open(incdir + '/' + fn);
if (!ff.fail()) break;
}
}
if (fp != NULL) {
input_file(fp, fn);
fclose(fp);
} else
output_code.push_back("`file_notfound " + fn + "\n");
if (ff.fail())
output_code.push_back("`file_notfound " + fn);
else
input_file(ff, fn);
continue;
}
@ -310,12 +318,17 @@ std::string frontend_verilog_preproc(FILE *f, std::string filename, const std::m
std::map<std::string, int> args;
skip_spaces();
name = next_token(true);
bool here_doc_mode = false;
int newline_count = 0;
int state = 0;
if (skip_spaces() != "")
state = 3;
while (!tok.empty()) {
tok = next_token();
if (tok == "\"\"\"") {
here_doc_mode = !here_doc_mode;
continue;
}
if (state == 0 && tok == "(") {
state = 1;
skip_spaces();
@ -332,9 +345,14 @@ std::string frontend_verilog_preproc(FILE *f, std::string filename, const std::m
if (state != 2)
state = 3;
if (tok == "\n") {
return_char('\n');
break;
}
if (here_doc_mode) {
value += " ";
newline_count++;
} else {
return_char('\n');
break;
}
} else
if (tok == "\\") {
char ch = next_char();
if (ch == '\n') {
@ -373,7 +391,6 @@ std::string frontend_verilog_preproc(FILE *f, std::string filename, const std::m
}
if (tok == "`timescale") {
std::string name;
skip_spaces();
while (!tok.empty() && tok != "\n")
tok = next_token(true);
@ -429,3 +446,5 @@ std::string frontend_verilog_preproc(FILE *f, std::string filename, const std::m
return output;
}
YOSYS_NAMESPACE_END

View file

@ -27,13 +27,11 @@
*/
#include "verilog_frontend.h"
#include "kernel/register.h"
#include "kernel/log.h"
#include "kernel/yosys.h"
#include "libs/sha1/sha1.h"
#include <sstream>
#include <stdarg.h>
#include <assert.h>
YOSYS_NAMESPACE_BEGIN
using namespace VERILOG_FRONTEND;
// use the Verilog bison/flex parser to generate an AST and use AST::process() to convert it to RTLIL
@ -47,11 +45,15 @@ struct VerilogFrontend : public Frontend {
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" read_verilog [filename]\n");
log(" read_verilog [options] [filename]\n");
log("\n");
log("Load modules from a verilog file to the current design. A large subset of\n");
log("Verilog-2005 is supported.\n");
log("\n");
log(" -sv\n");
log(" enable support for SystemVerilog features. (only a small subset\n");
log(" of SystemVerilog is supported)\n");
log("\n");
log(" -dump_ast1\n");
log(" dump abstract syntax tree (before simplification)\n");
log("\n");
@ -106,6 +108,11 @@ struct VerilogFrontend : public Frontend {
log(" ignore re-definitions of modules. (the default behavior is to\n");
log(" create an error message.)\n");
log("\n");
log(" -defer\n");
log(" only read the abstract syntax tree and defer actual compilation\n");
log(" to a later 'hierarchy' command. Useful in cases where the default\n");
log(" parameters of modules yield invalid or not synthesizable code.\n");
log("\n");
log(" -setattr <attribute_name>\n");
log(" set the specified attribute (to the value 1) on all loaded modules\n");
log("\n");
@ -120,8 +127,13 @@ struct VerilogFrontend : public Frontend {
log("The command 'verilog_defaults' can be used to register default options for\n");
log("subsequent calls to 'read_verilog'.\n");
log("\n");
log("Note that the Verilog frontend does a pretty good job of processing valid\n");
log("verilog input, but has not very good error reporting. It generally is\n");
log("recommended to use a simulator (for example icarus verilog) for checking\n");
log("the syntax of the code, rather than to rely on read_verilog for that.\n");
log("\n");
}
virtual void execute(FILE *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
{
bool flag_dump_ast1 = false;
bool flag_dump_ast2 = false;
@ -135,10 +147,13 @@ struct VerilogFrontend : public Frontend {
bool flag_noopt = false;
bool flag_icells = false;
bool flag_ignore_redef = false;
bool flag_defer = false;
std::map<std::string, std::string> defines_map;
std::list<std::string> include_dirs;
std::list<std::string> attributes;
frontend_verilog_yydebug = false;
sv_mode = false;
log_header("Executing Verilog-2005 frontend.\n");
@ -147,6 +162,10 @@ struct VerilogFrontend : public Frontend {
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
std::string arg = args[argidx];
if (arg == "-sv") {
sv_mode = true;
continue;
}
if (arg == "-dump_ast1") {
flag_dump_ast1 = true;
continue;
@ -199,6 +218,10 @@ struct VerilogFrontend : public Frontend {
flag_ignore_redef = true;
continue;
}
if (arg == "-defer") {
flag_defer = true;
continue;
}
if (arg == "-setattr" && argidx+1 < args.size()) {
attributes.push_back(RTLIL::escape_id(args[++argidx]));
continue;
@ -241,33 +264,34 @@ struct VerilogFrontend : public Frontend {
AST::get_line_num = &frontend_verilog_yyget_lineno;
current_ast = new AST::AstNode(AST::AST_DESIGN);
default_nettype_wire = true;
FILE *fp = f;
lexin = f;
std::string code_after_preproc;
if (!flag_nopp) {
code_after_preproc = frontend_verilog_preproc(f, filename, defines_map, include_dirs);
code_after_preproc = frontend_verilog_preproc(*f, filename, defines_map, include_dirs);
if (flag_ppdump)
log("-- Verilog code after preprocessor --\n%s-- END OF DUMP --\n", code_after_preproc.c_str());
fp = fmemopen((void*)code_after_preproc.c_str(), code_after_preproc.size(), "r");
lexin = new std::istringstream(code_after_preproc);
}
frontend_verilog_yyset_lineno(1);
frontend_verilog_yyrestart(fp);
frontend_verilog_yyrestart(NULL);
frontend_verilog_yyparse();
frontend_verilog_yylex_destroy();
for (auto &child : current_ast->children) {
log_assert(child->type == AST::AST_MODULE);
for (auto &attr : attributes)
if (child->attributes.count(attr) == 0)
child->attributes[attr] = AST::AstNode::mkconst_int(1, false);
if (child->type == AST::AST_MODULE)
for (auto &attr : attributes)
if (child->attributes.count(attr) == 0)
child->attributes[attr] = AST::AstNode::mkconst_int(1, false);
}
AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, flag_nolatches, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_ignore_redef);
AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, flag_nolatches, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_ignore_redef, flag_defer, default_nettype_wire);
if (!flag_nopp)
fclose(fp);
delete lexin;
delete current_ast;
current_ast = NULL;
@ -350,3 +374,5 @@ struct VerilogDefaults : public Pass {
}
} VerilogDefaults;
YOSYS_NAMESPACE_END

View file

@ -29,12 +29,14 @@
#ifndef VERILOG_FRONTEND_H
#define VERILOG_FRONTEND_H
#include "kernel/rtlil.h"
#include "kernel/yosys.h"
#include "frontends/ast/ast.h"
#include <stdio.h>
#include <stdint.h>
#include <list>
YOSYS_NAMESPACE_BEGIN
namespace VERILOG_FRONTEND
{
// this variable is set to a new AST_DESIGN node and then filled with the AST by the bison parser
@ -42,10 +44,21 @@ namespace VERILOG_FRONTEND
// this function converts a Verilog constant to an AST_CONSTANT node
AST::AstNode *const2ast(std::string code, char case_type = 0);
// state of `default_nettype
extern bool default_nettype_wire;
// running in SystemVerilog mode
extern bool sv_mode;
// lexer input stream
extern std::istream *lexin;
}
// the pre-processor
std::string frontend_verilog_preproc(FILE *f, std::string filename, const std::map<std::string, std::string> pre_defines_map, const std::list<std::string> include_dirs);
std::string frontend_verilog_preproc(std::istream &f, std::string filename, const std::map<std::string, std::string> pre_defines_map, const std::list<std::string> include_dirs);
YOSYS_NAMESPACE_END
// the usual bison/flex stuff
extern int frontend_verilog_yydebug;

View file

@ -0,0 +1 @@
OBJS += frontends/vhdl2verilog/vhdl2verilog.o

View file

@ -0,0 +1,196 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include "kernel/register.h"
#include "kernel/sigtools.h"
#include "kernel/log.h"
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <errno.h>
#include <limits.h>
YOSYS_NAMESPACE_BEGIN
struct Vhdl2verilogPass : public Pass {
Vhdl2verilogPass() : Pass("vhdl2verilog", "importing VHDL designs using vhdl2verilog") { }
virtual void help()
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" vhdl2verilog [options] <vhdl-file>..\n");
log("\n");
log("This command reads VHDL source files using the 'vhdl2verilog' tool and the\n");
log("Yosys Verilog frontend.\n");
log("\n");
log(" -out <out_file>\n");
log(" do not import the vhdl2verilog output. instead write it to the\n");
log(" specified file.\n");
log("\n");
log(" -vhdl2verilog_dir <directory>\n");
log(" do use the specified vhdl2verilog installation. this is the directory\n");
log(" that contains the setup_env.sh file. when this option is not present,\n");
log(" it is assumed that vhdl2verilog is in the PATH environment variable.\n");
log("\n");
log(" -top <top-entity-name>\n");
log(" The name of the top entity. This option is mandatory.\n");
log("\n");
log("The following options are passed as-is to vhdl2verilog:\n");
log("\n");
log(" -arch <architecture_name>\n");
log(" -unroll_generate\n");
log(" -nogenericeval\n");
log(" -nouniquify\n");
log(" -oldparser\n");
log(" -suppress <list>\n");
log(" -quiet\n");
log(" -nobanner\n");
log(" -mapfile <file>\n");
log("\n");
log("vhdl2verilog can be obtained from:\n");
log("http://www.edautils.com/vhdl2verilog.html\n");
log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
log_header("Executing VHDL2VERILOG (importing VHDL designs using vhdl2verilog).\n");
log_push();
std::string out_file, top_entity;
std::string vhdl2verilog_dir;
std::string extra_opts;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
if (args[argidx] == "-out" && argidx+1 < args.size()) {
out_file = args[++argidx];
continue;
}
if (args[argidx] == "-top" && argidx+1 < args.size()) {
top_entity = args[++argidx];
continue;
}
if (args[argidx] == "-vhdl2verilog_dir" && argidx+1 < args.size()) {
vhdl2verilog_dir = args[++argidx];
continue;
}
if ((args[argidx] == "-arch" || args[argidx] == "-suppress" || args[argidx] == "-mapfile") && argidx+1 < args.size()) {
if (args[argidx] == "-mapfile" && !args[argidx+1].empty() && args[argidx+1][0] != '/') {
char pwd[PATH_MAX];
if (!getcwd(pwd, sizeof(pwd))) {
log_cmd_error("getcwd failed: %s", strerror(errno));
log_abort();
}
args[argidx+1] = pwd + ("/" + args[argidx+1]);
}
extra_opts += std::string(" ") + args[argidx];
extra_opts += std::string(" '") + args[++argidx] + std::string("'");
continue;
}
if (args[argidx] == "-unroll_generate" || args[argidx] == "-nogenericeval" || args[argidx] == "-nouniquify" ||
args[argidx] == "-oldparser" || args[argidx] == "-quiet" || args[argidx] == "-nobanner") {
extra_opts += std::string(" ") + args[argidx];
continue;
}
break;
}
if (argidx == args.size())
cmd_error(args, argidx, "Missing filenames.");
if (args[argidx].substr(0, 1) == "-")
cmd_error(args, argidx, "Unknown option.");
if (top_entity.empty())
log_cmd_error("Missing -top option.\n");
char tempdir_name[] = "/tmp/yosys-vhdl2verilog-XXXXXX";
char *p = mkdtemp(tempdir_name);
log("Using temp directory %s.\n", tempdir_name);
if (p == NULL)
log_error("For some reason mkdtemp() failed!\n");
if (!out_file.empty() && out_file[0] != '/') {
char pwd[PATH_MAX];
if (!getcwd(pwd, sizeof(pwd))) {
log_cmd_error("getcwd failed: %s", strerror(errno));
log_abort();
}
out_file = pwd + ("/" + out_file);
}
FILE *f = fopen(stringf("%s/files.list", tempdir_name).c_str(), "wt");
while (argidx < args.size()) {
std::string file = args[argidx++];
if (file.empty())
continue;
if (file[0] != '/') {
char pwd[PATH_MAX];
if (!getcwd(pwd, sizeof(pwd))) {
log_cmd_error("getcwd failed: %s", strerror(errno));
log_abort();
}
file = pwd + ("/" + file);
}
fprintf(f, "%s\n", file.c_str());
log("Adding '%s' to the file list.\n", file.c_str());
}
fclose(f);
std::string command = "exec 2>&1; ";
if (!vhdl2verilog_dir.empty())
command += stringf("cd '%s'; . ./setup_env.sh; ", vhdl2verilog_dir.c_str());
command += stringf("cd '%s'; vhdl2verilog -out '%s' -filelist files.list -top '%s'%s", tempdir_name,
out_file.empty() ? "vhdl2verilog_output.v" : out_file.c_str(), top_entity.c_str(), extra_opts.c_str());
log("Running '%s'..\n", command.c_str());
errno = ENOMEM; // popen does not set errno if memory allocation fails, therefore set it by hand
f = popen(command.c_str(), "r");
if (f == NULL)
log_error("Opening pipe to `%s' for reading failed: %s\n", command.c_str(), strerror(errno));
char logbuf[1024];
while (fgets(logbuf, 1024, f) != NULL)
log("%s", logbuf);
int ret = pclose(f);
if (ret < 0)
log_error("Closing pipe to `%s' failed: %s\n", command.c_str(), strerror(errno));
if (WEXITSTATUS(ret) != 0)
log_error("Execution of command \"%s\" failed: the shell returned %d\n", command.c_str(), WEXITSTATUS(ret));
if (out_file.empty()) {
std::ifstream ff;
ff.open(stringf("%s/vhdl2verilog_output.v", tempdir_name).c_str());
if (ff.fail())
log_error("Can't open vhdl2verilog output file `vhdl2verilog_output.v'.\n");
Frontend::frontend_call(design, &ff, stringf("%s/vhdl2verilog_output.v", tempdir_name), "verilog");
}
log_header("Removing temp directory `%s':\n", tempdir_name);
if (system(stringf("rm -rf '%s'", tempdir_name).c_str()) != 0)
log_error("Execution of \"rm -rf '%s'\" failed!\n", tempdir_name);
log_pop();
}
} Vhdl2verilogPass;
YOSYS_NAMESPACE_END

View file

@ -31,16 +31,12 @@ struct BitPatternPool
BitPatternPool(RTLIL::SigSpec sig)
{
width = sig.width;
width = sig.size();
if (width > 0) {
std::vector<RTLIL::State> pattern(width);
sig.optimize();
for (int i = 0; i < width; i++) {
RTLIL::SigSpec s = sig.extract(i, 1);
s.optimize();
assert(s.chunks.size() == 1);
if (s.chunks[0].wire == NULL && s.chunks[0].data.bits[0] <= RTLIL::State::S1)
pattern[i] = s.chunks[0].data.bits[0];
if (sig[i].wire == NULL && sig[i].data <= RTLIL::State::S1)
pattern[i] = sig[i].data;
else
pattern[i] = RTLIL::State::Sa;
}
@ -61,10 +57,7 @@ struct BitPatternPool
bits_t sig2bits(RTLIL::SigSpec sig)
{
sig.optimize();
assert(sig.is_fully_const());
assert(sig.chunks.size() == 1);
bits_t bits = sig.chunks[0].data.bits;
bits_t bits = sig.as_const().bits;
for (auto &b : bits)
if (b > RTLIL::State::S1)
b = RTLIL::State::Sa;
@ -73,8 +66,8 @@ struct BitPatternPool
bool match(bits_t a, bits_t b)
{
assert(int(a.size()) == width);
assert(int(b.size()) == width);
log_assert(int(a.size()) == width);
log_assert(int(b.size()) == width);
for (int i = 0; i < width; i++)
if (a[i] <= RTLIL::State::S1 && b[i] <= RTLIL::State::S1 && a[i] != b[i])
return false;

View file

@ -21,21 +21,10 @@
// Schneier, Bruce (1996). Applied Cryptography: Protocols, Algorithms, and Source Code in C,
// Second Edition (2nd ed.). Wiley. ISBN 978-0-471-11709-4, page 244
#include "kernel/log.h"
#include "kernel/rtlil.h"
#include "kernel/yosys.h"
#include "libs/bigint/BigIntegerLibrary.hh"
#include <assert.h>
static void extend(RTLIL::Const &arg, int width, bool is_signed)
{
RTLIL::State padding = RTLIL::State::S0;
if (arg.bits.size() > 0 && (is_signed || arg.bits.back() > RTLIL::State::S1))
padding = arg.bits.back();
while (int(arg.bits.size()) < width)
arg.bits.push_back(padding);
}
YOSYS_NAMESPACE_BEGIN
static void extend_u0(RTLIL::Const &arg, int width, bool is_signed)
{
@ -46,6 +35,8 @@ static void extend_u0(RTLIL::Const &arg, int width, bool is_signed)
while (int(arg.bits.size()) < width)
arg.bits.push_back(padding);
arg.bits.resize(width);
}
static BigInteger const2big(const RTLIL::Const &val, bool as_signed, int &undef_bit_pos)
@ -277,7 +268,7 @@ RTLIL::Const RTLIL::const_logic_or(const RTLIL::Const &arg1, const RTLIL::Const
return result;
}
static RTLIL::Const const_shift(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool sign_ext, int direction, int result_len)
static RTLIL::Const const_shift_worker(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool sign_ext, int direction, int result_len)
{
int undef_bit_pos = -1;
BigInteger offset = const2big(arg2, false, undef_bit_pos) * direction;
@ -305,29 +296,62 @@ static RTLIL::Const const_shift(const RTLIL::Const &arg1, const RTLIL::Const &ar
RTLIL::Const RTLIL::const_shl(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool, int result_len)
{
RTLIL::Const arg1_ext = arg1;
extend(arg1_ext, result_len, signed1);
return const_shift(arg1_ext, arg2, false, -1, result_len);
extend_u0(arg1_ext, result_len, signed1);
return const_shift_worker(arg1_ext, arg2, false, -1, result_len);
}
RTLIL::Const RTLIL::const_shr(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool, int result_len)
{
RTLIL::Const arg1_ext = arg1;
extend(arg1_ext, result_len, signed1);
return const_shift(arg1_ext, arg2, false, +1, result_len);
extend_u0(arg1_ext, std::max(result_len, SIZE(arg1)), signed1);
return const_shift_worker(arg1_ext, arg2, false, +1, result_len);
}
RTLIL::Const RTLIL::const_sshl(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
{
if (!signed1)
return const_shl(arg1, arg2, signed1, signed2, result_len);
return const_shift(arg1, arg2, true, -1, result_len);
return const_shift_worker(arg1, arg2, true, -1, result_len);
}
RTLIL::Const RTLIL::const_sshr(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
{
if (!signed1)
return const_shr(arg1, arg2, signed1, signed2, result_len);
return const_shift(arg1, arg2, true, +1, result_len);
return const_shift_worker(arg1, arg2, true, +1, result_len);
}
static RTLIL::Const const_shift_shiftx(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool, bool signed2, int result_len, RTLIL::State other_bits)
{
int undef_bit_pos = -1;
BigInteger offset = const2big(arg2, signed2, undef_bit_pos);
if (result_len < 0)
result_len = arg1.bits.size();
RTLIL::Const result(RTLIL::State::Sx, result_len);
if (undef_bit_pos >= 0)
return result;
for (int i = 0; i < result_len; i++) {
BigInteger pos = BigInteger(i) + offset;
if (pos < 0 || pos >= arg1.bits.size())
result.bits[i] = other_bits;
else
result.bits[i] = arg1.bits[pos.toInt()];
}
return result;
}
RTLIL::Const RTLIL::const_shift(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
{
return const_shift_shiftx(arg1, arg2, signed1, signed2, result_len, RTLIL::State::S0);
}
RTLIL::Const RTLIL::const_shiftx(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
{
return const_shift_shiftx(arg1, arg2, signed1, signed2, result_len, RTLIL::State::Sx);
}
RTLIL::Const RTLIL::const_lt(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
@ -536,14 +560,6 @@ RTLIL::Const RTLIL::const_pow(const RTLIL::Const &arg1, const RTLIL::Const &arg2
}
RTLIL::Const RTLIL::const_pos(const RTLIL::Const &arg1, const RTLIL::Const&, bool signed1, bool, int result_len)
{
RTLIL::Const arg1_ext = arg1;
extend(arg1_ext, result_len, signed1);
return arg1_ext;
}
RTLIL::Const RTLIL::const_bu0(const RTLIL::Const &arg1, const RTLIL::Const&, bool signed1, bool, int result_len)
{
RTLIL::Const arg1_ext = arg1;
extend_u0(arg1_ext, result_len, signed1);
@ -554,9 +570,10 @@ RTLIL::Const RTLIL::const_bu0(const RTLIL::Const &arg1, const RTLIL::Const&, boo
RTLIL::Const RTLIL::const_neg(const RTLIL::Const &arg1, const RTLIL::Const&, bool signed1, bool, int result_len)
{
RTLIL::Const arg1_ext = arg1;
extend(arg1_ext, result_len, signed1);
RTLIL::Const zero(RTLIL::State::S0, 1);
return RTLIL::const_sub(zero, arg1_ext, false, signed1, result_len);
return RTLIL::const_sub(zero, arg1_ext, true, signed1, result_len);
}
YOSYS_NAMESPACE_END

View file

@ -20,202 +20,204 @@
#ifndef CELLTYPES_H
#define CELLTYPES_H
#include <set>
#include <string>
#include <stdlib.h>
#include <kernel/yosys.h>
#include <kernel/rtlil.h>
#include <kernel/log.h>
YOSYS_NAMESPACE_BEGIN
struct CellType
{
RTLIL::IdString type;
std::set<RTLIL::IdString> inputs, outputs;
bool is_evaluable;
};
struct CellTypes
{
std::set<std::string> cell_types;
std::vector<const RTLIL::Design*> designs;
std::map<RTLIL::IdString, CellType> cell_types;
CellTypes()
{
}
CellTypes(const RTLIL::Design *design)
CellTypes(RTLIL::Design *design)
{
setup(design);
}
void setup(const RTLIL::Design *design = NULL)
void setup(RTLIL::Design *design = NULL)
{
if (design)
setup_design(design);
setup_internals();
setup_internals_mem();
setup_stdcells();
setup_stdcells_mem();
}
void setup_design(const RTLIL::Design *design)
void setup_type(RTLIL::IdString type, const std::set<RTLIL::IdString> &inputs, const std::set<RTLIL::IdString> &outputs, bool is_evaluable = false)
{
designs.push_back(design);
CellType ct = {type, inputs, outputs, is_evaluable};
cell_types[ct.type] = ct;
}
void setup_module(RTLIL::Module *module)
{
std::set<RTLIL::IdString> inputs, outputs;
for (RTLIL::IdString wire_name : module->ports) {
RTLIL::Wire *wire = module->wire(wire_name);
if (wire->port_input)
inputs.insert(wire->name);
if (wire->port_output)
outputs.insert(wire->name);
}
setup_type(module->name, inputs, outputs);
}
void setup_design(RTLIL::Design *design)
{
for (auto module : design->modules())
setup_module(module);
}
void setup_internals()
{
cell_types.insert("$not");
cell_types.insert("$pos");
cell_types.insert("$bu0");
cell_types.insert("$neg");
cell_types.insert("$and");
cell_types.insert("$or");
cell_types.insert("$xor");
cell_types.insert("$xnor");
cell_types.insert("$reduce_and");
cell_types.insert("$reduce_or");
cell_types.insert("$reduce_xor");
cell_types.insert("$reduce_xnor");
cell_types.insert("$reduce_bool");
cell_types.insert("$shl");
cell_types.insert("$shr");
cell_types.insert("$sshl");
cell_types.insert("$sshr");
cell_types.insert("$lt");
cell_types.insert("$le");
cell_types.insert("$eq");
cell_types.insert("$ne");
cell_types.insert("$eqx");
cell_types.insert("$nex");
cell_types.insert("$ge");
cell_types.insert("$gt");
cell_types.insert("$add");
cell_types.insert("$sub");
cell_types.insert("$mul");
cell_types.insert("$div");
cell_types.insert("$mod");
cell_types.insert("$pow");
cell_types.insert("$logic_not");
cell_types.insert("$logic_and");
cell_types.insert("$logic_or");
cell_types.insert("$mux");
cell_types.insert("$pmux");
cell_types.insert("$slice");
cell_types.insert("$concat");
cell_types.insert("$safe_pmux");
cell_types.insert("$lut");
cell_types.insert("$assert");
std::vector<RTLIL::IdString> unary_ops = {
"$not", "$pos", "$neg",
"$reduce_and", "$reduce_or", "$reduce_xor", "$reduce_xnor", "$reduce_bool",
"$logic_not", "$slice", "$lut"
};
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"
};
for (auto type : unary_ops)
setup_type(type, {"\\A"}, {"\\Y"}, true);
for (auto type : binary_ops)
setup_type(type, {"\\A", "\\B"}, {"\\Y"}, true);
for (auto type : std::vector<RTLIL::IdString>({"$mux", "$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("$assert", {"\\A", "\\EN"}, std::set<RTLIL::IdString>(), true);
}
void setup_internals_mem()
{
cell_types.insert("$sr");
cell_types.insert("$dff");
cell_types.insert("$dffsr");
cell_types.insert("$adff");
cell_types.insert("$dlatch");
cell_types.insert("$memrd");
cell_types.insert("$memwr");
cell_types.insert("$mem");
cell_types.insert("$fsm");
setup_type("$sr", {"\\SET", "\\CLR"}, {"\\Q"});
setup_type("$dff", {"\\CLK", "\\D"}, {"\\Q"});
setup_type("$dffsr", {"\\CLK", "\\SET", "\\CLR", "\\D"}, {"\\Q"});
setup_type("$adff", {"\\CLK", "\\ARST", "\\D"}, {"\\Q"});
setup_type("$dlatch", {"\\EN", "\\D"}, {"\\Q"});
setup_type("$dlatchsr", {"\\EN", "\\SET", "\\CLR", "\\D"}, {"\\Q"});
setup_type("$memrd", {"\\CLK", "\\ADDR"}, {"\\DATA"});
setup_type("$memwr", {"\\CLK", "\\EN", "\\ADDR", "\\DATA"}, std::set<RTLIL::IdString>());
setup_type("$mem", {"\\RD_CLK", "\\RD_ADDR", "\\WR_CLK", "\\WR_EN", "\\WR_ADDR", "\\WR_DATA"}, {"\\RD_DATA"});
setup_type("$fsm", {"\\CLK", "\\ARST", "\\CTRL_IN"}, {"\\CTRL_OUT"});
}
void setup_stdcells()
{
cell_types.insert("$_INV_");
cell_types.insert("$_AND_");
cell_types.insert("$_OR_");
cell_types.insert("$_XOR_");
cell_types.insert("$_MUX_");
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("$_MUX_", {"\\A", "\\B", "\\S"}, {"\\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);
}
void setup_stdcells_mem()
{
cell_types.insert("$_SR_NN_");
cell_types.insert("$_SR_NP_");
cell_types.insert("$_SR_PN_");
cell_types.insert("$_SR_PP_");
cell_types.insert("$_DFF_N_");
cell_types.insert("$_DFF_P_");
cell_types.insert("$_DFF_NN0_");
cell_types.insert("$_DFF_NN1_");
cell_types.insert("$_DFF_NP0_");
cell_types.insert("$_DFF_NP1_");
cell_types.insert("$_DFF_PN0_");
cell_types.insert("$_DFF_PN1_");
cell_types.insert("$_DFF_PP0_");
cell_types.insert("$_DFF_PP1_");
cell_types.insert("$_DFFSR_NNN_");
cell_types.insert("$_DFFSR_NNP_");
cell_types.insert("$_DFFSR_NPN_");
cell_types.insert("$_DFFSR_NPP_");
cell_types.insert("$_DFFSR_PNN_");
cell_types.insert("$_DFFSR_PNP_");
cell_types.insert("$_DFFSR_PPN_");
cell_types.insert("$_DFFSR_PPP_");
cell_types.insert("$_DLATCH_N_");
cell_types.insert("$_DLATCH_P_");
std::vector<char> list_np = {'N', 'P'}, list_01 = {'0', '1'};
for (auto c1 : list_np)
for (auto c2 : list_np)
setup_type(stringf("$_SR_%c%c_", c1, c2), {"\\S", "\\R"}, {"\\Q"});
for (auto c1 : list_np)
setup_type(stringf("$_DFF_%c_", c1), {"\\C", "\\D"}, {"\\Q"});
for (auto c1 : list_np)
for (auto c2 : list_np)
for (auto c3 : list_01)
setup_type(stringf("$_DFF_%c%c%c_", c1, c2, c3), {"\\C", "\\R", "\\D"}, {"\\Q"});
for (auto c1 : list_np)
for (auto c2 : list_np)
for (auto c3 : list_np)
setup_type(stringf("$_DFFSR_%c%c%c_", c1, c2, c3), {"\\C", "\\S", "\\R", "\\D"}, {"\\Q"});
for (auto c1 : list_np)
setup_type(stringf("$_DLATCH_%c_", c1), {"\\E", "\\D"}, {"\\Q"});
for (auto c1 : list_np)
for (auto c2 : list_np)
for (auto c3 : list_np)
setup_type(stringf("$_DLATCHSR_%c%c%c_", c1, c2, c3), {"\\E", "\\S", "\\R", "\\D"}, {"\\Q"});
}
void clear()
{
cell_types.clear();
designs.clear();
}
bool cell_known(std::string type)
bool cell_known(RTLIL::IdString type)
{
if (cell_types.count(type) > 0)
return true;
for (auto design : designs)
if (design->modules.count(type) > 0)
return true;
return false;
return cell_types.count(type) != 0;
}
bool cell_output(std::string type, std::string port)
bool cell_output(RTLIL::IdString type, RTLIL::IdString port)
{
if (cell_types.count(type) == 0) {
for (auto design : designs)
if (design->modules.count(type) > 0) {
if (design->modules.at(type)->wires.count(port))
return design->modules.at(type)->wires.at(port)->port_output;
return false;
}
return false;
}
if (port == "\\Y" || port == "\\Q" || port == "\\RD_DATA")
return true;
if (type == "$memrd" && port == "\\DATA")
return true;
if (type == "$fsm" && port == "\\CTRL_OUT")
return true;
if (type == "$lut" && port == "\\O")
return true;
return false;
auto it = cell_types.find(type);
return it != cell_types.end() && it->second.outputs.count(port) != 0;
}
bool cell_input(std::string type, std::string port)
bool cell_input(RTLIL::IdString type, RTLIL::IdString port)
{
if (cell_types.count(type) == 0) {
for (auto design : designs)
if (design->modules.count(type) > 0) {
if (design->modules.at(type)->wires.count(port))
return design->modules.at(type)->wires.at(port)->port_input;
return false;
}
return false;
}
if (cell_types.count(type) > 0)
return !cell_output(type, port);
return false;
auto it = cell_types.find(type);
return it != cell_types.end() && it->second.inputs.count(port) != 0;
}
static RTLIL::Const eval(std::string type, const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
bool cell_evaluable(RTLIL::IdString type)
{
auto it = cell_types.find(type);
return it != cell_types.end() && it->second.is_evaluable;
}
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;
return v;
}
static RTLIL::Const eval(RTLIL::IdString type, const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len)
{
if (type == "$sshr" && !signed1)
type = "$shr";
if (type == "$sshl" && !signed1)
type = "$shl";
if (type != "$sshr" && type != "$sshl" && type != "$shr" && type != "$shl" &&
if (type != "$sshr" && type != "$sshl" && type != "$shr" && type != "$shl" && type != "$shift" && type != "$shiftx" &&
type != "$pos" && type != "$neg" && type != "$not") {
if (!signed1 || !signed2)
signed1 = false, signed2 = false;
@ -239,6 +241,8 @@ struct CellTypes
HANDLE_CELL_TYPE(shr)
HANDLE_CELL_TYPE(sshl)
HANDLE_CELL_TYPE(sshr)
HANDLE_CELL_TYPE(shift)
HANDLE_CELL_TYPE(shiftx)
HANDLE_CELL_TYPE(lt)
HANDLE_CELL_TYPE(le)
HANDLE_CELL_TYPE(eq)
@ -254,18 +258,23 @@ struct CellTypes
HANDLE_CELL_TYPE(mod)
HANDLE_CELL_TYPE(pow)
HANDLE_CELL_TYPE(pos)
HANDLE_CELL_TYPE(bu0)
HANDLE_CELL_TYPE(neg)
#undef HANDLE_CELL_TYPE
if (type == "$_INV_")
return const_not(arg1, arg2, false, false, 1);
if (type == "$_NOT_")
return eval_not(arg1);
if (type == "$_AND_")
return const_and(arg1, arg2, false, false, 1);
if (type == "$_NAND_")
return eval_not(const_and(arg1, arg2, false, false, 1));
if (type == "$_OR_")
return const_or(arg1, arg2, false, false, 1);
if (type == "$_NOR_")
return eval_not(const_and(arg1, arg2, false, false, 1));
if (type == "$_XOR_")
return const_xor(arg1, arg2, false, false, 1);
if (type == "$_XNOR_")
return const_xnor(arg1, arg2, false, false, 1);
log_abort();
}
@ -286,28 +295,72 @@ struct CellTypes
return ret;
}
if (cell->type == "$lut")
{
int width = cell->parameters.at("\\WIDTH").as_int();
std::vector<RTLIL::State> t = cell->parameters.at("\\LUT").bits;
while (SIZE(t) < (1 << width))
t.push_back(RTLIL::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)
new_t = std::vector<RTLIL::State>(t.begin(), t.begin() + SIZE(t)/2);
else if (sel == RTLIL::S1)
new_t = std::vector<RTLIL::State>(t.begin() + SIZE(t)/2, t.end());
else
for (int j = 0; j < SIZE(t)/2; j++)
new_t.push_back(t[j] == t[j + SIZE(t)/2] ? t[j] : RTLIL::Sx);
t.swap(new_t);
}
log_assert(SIZE(t) == 1);
return t;
}
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);
}
static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &sel)
static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3)
{
if (cell->type == "$mux" || cell->type == "$pmux" || cell->type == "$safe_pmux" || cell->type == "$_MUX_") {
if (cell->type.in("$mux", "$pmux", "$_MUX_")) {
RTLIL::Const ret = arg1;
for (size_t i = 0; i < sel.bits.size(); i++)
if (sel.bits[i] == RTLIL::State::S1) {
for (size_t i = 0; i < arg3.bits.size(); i++)
if (arg3.bits[i] == RTLIL::State::S1) {
std::vector<RTLIL::State> bits(arg2.bits.begin() + i*arg1.bits.size(), arg2.bits.begin() + (i+1)*arg1.bits.size());
ret = RTLIL::Const(bits);
}
return ret;
}
assert(sel.bits.size() == 0);
if (cell->type == "$_AOI3_")
return eval_not(const_or(const_and(arg1, arg2, false, false, 1), arg3, false, false, 1));
if (cell->type == "$_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);
}
static RTLIL::Const eval(RTLIL::Cell *cell, const RTLIL::Const &arg1, const RTLIL::Const &arg2, const RTLIL::Const &arg3, const RTLIL::Const &arg4)
{
if (cell->type == "$_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));
log_assert(arg4.bits.size() == 0);
return eval(cell, arg1, arg2, arg3);
}
};
YOSYS_NAMESPACE_END
#endif

View file

@ -23,6 +23,7 @@
#include "kernel/rtlil.h"
#include "kernel/sigtools.h"
#include "kernel/celltypes.h"
#include "kernel/macc.h"
struct ConstEval
{
@ -40,10 +41,10 @@ struct ConstEval
ct.setup_internals();
ct.setup_stdcells();
for (auto &it : module->cells) {
for (auto &it : module->cells_) {
if (!ct.cell_known(it.second->type))
continue;
for (auto &it2 : it.second->connections)
for (auto &it2 : it.second->connections())
if (ct.cell_output(it.second->type, it2.first))
sig2driver.insert(assign_map(it2.second), it.second);
}
@ -71,11 +72,8 @@ struct ConstEval
assign_map.apply(sig);
#ifndef NDEBUG
RTLIL::SigSpec current_val = values_map(sig);
current_val.expand();
for (size_t i = 0; i < current_val.chunks.size(); i++) {
RTLIL::SigChunk &chunk = current_val.chunks[i];
assert(chunk.wire != NULL || chunk.data.bits[0] == value.bits[i]);
}
for (int i = 0; i < SIZE(current_val); i++)
log_assert(current_val[i].wire != NULL || current_val[i] == value.bits[i]);
#endif
values_map.add(sig, RTLIL::SigSpec(value));
}
@ -88,35 +86,72 @@ struct ConstEval
bool eval(RTLIL::Cell *cell, RTLIL::SigSpec &undef)
{
if (cell->type == "$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")));
if (sig_co.is_fully_const())
return true;
if (!eval(sig_p, undef, cell))
return false;
if (!eval(sig_g, undef, cell))
return false;
if (!eval(sig_ci, undef, cell))
return false;
if (sig_p.is_fully_def() && sig_g.is_fully_def() && sig_ci.is_fully_def())
{
RTLIL::Const coval(RTLIL::Sx, SIZE(sig_co));
bool carry = sig_ci.as_bool();
for (int i = 0; i < SIZE(coval); i++) {
carry = (sig_g[i] == RTLIL::S1) || (sig_p[i] == RTLIL::S1 && carry);
coval.bits[i] = carry ? RTLIL::S1 : RTLIL::S0;
}
set(sig_co, coval);
}
else
set(sig_co, RTLIL::Const(RTLIL::Sx, SIZE(sig_co)));
return true;
}
RTLIL::SigSpec sig_a, sig_b, sig_s, sig_y;
assert(cell->connections.count("\\Y") > 0);
sig_y = values_map(assign_map(cell->connections["\\Y"]));
log_assert(cell->hasPort("\\Y"));
sig_y = values_map(assign_map(cell->getPort("\\Y")));
if (sig_y.is_fully_const())
return true;
if (cell->connections.count("\\S") > 0) {
sig_s = cell->connections["\\S"];
if (cell->hasPort("\\S")) {
sig_s = cell->getPort("\\S");
if (!eval(sig_s, undef, cell))
return false;
}
if (cell->connections.count("\\A") > 0)
sig_a = cell->connections["\\A"];
if (cell->hasPort("\\A"))
sig_a = cell->getPort("\\A");
if (cell->connections.count("\\B") > 0)
sig_b = cell->connections["\\B"];
if (cell->hasPort("\\B"))
sig_b = cell->getPort("\\B");
if (cell->type == "$mux" || cell->type == "$pmux" || cell->type == "$safe_pmux" || cell->type == "$_MUX_")
if (cell->type == "$mux" || cell->type == "$pmux" || cell->type == "$_MUX_")
{
std::vector<RTLIL::SigSpec> y_candidates;
int count_maybe_set_s_bits = 0;
int count_set_s_bits = 0;
for (int i = 0; i < sig_s.width; i++)
for (int i = 0; i < sig_s.size(); i++)
{
RTLIL::State s_bit = sig_s.extract(i, 1).as_const().bits.at(0);
RTLIL::SigSpec b_slice = sig_b.extract(sig_y.width*i, sig_y.width);
RTLIL::SigSpec b_slice = sig_b.extract(sig_y.size()*i, sig_y.size());
if (s_bit == RTLIL::State::Sx || s_bit == RTLIL::State::S1)
y_candidates.push_back(b_slice);
@ -128,15 +163,12 @@ struct ConstEval
count_set_s_bits++;
}
if (cell->type == "$safe_pmux" && count_set_s_bits > 1)
y_candidates.clear();
if ((cell->type == "$safe_pmux" && count_maybe_set_s_bits > 1) || count_set_s_bits == 0)
if (count_set_s_bits == 0)
y_candidates.push_back(sig_a);
std::vector<RTLIL::Const> y_values;
assert(y_candidates.size() > 0);
log_assert(y_candidates.size() > 0);
for (auto &yc : y_candidates) {
if (!eval(yc, undef, cell))
return false;
@ -149,7 +181,7 @@ struct ConstEval
for (size_t i = 1; i < y_values.size(); i++) {
std::vector<RTLIL::State> &slave_bits = y_values.at(i).bits;
assert(master_bits.size() == slave_bits.size());
log_assert(master_bits.size() == slave_bits.size());
for (size_t j = 0; j < master_bits.size(); j++)
if (master_bits[j] != slave_bits[j])
master_bits[j] = RTLIL::State::Sx;
@ -160,13 +192,134 @@ struct ConstEval
else
set(sig_y, y_values.front());
}
else if (cell->type == "$fa")
{
RTLIL::SigSpec sig_c = cell->getPort("\\C");
RTLIL::SigSpec sig_x = cell->getPort("\\X");
int width = SIZE(sig_c);
if (!eval(sig_a, undef, cell))
return false;
if (!eval(sig_b, undef, cell))
return false;
if (!eval(sig_c, undef, cell))
return false;
RTLIL::Const t1 = const_xor(sig_a.as_const(), sig_b.as_const(), false, false, width);
RTLIL::Const val_y = const_xor(t1, sig_c.as_const(), false, false, width);
RTLIL::Const t2 = const_and(sig_a.as_const(), sig_b.as_const(), false, false, width);
RTLIL::Const t3 = const_and(sig_c.as_const(), t1, false, false, width);
RTLIL::Const val_x = const_or(t2, t3, false, false, width);
for (int i = 0; i < SIZE(val_y); i++)
if (val_y.bits[i] == RTLIL::Sx)
val_x.bits[i] = RTLIL::Sx;
set(sig_y, val_y);
set(sig_x, val_x);
}
else if (cell->type == "$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();
RTLIL::SigSpec sig_ci = cell->getPort("\\CI");
RTLIL::SigSpec sig_bi = cell->getPort("\\BI");
if (!eval(sig_a, undef, cell))
return false;
if (!eval(sig_b, undef, cell))
return false;
if (!eval(sig_ci, undef, cell))
return false;
if (!eval(sig_bi, undef, cell))
return false;
RTLIL::SigSpec sig_x = cell->getPort("\\X");
RTLIL::SigSpec sig_co = cell->getPort("\\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(SIZE(sig_y), signed_a);
sig_b.extend_u0(SIZE(sig_y), signed_b);
bool carry = sig_ci[0] == RTLIL::S1;
bool b_inv = sig_bi[0] == RTLIL::S1;
for (int i = 0; i < SIZE(sig_y); i++)
{
RTLIL::SigSpec x_inputs = { sig_a[i], sig_b[i], sig_bi[0] };
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_x = bit_a != bit_b;
set(sig_x[i], bit_x ? RTLIL::S1 : RTLIL::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_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);
}
}
}
else if (cell->type == "$macc")
{
Macc macc;
macc.from_cell(cell);
if (!eval(macc.bit_ports, undef, cell))
return false;
for (auto &port : macc.ports) {
if (!eval(port.in_a, undef, cell))
return false;
if (!eval(port.in_b, undef, cell))
return false;
}
RTLIL::Const result(0, SIZE(cell->getPort("\\Y")));
if (!macc.eval(result))
log_abort();
set(cell->getPort("\\Y"), result);
}
else
{
if (sig_a.width > 0 && !eval(sig_a, undef, cell))
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 (sig_a.size() > 0 && !eval(sig_a, undef, cell))
return false;
if (sig_b.width > 0 && !eval(sig_b, undef, cell))
if (sig_b.size() > 0 && !eval(sig_b, undef, cell))
return false;
set(sig_y, CellTypes::eval(cell, sig_a.as_const(), sig_b.as_const()));
if (sig_c.size() > 0 && !eval(sig_c, undef, cell))
return false;
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()));
}
return true;
@ -210,9 +363,9 @@ struct ConstEval
if (sig.is_fully_const())
return true;
for (size_t i = 0; i < sig.chunks.size(); i++)
if (sig.chunks[i].wire != NULL)
undef.append(sig.chunks[i]);
for (auto &c : sig.chunks())
if (c.wire != NULL)
undef.append(c);
return false;
}

View file

@ -17,464 +17,38 @@
*
*/
#include "kernel/yosys.h"
#include "libs/sha1/sha1.h"
#ifdef YOSYS_ENABLE_READLINE
# include <readline/readline.h>
# include <readline/history.h>
#endif
#include <stdio.h>
#include <readline/readline.h>
#include <readline/history.h>
#include <string.h>
#include <unistd.h>
#include <libgen.h>
#include <dlfcn.h>
#include <limits.h>
#include <errno.h>
#include <algorithm>
#include "kernel/rtlil.h"
#include "kernel/register.h"
#include "kernel/log.h"
bool fgetline(FILE *f, std::string &buffer)
{
buffer = "";
char block[4096];
while (1) {
if (fgets(block, 4096, f) == NULL)
return false;
buffer += block;
if (buffer.size() > 0 && (buffer[buffer.size()-1] == '\n' || buffer[buffer.size()-1] == '\r')) {
while (buffer.size() > 0 && (buffer[buffer.size()-1] == '\n' || buffer[buffer.size()-1] == '\r'))
buffer.resize(buffer.size()-1);
return true;
}
}
}
static void run_frontend(std::string filename, std::string command, RTLIL::Design *design, std::string *backend_command)
{
if (command == "auto") {
if (filename.size() > 2 && filename.substr(filename.size()-2) == ".v")
command = "verilog";
else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".il")
command = "ilang";
else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".ys")
command = "script";
else if (filename == "-")
command = "script";
else
log_error("Can't guess frontend for input file `%s' (missing -f option)!\n", filename.c_str());
}
if (command == "script") {
log("\n-- Executing script file `%s' --\n", filename.c_str());
FILE *f = stdin;
if (filename != "-")
f = fopen(filename.c_str(), "r");
if (f == NULL)
log_error("Can't open script file `%s' for reading: %s\n", filename.c_str(), strerror(errno));
std::string command;
while (fgetline(f, command)) {
while (!command.empty() && command[command.size()-1] == '\\') {
std::string next_line;
if (!fgetline(f, next_line))
break;
command.resize(command.size()-1);
command += next_line;
}
Pass::call(design, command);
}
if (!command.empty())
Pass::call(design, command);
if (filename != "-")
fclose(f);
if (backend_command != NULL && *backend_command == "auto")
*backend_command = "";
return;
}
if (filename == "-") {
log("\n-- Parsing stdin using frontend `%s' --\n", command.c_str());
} else {
log("\n-- Parsing `%s' using frontend `%s' --\n", filename.c_str(), command.c_str());
}
Frontend::frontend_call(design, NULL, filename, command);
}
static void run_pass(std::string command, RTLIL::Design *design)
{
log("\n-- Running pass `%s' --\n", command.c_str());
Pass::call(design, command);
}
static void run_backend(std::string filename, std::string command, RTLIL::Design *design)
{
if (command == "auto") {
if (filename.size() > 2 && filename.substr(filename.size()-2) == ".v")
command = "verilog";
else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".il")
command = "ilang";
else if (filename.size() > 5 && filename.substr(filename.size()-5) == ".blif")
command = "blif";
else if (filename == "-")
command = "ilang";
else if (filename.empty())
return;
else
log_error("Can't guess backend for output file `%s' (missing -b option)!\n", filename.c_str());
}
if (filename.empty())
filename = "-";
if (filename == "-") {
log("\n-- Writing to stdout using backend `%s' --\n", command.c_str());
} else {
log("\n-- Writing to `%s' using backend `%s' --\n", filename.c_str(), command.c_str());
}
Backend::backend_call(design, NULL, filename, command);
}
static char *readline_cmd_generator(const char *text, int state)
{
static std::map<std::string, Pass*>::iterator it;
static int len;
if (!state) {
it = REGISTER_INTERN::pass_register.begin();
len = strlen(text);
}
for (; it != REGISTER_INTERN::pass_register.end(); it++) {
if (it->first.substr(0, len) == text)
return strdup((it++)->first.c_str());
}
return NULL;
}
static char *readline_obj_generator(const char *text, int state)
{
static std::vector<char*> obj_names;
static size_t idx;
if (!state)
{
idx = 0;
obj_names.clear();
RTLIL::Design *design = yosys_get_design();
int len = strlen(text);
if (design->selected_active_module.empty())
{
for (auto &it : design->modules)
if (RTLIL::unescape_id(it.first).substr(0, len) == text)
obj_names.push_back(strdup(RTLIL::id2cstr(it.first.c_str())));
}
else
if (design->modules.count(design->selected_active_module) > 0)
{
RTLIL::Module *module = design->modules.at(design->selected_active_module);
for (auto &it : module->wires)
if (RTLIL::unescape_id(it.first).substr(0, len) == text)
obj_names.push_back(strdup(RTLIL::id2cstr(it.first.c_str())));
for (auto &it : module->memories)
if (RTLIL::unescape_id(it.first).substr(0, len) == text)
obj_names.push_back(strdup(RTLIL::id2cstr(it.first.c_str())));
for (auto &it : module->cells)
if (RTLIL::unescape_id(it.first).substr(0, len) == text)
obj_names.push_back(strdup(RTLIL::id2cstr(it.first.c_str())));
for (auto &it : module->processes)
if (RTLIL::unescape_id(it.first).substr(0, len) == text)
obj_names.push_back(strdup(RTLIL::id2cstr(it.first.c_str())));
}
std::sort(obj_names.begin(), obj_names.end());
}
if (idx < obj_names.size())
return strdup(obj_names[idx++]);
idx = 0;
obj_names.clear();
return NULL;
}
static char **readline_completion(const char *text, int start, int)
{
if (start == 0)
return rl_completion_matches(text, readline_cmd_generator);
if (strncmp(rl_line_buffer, "read_", 5) && strncmp(rl_line_buffer, "write_", 6))
return rl_completion_matches(text, readline_obj_generator);
return NULL;
}
const char *create_prompt(RTLIL::Design *design, int recursion_counter)
{
static char buffer[100];
std::string str = "\n";
if (recursion_counter > 1)
str += stringf("(%d) ", recursion_counter);
str += "yosys";
if (!design->selected_active_module.empty())
str += stringf(" [%s]", RTLIL::id2cstr(design->selected_active_module));
if (!design->selection_stack.back().full_selection) {
if (design->selected_active_module.empty())
str += "*";
else if (design->selection_stack.back().selected_modules.size() != 1 || design->selection_stack.back().selected_members.size() != 0 ||
design->selection_stack.back().selected_modules.count(design->selected_active_module) == 0)
str += "*";
}
snprintf(buffer, 100, "%s> ", str.c_str());
return buffer;
}
static void shell(RTLIL::Design *design)
{
static int recursion_counter = 0;
recursion_counter++;
log_cmd_error_throw = true;
rl_readline_name = "yosys";
rl_attempted_completion_function = readline_completion;
rl_basic_word_break_characters = " \t\n";
char *command = NULL;
while ((command = readline(create_prompt(design, recursion_counter))) != NULL)
{
if (command[strspn(command, " \t\r\n")] == 0)
continue;
add_history(command);
char *p = command + strspn(command, " \t\r\n");
if (!strncmp(p, "exit", 4)) {
p += 4;
p += strspn(p, " \t\r\n");
if (*p == 0)
break;
}
try {
assert(design->selection_stack.size() == 1);
Pass::call(design, command);
} catch (int) {
while (design->selection_stack.size() > 1)
design->selection_stack.pop_back();
log_reset_stack();
}
}
if (command == NULL)
printf("exit\n");
recursion_counter--;
log_cmd_error_throw = false;
}
struct ShellPass : public Pass {
ShellPass() : Pass("shell", "enter interactive command mode") { }
virtual void help() {
log("\n");
log(" shell\n");
log("\n");
log("This command enters the interactive command mode. This can be useful\n");
log("in a script to interrupt the script at a certain point and allow for\n");
log("interactive inspection or manual synthesis of the design at this point.\n");
log("\n");
log("The command prompt of the interactive shell indicates the current\n");
log("selection (see 'help select'):\n");
log("\n");
log(" yosys>\n");
log(" the entire design is selected\n");
log("\n");
log(" yosys*>\n");
log(" only part of the design is selected\n");
log("\n");
log(" yosys [modname]>\n");
log(" the entire module 'modname' is selected using 'select -module modname'\n");
log("\n");
log(" yosys [modname]*>\n");
log(" only part of current module 'modname' is selected\n");
log("\n");
log("When in interactive shell, some errors (e.g. invalid command arguments)\n");
log("do not terminate yosys but return to the command prompt.\n");
log("\n");
log("This command is the default action if nothing else has been specified\n");
log("on the command line.\n");
log("\n");
log("Press Ctrl-D or type 'exit' to leave the interactive shell.\n");
log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
extra_args(args, 1, design, false);
shell(design);
}
} ShellPass;
struct HistoryPass : public Pass {
HistoryPass() : Pass("history", "show last interactive commands") { }
virtual void help() {
log("\n");
log(" history\n");
log("\n");
log("This command prints all commands in the shell history buffer. This are\n");
log("all commands executed in an interactive session, but not the commands\n");
log("from executed scripts.\n");
log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
extra_args(args, 1, design, false);
for(HIST_ENTRY **list = history_list(); *list != NULL; list++)
log("%s\n", (*list)->line);
}
} HistoryPass;
struct ScriptPass : public Pass {
ScriptPass() : Pass("script", "execute commands from script file") { }
virtual void help() {
log("\n");
log(" script <filename>\n");
log("\n");
log("This command executes the yosys commands in the specified file.\n");
log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
if (args.size() < 2)
log_cmd_error("Missing script file.\n");
if (args.size() > 2)
extra_args(args, 1, design, false);
run_frontend(args[1], "script", design, NULL);
}
} ScriptPass;
#ifdef YOSYS_ENABLE_TCL
static Tcl_Interp *yosys_tcl_interp = NULL;
static int tcl_yosys_cmd(ClientData, Tcl_Interp *interp, int argc, const char *argv[])
{
std::vector<std::string> args;
for (int i = 1; i < argc; i++)
args.push_back(argv[i]);
if (args.size() >= 1 && args[0] == "-import") {
for (auto &it : REGISTER_INTERN::pass_register) {
std::string tcl_command_name = it.first;
if (tcl_command_name == "proc")
tcl_command_name = "procs";
Tcl_CmdInfo info;
if (Tcl_GetCommandInfo(interp, tcl_command_name.c_str(), &info) != 0) {
log("[TCL: yosys -import] Command name collision: found pre-existing command `%s' -> skip.\n", it.first.c_str());
} else {
std::string tcl_script = stringf("proc %s args { yosys %s {*}$args }", tcl_command_name.c_str(), it.first.c_str());
Tcl_Eval(interp, tcl_script.c_str());
}
}
return TCL_OK;
}
if (args.size() == 1) {
Pass::call(yosys_get_design(), args[0]);
return TCL_OK;
}
Pass::call(yosys_get_design(), args);
return TCL_OK;
}
extern Tcl_Interp *yosys_get_tcl_interp()
{
if (yosys_tcl_interp == NULL) {
yosys_tcl_interp = Tcl_CreateInterp();
Tcl_CreateCommand(yosys_tcl_interp, "yosys", tcl_yosys_cmd, NULL, NULL);
}
return yosys_tcl_interp;
}
struct TclPass : public Pass {
TclPass() : Pass("tcl", "execute a TCL script file") { }
virtual void help() {
log("\n");
log(" tcl <filename>\n");
log("\n");
log("This command executes the tcl commands in the specified file.\n");
log("Use 'yosys cmd' to run the yosys command 'cmd' from tcl.\n");
log("\n");
log("The tcl command 'yosys -import' can be used to import all yosys\n");
log("commands directly as tcl commands to the tcl shell. The yosys\n");
log("command 'proc' is wrapped using the tcl command 'procs' in order\n");
log("to avoid a name collision with the tcl builting command 'proc'.\n");
log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
if (args.size() < 2)
log_cmd_error("Missing script file.\n");
if (args.size() > 2)
extra_args(args, 1, design, false);
if (Tcl_EvalFile(yosys_get_tcl_interp(), args[1].c_str()) != TCL_OK)
log_cmd_error("TCL interpreter returned an error: %s\n", Tcl_GetStringResult(yosys_get_tcl_interp()));
}
} TclPass;
#endif
static RTLIL::Design *yosys_design = NULL;
extern RTLIL::Design *yosys_get_design()
{
return yosys_design;
}
std::string rewrite_yosys_exe(std::string exe)
{
char buffer[1024];
ssize_t buflen = readlink("/proc/self/exe", buffer, sizeof(buffer)-1);
if (buflen < 0)
return exe;
buffer[buflen] = 0;
std::string newexe = stringf("%s/%s", dirname(buffer), exe.c_str());
if (access(newexe.c_str(), X_OK) == 0)
return newexe;
return exe;
}
std::string get_share_file_name(std::string file)
{
char buffer[1024];
ssize_t buflen = readlink("/proc/self/exe", buffer, sizeof(buffer)-1);
if (buflen < 0)
log_error("Can't find file `%s': reading of /proc/self/exe failed!\n", file.c_str());
buffer[buflen] = 0;
const char *dir = dirname(buffer);
std::string newfile_inplace = stringf("%s/share/%s", dir, file.c_str());
if (access(newfile_inplace.c_str(), F_OK) == 0)
return newfile_inplace;
std::string newfile_system = stringf("%s/../share/yosys/%s", dir, file.c_str());
if (access(newfile_system.c_str(), F_OK) == 0)
return newfile_system;
log_error("Can't find file `%s': no `%s' and no `%s' found!\n", file.c_str(), newfile_inplace.c_str(), newfile_system.c_str());
}
USING_YOSYS_NAMESPACE
int main(int argc, char **argv)
{
std::string frontend_command = "auto";
std::string backend_command = "auto";
std::vector<std::string> passes_commands;
std::vector<void*> loaded_modules;
std::vector<std::string> plugin_filenames;
std::string output_filename = "";
std::string scriptfile = "";
bool scriptfile_tcl = false;
bool got_output_filename = false;
bool print_banner = true;
bool print_stats = true;
bool call_abort = false;
#ifdef YOSYS_ENABLE_READLINE
int history_offset = 0;
std::string history_file;
if (getenv("HOME") != NULL) {
@ -482,30 +56,30 @@ int main(int argc, char **argv)
read_history(history_file.c_str());
history_offset = where_history();
}
#endif
int opt;
while ((opt = getopt(argc, argv, "VSm:f:Hh:b:o:p:l:qv:ts:c:")) != -1)
while ((opt = getopt(argc, argv, "AQTVSm:f:Hh:b:o:p:l:qv:ts:c:")) != -1)
{
switch (opt)
{
case 'A':
call_abort = true;
break;
case 'Q':
print_banner = false;
break;
case 'T':
print_stats = false;
break;
case 'V':
printf("%s\n", yosys_version_str);
exit(0);
case 'S':
passes_commands.push_back("hierarchy");
passes_commands.push_back("proc");
passes_commands.push_back("opt");
passes_commands.push_back("memory");
passes_commands.push_back("opt");
passes_commands.push_back("techmap");
passes_commands.push_back("opt");
passes_commands.push_back("synth");
break;
case 'm':
loaded_modules.push_back(dlopen(optarg, RTLD_LAZY|RTLD_GLOBAL));
if (loaded_modules.back() == NULL) {
fprintf(stderr, "Can't load module `%s': %s\n", optarg, dlerror());
exit(1);
}
plugin_filenames.push_back(optarg);
break;
case 'f':
frontend_command = optarg;
@ -553,9 +127,15 @@ int main(int argc, char **argv)
break;
default:
fprintf(stderr, "\n");
fprintf(stderr, "Usage: %s [-V] [-S] [-q] [-v <level>[-t] [-l <logfile>] [-o <outfile>] [-f <frontend>] [-h cmd] \\\n", argv[0]);
fprintf(stderr, "Usage: %s [-V -S -Q -T -q] [-v <level>[-t] [-l <logfile>] [-o <outfile>] [-f <frontend>] [-h cmd] \\\n", argv[0]);
fprintf(stderr, " %*s[{-s|-c} <scriptfile>] [-p <pass> [-p ..]] [-b <backend>] [-m <module_file>] [<infile> [..]]\n", int(strlen(argv[0])+1), "");
fprintf(stderr, "\n");
fprintf(stderr, " -Q\n");
fprintf(stderr, " suppress printing of banner (copyright, disclaimer, version)\n");
fprintf(stderr, "\n");
fprintf(stderr, " -T\n");
fprintf(stderr, " suppress printing of footer (log hash, version, timing statistics)\n");
fprintf(stderr, "\n");
fprintf(stderr, " -q\n");
fprintf(stderr, " quiet operation. only write error messages to console\n");
fprintf(stderr, "\n");
@ -595,13 +175,16 @@ int main(int argc, char **argv)
fprintf(stderr, " -m module_file\n");
fprintf(stderr, " load the specified module (aka plugin)\n");
fprintf(stderr, "\n");
fprintf(stderr, " -A\n");
fprintf(stderr, " will call abort() at the end of the script. useful for debugging\n");
fprintf(stderr, "\n");
fprintf(stderr, " -V\n");
fprintf(stderr, " print version information and exit\n");
fprintf(stderr, "\n");
fprintf(stderr, "The option -S is an alias for the following options that perform a simple\n");
fprintf(stderr, "transformation of the input to a gate-level netlist.\n");
fprintf(stderr, "The option -S is an shortcut for calling the \"synth\" command, a default\n");
fprintf(stderr, "script for transforming the verilog input to a gate-level netlist. For example:\n");
fprintf(stderr, "\n");
fprintf(stderr, " -p hierarchy -p proc -p opt -p memory -p opt -p techmap -p opt\n");
fprintf(stderr, " yosys -o output.blif -S input.v\n");
fprintf(stderr, "\n");
fprintf(stderr, "For more complex synthesis jobs it is recommended to use the read_* and write_*\n");
fprintf(stderr, "commands in a script file instead of specifying input and output files on the\n");
@ -618,35 +201,39 @@ int main(int argc, char **argv)
if (log_errfile == NULL)
log_files.push_back(stderr);
log("\n");
log(" /-----------------------------------------------------------------------------\\\n");
log(" | |\n");
log(" | yosys -- Yosys Open SYnthesis Suite |\n");
log(" | |\n");
log(" | Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> |\n");
log(" | |\n");
log(" | Permission to use, copy, modify, and/or distribute this software for any |\n");
log(" | purpose with or without fee is hereby granted, provided that the above |\n");
log(" | copyright notice and this permission notice appear in all copies. |\n");
log(" | |\n");
log(" | THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |\n");
log(" | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |\n");
log(" | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |\n");
log(" | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |\n");
log(" | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |\n");
log(" | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |\n");
log(" | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |\n");
log(" | |\n");
log(" \\-----------------------------------------------------------------------------/\n");
log("\n");
log(" %s\n", yosys_version_str);
log("\n");
if (print_banner) {
log("\n");
log(" /-----------------------------------------------------------------------------\\\n");
log(" | |\n");
log(" | yosys -- Yosys Open SYnthesis Suite |\n");
log(" | |\n");
log(" | Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> |\n");
log(" | |\n");
log(" | Permission to use, copy, modify, and/or distribute this software for any |\n");
log(" | purpose with or without fee is hereby granted, provided that the above |\n");
log(" | copyright notice and this permission notice appear in all copies. |\n");
log(" | |\n");
log(" | THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |\n");
log(" | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |\n");
log(" | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |\n");
log(" | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |\n");
log(" | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |\n");
log(" | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |\n");
log(" | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |\n");
log(" | |\n");
log(" \\-----------------------------------------------------------------------------/\n");
log("\n");
log(" %s\n", yosys_version_str);
log("\n");
}
Pass::init_register();
if (print_stats)
log_hasher = new SHA1;
yosys_design = new RTLIL::Design;
yosys_design->selection_stack.push_back(RTLIL::Selection());
log_push();
yosys_setup();
for (auto &fn : plugin_filenames)
load_plugin(fn, {});
if (optind == argc && passes_commands.size() == 0 && scriptfile.empty()) {
if (!got_output_filename)
@ -655,7 +242,7 @@ int main(int argc, char **argv)
}
while (optind < argc)
run_frontend(argv[optind++], frontend_command, yosys_design, output_filename == "-" ? &backend_command : NULL);
run_frontend(argv[optind++], frontend_command, yosys_design, output_filename == "-" ? &backend_command : NULL, NULL);
if (!scriptfile.empty()) {
if (scriptfile_tcl) {
@ -666,7 +253,7 @@ int main(int argc, char **argv)
log_error("Can't exectue TCL script: this version of yosys is not built with TCL support enabled.\n");
#endif
} else
run_frontend(scriptfile, "script", yosys_design, output_filename == "-" ? &backend_command : NULL);
run_frontend(scriptfile, "script", yosys_design, output_filename == "-" ? &backend_command : NULL, NULL);
}
for (auto it = passes_commands.begin(); it != passes_commands.end(); it++)
@ -675,12 +262,72 @@ int main(int argc, char **argv)
if (!backend_command.empty())
run_backend(output_filename, backend_command, yosys_design);
delete yosys_design;
yosys_design = NULL;
if (print_stats)
{
std::string hash = log_hasher->final().substr(0, 10);
delete log_hasher;
log_hasher = nullptr;
log("\nREADY.\n");
log_pop();
struct rusage ru_buffer;
getrusage(RUSAGE_SELF, &ru_buffer);
log_spacer();
log("End of script. Logfile hash: %s, CPU: user %.2fs system %.2fs\n", hash.c_str(),
ru_buffer.ru_utime.tv_sec + 1e-6 * ru_buffer.ru_utime.tv_usec,
ru_buffer.ru_stime.tv_sec + 1e-6 * ru_buffer.ru_stime.tv_usec);
log("%s\n", yosys_version_str);
int64_t total_ns = 0;
std::set<std::tuple<int64_t, int, std::string>> timedat;
for (auto &it : pass_register)
if (it.second->call_counter) {
total_ns += it.second->runtime_ns + 1;
timedat.insert(make_tuple(it.second->runtime_ns + 1, it.second->call_counter, it.first));
}
int out_count = 0;
log("Time spent:");
for (auto it = timedat.rbegin(); it != timedat.rend() && out_count < 4; it++, out_count++) {
if (out_count >= 2 && (std::get<0>(*it) < 1000000000 || int(100*std::get<0>(*it) / total_ns) < 20)) {
log(", ...");
break;
}
log("%s %d%% %dx %s (%d sec)", out_count ? "," : "", int(100*std::get<0>(*it) / total_ns),
std::get<1>(*it), std::get<2>(*it).c_str(), int(std::get<0>(*it) / 1000000000));
}
log("%s\n", out_count ? "" : " no commands executed");
}
#ifdef COVER_ACTIVE
if (getenv("YOSYS_COVER_DIR") || getenv("YOSYS_COVER_FILE"))
{
char filename_buffer[4096];
FILE *f;
if (getenv("YOSYS_COVER_DIR")) {
snprintf(filename_buffer, 4096, "%s/yosys_cover_%d_XXXXXX.txt", getenv("YOSYS_COVER_DIR"), getpid());
f = fdopen(mkstemps(filename_buffer, 4), "w");
} else {
snprintf(filename_buffer, 4096, "%s", getenv("YOSYS_COVER_FILE"));
f = fopen(filename_buffer, "a+");
}
if (f == NULL)
log_error("Can't create coverage file `%s'.\n", filename_buffer);
log("<writing coverage file \"%s\">\n", filename_buffer);
for (auto &it : get_coverage_data())
fprintf(f, "%-60s %10d %s\n", it.second.first.c_str(), it.second.second, it.first.c_str());
fclose(f);
}
#endif
if (call_abort)
abort();
#ifdef YOSYS_ENABLE_READLINE
if (!history_file.empty()) {
if (history_offset > 0) {
history_truncate_file(history_file.c_str(), 100);
@ -693,26 +340,10 @@ int main(int argc, char **argv)
HIST_ENTRY **hist_list = history_list();
if (hist_list != NULL)
free(hist_list);
for (auto f : log_files)
if (f != stderr)
fclose(f);
log_errfile = NULL;
log_files.clear();
Pass::done_register();
for (auto mod : loaded_modules)
dlclose(mod);
#ifdef YOSYS_ENABLE_TCL
if (yosys_tcl_interp != NULL) {
Tcl_DeleteInterp(yosys_tcl_interp);
Tcl_Finalize();
yosys_tcl_interp = NULL;
}
#endif
yosys_shutdown();
return 0;
}

View file

@ -17,7 +17,8 @@
*
*/
#include "kernel/log.h"
#include "kernel/yosys.h"
#include "libs/sha1/sha1.h"
#include "backends/ilang/ilang_backend.h"
#include <sys/time.h>
@ -28,44 +29,50 @@
#include <vector>
#include <list>
YOSYS_NAMESPACE_BEGIN
std::vector<FILE*> log_files;
std::vector<std::ostream*> log_streams;
FILE *log_errfile = NULL;
SHA1 *log_hasher = NULL;
bool log_time = false;
bool log_cmd_error_throw = false;
int log_verbose_level;
std::vector<int> header_count;
std::list<std::string> string_buf;
int string_buf_size = 0;
static struct timeval initial_tv = { 0, 0 };
static bool next_print_log = false;
std::string stringf(const char *fmt, ...)
{
std::string string;
char *str = NULL;
va_list ap;
va_start(ap, fmt);
if (vasprintf(&str, fmt, ap) < 0)
str = NULL;
va_end(ap);
if (str != NULL) {
string = str;
free(str);
}
return string;
}
static int log_newline_count = 0;
void logv(const char *format, va_list ap)
{
if (log_time) {
while (format[0] == '\n' && format[1] != 0) {
format++;
log("\n");
}
while (format[0] == '\n' && format[1] != 0) {
log("\n");
format++;
}
std::string str = vstringf(format, ap);
if (str.empty())
return;
size_t nnl_pos = str.find_last_not_of('\n');
if (nnl_pos == std::string::npos)
log_newline_count += SIZE(str);
else
log_newline_count = SIZE(str) - nnl_pos - 1;
if (log_hasher)
log_hasher->update(str);
if (log_time)
{
std::string time_str;
if (next_print_log || initial_tv.tv_sec == 0) {
next_print_log = false;
struct timeval tv;
@ -78,48 +85,56 @@ void logv(const char *format, va_list ap)
}
tv.tv_sec -= initial_tv.tv_sec;
tv.tv_usec -= initial_tv.tv_usec;
log("[%05d.%06d] ", int(tv.tv_sec), int(tv.tv_usec));
time_str += stringf("[%05d.%06d] ", int(tv.tv_sec), int(tv.tv_usec));
}
if (format[0] && format[strlen(format)-1] == '\n')
next_print_log = true;
for (auto f : log_files)
fputs(time_str.c_str(), f);
for (auto f : log_streams)
*f << time_str;
}
for (auto f : log_files) {
va_list aq;
va_copy(aq, ap);
vfprintf(f, format, aq);
va_end(aq);
}
for (auto f : log_files)
fputs(str.c_str(), f);
for (auto f : log_streams)
*f << str;
}
void logv_header(const char *format, va_list ap)
{
log("\n");
bool pop_errfile = false;
log_spacer();
if (header_count.size() > 0)
header_count.back()++;
if (int(header_count.size()) <= log_verbose_level && log_errfile != NULL) {
log_files.push_back(log_errfile);
pop_errfile = true;
}
for (int c : header_count)
log("%d.", c);
log(" ");
logv(format, ap);
log_flush();
if (int(header_count.size()) <= log_verbose_level && log_errfile != NULL) {
for (int c : header_count)
fprintf(log_errfile, "%d.", c);
fprintf(log_errfile, " ");
vfprintf(log_errfile, format, ap);
fflush(log_errfile);
}
if (pop_errfile)
log_files.pop_back();
}
void logv_error(const char *format, va_list ap)
{
if (log_errfile != NULL)
log_files.push_back(log_errfile);
log("ERROR: ");
logv(format, ap);
if (log_errfile != NULL) {
fprintf(log_errfile, "ERROR: ");
vfprintf(log_errfile, format, ap);
}
log_flush();
exit(1);
}
@ -156,12 +171,18 @@ void log_cmd_error(const char *format, ...)
log("ERROR: ");
logv(format, ap);
log_flush();
throw 0;
throw log_cmd_error_expection();
}
logv_error(format, ap);
}
void log_spacer()
{
while (log_newline_count < 2)
log("\n");
}
void log_push()
{
header_count.push_back(0);
@ -171,6 +192,7 @@ void log_pop()
{
header_count.pop_back();
string_buf.clear();
string_buf_size = 0;
log_flush();
}
@ -179,6 +201,7 @@ void log_reset_stack()
while (header_count.size() > 1)
header_count.pop_back();
string_buf.clear();
string_buf_size = 0;
log_flush();
}
@ -186,21 +209,95 @@ void log_flush()
{
for (auto f : log_files)
fflush(f);
for (auto f : log_streams)
f->flush();
}
void log_dump_val_worker(RTLIL::SigSpec v) {
log("%s", log_signal(v));
}
const char *log_signal(const RTLIL::SigSpec &sig, bool autoint)
{
char *ptr;
size_t size;
std::stringstream buf;
ILANG_BACKEND::dump_sigspec(buf, sig, autoint);
FILE *f = open_memstream(&ptr, &size);
ILANG_BACKEND::dump_sigspec(f, sig, autoint);
fputc(0, f);
fclose(f);
string_buf.push_back(ptr);
free(ptr);
if (string_buf_size < 100)
string_buf_size++;
else
string_buf.pop_front();
string_buf.push_back(buf.str());
return string_buf.back().c_str();
}
const char *log_id(RTLIL::IdString str)
{
const char *p = str.c_str();
log_assert(RTLIL::IdString::global_refcount_storage_[str.index_] > 1);
if (p[0] == '\\' && p[1] != '$' && p[1] != 0)
return p+1;
return p;
}
void log_cell(RTLIL::Cell *cell, std::string indent)
{
std::stringstream buf;
ILANG_BACKEND::dump_cell(buf, indent, cell);
log("%s", buf.str().c_str());
}
// ---------------------------------------------------
// This is the magic behind the code coverage counters
// ---------------------------------------------------
#ifdef COVER_ACTIVE
std::map<std::string, std::pair<std::string, int>> extra_coverage_data;
void cover_extra(std::string parent, std::string id, bool increment) {
if (extra_coverage_data.count(id) == 0) {
for (CoverData *p = __start_yosys_cover_list; p != __stop_yosys_cover_list; p++)
if (p->id == parent)
extra_coverage_data[id].first = stringf("%s:%d:%s", p->file, p->line, p->func);
log_assert(extra_coverage_data.count(id));
}
if (increment)
extra_coverage_data[id].second++;
}
std::map<std::string, std::pair<std::string, int>> get_coverage_data()
{
std::map<std::string, std::pair<std::string, int>> coverage_data;
for (auto &it : pass_register) {
std::string key = stringf("passes.%s", it.first.c_str());
coverage_data[key].first = stringf("%s:%d:%s", __FILE__, __LINE__, __FUNCTION__);
coverage_data[key].second += it.second->call_counter;
}
for (auto &it : extra_coverage_data) {
if (coverage_data.count(it.first))
log("WARNING: found duplicate coverage id \"%s\".\n", it.first.c_str());
coverage_data[it.first].first = it.second.first;
coverage_data[it.first].second += it.second.second;
}
for (CoverData *p = __start_yosys_cover_list; p != __stop_yosys_cover_list; p++) {
if (coverage_data.count(p->id))
log("WARNING: found duplicate coverage id \"%s\".\n", p->id);
coverage_data[p->id].first = stringf("%s:%d:%s", p->file, p->line, p->func);
coverage_data[p->id].second += p->counter;
}
for (auto &it : coverage_data)
if (!it.second.first.compare(0, strlen(YOSYS_SRC "/"), YOSYS_SRC "/"))
it.second.first = it.second.first.substr(strlen(YOSYS_SRC "/"));
return coverage_data;
}
#endif
YOSYS_NAMESPACE_END

View file

@ -17,22 +17,32 @@
*
*/
#include "kernel/yosys.h"
#ifndef LOG_H
#define LOG_H
#include "kernel/rtlil.h"
#include <stdio.h>
#include <time.h>
#include <vector>
#include <sys/time.h>
#include <sys/resource.h>
YOSYS_NAMESPACE_BEGIN
#define S__LINE__sub2(x) #x
#define S__LINE__sub1(x) S__LINE__sub2(x)
#define S__LINE__ S__LINE__sub1(__LINE__)
struct log_cmd_error_expection { };
extern std::vector<FILE*> log_files;
extern std::vector<std::ostream*> log_streams;
extern FILE *log_errfile;
extern class SHA1 *log_hasher;
extern bool log_time;
extern bool log_cmd_error_throw;
extern int log_verbose_level;
std::string stringf(const char *fmt, ...);
void logv(const char *format, va_list ap);
void logv_header(const char *format, va_list ap);
void logv_error(const char *format, va_list ap) __attribute__ ((noreturn));
@ -42,6 +52,7 @@ void log_header(const char *format, ...) __attribute__ ((format (printf, 1, 2)))
void log_error(const char *format, ...) __attribute__ ((format (printf, 1, 2))) __attribute__ ((noreturn));
void log_cmd_error(const char *format, ...) __attribute__ ((format (printf, 1, 2))) __attribute__ ((noreturn));
void log_spacer();
void log_push();
void log_pop();
@ -49,9 +60,70 @@ void log_reset_stack();
void log_flush();
const char *log_signal(const RTLIL::SigSpec &sig, bool autoint = true);
const char *log_id(RTLIL::IdString id);
template<typename T> static inline const char *log_id(T *obj) {
return log_id(obj->name);
}
void log_cell(RTLIL::Cell *cell, std::string indent = "");
#define log_abort() log_error("Abort in %s:%d.\n", __FILE__, __LINE__)
#define log_assert(_assert_expr_) do { if (_assert_expr_) break; log_error("Assert `%s' failed in %s:%d.\n", #_assert_expr_, __FILE__, __LINE__); } while (0)
#define log_ping() log("-- %s:%d %s --\n", __FILE__, __LINE__, __PRETTY_FUNCTION__)
// ---------------------------------------------------
// This is the magic behind the code coverage counters
// ---------------------------------------------------
#if defined(__linux__) && !defined(NDEBUG)
#define COVER_ACTIVE
#define cover(_id) do { \
static CoverData __d __attribute__((section("yosys_cover_list"), aligned(1))) = { __FILE__, __FUNCTION__, _id, __LINE__, 0 }; \
__d.counter++; \
} while (0)
struct CoverData {
const char *file, *func, *id;
int line, counter;
} __attribute__ ((packed));
// this two symbols are created by the linker for the "yosys_cover_list" ELF section
extern "C" struct CoverData __start_yosys_cover_list[];
extern "C" struct CoverData __stop_yosys_cover_list[];
extern std::map<std::string, std::pair<std::string, int>> extra_coverage_data;
void cover_extra(std::string parent, std::string id, bool increment = true);
std::map<std::string, std::pair<std::string, int>> get_coverage_data();
#define cover_list(_id, ...) do { cover(_id); \
std::string r = cover_list_worker(_id, __VA_ARGS__); \
log_assert(r.empty()); \
} while (0)
static inline std::string cover_list_worker(std::string, std::string last) {
return last;
}
template<typename... T>
std::string cover_list_worker(std::string prefix, std::string first, T... rest) {
std::string selected = cover_list_worker(prefix, rest...);
cover_extra(prefix, prefix + "." + first, first == selected);
return first == selected ? "" : selected;
}
#else
# define cover(...) do { } while (0)
# define cover_list(...) do { } while (0)
#endif
// ------------------------------------------------------------
// everything below this line are utilities for troubleshooting
// ------------------------------------------------------------
// simple timer for performance measurements
// toggle the '#if 1' to get a baseline for the perormance penalty added by the measurement
@ -65,30 +137,45 @@ struct PerformanceTimer
}
static int64_t query() {
#if defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0)
struct timespec ts;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts);
return int64_t(ts.tv_sec)*1000000000 + ts.tv_nsec;
#elif defined(RUSAGE_SELF)
struct rusage rusage;
int64_t t;
if (getrusage(RUSAGE_SELF, &rusage) == -1) {
log_cmd_error("getrusage failed!\n");
log_abort();
}
t = 1000000000ULL * (int64_t) rusage.ru_utime.tv_sec + (int64_t) rusage.ru_utime.tv_usec * 1000ULL;
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()?).
#endif
}
void reset() {
total_ns = 0;
}
void add() {
total_ns += query();
void begin() {
total_ns -= query();
}
void sub() {
total_ns -= query();
void end() {
total_ns += query();
}
float sec() const {
return total_ns * 1e-9;
}
#else
static int64_t query() { return 0; }
void reset() { }
void add() { }
void sub() { }
void begin() { }
void end() { }
float sec() const { return 0; }
#endif
};
@ -107,12 +194,17 @@ static inline void log_dump_val_worker(char c) { log(c >= 32 && c < 127 ? "'%c'"
static inline void log_dump_val_worker(unsigned char c) { log(c >= 32 && c < 127 ? "'%c'" : "'\\x%02x'", c); }
static inline void log_dump_val_worker(bool v) { log("%s", v ? "true" : "false"); }
static inline void log_dump_val_worker(double v) { log("%f", v); }
static inline void log_dump_val_worker(char *v) { log("%s", v); }
static inline void log_dump_val_worker(const char *v) { log("%s", v); }
static inline void log_dump_val_worker(std::string v) { log("%s", v.c_str()); }
static inline void log_dump_val_worker(RTLIL::SigSpec v) { log("%s", log_signal(v)); }
static inline void log_dump_val_worker(PerformanceTimer p) { log("%f seconds", p.sec()); }
static inline void log_dump_args_worker(const char *p) { log_assert(*p == 0); }
void log_dump_val_worker(RTLIL::SigSpec v);
template <typename T, typename ... Args>
template<typename T>
static inline void log_dump_val_worker(T *ptr) { log("%p", ptr); }
template<typename T, typename ... Args>
void log_dump_args_worker(const char *p, T first, Args ... args)
{
int next_p_state = 0;
@ -152,4 +244,6 @@ void log_dump_args_worker(const char *p, T first, Args ... args)
log("\n"); \
} while (0)
YOSYS_NAMESPACE_END
#endif

231
kernel/macc.h Normal file
View file

@ -0,0 +1,231 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#ifndef MACC_H
#define MACC_H
#include "kernel/yosys.h"
YOSYS_NAMESPACE_BEGIN
struct Macc
{
struct port_t {
RTLIL::SigSpec in_a, in_b;
bool is_signed, do_subtract;
};
std::vector<port_t> ports;
RTLIL::SigSpec bit_ports;
void optimize(int width)
{
std::vector<port_t> new_ports;
RTLIL::SigSpec new_bit_ports;
RTLIL::Const off(0, width);
for (auto &port : ports)
{
if (SIZE(port.in_a) == 0 && SIZE(port.in_b) == 0)
continue;
if (SIZE(port.in_a) == 1 && SIZE(port.in_b) == 0 && !port.is_signed && !port.do_subtract) {
bit_ports.append(port.in_a);
continue;
}
if (port.in_a.is_fully_const() && port.in_b.is_fully_const()) {
RTLIL::Const v = port.in_a.as_const();
if (SIZE(port.in_b))
v = const_mul(v, port.in_b.as_const(), port.is_signed, port.is_signed, width);
if (port.do_subtract)
off = const_sub(off, v, port.is_signed, port.is_signed, width);
else
off = const_add(off, v, port.is_signed, port.is_signed, width);
continue;
}
if (port.is_signed) {
while (SIZE(port.in_a) > 1 && port.in_a[SIZE(port.in_a)-1] == port.in_a[SIZE(port.in_a)-2])
port.in_a.remove(SIZE(port.in_a)-1);
while (SIZE(port.in_b) > 1 && port.in_b[SIZE(port.in_b)-1] == port.in_b[SIZE(port.in_b)-2])
port.in_b.remove(SIZE(port.in_b)-1);
} else {
while (SIZE(port.in_a) > 1 && port.in_a[SIZE(port.in_a)-1] == RTLIL::S0)
port.in_a.remove(SIZE(port.in_a)-1);
while (SIZE(port.in_b) > 1 && port.in_b[SIZE(port.in_b)-1] == RTLIL::S0)
port.in_b.remove(SIZE(port.in_b)-1);
}
new_ports.push_back(port);
}
for (auto &bit : bit_ports)
if (bit == RTLIL::S1)
off = const_add(off, RTLIL::Const(1, width), false, false, width);
else if (bit != RTLIL::S0)
new_bit_ports.append(bit);
if (off.as_bool()) {
port_t port;
port.in_a = off;
port.is_signed = false;
port.do_subtract = false;
new_ports.push_back(port);
}
new_ports.swap(ports);
bit_ports = new_bit_ports;
}
void from_cell(RTLIL::Cell *cell)
{
RTLIL::SigSpec port_a = cell->getPort("\\A");
ports.clear();
bit_ports = cell->getPort("\\B");
std::vector<RTLIL::State> config_bits = cell->getParam("\\CONFIG").bits;
int config_width = cell->getParam("\\CONFIG_WIDTH").as_int();
int config_cursor = 0;
log_assert(SIZE(config_bits) >= config_width);
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;
int port_a_cursor = 0;
while (port_a_cursor < SIZE(port_a))
{
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;
int size_a = 0;
for (int i = 0; i < num_bits; i++)
if (config_bits[config_cursor++] == RTLIL::S1)
size_a |= 1 << i;
this_port.in_a = port_a.extract(port_a_cursor, size_a);
port_a_cursor += size_a;
int size_b = 0;
for (int i = 0; i < num_bits; i++)
if (config_bits[config_cursor++] == RTLIL::S1)
size_b |= 1 << i;
this_port.in_b = port_a.extract(port_a_cursor, size_b);
port_a_cursor += size_b;
if (size_a || size_b)
ports.push_back(this_port);
}
log_assert(config_cursor == config_width);
log_assert(port_a_cursor == SIZE(port_a));
}
void to_cell(RTLIL::Cell *cell) const
{
RTLIL::SigSpec port_a;
std::vector<RTLIL::State> config_bits;
int max_size = 0, num_bits = 0;
for (auto &port : ports) {
max_size = std::max(max_size, SIZE(port.in_a));
max_size = std::max(max_size, SIZE(port.in_b));
}
while (max_size)
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);
for (auto &port : ports)
{
if (SIZE(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);
int size_a = SIZE(port.in_a);
for (int i = 0; i < num_bits; i++)
config_bits.push_back(size_a & (1 << i) ? RTLIL::S1 : RTLIL::S0);
int size_b = SIZE(port.in_b);
for (int i = 0; i < num_bits; i++)
config_bits.push_back(size_b & (1 << i) ? RTLIL::S1 : RTLIL::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", SIZE(config_bits));
cell->setParam("\\A_WIDTH", SIZE(port_a));
cell->setParam("\\B_WIDTH", SIZE(bit_ports));
}
bool eval(RTLIL::Const &result) const
{
for (auto &bit : result.bits)
bit = RTLIL::S0;
for (auto &port : ports)
{
if (!port.in_a.is_fully_const() || !port.in_b.is_fully_const())
return false;
RTLIL::Const summand;
if (SIZE(port.in_b) == 0)
summand = const_pos(port.in_a.as_const(), port.in_b.as_const(), port.is_signed, port.is_signed, SIZE(result));
else
summand = const_mul(port.in_a.as_const(), port.in_b.as_const(), port.is_signed, port.is_signed, SIZE(result));
if (port.do_subtract)
result = const_sub(result, summand, port.is_signed, port.is_signed, SIZE(result));
else
result = const_add(result, summand, port.is_signed, port.is_signed, SIZE(result));
}
for (auto bit : bit_ports) {
if (bit.wire)
return false;
result = const_add(result, bit.data, false, false, SIZE(result));
}
return true;
}
};
YOSYS_NAMESPACE_END
#endif

455
kernel/modtools.h Normal file
View file

@ -0,0 +1,455 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#ifndef MODTOOLS_H
#define MODTOOLS_H
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
#include "kernel/celltypes.h"
YOSYS_NAMESPACE_BEGIN
struct ModIndex : public RTLIL::Monitor
{
struct PortInfo {
RTLIL::Cell* cell;
RTLIL::IdString port;
int offset;
PortInfo(RTLIL::Cell* _c, RTLIL::IdString _p, int _o) : cell(_c), port(_p), offset(_o) { }
bool operator<(const PortInfo &other) const {
if (cell != other.cell)
return cell < other.cell;
if (offset != other.offset)
return offset < other.offset;
return port < other.port;
}
};
struct SigBitInfo
{
bool is_input, is_output;
std::set<PortInfo> ports;
SigBitInfo() : is_input(false), is_output(false) { }
};
SigMap sigmap;
RTLIL::Module *module;
std::map<RTLIL::SigBit, SigBitInfo> database;
bool auto_reload_module;
void port_add(RTLIL::Cell *cell, RTLIL::IdString port, const RTLIL::SigSpec &sig)
{
for (int i = 0; i < SIZE(sig); i++) {
RTLIL::SigBit bit = sigmap(sig[i]);
if (bit.wire)
database[bit].ports.insert(PortInfo(cell, port, i));
}
}
void port_del(RTLIL::Cell *cell, RTLIL::IdString port, const RTLIL::SigSpec &sig)
{
for (int i = 0; i < SIZE(sig); i++) {
RTLIL::SigBit bit = sigmap(sig[i]);
if (bit.wire)
database[bit].ports.erase(PortInfo(cell, port, i));
}
}
const SigBitInfo &info(RTLIL::SigBit bit)
{
return database[sigmap(bit)];
}
void reload_module()
{
sigmap.clear();
sigmap.set(module);
database.clear();
for (auto wire : module->wires())
if (wire->port_input || wire->port_output)
for (int i = 0; i < SIZE(wire); i++) {
RTLIL::SigBit bit = sigmap(RTLIL::SigBit(wire, i));
if (bit.wire && wire->port_input)
database[bit].is_input = true;
if (bit.wire && wire->port_output)
database[bit].is_output = true;
}
for (auto cell : module->cells())
for (auto &conn : cell->connections())
port_add(cell, conn.first, conn.second);
auto_reload_module = false;
}
virtual void notify_connect(RTLIL::Cell *cell, const RTLIL::IdString &port, const RTLIL::SigSpec &old_sig, RTLIL::SigSpec &sig) OVERRIDE
{
if (auto_reload_module)
reload_module();
port_del(cell, port, old_sig);
port_add(cell, port, sig);
}
virtual void notify_connect(RTLIL::Module *mod, const RTLIL::SigSig&)
{
log_assert(module == mod);
auto_reload_module = true;
}
virtual void notify_connect(RTLIL::Module *mod, const std::vector<RTLIL::SigSig>&)
{
log_assert(module == mod);
auto_reload_module = true;
}
virtual void notify_blackout(RTLIL::Module *mod)
{
log_assert(module == mod);
auto_reload_module = true;
}
ModIndex(RTLIL::Module *_m) : module(_m)
{
auto_reload_module = true;
module->monitors.insert(this);
}
~ModIndex()
{
module->monitors.erase(this);
}
SigBitInfo *query(RTLIL::SigBit bit)
{
if (auto_reload_module)
reload_module();
auto it = database.find(sigmap(bit));
if (it == database.end())
return nullptr;
else
return &it->second;
}
bool query_is_input(RTLIL::SigBit bit)
{
const SigBitInfo *info = query(bit);
if (info == nullptr)
return false;
return info->is_input;
}
bool query_is_output(RTLIL::SigBit bit)
{
const SigBitInfo *info = query(bit);
if (info == nullptr)
return false;
return info->is_output;
}
std::set<PortInfo> &query_ports(RTLIL::SigBit bit)
{
static std::set<PortInfo> empty_result_set;
SigBitInfo *info = query(bit);
if (info == nullptr)
return empty_result_set;
return info->ports;
}
};
struct ModWalker
{
struct PortBit
{
RTLIL::Cell *cell;
RTLIL::IdString port;
int offset;
bool operator<(const PortBit &other) const {
if (cell != other.cell)
return cell < other.cell;
if (port != other.port)
return port < other.port;
return offset < other.offset;
}
};
RTLIL::Design *design;
RTLIL::Module *module;
CellTypes ct;
SigMap sigmap;
std::map<RTLIL::SigBit, std::set<PortBit>> signal_drivers;
std::map<RTLIL::SigBit, std::set<PortBit>> signal_consumers;
std::set<RTLIL::SigBit> signal_inputs, signal_outputs;
std::map<RTLIL::Cell*, std::set<RTLIL::SigBit>> cell_outputs, cell_inputs;
void add_wire(RTLIL::Wire *wire)
{
if (wire->port_input) {
std::vector<RTLIL::SigBit> bits = sigmap(wire);
for (auto bit : bits)
if (bit.wire != NULL)
signal_inputs.insert(bit);
}
if (wire->port_output) {
std::vector<RTLIL::SigBit> bits = sigmap(wire);
for (auto bit : bits)
if (bit.wire != NULL)
signal_outputs.insert(bit);
}
}
void add_cell_port(RTLIL::Cell *cell, RTLIL::IdString port, std::vector<RTLIL::SigBit> bits, bool is_output, bool is_input)
{
for (int i = 0; i < int(bits.size()); i++)
if (bits[i].wire != NULL) {
PortBit pbit = { cell, port, i };
if (is_output) {
signal_drivers[bits[i]].insert(pbit);
cell_outputs[cell].insert(bits[i]);
}
if (is_input) {
signal_consumers[bits[i]].insert(pbit);
cell_inputs[cell].insert(bits[i]);
}
}
}
void add_cell(RTLIL::Cell *cell)
{
if (ct.cell_known(cell->type)) {
for (auto &conn : cell->connections())
add_cell_port(cell, conn.first, sigmap(conn.second),
ct.cell_output(cell->type, conn.first),
ct.cell_input(cell->type, conn.first));
} else {
for (auto &conn : cell->connections())
add_cell_port(cell, conn.first, sigmap(conn.second), true, true);
}
}
ModWalker() : design(NULL), module(NULL)
{
}
ModWalker(RTLIL::Design *design, RTLIL::Module *module, CellTypes *filter_ct = NULL)
{
setup(design, module, filter_ct);
}
void setup(RTLIL::Design *design, RTLIL::Module *module, CellTypes *filter_ct = NULL)
{
this->design = design;
this->module = module;
ct.clear();
ct.setup(design);
sigmap.set(module);
signal_drivers.clear();
signal_consumers.clear();
signal_inputs.clear();
signal_outputs.clear();
for (auto &it : module->wires_)
add_wire(it.second);
for (auto &it : module->cells_)
if (filter_ct == NULL || filter_ct->cell_known(it.second->type))
add_cell(it.second);
}
// get_* methods -- single RTLIL::SigBit
template<typename T>
inline bool get_drivers(std::set<PortBit> &result, RTLIL::SigBit bit) const
{
bool found = false;
if (signal_drivers.count(bit)) {
const std::set<PortBit> &r = signal_drivers.at(bit);
result.insert(r.begin(), r.end());
found = true;
}
return found;
}
template<typename T>
inline bool get_consumers(std::set<PortBit> &result, RTLIL::SigBit bit) const
{
bool found = false;
if (signal_consumers.count(bit)) {
const std::set<PortBit> &r = signal_consumers.at(bit);
result.insert(r.begin(), r.end());
found = true;
}
return found;
}
template<typename T>
inline bool get_inputs(std::set<RTLIL::SigBit> &result, RTLIL::SigBit bit) const
{
bool found = false;
if (signal_inputs.count(bit))
result.insert(bit), found = true;
return found;
}
template<typename T>
inline bool get_outputs(std::set<RTLIL::SigBit> &result, RTLIL::SigBit bit) const
{
bool found = false;
if (signal_outputs.count(bit))
result.insert(bit), found = true;
return found;
}
// get_* methods -- container of RTLIL::SigBit's (always by reference)
template<typename T>
inline bool get_drivers(std::set<PortBit> &result, const T &bits) const
{
bool found = false;
for (RTLIL::SigBit bit : bits)
if (signal_drivers.count(bit)) {
const std::set<PortBit> &r = signal_drivers.at(bit);
result.insert(r.begin(), r.end());
found = true;
}
return found;
}
template<typename T>
inline bool get_consumers(std::set<PortBit> &result, const T &bits) const
{
bool found = false;
for (RTLIL::SigBit bit : bits)
if (signal_consumers.count(bit)) {
const std::set<PortBit> &r = signal_consumers.at(bit);
result.insert(r.begin(), r.end());
found = true;
}
return found;
}
template<typename T>
inline bool get_inputs(std::set<RTLIL::SigBit> &result, const T &bits) const
{
bool found = false;
for (RTLIL::SigBit bit : bits)
if (signal_inputs.count(bit))
result.insert(bit), found = true;
return found;
}
template<typename T>
inline bool get_outputs(std::set<RTLIL::SigBit> &result, const T &bits) const
{
bool found = false;
for (RTLIL::SigBit bit : bits)
if (signal_outputs.count(bit))
result.insert(bit), found = true;
return found;
}
// get_* methods -- call by RTLIL::SigSpec (always by value)
bool get_drivers(std::set<PortBit> &result, RTLIL::SigSpec signal) const
{
std::vector<RTLIL::SigBit> bits = sigmap(signal);
return get_drivers(result, bits);
}
bool get_consumers(std::set<PortBit> &result, RTLIL::SigSpec signal) const
{
std::vector<RTLIL::SigBit> bits = sigmap(signal);
return get_consumers(result, bits);
}
bool get_inputs(std::set<RTLIL::SigBit> &result, RTLIL::SigSpec signal) const
{
std::vector<RTLIL::SigBit> bits = sigmap(signal);
return get_inputs(result, bits);
}
bool get_outputs(std::set<RTLIL::SigBit> &result, RTLIL::SigSpec signal) const
{
std::vector<RTLIL::SigBit> bits = sigmap(signal);
return get_outputs(result, bits);
}
// has_* methods -- call by reference
template<typename T>
inline bool has_drivers(const T &sig) const {
std::set<PortBit> result;
return get_drivers(result, sig);
}
template<typename T>
inline bool has_consumers(const T &sig) const {
std::set<PortBit> result;
return get_consumers(result, sig);
}
template<typename T>
inline bool has_inputs(const T &sig) const {
std::set<RTLIL::SigBit> result;
return get_inputs(result, sig);
}
template<typename T>
inline bool has_outputs(const T &sig) const {
std::set<RTLIL::SigBit> result;
return get_outputs(result, sig);
}
// has_* methods -- call by value
inline bool has_drivers(RTLIL::SigSpec sig) const {
std::set<PortBit> result;
return get_drivers(result, sig);
}
inline bool has_consumers(RTLIL::SigSpec sig) const {
std::set<PortBit> result;
return get_consumers(result, sig);
}
inline bool has_inputs(RTLIL::SigSpec sig) const {
std::set<RTLIL::SigBit> result;
return get_inputs(result, sig);
}
inline bool has_outputs(RTLIL::SigSpec sig) const {
std::set<RTLIL::SigBit> result;
return get_outputs(result, sig);
}
};
YOSYS_NAMESPACE_END
#endif

View file

@ -17,50 +17,46 @@
*
*/
#include "register.h"
#include "log.h"
#include <assert.h>
#include "kernel/yosys.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
YOSYS_NAMESPACE_BEGIN
using namespace REGISTER_INTERN;
#define MAX_REG_COUNT 1000
namespace REGISTER_INTERN
{
bool echo_mode = false;
int raw_register_count = 0;
bool raw_register_done = false;
Pass *raw_register_array[MAX_REG_COUNT];
bool echo_mode = false;
Pass *first_queued_pass;
Pass *current_pass;
std::map<std::string, Frontend*> frontend_register;
std::map<std::string, Pass*> pass_register;
std::map<std::string, Backend*> backend_register;
}
std::map<std::string, Frontend*> frontend_register;
std::map<std::string, Pass*> pass_register;
std::map<std::string, Backend*> backend_register;
std::vector<std::string> Frontend::next_args;
Pass::Pass(std::string name, std::string short_help) : pass_name(name), short_help(short_help)
{
assert(!raw_register_done);
assert(raw_register_count < MAX_REG_COUNT);
raw_register_array[raw_register_count++] = this;
next_queued_pass = first_queued_pass;
first_queued_pass = this;
call_counter = 0;
runtime_ns = 0;
}
void Pass::run_register()
{
assert(pass_register.count(pass_name) == 0);
log_assert(pass_register.count(pass_name) == 0);
pass_register[pass_name] = this;
}
void Pass::init_register()
{
if (raw_register_done)
done_register();
while (raw_register_count > 0)
raw_register_array[--raw_register_count]->run_register();
raw_register_done = true;
while (first_queued_pass) {
first_queued_pass->run_register();
first_queued_pass = first_queued_pass->next_queued_pass;
}
}
void Pass::done_register()
@ -68,13 +64,32 @@ void Pass::done_register()
frontend_register.clear();
pass_register.clear();
backend_register.clear();
raw_register_done = false;
log_assert(first_queued_pass == NULL);
}
Pass::~Pass()
{
}
Pass::pre_post_exec_state_t Pass::pre_execute()
{
pre_post_exec_state_t state;
call_counter++;
state.begin_ns = PerformanceTimer::query();
state.parent_pass = current_pass;
current_pass = this;
return state;
}
void Pass::post_execute(Pass::pre_post_exec_state_t state)
{
int64_t time_ns = PerformanceTimer::query() - state.begin_ns;
runtime_ns += time_ns;
current_pass = state.parent_pass;
if (current_pass)
current_pass->runtime_ns -= time_ns;
}
void Pass::help()
{
log("\n");
@ -117,7 +132,7 @@ void Pass::extra_args(std::vector<std::string> args, size_t argidx, RTLIL::Desig
std::string arg = args[argidx];
if (arg.substr(0, 1) == "-")
cmd_error(args, argidx, "Unkown option or option in arguments.");
cmd_error(args, argidx, "Unknown option or option in arguments.");
if (!select)
cmd_error(args, argidx, "Extra argument.");
@ -133,8 +148,10 @@ void Pass::call(RTLIL::Design *design, std::string command)
std::vector<std::string> args;
char *s = strdup(command.c_str()), *sstart = s, *saveptr;
s += strspn(s, " \t\r\n");
if (*s == 0 || *s == '#')
if (*s == 0 || *s == '#') {
free(sstart);
return;
}
if (*s == '!') {
for (s++; *s == ' ' || *s == '\t'; s++) { }
char *p = s + strlen(s) - 1;
@ -144,6 +161,7 @@ void Pass::call(RTLIL::Design *design, std::string command)
int retCode = system(s);
if (retCode != 0)
log_cmd_error("Shell command returned error code %d.\n", retCode);
free(sstart);
return;
}
for (char *p = strtok_r(s, " \t\r\n", &saveptr); p; p = strtok_r(NULL, " \t\r\n", &saveptr)) {
@ -186,18 +204,20 @@ void Pass::call(RTLIL::Design *design, std::vector<std::string> args)
log_cmd_error("No such command: %s (type 'help' for a command overview)\n", args[0].c_str());
size_t orig_sel_stack_pos = design->selection_stack.size();
auto state = pass_register[args[0]]->pre_execute();
pass_register[args[0]]->execute(args, design);
pass_register[args[0]]->post_execute(state);
while (design->selection_stack.size() > orig_sel_stack_pos)
design->selection_stack.pop_back();
design->check();
}
void Pass::call_newsel(RTLIL::Design *design, std::string command)
void Pass::call_on_selection(RTLIL::Design *design, const RTLIL::Selection &selection, std::string command)
{
std::string backup_selected_active_module = design->selected_active_module;
design->selected_active_module.clear();
design->selection_stack.push_back(RTLIL::Selection());
design->selection_stack.push_back(selection);
Pass::call(design, command);
@ -205,11 +225,11 @@ void Pass::call_newsel(RTLIL::Design *design, std::string command)
design->selected_active_module = backup_selected_active_module;
}
void Pass::call_newsel(RTLIL::Design *design, std::vector<std::string> args)
void Pass::call_on_selection(RTLIL::Design *design, const RTLIL::Selection &selection, std::vector<std::string> args)
{
std::string backup_selected_active_module = design->selected_active_module;
design->selected_active_module.clear();
design->selection_stack.push_back(RTLIL::Selection());
design->selection_stack.push_back(selection);
Pass::call(design, args);
@ -217,16 +237,44 @@ void Pass::call_newsel(RTLIL::Design *design, std::vector<std::string> args)
design->selected_active_module = backup_selected_active_module;
}
Frontend::Frontend(std::string name, std::string short_help) : Pass("read_"+name, short_help), frontend_name(name)
void Pass::call_on_module(RTLIL::Design *design, RTLIL::Module *module, std::string command)
{
std::string backup_selected_active_module = design->selected_active_module;
design->selected_active_module = module->name.str();
design->selection_stack.push_back(RTLIL::Selection(false));
design->selection_stack.back().select(module);
Pass::call(design, command);
design->selection_stack.pop_back();
design->selected_active_module = backup_selected_active_module;
}
void Pass::call_on_module(RTLIL::Design *design, RTLIL::Module *module, std::vector<std::string> args)
{
std::string backup_selected_active_module = design->selected_active_module;
design->selected_active_module = module->name.str();
design->selection_stack.push_back(RTLIL::Selection(false));
design->selection_stack.back().select(module);
Pass::call(design, args);
design->selection_stack.pop_back();
design->selected_active_module = backup_selected_active_module;
}
Frontend::Frontend(std::string name, std::string short_help) :
Pass(name.rfind("=", 0) == 0 ? name.substr(1) : "read_" + name, short_help),
frontend_name(name.rfind("=", 0) == 0 ? name.substr(1) : name)
{
}
void Frontend::run_register()
{
assert(pass_register.count(pass_name) == 0);
log_assert(pass_register.count(pass_name) == 0);
pass_register[pass_name] = this;
assert(frontend_register.count(frontend_name) == 0);
log_assert(frontend_register.count(frontend_name) == 0);
frontend_register[frontend_name] = this;
}
@ -236,17 +284,22 @@ Frontend::~Frontend()
void Frontend::execute(std::vector<std::string> args, RTLIL::Design *design)
{
assert(next_args.empty());
log_assert(next_args.empty());
do {
FILE *f = NULL;
std::istream *f = NULL;
next_args.clear();
auto state = pre_execute();
execute(f, std::string(), args, design);
post_execute(state);
args = next_args;
fclose(f);
delete f;
} while (!args.empty());
}
void Frontend::extra_args(FILE *&f, std::string &filename, std::vector<std::string> args, size_t argidx)
FILE *Frontend::current_script_file = NULL;
std::string Frontend::last_here_document;
void Frontend::extra_args(std::istream *&f, std::string &filename, std::vector<std::string> args, size_t argidx)
{
bool called_with_fp = f != NULL;
@ -256,15 +309,53 @@ void Frontend::extra_args(FILE *&f, std::string &filename, std::vector<std::stri
std::string arg = args[argidx];
if (arg.substr(0, 1) == "-")
cmd_error(args, argidx, "Unkown option or option in arguments.");
cmd_error(args, argidx, "Unknown option or option in arguments.");
if (f != NULL)
cmd_error(args, argidx, "Extra filename argument in direct file mode.");
filename = arg;
f = fopen(filename.c_str(), "r");
if (filename == "<<" && argidx+1 < args.size())
filename += args[++argidx];
if (filename.substr(0, 2) == "<<") {
if (Frontend::current_script_file == NULL)
log_error("Unexpected here document '%s' outside of script!\n", filename.c_str());
if (filename.size() <= 2)
log_error("Missing EOT marker in here document!\n");
std::string eot_marker = filename.substr(2);
last_here_document.clear();
while (1) {
std::string buffer;
char block[4096];
while (1) {
if (fgets(block, 4096, Frontend::current_script_file) == NULL)
log_error("Unexpected end of file in here document '%s'!\n", filename.c_str());
buffer += block;
if (buffer.size() > 0 && (buffer[buffer.size() - 1] == '\n' || buffer[buffer.size() - 1] == '\r'))
break;
}
int indent = buffer.find_first_not_of(" \t\r\n");
if (buffer.substr(indent, eot_marker.size()) == eot_marker)
break;
last_here_document += buffer;
}
f = new std::istringstream(last_here_document);
} else {
if (filename.substr(0, 2) == "+/")
filename = proc_share_dirname() + filename.substr(1);
std::ifstream *ff = new std::ifstream;
ff->open(filename.c_str());
if (ff->fail())
delete ff;
else
f = ff;
}
if (f == NULL)
log_cmd_error("Can't open input file `%s' for reading: %s\n", filename.c_str(), strerror(errno));
for (size_t i = argidx+1; i < args.size(); i++)
if (args[i].substr(0, 1) == "-")
cmd_error(args, i, "Found option, expected arguments.");
if (argidx+1 < args.size()) {
next_args.insert(next_args.begin(), args.begin(), args.begin()+argidx);
next_args.insert(next_args.begin()+argidx, args.begin()+argidx+1, args.end());
@ -281,7 +372,7 @@ void Frontend::extra_args(FILE *&f, std::string &filename, std::vector<std::stri
// cmd_log_args(args);
}
void Frontend::frontend_call(RTLIL::Design *design, FILE *f, std::string filename, std::string command)
void Frontend::frontend_call(RTLIL::Design *design, std::istream *f, std::string filename, std::string command)
{
std::vector<std::string> args;
char *s = strdup(command.c_str());
@ -291,7 +382,7 @@ void Frontend::frontend_call(RTLIL::Design *design, FILE *f, std::string filenam
frontend_call(design, f, filename, args);
}
void Frontend::frontend_call(RTLIL::Design *design, FILE *f, std::string filename, std::vector<std::string> args)
void Frontend::frontend_call(RTLIL::Design *design, std::istream *f, std::string filename, std::vector<std::string> args)
{
if (args.size() == 0)
return;
@ -299,9 +390,14 @@ void Frontend::frontend_call(RTLIL::Design *design, FILE *f, std::string filenam
log_cmd_error("No such frontend: %s\n", args[0].c_str());
if (f != NULL) {
auto state = frontend_register[args[0]]->pre_execute();
frontend_register[args[0]]->execute(f, filename, args, design);
frontend_register[args[0]]->post_execute(state);
} else if (filename == "-") {
frontend_register[args[0]]->execute(stdin, "<stdin>", args, design);
std::istream *f_cin = &std::cin;
auto state = frontend_register[args[0]]->pre_execute();
frontend_register[args[0]]->execute(f_cin, "<stdin>", args, design);
frontend_register[args[0]]->post_execute(state);
} else {
if (!filename.empty())
args.push_back(filename);
@ -311,16 +407,18 @@ void Frontend::frontend_call(RTLIL::Design *design, FILE *f, std::string filenam
design->check();
}
Backend::Backend(std::string name, std::string short_help) : Pass("write_"+name, short_help), backend_name(name)
Backend::Backend(std::string name, std::string short_help) :
Pass(name.rfind("=", 0) == 0 ? name.substr(1) : "write_" + name, short_help),
backend_name(name.rfind("=", 0) == 0 ? name.substr(1) : name)
{
}
void Backend::run_register()
{
assert(pass_register.count(pass_name) == 0);
log_assert(pass_register.count(pass_name) == 0);
pass_register[pass_name] = this;
assert(backend_register.count(backend_name) == 0);
log_assert(backend_register.count(backend_name) == 0);
backend_register[backend_name] = this;
}
@ -330,13 +428,15 @@ Backend::~Backend()
void Backend::execute(std::vector<std::string> args, RTLIL::Design *design)
{
FILE *f = NULL;
std::ostream *f = NULL;
auto state = pre_execute();
execute(f, std::string(), args, design);
if (f != stdout)
fclose(f);
post_execute(state);
if (f != &std::cout)
delete f;
}
void Backend::extra_args(FILE *&f, std::string &filename, std::vector<std::string> args, size_t argidx)
void Backend::extra_args(std::ostream *&f, std::string &filename, std::vector<std::string> args, size_t argidx)
{
bool called_with_fp = f != NULL;
@ -345,20 +445,24 @@ void Backend::extra_args(FILE *&f, std::string &filename, std::vector<std::strin
std::string arg = args[argidx];
if (arg.substr(0, 1) == "-" && arg != "-")
cmd_error(args, argidx, "Unkown option or option in arguments.");
cmd_error(args, argidx, "Unknown option or option in arguments.");
if (f != NULL)
cmd_error(args, argidx, "Extra filename argument in direct file mode.");
if (arg == "-") {
filename = "<stdout>";
f = stdout;
f = &std::cout;
continue;
}
filename = arg;
f = fopen(filename.c_str(), "w");
if (f == NULL)
std::ofstream *ff = new std::ofstream;
ff->open(filename.c_str(), std::ofstream::trunc);
if (ff->fail()) {
delete ff;
log_cmd_error("Can't open output file `%s' for writing: %s\n", filename.c_str(), strerror(errno));
}
f = ff;
}
if (called_with_fp)
@ -368,11 +472,11 @@ void Backend::extra_args(FILE *&f, std::string &filename, std::vector<std::strin
if (f == NULL) {
filename = "<stdout>";
f = stdout;
f = &std::cout;
}
}
void Backend::backend_call(RTLIL::Design *design, FILE *f, std::string filename, std::string command)
void Backend::backend_call(RTLIL::Design *design, std::ostream *f, std::string filename, std::string command)
{
std::vector<std::string> args;
char *s = strdup(command.c_str());
@ -382,7 +486,7 @@ void Backend::backend_call(RTLIL::Design *design, FILE *f, std::string filename,
backend_call(design, f, filename, args);
}
void Backend::backend_call(RTLIL::Design *design, FILE *f, std::string filename, std::vector<std::string> args)
void Backend::backend_call(RTLIL::Design *design, std::ostream *f, std::string filename, std::vector<std::string> args)
{
if (args.size() == 0)
return;
@ -392,9 +496,14 @@ void Backend::backend_call(RTLIL::Design *design, FILE *f, std::string filename,
size_t orig_sel_stack_pos = design->selection_stack.size();
if (f != NULL) {
auto state = backend_register[args[0]]->pre_execute();
backend_register[args[0]]->execute(f, filename, args, design);
backend_register[args[0]]->post_execute(state);
} else if (filename == "-") {
backend_register[args[0]]->execute(stdout, "<stdout>", args, design);
std::ostream *f_cout = &std::cout;
auto state = backend_register[args[0]]->pre_execute();
backend_register[args[0]]->execute(f_cout, "<stdout>", args, design);
backend_register[args[0]]->post_execute(state);
} else {
if (!filename.empty())
args.push_back(filename);
@ -479,7 +588,7 @@ struct HelpPass : public Pass {
{
if (args.size() == 1) {
log("\n");
for (auto &it : REGISTER_INTERN::pass_register)
for (auto &it : pass_register)
log(" %-20s %s\n", it.first.c_str(), it.second->short_help.c_str());
log("\n");
log("Type 'help <command>' for more information on a command.\n");
@ -489,7 +598,7 @@ struct HelpPass : public Pass {
if (args.size() == 2) {
if (args[1] == "-all") {
for (auto &it : REGISTER_INTERN::pass_register) {
for (auto &it : pass_register) {
log("\n\n");
log("%s -- %s\n", it.first.c_str(), it.second->short_help.c_str());
for (size_t i = 0; i < it.first.size() + it.second->short_help.size() + 6; i++)
@ -502,39 +611,31 @@ struct HelpPass : public Pass {
else if (args[1] == "-write-tex-command-reference-manual") {
FILE *f = fopen("command-reference-manual.tex", "wt");
fprintf(f, "%% Generated using the yosys 'help -write-tex-command-reference-manual' command.\n\n");
for (auto &it : REGISTER_INTERN::pass_register) {
size_t memsize;
char *memptr;
FILE *memf = open_memstream(&memptr, &memsize);
log_files.push_back(memf);
for (auto &it : pass_register) {
std::ostringstream buf;
log_streams.push_back(&buf);
it.second->help();
log_files.pop_back();
fclose(memf);
write_tex(f, it.first, it.second->short_help, memptr);
free(memptr);
log_streams.pop_back();
write_tex(f, it.first, it.second->short_help, buf.str());
}
fclose(f);
}
// this option is undocumented as it is for internal use only
else if (args[1] == "-write-web-command-reference-manual") {
FILE *f = fopen("templates/cmd_index.in", "wt");
for (auto &it : REGISTER_INTERN::pass_register) {
size_t memsize;
char *memptr;
FILE *memf = open_memstream(&memptr, &memsize);
log_files.push_back(memf);
for (auto &it : pass_register) {
std::ostringstream buf;
log_streams.push_back(&buf);
it.second->help();
log_files.pop_back();
fclose(memf);
write_html(f, it.first, it.second->short_help, memptr);
free(memptr);
log_streams.pop_back();
write_html(f, it.first, it.second->short_help, buf.str());
}
fclose(f);
}
else if (REGISTER_INTERN::pass_register.count(args[1]) == 0)
else if (pass_register.count(args[1]) == 0)
log("No such command: %s\n", args[1].c_str());
else
REGISTER_INTERN::pass_register.at(args[1])->help();
pass_register.at(args[1])->help();
return;
}
@ -575,3 +676,5 @@ struct EchoPass : public Pass {
}
} EchoPass;
YOSYS_NAMESPACE_END

View file

@ -17,38 +17,33 @@
*
*/
#include "kernel/yosys.h"
#ifndef REGISTER_H
#define REGISTER_H
#include "kernel/rtlil.h"
#include <stdio.h>
#include <string>
#include <vector>
#include <map>
#ifdef YOSYS_ENABLE_TCL
#include <tcl.h>
extern Tcl_Interp *yosys_get_tcl_interp();
#endif
// from kernel/version_*.o (cc source generated from Makefile)
extern const char *yosys_version_str;
// implemented in driver.cc
extern RTLIL::Design *yosys_get_design();
std::string rewrite_yosys_exe(std::string exe);
std::string get_share_file_name(std::string file);
const char *create_prompt(RTLIL::Design *design, int recursion_counter);
YOSYS_NAMESPACE_BEGIN
struct Pass
{
std::string pass_name, short_help;
Pass(std::string name, std::string short_help = "** document me **");
virtual void run_register();
virtual ~Pass();
virtual void help();
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) = 0;
int call_counter;
int64_t runtime_ns;
struct pre_post_exec_state_t {
Pass *parent_pass;
int64_t begin_ns;
};
pre_post_exec_state_t pre_execute();
void post_execute(pre_post_exec_state_t state);
void cmd_log_args(const std::vector<std::string> &args);
void cmd_error(const std::vector<std::string> &args, size_t argidx, std::string msg);
void extra_args(std::vector<std::string> args, size_t argidx, RTLIL::Design *design, bool select = true);
@ -56,27 +51,36 @@ struct Pass
static void call(RTLIL::Design *design, std::string command);
static void call(RTLIL::Design *design, std::vector<std::string> args);
static void call_newsel(RTLIL::Design *design, std::string command);
static void call_newsel(RTLIL::Design *design, std::vector<std::string> args);
static void call_on_selection(RTLIL::Design *design, const RTLIL::Selection &selection, std::string command);
static void call_on_selection(RTLIL::Design *design, const RTLIL::Selection &selection, std::vector<std::string> args);
static void call_on_module(RTLIL::Design *design, RTLIL::Module *module, std::string command);
static void call_on_module(RTLIL::Design *design, RTLIL::Module *module, std::vector<std::string> args);
Pass *next_queued_pass;
virtual void run_register();
static void init_register();
static void done_register();
};
struct Frontend : Pass
{
// for reading of here documents
static FILE *current_script_file;
static std::string last_here_document;
std::string frontend_name;
Frontend(std::string name, std::string short_help = "** document me **");
virtual void run_register();
virtual ~Frontend();
virtual void execute(std::vector<std::string> args, RTLIL::Design *design);
virtual void execute(FILE *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) = 0;
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) OVERRIDE FINAL;
virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) = 0;
static std::vector<std::string> next_args;
void extra_args(FILE *&f, std::string &filename, std::vector<std::string> args, size_t argidx);
void extra_args(std::istream *&f, std::string &filename, std::vector<std::string> args, size_t argidx);
static void frontend_call(RTLIL::Design *design, FILE *f, std::string filename, std::string command);
static void frontend_call(RTLIL::Design *design, FILE *f, std::string filename, std::vector<std::string> args);
static void frontend_call(RTLIL::Design *design, std::istream *f, std::string filename, std::string command);
static void frontend_call(RTLIL::Design *design, std::istream *f, std::string filename, std::vector<std::string> args);
};
struct Backend : Pass
@ -85,25 +89,22 @@ struct Backend : Pass
Backend(std::string name, std::string short_help = "** document me **");
virtual void run_register();
virtual ~Backend();
virtual void execute(std::vector<std::string> args, RTLIL::Design *design);
virtual void execute(FILE *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) = 0;
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) OVERRIDE FINAL;
virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) = 0;
void extra_args(FILE *&f, std::string &filename, std::vector<std::string> args, size_t argidx);
void extra_args(std::ostream *&f, std::string &filename, std::vector<std::string> args, size_t argidx);
static void backend_call(RTLIL::Design *design, FILE *f, std::string filename, std::string command);
static void backend_call(RTLIL::Design *design, FILE *f, std::string filename, std::vector<std::string> args);
static void backend_call(RTLIL::Design *design, std::ostream *f, std::string filename, std::string command);
static void backend_call(RTLIL::Design *design, std::ostream *f, std::string filename, std::vector<std::string> args);
};
// implemented in passes/cmds/select.cc
extern void handle_extra_select_args(Pass *pass, std::vector<std::string> args, size_t argidx, size_t args_size, RTLIL::Design *design);
namespace REGISTER_INTERN {
extern int raw_register_count;
extern bool raw_register_done;
extern Pass *raw_register_array[];
extern std::map<std::string, Pass*> pass_register;
extern std::map<std::string, Frontend*> frontend_register;
extern std::map<std::string, Backend*> backend_register;
}
extern std::map<std::string, Pass*> pass_register;
extern std::map<std::string, Frontend*> frontend_register;
extern std::map<std::string, Backend*> backend_register;
YOSYS_NAMESPACE_END
#endif

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -23,14 +23,10 @@
#include "kernel/rtlil.h"
#include "kernel/sigtools.h"
#include "kernel/celltypes.h"
#include "kernel/macc.h"
#ifdef YOSYS_ENABLE_MINISAT
# include "libs/ezsat/ezminisat.h"
#include "libs/ezsat/ezminisat.h"
typedef ezMiniSAT ezDefaultSAT;
#else
# include "libs/ezsat/ezsat.h"
typedef ezSAT ezDefaultSAT;
#endif
struct SatGen
{
@ -57,21 +53,19 @@ struct SatGen
{
log_assert(!undef_mode || model_undef);
sigmap->apply(sig);
sig.expand();
std::vector<int> vec;
vec.reserve(sig.chunks.size());
vec.reserve(SIZE(sig));
for (auto &c : sig.chunks)
if (c.wire == NULL) {
RTLIL::State bit = c.data.bits.at(0);
for (auto &bit : sig)
if (bit.wire == NULL) {
if (model_undef && dup_undef && bit == RTLIL::State::Sx)
vec.push_back(ez->literal());
vec.push_back(ez->frozen_literal());
else
vec.push_back(bit == (undef_mode ? RTLIL::State::Sx : RTLIL::State::S1) ? ez->TRUE : ez->FALSE);
} else {
std::string name = pf + stringf(c.wire->width == 1 ? "%s" : "%s [%d]", RTLIL::id2cstr(c.wire->name), c.offset);
vec.push_back(ez->literal(name));
std::string name = pf + stringf(bit.wire->width == 1 ? "%s" : "%s [%d]", RTLIL::id2cstr(bit.wire->name), bit.offset);
vec.push_back(ez->frozen_literal(name));
}
return vec;
}
@ -123,7 +117,7 @@ struct SatGen
if (timestep_rhs < 0)
timestep_rhs = timestep_lhs;
assert(lhs.width == rhs.width);
log_assert(lhs.size() == rhs.size());
std::vector<int> vec_lhs = importSigSpec(lhs, timestep_lhs);
std::vector<int> vec_rhs = importSigSpec(rhs, timestep_rhs);
@ -135,7 +129,7 @@ struct SatGen
std::vector<int> undef_rhs = importUndefSigSpec(rhs, timestep_rhs);
std::vector<int> eq_bits;
for (int i = 0; i < lhs.width; i++)
for (int i = 0; i < lhs.size(); i++)
eq_bits.push_back(ez->AND(ez->IFF(undef_lhs.at(i), undef_rhs.at(i)),
ez->IFF(ez->OR(vec_lhs.at(i), undef_lhs.at(i)), ez->OR(vec_rhs.at(i), undef_rhs.at(i)))));
return ez->expression(ezSAT::OpAnd, eq_bits);
@ -170,20 +164,33 @@ struct SatGen
void undefGating(std::vector<int> &vec_y, std::vector<int> &vec_yy, std::vector<int> &vec_undef)
{
assert(model_undef);
ez->assume(ez->expression(ezSAT::OpAnd, ez->vec_or(vec_undef, ez->vec_iff(vec_y, vec_yy))));
log_assert(model_undef);
log_assert(vec_y.size() == vec_yy.size());
if (vec_y.size() > vec_undef.size()) {
std::vector<int> trunc_y(vec_y.begin(), vec_y.begin() + vec_undef.size());
std::vector<int> trunc_yy(vec_yy.begin(), vec_yy.begin() + vec_undef.size());
ez->assume(ez->expression(ezSAT::OpAnd, ez->vec_or(vec_undef, ez->vec_iff(trunc_y, trunc_yy))));
} else {
log_assert(vec_y.size() == vec_undef.size());
ez->assume(ez->expression(ezSAT::OpAnd, ez->vec_or(vec_undef, ez->vec_iff(vec_y, vec_yy))));
}
}
void undefGating(int y, int yy, int undef)
{
ez->assume(ez->OR(undef, ez->IFF(y, yy)));
}
bool importCell(RTLIL::Cell *cell, int timestep = -1)
{
bool arith_undef_handled = false;
bool is_arith_compare = cell->type == "$lt" || cell->type == "$le" || cell->type == "$ge" || cell->type == "$gt";
bool is_arith_compare = cell->type.in("$lt", "$le", "$ge", "$gt");
if (model_undef && (cell->type == "$add" || cell->type == "$sub" || cell->type == "$mul" || cell->type == "$div" || cell->type == "$mod" || is_arith_compare))
if (model_undef && (cell->type.in("$add", "$sub", "$mul", "$div", "$mod") || is_arith_compare))
{
std::vector<int> undef_a = importUndefSigSpec(cell->connections.at("\\A"), timestep);
std::vector<int> undef_b = importUndefSigSpec(cell->connections.at("\\B"), timestep);
std::vector<int> undef_y = importUndefSigSpec(cell->connections.at("\\Y"), timestep);
std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep);
std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
if (is_arith_compare)
extendSignalWidth(undef_a, undef_b, cell, true);
else
@ -194,7 +201,7 @@ struct SatGen
int undef_y_bit = ez->OR(undef_any_a, undef_any_b);
if (cell->type == "$div" || cell->type == "$mod") {
std::vector<int> b = importSigSpec(cell->connections.at("\\B"), timestep);
std::vector<int> b = importSigSpec(cell->getPort("\\B"), timestep);
undef_y_bit = ez->OR(undef_y_bit, ez->NOT(ez->expression(ezSAT::OpOr, b)));
}
@ -210,24 +217,27 @@ struct SatGen
arith_undef_handled = true;
}
if (cell->type == "$_AND_" || cell->type == "$_OR_" || cell->type == "$_XOR_" ||
cell->type == "$and" || cell->type == "$or" || cell->type == "$xor" || cell->type == "$xnor" ||
cell->type == "$add" || cell->type == "$sub")
if (cell->type.in("$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_",
"$and", "$or", "$xor", "$xnor", "$add", "$sub"))
{
std::vector<int> a = importDefSigSpec(cell->connections.at("\\A"), timestep);
std::vector<int> b = importDefSigSpec(cell->connections.at("\\B"), timestep);
std::vector<int> y = importDefSigSpec(cell->connections.at("\\Y"), timestep);
std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep);
std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep);
std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep);
extendSignalWidth(a, b, y, cell);
std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
if (cell->type == "$and" || cell->type == "$_AND_")
ez->assume(ez->vec_eq(ez->vec_and(a, b), yy));
if (cell->type == "$_NAND_")
ez->assume(ez->vec_eq(ez->vec_not(ez->vec_and(a, b)), yy));
if (cell->type == "$or" || cell->type == "$_OR_")
ez->assume(ez->vec_eq(ez->vec_or(a, b), yy));
if (cell->type == "$_NOR_")
ez->assume(ez->vec_eq(ez->vec_not(ez->vec_or(a, b)), yy));
if (cell->type == "$xor" || cell->type == "$_XOR_")
ez->assume(ez->vec_eq(ez->vec_xor(a, b), yy));
if (cell->type == "$xnor")
if (cell->type == "$xnor" || cell->type == "$_XNOR_")
ez->assume(ez->vec_eq(ez->vec_not(ez->vec_xor(a, b)), yy));
if (cell->type == "$add")
ez->assume(ez->vec_eq(ez->vec_add(a, b), yy));
@ -236,24 +246,24 @@ struct SatGen
if (model_undef && !arith_undef_handled)
{
std::vector<int> undef_a = importUndefSigSpec(cell->connections.at("\\A"), timestep);
std::vector<int> undef_b = importUndefSigSpec(cell->connections.at("\\B"), timestep);
std::vector<int> undef_y = importUndefSigSpec(cell->connections.at("\\Y"), timestep);
std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep);
std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
extendSignalWidth(undef_a, undef_b, undef_y, cell, false);
if (cell->type == "$and" || cell->type == "$_AND_") {
if (cell->type.in("$and", "$_AND_", "$_NAND_")) {
std::vector<int> a0 = ez->vec_and(ez->vec_not(a), ez->vec_not(undef_a));
std::vector<int> b0 = ez->vec_and(ez->vec_not(b), ez->vec_not(undef_b));
std::vector<int> yX = ez->vec_and(ez->vec_or(undef_a, undef_b), ez->vec_not(ez->vec_or(a0, b0)));
ez->assume(ez->vec_eq(yX, undef_y));
}
else if (cell->type == "$or" || cell->type == "$_OR_") {
else if (cell->type.in("$or", "$_OR_", "$_NOR_")) {
std::vector<int> a1 = ez->vec_and(a, ez->vec_not(undef_a));
std::vector<int> b1 = ez->vec_and(b, ez->vec_not(undef_b));
std::vector<int> yX = ez->vec_and(ez->vec_or(undef_a, undef_b), ez->vec_not(ez->vec_or(a1, b1)));
ez->assume(ez->vec_eq(yX, undef_y));
}
else if (cell->type == "$xor" || cell->type == "$_XOR_" || cell->type == "$xnor") {
else if (cell->type.in("$xor", "$xnor", "$_XOR_", "$_XNOR_")) {
std::vector<int> yX = ez->vec_or(undef_a, undef_b);
ez->assume(ez->vec_eq(yX, undef_y));
}
@ -264,25 +274,91 @@ struct SatGen
}
else if (model_undef)
{
std::vector<int> undef_y = importUndefSigSpec(cell->connections.at("\\Y"), timestep);
std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
undefGating(y, yy, undef_y);
}
return true;
}
if (cell->type == "$_INV_" || cell->type == "$not")
if (cell->type.in("$_AOI3_", "$_OAI3_", "$_AOI4_", "$_OAI4_"))
{
std::vector<int> a = importDefSigSpec(cell->connections.at("\\A"), timestep);
std::vector<int> y = importDefSigSpec(cell->connections.at("\\Y"), timestep);
bool aoi_mode = cell->type.in("$_AOI3_", "$_AOI4_");
bool three_mode = cell->type.in("$_AOI3_", "$_OAI3_");
int a = importDefSigSpec(cell->getPort("\\A"), timestep).at(0);
int b = importDefSigSpec(cell->getPort("\\B"), timestep).at(0);
int c = importDefSigSpec(cell->getPort("\\C"), timestep).at(0);
int d = three_mode ? (aoi_mode ? ez->TRUE : ez->FALSE) : importDefSigSpec(cell->getPort("\\D"), timestep).at(0);
int y = importDefSigSpec(cell->getPort("\\Y"), timestep).at(0);
int yy = model_undef ? ez->literal() : y;
if (cell->type.in("$_AOI3_", "$_AOI4_"))
ez->assume(ez->IFF(ez->NOT(ez->OR(ez->AND(a, b), ez->AND(c, d))), yy));
else
ez->assume(ez->IFF(ez->NOT(ez->AND(ez->OR(a, b), ez->OR(c, d))), yy));
if (model_undef)
{
int undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep).at(0);
int undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep).at(0);
int undef_c = importUndefSigSpec(cell->getPort("\\C"), timestep).at(0);
int undef_d = three_mode ? ez->FALSE : importUndefSigSpec(cell->getPort("\\D"), timestep).at(0);
int undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep).at(0);
if (aoi_mode)
{
int a0 = ez->AND(ez->NOT(a), ez->NOT(undef_a));
int b0 = ez->AND(ez->NOT(b), ez->NOT(undef_b));
int c0 = ez->AND(ez->NOT(c), ez->NOT(undef_c));
int d0 = ez->AND(ez->NOT(d), ez->NOT(undef_d));
int ab = ez->AND(a, b), cd = ez->AND(c, d);
int undef_ab = ez->AND(ez->OR(undef_a, undef_b), ez->NOT(ez->OR(a0, b0)));
int undef_cd = ez->AND(ez->OR(undef_c, undef_d), ez->NOT(ez->OR(c0, d0)));
int ab1 = ez->AND(ab, ez->NOT(undef_ab));
int cd1 = ez->AND(cd, ez->NOT(undef_cd));
int yX = ez->AND(ez->OR(undef_ab, undef_cd), ez->NOT(ez->OR(ab1, cd1)));
ez->assume(ez->IFF(yX, undef_y));
}
else
{
int a1 = ez->AND(a, ez->NOT(undef_a));
int b1 = ez->AND(b, ez->NOT(undef_b));
int c1 = ez->AND(c, ez->NOT(undef_c));
int d1 = ez->AND(d, ez->NOT(undef_d));
int ab = ez->OR(a, b), cd = ez->OR(c, d);
int undef_ab = ez->AND(ez->OR(undef_a, undef_b), ez->NOT(ez->OR(a1, b1)));
int undef_cd = ez->AND(ez->OR(undef_c, undef_d), ez->NOT(ez->OR(c1, d1)));
int ab0 = ez->AND(ez->NOT(ab), ez->NOT(undef_ab));
int cd0 = ez->AND(ez->NOT(cd), ez->NOT(undef_cd));
int yX = ez->AND(ez->OR(undef_ab, undef_cd), ez->NOT(ez->OR(ab0, cd0)));
ez->assume(ez->IFF(yX, undef_y));
}
undefGating(y, yy, undef_y);
}
return true;
}
if (cell->type == "$_NOT_" || cell->type == "$not")
{
std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep);
std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep);
extendSignalWidthUnary(a, y, cell);
std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
ez->assume(ez->vec_eq(ez->vec_not(a), yy));
if (model_undef) {
std::vector<int> undef_a = importUndefSigSpec(cell->connections.at("\\A"), timestep);
std::vector<int> undef_y = importUndefSigSpec(cell->connections.at("\\Y"), timestep);
extendSignalWidthUnary(undef_a, undef_y, cell, true);
std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
extendSignalWidthUnary(undef_a, undef_y, cell, false);
ez->assume(ez->vec_eq(undef_a, undef_y));
undefGating(y, yy, undef_y);
}
@ -291,20 +367,20 @@ struct SatGen
if (cell->type == "$_MUX_" || cell->type == "$mux")
{
std::vector<int> a = importDefSigSpec(cell->connections.at("\\A"), timestep);
std::vector<int> b = importDefSigSpec(cell->connections.at("\\B"), timestep);
std::vector<int> s = importDefSigSpec(cell->connections.at("\\S"), timestep);
std::vector<int> y = importDefSigSpec(cell->connections.at("\\Y"), timestep);
std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep);
std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep);
std::vector<int> s = importDefSigSpec(cell->getPort("\\S"), timestep);
std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep);
std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
ez->assume(ez->vec_eq(ez->vec_ite(s.at(0), b, a), yy));
if (model_undef)
{
std::vector<int> undef_a = importUndefSigSpec(cell->connections.at("\\A"), timestep);
std::vector<int> undef_b = importUndefSigSpec(cell->connections.at("\\B"), timestep);
std::vector<int> undef_s = importUndefSigSpec(cell->connections.at("\\S"), timestep);
std::vector<int> undef_y = importUndefSigSpec(cell->connections.at("\\Y"), timestep);
std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep);
std::vector<int> undef_s = importUndefSigSpec(cell->getPort("\\S"), timestep);
std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
std::vector<int> unequal_ab = ez->vec_not(ez->vec_iff(a, b));
std::vector<int> undef_ab = ez->vec_or(unequal_ab, ez->vec_or(undef_a, undef_b));
@ -315,12 +391,12 @@ struct SatGen
return true;
}
if (cell->type == "$pmux" || cell->type == "$safe_pmux")
if (cell->type == "$pmux")
{
std::vector<int> a = importDefSigSpec(cell->connections.at("\\A"), timestep);
std::vector<int> b = importDefSigSpec(cell->connections.at("\\B"), timestep);
std::vector<int> s = importDefSigSpec(cell->connections.at("\\S"), timestep);
std::vector<int> y = importDefSigSpec(cell->connections.at("\\Y"), timestep);
std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep);
std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep);
std::vector<int> s = importDefSigSpec(cell->getPort("\\S"), timestep);
std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep);
std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
@ -329,16 +405,14 @@ struct SatGen
std::vector<int> part_of_b(b.begin()+i*a.size(), b.begin()+(i+1)*a.size());
tmp = ez->vec_ite(s.at(i), part_of_b, tmp);
}
if (cell->type == "$safe_pmux")
tmp = ez->vec_ite(ez->onehot(s, true), tmp, a);
ez->assume(ez->vec_eq(tmp, yy));
if (model_undef)
{
std::vector<int> undef_a = importUndefSigSpec(cell->connections.at("\\A"), timestep);
std::vector<int> undef_b = importUndefSigSpec(cell->connections.at("\\B"), timestep);
std::vector<int> undef_s = importUndefSigSpec(cell->connections.at("\\S"), timestep);
std::vector<int> undef_y = importUndefSigSpec(cell->connections.at("\\Y"), timestep);
std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep);
std::vector<int> undef_s = importUndefSigSpec(cell->getPort("\\S"), timestep);
std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
int maybe_one_hot = ez->FALSE;
int maybe_many_hot = ez->FALSE;
@ -369,12 +443,6 @@ struct SatGen
int maybe_a = ez->NOT(maybe_one_hot);
if (cell->type == "$safe_pmux") {
maybe_a = ez->OR(maybe_a, maybe_many_hot);
bits_set = ez->vec_ite(sure_many_hot, ez->vec_or(a, undef_a), bits_set);
bits_clr = ez->vec_ite(sure_many_hot, ez->vec_or(ez->vec_not(a), undef_a), bits_clr);
}
bits_set = ez->vec_ite(maybe_a, ez->vec_or(bits_set, ez->vec_or(bits_set, ez->vec_or(a, undef_a))), bits_set);
bits_clr = ez->vec_ite(maybe_a, ez->vec_or(bits_clr, ez->vec_or(bits_clr, ez->vec_or(ez->vec_not(a), undef_a))), bits_clr);
@ -386,8 +454,8 @@ struct SatGen
if (cell->type == "$pos" || cell->type == "$neg")
{
std::vector<int> a = importDefSigSpec(cell->connections.at("\\A"), timestep);
std::vector<int> y = importDefSigSpec(cell->connections.at("\\Y"), timestep);
std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep);
std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep);
extendSignalWidthUnary(a, y, cell);
std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
@ -401,9 +469,9 @@ struct SatGen
if (model_undef)
{
std::vector<int> undef_a = importUndefSigSpec(cell->connections.at("\\A"), timestep);
std::vector<int> undef_y = importUndefSigSpec(cell->connections.at("\\Y"), timestep);
extendSignalWidthUnary(undef_a, undef_y, cell, true);
std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
extendSignalWidthUnary(undef_a, undef_y, cell);
if (cell->type == "$pos") {
ez->assume(ez->vec_eq(undef_a, undef_y));
@ -421,8 +489,8 @@ struct SatGen
if (cell->type == "$reduce_and" || cell->type == "$reduce_or" || cell->type == "$reduce_xor" ||
cell->type == "$reduce_xnor" || cell->type == "$reduce_bool" || cell->type == "$logic_not")
{
std::vector<int> a = importDefSigSpec(cell->connections.at("\\A"), timestep);
std::vector<int> y = importDefSigSpec(cell->connections.at("\\Y"), timestep);
std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep);
std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep);
std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
@ -441,8 +509,8 @@ struct SatGen
if (model_undef)
{
std::vector<int> undef_a = importUndefSigSpec(cell->connections.at("\\A"), timestep);
std::vector<int> undef_y = importUndefSigSpec(cell->connections.at("\\Y"), timestep);
std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
int aX = ez->expression(ezSAT::OpOr, undef_a);
if (cell->type == "$reduce_and") {
@ -468,12 +536,12 @@ struct SatGen
if (cell->type == "$logic_and" || cell->type == "$logic_or")
{
std::vector<int> vec_a = importDefSigSpec(cell->connections.at("\\A"), timestep);
std::vector<int> vec_b = importDefSigSpec(cell->connections.at("\\B"), timestep);
std::vector<int> vec_a = importDefSigSpec(cell->getPort("\\A"), timestep);
std::vector<int> vec_b = importDefSigSpec(cell->getPort("\\B"), timestep);
int a = ez->expression(ez->OpOr, vec_a);
int b = ez->expression(ez->OpOr, vec_b);
std::vector<int> y = importDefSigSpec(cell->connections.at("\\Y"), timestep);
std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep);
std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
@ -486,9 +554,9 @@ struct SatGen
if (model_undef)
{
std::vector<int> undef_a = importUndefSigSpec(cell->connections.at("\\A"), timestep);
std::vector<int> undef_b = importUndefSigSpec(cell->connections.at("\\B"), timestep);
std::vector<int> undef_y = importUndefSigSpec(cell->connections.at("\\Y"), timestep);
std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep);
std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
int a0 = ez->NOT(ez->OR(ez->expression(ezSAT::OpOr, vec_a), ez->expression(ezSAT::OpOr, undef_a)));
int b0 = ez->NOT(ez->OR(ez->expression(ezSAT::OpOr, vec_b), ez->expression(ezSAT::OpOr, undef_b)));
@ -515,16 +583,16 @@ struct SatGen
if (cell->type == "$lt" || cell->type == "$le" || cell->type == "$eq" || cell->type == "$ne" || cell->type == "$eqx" || cell->type == "$nex" || cell->type == "$ge" || cell->type == "$gt")
{
bool is_signed = cell->parameters["\\A_SIGNED"].as_bool() && cell->parameters["\\B_SIGNED"].as_bool();
std::vector<int> a = importDefSigSpec(cell->connections.at("\\A"), timestep);
std::vector<int> b = importDefSigSpec(cell->connections.at("\\B"), timestep);
std::vector<int> y = importDefSigSpec(cell->connections.at("\\Y"), timestep);
std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep);
std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep);
std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep);
extendSignalWidth(a, b, cell);
std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
if (model_undef && (cell->type == "$eqx" || cell->type == "$nex")) {
std::vector<int> undef_a = importUndefSigSpec(cell->connections.at("\\A"), timestep);
std::vector<int> undef_b = importUndefSigSpec(cell->connections.at("\\B"), timestep);
std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep);
extendSignalWidth(undef_a, undef_b, cell, true);
a = ez->vec_or(a, undef_a);
b = ez->vec_or(b, undef_b);
@ -547,9 +615,9 @@ struct SatGen
if (model_undef && (cell->type == "$eqx" || cell->type == "$nex"))
{
std::vector<int> undef_a = importUndefSigSpec(cell->connections.at("\\A"), timestep);
std::vector<int> undef_b = importUndefSigSpec(cell->connections.at("\\B"), timestep);
std::vector<int> undef_y = importUndefSigSpec(cell->connections.at("\\Y"), timestep);
std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep);
std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
extendSignalWidth(undef_a, undef_b, cell, true);
if (cell->type == "$eqx")
@ -564,9 +632,9 @@ struct SatGen
}
else if (model_undef && (cell->type == "$eq" || cell->type == "$ne"))
{
std::vector<int> undef_a = importUndefSigSpec(cell->connections.at("\\A"), timestep);
std::vector<int> undef_b = importUndefSigSpec(cell->connections.at("\\B"), timestep);
std::vector<int> undef_y = importUndefSigSpec(cell->connections.at("\\Y"), timestep);
std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep);
std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
extendSignalWidth(undef_a, undef_b, cell, true);
int undef_any_a = ez->expression(ezSAT::OpOr, undef_a);
@ -588,7 +656,7 @@ struct SatGen
else
{
if (model_undef) {
std::vector<int> undef_y = importUndefSigSpec(cell->connections.at("\\Y"), timestep);
std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
undefGating(y, yy, undef_y);
}
log_assert(!model_undef || arith_undef_handled);
@ -596,59 +664,73 @@ struct SatGen
return true;
}
if (cell->type == "$shl" || cell->type == "$shr" || cell->type == "$sshl" || cell->type == "$sshr")
if (cell->type == "$shl" || cell->type == "$shr" || cell->type == "$sshl" || cell->type == "$sshr" || cell->type == "$shift" || cell->type == "$shiftx")
{
std::vector<int> a = importDefSigSpec(cell->connections.at("\\A"), timestep);
std::vector<int> b = importDefSigSpec(cell->connections.at("\\B"), timestep);
std::vector<int> y = importDefSigSpec(cell->connections.at("\\Y"), timestep);
std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep);
std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep);
std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep);
char shift_left = cell->type == "$shl" || cell->type == "$sshl";
bool sign_extend = cell->type == "$sshr" && cell->parameters["\\A_SIGNED"].as_bool();
int extend_bit = ez->FALSE;
if (!cell->type.in("$shift", "$shiftx") && cell->parameters["\\A_SIGNED"].as_bool())
extend_bit = a.back();
while (y.size() < a.size())
y.push_back(ez->literal());
while (y.size() > a.size())
a.push_back(cell->parameters["\\A_SIGNED"].as_bool() ? a.back() : ez->FALSE);
a.push_back(extend_bit);
std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
std::vector<int> shifted_a;
std::vector<int> tmp = a;
for (size_t i = 0; i < b.size(); i++)
{
std::vector<int> tmp_shifted(tmp.size());
for (size_t j = 0; j < tmp.size(); j++) {
int idx = j + (1 << (i > 30 ? 30 : i)) * (shift_left ? -1 : +1);
tmp_shifted.at(j) = (0 <= idx && idx < int(tmp.size())) ? tmp.at(idx) : sign_extend ? tmp.back() : ez->FALSE;
}
tmp = ez->vec_ite(b.at(i), tmp_shifted, tmp);
}
ez->assume(ez->vec_eq(tmp, yy));
if (cell->type == "$shl" || cell->type == "$sshl")
shifted_a = ez->vec_shift_left(a, b, false, ez->FALSE, ez->FALSE);
if (cell->type == "$shr")
shifted_a = ez->vec_shift_right(a, b, false, ez->FALSE, ez->FALSE);
if (cell->type == "$sshr")
shifted_a = ez->vec_shift_right(a, b, false, cell->parameters["\\A_SIGNED"].as_bool() ? a.back() : ez->FALSE, ez->FALSE);
if (cell->type == "$shift" || cell->type == "$shiftx")
shifted_a = ez->vec_shift_right(a, b, cell->parameters["\\B_SIGNED"].as_bool(), ez->FALSE, ez->FALSE);
ez->assume(ez->vec_eq(shifted_a, yy));
if (model_undef)
{
std::vector<int> undef_a = importUndefSigSpec(cell->connections.at("\\A"), timestep);
std::vector<int> undef_b = importUndefSigSpec(cell->connections.at("\\B"), timestep);
std::vector<int> undef_y = importUndefSigSpec(cell->connections.at("\\Y"), timestep);
std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep);
std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
std::vector<int> undef_a_shifted;
extend_bit = cell->type == "$shiftx" ? ez->TRUE : ez->FALSE;
if (!cell->type.in("$shift", "$shiftx") && cell->parameters["\\A_SIGNED"].as_bool())
extend_bit = undef_a.back();
while (undef_y.size() < undef_a.size())
undef_y.push_back(ez->literal());
while (undef_y.size() > undef_a.size())
undef_a.push_back(undef_a.back());
undef_a.push_back(extend_bit);
tmp = undef_a;
for (size_t i = 0; i < b.size(); i++)
{
std::vector<int> tmp_shifted(tmp.size());
for (size_t j = 0; j < tmp.size(); j++) {
int idx = j + (1 << (i > 30 ? 30 : i)) * (shift_left ? -1 : +1);
tmp_shifted.at(j) = (0 <= idx && idx < int(tmp.size())) ? tmp.at(idx) : sign_extend ? tmp.back() : ez->FALSE;
}
tmp = ez->vec_ite(b.at(i), tmp_shifted, tmp);
}
if (cell->type == "$shl" || cell->type == "$sshl")
undef_a_shifted = ez->vec_shift_left(undef_a, b, false, ez->FALSE, ez->FALSE);
if (cell->type == "$shr")
undef_a_shifted = ez->vec_shift_right(undef_a, b, false, ez->FALSE, ez->FALSE);
if (cell->type == "$sshr")
undef_a_shifted = ez->vec_shift_right(undef_a, b, false, cell->parameters["\\A_SIGNED"].as_bool() ? undef_a.back() : ez->FALSE, ez->FALSE);
if (cell->type == "$shift")
undef_a_shifted = ez->vec_shift_right(undef_a, b, cell->parameters["\\B_SIGNED"].as_bool(), ez->FALSE, ez->FALSE);
if (cell->type == "$shiftx")
undef_a_shifted = ez->vec_shift_right(undef_a, b, cell->parameters["\\B_SIGNED"].as_bool(), ez->TRUE, ez->TRUE);
int undef_any_b = ez->expression(ezSAT::OpOr, undef_b);
std::vector<int> undef_all_y_bits(undef_y.size(), undef_any_b);
ez->assume(ez->vec_eq(ez->vec_or(tmp, undef_all_y_bits), undef_y));
ez->assume(ez->vec_eq(ez->vec_or(undef_a_shifted, undef_all_y_bits), undef_y));
undefGating(y, yy, undef_y);
}
return true;
@ -656,9 +738,9 @@ struct SatGen
if (cell->type == "$mul")
{
std::vector<int> a = importDefSigSpec(cell->connections.at("\\A"), timestep);
std::vector<int> b = importDefSigSpec(cell->connections.at("\\B"), timestep);
std::vector<int> y = importDefSigSpec(cell->connections.at("\\Y"), timestep);
std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep);
std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep);
std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep);
extendSignalWidth(a, b, y, cell);
std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
@ -675,17 +757,87 @@ struct SatGen
if (model_undef) {
log_assert(arith_undef_handled);
std::vector<int> undef_y = importUndefSigSpec(cell->connections.at("\\Y"), timestep);
std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
undefGating(y, yy, undef_y);
}
return true;
}
if (cell->type == "$macc")
{
std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep);
std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep);
std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep);
Macc macc;
macc.from_cell(cell);
std::vector<int> tmp(SIZE(y), ez->FALSE);
for (auto &port : macc.ports)
{
std::vector<int> in_a = importDefSigSpec(port.in_a, timestep);
std::vector<int> in_b = importDefSigSpec(port.in_b, timestep);
while (SIZE(in_a) < SIZE(y))
in_a.push_back(port.is_signed && !in_a.empty() ? in_a.back() : ez->FALSE);
in_a.resize(SIZE(y));
if (SIZE(in_b))
{
while (SIZE(in_b) < SIZE(y))
in_b.push_back(port.is_signed && !in_b.empty() ? in_b.back() : ez->FALSE);
in_b.resize(SIZE(y));
for (int i = 0; i < SIZE(in_b); i++) {
std::vector<int> shifted_a(in_a.size(), ez->FALSE);
for (int j = i; j < int(in_a.size()); j++)
shifted_a.at(j) = in_a.at(j-i);
if (port.do_subtract)
tmp = ez->vec_ite(in_b.at(i), ez->vec_sub(tmp, shifted_a), tmp);
else
tmp = ez->vec_ite(in_b.at(i), ez->vec_add(tmp, shifted_a), tmp);
}
}
else
{
if (port.do_subtract)
tmp = ez->vec_sub(tmp, in_a);
else
tmp = ez->vec_add(tmp, in_a);
}
}
for (int i = 0; i < SIZE(b); i++) {
std::vector<int> val(SIZE(y), ez->FALSE);
val.at(0) = b.at(i);
tmp = ez->vec_add(tmp, val);
}
if (model_undef)
{
std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep);
int undef_any_a = ez->expression(ezSAT::OpOr, undef_a);
int undef_any_b = ez->expression(ezSAT::OpOr, undef_b);
std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
ez->assume(ez->vec_eq(undef_y, std::vector<int>(SIZE(y), ez->OR(undef_any_a, undef_any_b))));
undefGating(y, tmp, undef_y);
}
else
ez->assume(ez->vec_eq(y, tmp));
return true;
}
if (cell->type == "$div" || cell->type == "$mod")
{
std::vector<int> a = importDefSigSpec(cell->connections.at("\\A"), timestep);
std::vector<int> b = importDefSigSpec(cell->connections.at("\\B"), timestep);
std::vector<int> y = importDefSigSpec(cell->connections.at("\\Y"), timestep);
std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep);
std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep);
std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep);
extendSignalWidth(a, b, y, cell);
std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
@ -739,11 +891,11 @@ struct SatGen
only_first_one.at(0) = ez->TRUE;
div_zero_result = ez->vec_ite(a.back(), only_first_one, all_ones);
} else {
div_zero_result.insert(div_zero_result.end(), cell->connections.at("\\A").width, ez->TRUE);
div_zero_result.insert(div_zero_result.end(), cell->getPort("\\A").size(), ez->TRUE);
div_zero_result.insert(div_zero_result.end(), y.size() - div_zero_result.size(), ez->FALSE);
}
} else {
int copy_a_bits = std::min(cell->connections.at("\\A").width, cell->connections.at("\\B").width);
int copy_a_bits = std::min(cell->getPort("\\A").size(), cell->getPort("\\B").size());
div_zero_result.insert(div_zero_result.end(), a.begin(), a.begin() + copy_a_bits);
if (cell->parameters["\\A_SIGNED"].as_bool() && cell->parameters["\\B_SIGNED"].as_bool())
div_zero_result.insert(div_zero_result.end(), y.size() - div_zero_result.size(), div_zero_result.back());
@ -755,25 +907,209 @@ struct SatGen
if (model_undef) {
log_assert(arith_undef_handled);
std::vector<int> undef_y = importUndefSigSpec(cell->connections.at("\\Y"), timestep);
std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
undefGating(y, yy, undef_y);
}
return true;
}
if (cell->type == "$lut")
{
std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep);
std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep);
std::vector<int> lut;
for (auto bit : cell->getParam("\\LUT").bits)
lut.push_back(bit == RTLIL::S1 ? ez->TRUE : ez->FALSE);
while (SIZE(lut) < (1 << SIZE(a)))
lut.push_back(ez->FALSE);
lut.resize(1 << SIZE(a));
if (model_undef)
{
std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
std::vector<int> t(lut), u(SIZE(t), ez->FALSE);
for (int i = SIZE(a)-1; i >= 0; i--)
{
std::vector<int> t0(t.begin(), t.begin() + SIZE(t)/2);
std::vector<int> t1(t.begin() + SIZE(t)/2, t.end());
std::vector<int> u0(u.begin(), u.begin() + SIZE(u)/2);
std::vector<int> u1(u.begin() + SIZE(u)/2, u.end());
t = ez->vec_ite(a[i], t1, t0);
u = ez->vec_ite(undef_a[i], ez->vec_or(ez->vec_xor(t0, t1), ez->vec_or(u0, u1)), ez->vec_ite(a[i], u1, u0));
}
log_assert(SIZE(t) == 1);
log_assert(SIZE(u) == 1);
undefGating(y, t, u);
ez->assume(ez->vec_eq(importUndefSigSpec(cell->getPort("\\Y"), timestep), u));
}
else
{
std::vector<int> t = lut;
for (int i = SIZE(a)-1; i >= 0; i--)
{
std::vector<int> t0(t.begin(), t.begin() + SIZE(t)/2);
std::vector<int> t1(t.begin() + SIZE(t)/2, t.end());
t = ez->vec_ite(a[i], t1, t0);
}
log_assert(SIZE(t) == 1);
ez->assume(ez->vec_eq(y, t));
}
return true;
}
if (cell->type == "$fa")
{
std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep);
std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep);
std::vector<int> c = importDefSigSpec(cell->getPort("\\C"), timestep);
std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep);
std::vector<int> x = importDefSigSpec(cell->getPort("\\X"), timestep);
std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
std::vector<int> xx = model_undef ? ez->vec_var(x.size()) : x;
std::vector<int> t1 = ez->vec_xor(a, b);
ez->assume(ez->vec_eq(yy, ez->vec_xor(t1, c)));
std::vector<int> t2 = ez->vec_and(a, b);
std::vector<int> t3 = ez->vec_and(c, t1);
ez->assume(ez->vec_eq(xx, ez->vec_or(t2, t3)));
if (model_undef)
{
std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep);
std::vector<int> undef_c = importUndefSigSpec(cell->getPort("\\C"), timestep);
std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
std::vector<int> undef_x = importUndefSigSpec(cell->getPort("\\X"), timestep);
ez->assume(ez->vec_eq(undef_y, ez->vec_or(ez->vec_or(undef_a, undef_b), undef_c)));
ez->assume(ez->vec_eq(undef_x, undef_y));
undefGating(y, yy, undef_y);
undefGating(x, xx, undef_x);
}
return true;
}
if (cell->type == "$lcu")
{
std::vector<int> p = importDefSigSpec(cell->getPort("\\P"), timestep);
std::vector<int> g = importDefSigSpec(cell->getPort("\\G"), timestep);
std::vector<int> ci = importDefSigSpec(cell->getPort("\\CI"), timestep);
std::vector<int> co = importDefSigSpec(cell->getPort("\\CO"), timestep);
std::vector<int> yy = model_undef ? ez->vec_var(co.size()) : co;
for (int i = 0; i < SIZE(co); i++)
ez->SET(yy[i], ez->OR(g[i], ez->AND(p[i], i ? yy[i-1] : ci[0])));
if (model_undef)
{
std::vector<int> undef_p = importUndefSigSpec(cell->getPort("\\P"), timestep);
std::vector<int> undef_g = importUndefSigSpec(cell->getPort("\\G"), timestep);
std::vector<int> undef_ci = importUndefSigSpec(cell->getPort("\\CI"), timestep);
std::vector<int> undef_co = importUndefSigSpec(cell->getPort("\\CO"), timestep);
int undef_any_p = ez->expression(ezSAT::OpOr, undef_p);
int undef_any_g = ez->expression(ezSAT::OpOr, undef_g);
int undef_any_ci = ez->expression(ezSAT::OpOr, undef_ci);
int undef_co_bit = ez->OR(undef_any_p, undef_any_g, undef_any_ci);
std::vector<int> undef_co_bits(undef_co.size(), undef_co_bit);
ez->assume(ez->vec_eq(undef_co_bits, undef_co));
undefGating(co, yy, undef_co);
}
return true;
}
if (cell->type == "$alu")
{
std::vector<int> a = importDefSigSpec(cell->getPort("\\A"), timestep);
std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep);
std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep);
std::vector<int> x = importDefSigSpec(cell->getPort("\\X"), timestep);
std::vector<int> ci = importDefSigSpec(cell->getPort("\\CI"), timestep);
std::vector<int> bi = importDefSigSpec(cell->getPort("\\BI"), timestep);
std::vector<int> co = importDefSigSpec(cell->getPort("\\CO"), timestep);
extendSignalWidth(a, b, y, cell);
extendSignalWidth(a, b, x, cell);
extendSignalWidth(a, b, co, cell);
std::vector<int> def_y = model_undef ? ez->vec_var(y.size()) : y;
std::vector<int> def_x = model_undef ? ez->vec_var(x.size()) : x;
std::vector<int> def_co = model_undef ? ez->vec_var(co.size()) : co;
log_assert(SIZE(y) == SIZE(x));
log_assert(SIZE(y) == SIZE(co));
log_assert(SIZE(ci) == 1);
log_assert(SIZE(bi) == 1);
for (int i = 0; i < SIZE(y); i++)
{
int s1 = a.at(i), s2 = ez->XOR(b.at(i), bi.at(0)), s3 = i ? co.at(i-1) : ci.at(0);
ez->SET(def_x.at(i), ez->XOR(s1, s2));
ez->SET(def_y.at(i), ez->XOR(def_x.at(i), s3));
ez->SET(def_co.at(i), ez->OR(ez->AND(s1, s2), ez->AND(s1, s3), ez->AND(s2, s3)));
}
if (model_undef)
{
std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
std::vector<int> undef_b = importUndefSigSpec(cell->getPort("\\B"), timestep);
std::vector<int> undef_ci = importUndefSigSpec(cell->getPort("\\CI"), timestep);
std::vector<int> undef_bi = importUndefSigSpec(cell->getPort("\\BI"), timestep);
std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
std::vector<int> undef_x = importUndefSigSpec(cell->getPort("\\X"), timestep);
std::vector<int> undef_co = importUndefSigSpec(cell->getPort("\\CO"), timestep);
extendSignalWidth(undef_a, undef_b, undef_y, cell);
extendSignalWidth(undef_a, undef_b, undef_x, cell);
extendSignalWidth(undef_a, undef_b, undef_co, cell);
std::vector<int> all_inputs_undef;
all_inputs_undef.insert(all_inputs_undef.end(), undef_a.begin(), undef_a.end());
all_inputs_undef.insert(all_inputs_undef.end(), undef_b.begin(), undef_b.end());
all_inputs_undef.insert(all_inputs_undef.end(), undef_ci.begin(), undef_ci.end());
all_inputs_undef.insert(all_inputs_undef.end(), undef_bi.begin(), undef_bi.end());
int undef_any = ez->expression(ezSAT::OpOr, all_inputs_undef);
for (int i = 0; i < SIZE(undef_y); i++) {
ez->SET(undef_y.at(i), undef_any);
ez->SET(undef_x.at(i), ez->OR(undef_a.at(i), undef_b.at(i), undef_bi.at(0)));
ez->SET(undef_co.at(i), undef_any);
}
undefGating(y, def_y, undef_y);
undefGating(x, def_x, undef_x);
undefGating(co, def_co, undef_co);
}
return true;
}
if (cell->type == "$slice")
{
RTLIL::SigSpec a = cell->connections.at("\\A");
RTLIL::SigSpec y = cell->connections.at("\\Y");
ez->assume(signals_eq(a.extract(cell->parameters.at("\\OFFSET").as_int(), y.width), y, timestep));
RTLIL::SigSpec a = cell->getPort("\\A");
RTLIL::SigSpec y = cell->getPort("\\Y");
ez->assume(signals_eq(a.extract(cell->parameters.at("\\OFFSET").as_int(), y.size()), y, timestep));
return true;
}
if (cell->type == "$concat")
{
RTLIL::SigSpec a = cell->connections.at("\\A");
RTLIL::SigSpec b = cell->connections.at("\\B");
RTLIL::SigSpec y = cell->connections.at("\\Y");
RTLIL::SigSpec a = cell->getPort("\\A");
RTLIL::SigSpec b = cell->getPort("\\B");
RTLIL::SigSpec y = cell->getPort("\\Y");
RTLIL::SigSpec ab = a;
ab.append(b);
@ -786,20 +1122,20 @@ struct SatGen
{
if (timestep == 1)
{
initial_state.add((*sigmap)(cell->connections.at("\\Q")));
initial_state.add((*sigmap)(cell->getPort("\\Q")));
}
else
{
std::vector<int> d = importDefSigSpec(cell->connections.at("\\D"), timestep-1);
std::vector<int> q = importDefSigSpec(cell->connections.at("\\Q"), timestep);
std::vector<int> d = importDefSigSpec(cell->getPort("\\D"), timestep-1);
std::vector<int> q = importDefSigSpec(cell->getPort("\\Q"), timestep);
std::vector<int> qq = model_undef ? ez->vec_var(q.size()) : q;
ez->assume(ez->vec_eq(d, qq));
if (model_undef)
{
std::vector<int> undef_d = importUndefSigSpec(cell->connections.at("\\D"), timestep-1);
std::vector<int> undef_q = importUndefSigSpec(cell->connections.at("\\Q"), timestep);
std::vector<int> undef_d = importUndefSigSpec(cell->getPort("\\D"), timestep-1);
std::vector<int> undef_q = importUndefSigSpec(cell->getPort("\\Q"), timestep);
ez->assume(ez->vec_eq(undef_d, undef_q));
undefGating(q, qq, undef_q);
@ -811,8 +1147,8 @@ struct SatGen
if (cell->type == "$assert")
{
std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep));
asserts_a[pf].append((*sigmap)(cell->connections.at("\\A")));
asserts_en[pf].append((*sigmap)(cell->connections.at("\\EN")));
asserts_a[pf].append((*sigmap)(cell->getPort("\\A")));
asserts_en[pf].append((*sigmap)(cell->getPort("\\EN")));
return true;
}
@ -823,4 +1159,3 @@ struct SatGen
};
#endif

View file

@ -20,14 +20,17 @@
#ifndef SIGTOOLS_H
#define SIGTOOLS_H
#include "kernel/rtlil.h"
#include "kernel/log.h"
#include <assert.h>
#include <set>
#include "kernel/yosys.h"
YOSYS_NAMESPACE_BEGIN
struct SigPool
{
typedef std::pair<RTLIL::Wire*,int> bitDef_t;
struct bitDef_t : public std::pair<RTLIL::Wire*, int> {
bitDef_t() : std::pair<RTLIL::Wire*, int>(NULL, 0) { }
bitDef_t(const RTLIL::SigBit &bit) : std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset) { }
};
std::set<bitDef_t> bits;
void clear()
@ -37,14 +40,9 @@ struct SigPool
void add(RTLIL::SigSpec sig)
{
sig.expand();
for (auto &c : sig.chunks) {
if (c.wire == NULL)
continue;
assert(c.width == 1);
bitDef_t bit(c.wire, c.offset);
bits.insert(bit);
}
for (auto &bit : sig)
if (bit.wire != NULL)
bits.insert(bit);
}
void add(const SigPool &other)
@ -55,14 +53,9 @@ struct SigPool
void del(RTLIL::SigSpec sig)
{
sig.expand();
for (auto &c : sig.chunks) {
if (c.wire == NULL)
continue;
assert(c.width == 1);
bitDef_t bit(c.wire, c.offset);
bits.erase(bit);
}
for (auto &bit : sig)
if (bit.wire != NULL)
bits.erase(bit);
}
void del(const SigPool &other)
@ -73,15 +66,10 @@ struct SigPool
void expand(RTLIL::SigSpec from, RTLIL::SigSpec to)
{
from.expand();
to.expand();
assert(from.chunks.size() == to.chunks.size());
for (size_t i = 0; i < from.chunks.size(); i++) {
bitDef_t bit_from(from.chunks[i].wire, from.chunks[i].offset);
bitDef_t bit_to(to.chunks[i].wire, to.chunks[i].offset);
if (bit_from.first == NULL || bit_to.first == NULL)
continue;
if (bits.count(bit_from) > 0)
log_assert(SIZE(from) == SIZE(to));
for (int i = 0; i < SIZE(from); i++) {
bitDef_t bit_from(from[i]), bit_to(to[i]);
if (bit_from.first != NULL && bit_to.first != NULL && bits.count(bit_from) > 0)
bits.insert(bit_to);
}
}
@ -89,73 +77,54 @@ struct SigPool
RTLIL::SigSpec extract(RTLIL::SigSpec sig)
{
RTLIL::SigSpec result;
sig.expand();
for (auto &c : sig.chunks) {
if (c.wire == NULL)
continue;
bitDef_t bit(c.wire, c.offset);
if (bits.count(bit) > 0)
result.append(c);
}
for (auto &bit : sig)
if (bit.wire != NULL && bits.count(bit))
result.append_bit(bit);
return result;
}
RTLIL::SigSpec remove(RTLIL::SigSpec sig)
{
RTLIL::SigSpec result;
sig.expand();
for (auto &c : sig.chunks) {
if (c.wire == NULL)
continue;
bitDef_t bit(c.wire, c.offset);
if (bits.count(bit) == 0)
result.append(c);
}
for (auto &bit : sig)
if (bit.wire != NULL && bits.count(bit) == 0)
result.append(bit);
return result;
}
bool check(RTLIL::SigBit bit)
{
return bit.wire != NULL && bits.count(bit);
}
bool check_any(RTLIL::SigSpec sig)
{
sig.expand();
for (auto &c : sig.chunks) {
if (c.wire == NULL)
continue;
bitDef_t bit(c.wire, c.offset);
if (bits.count(bit) != 0)
for (auto &bit : sig)
if (bit.wire != NULL && bits.count(bit))
return true;
}
return false;
}
bool check_all(RTLIL::SigSpec sig)
{
sig.expand();
for (auto &c : sig.chunks) {
if (c.wire == NULL)
continue;
bitDef_t bit(c.wire, c.offset);
if (bits.count(bit) == 0)
for (auto &bit : sig)
if (bit.wire != NULL && bits.count(bit) == 0)
return false;
}
return true;
}
RTLIL::SigSpec export_one()
{
RTLIL::SigSpec sig;
for (auto &bit : bits) {
sig.append(RTLIL::SigSpec(bit.first, 1, bit.second));
break;
}
return sig;
for (auto &bit : bits)
return RTLIL::SigSpec(bit.first, bit.second);
return RTLIL::SigSpec();
}
RTLIL::SigSpec export_all()
{
RTLIL::SigSpec sig;
std::set<RTLIL::SigBit> sig;
for (auto &bit : bits)
sig.append(RTLIL::SigSpec(bit.first, 1, bit.second));
sig.sort_and_unify();
sig.insert(RTLIL::SigBit(bit.first, bit.second));
return sig;
}
@ -168,7 +137,11 @@ struct SigPool
template <typename T, class Compare = std::less<T>>
struct SigSet
{
typedef std::pair<RTLIL::Wire*,int> bitDef_t;
struct bitDef_t : public std::pair<RTLIL::Wire*, int> {
bitDef_t() : std::pair<RTLIL::Wire*, int>(NULL, 0) { }
bitDef_t(const RTLIL::SigBit &bit) : std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset) { }
};
std::map<bitDef_t, std::set<T, Compare>> bits;
void clear()
@ -178,75 +151,46 @@ struct SigSet
void insert(RTLIL::SigSpec sig, T data)
{
sig.expand();
for (auto &c : sig.chunks) {
if (c.wire == NULL)
continue;
assert(c.width == 1);
bitDef_t bit(c.wire, c.offset);
bits[bit].insert(data);
}
for (auto &bit : sig)
if (bit.wire != NULL)
bits[bit].insert(data);
}
void insert(RTLIL::SigSpec sig, const std::set<T> &data)
{
sig.expand();
for (auto &c : sig.chunks) {
if (c.wire == NULL)
continue;
assert(c.width == 1);
bitDef_t bit(c.wire, c.offset);
bits[bit].insert(data.begin(), data.end());
}
for (auto &bit : sig)
if (bit.wire != NULL)
bits[bit].insert(data.begin(), data.end());
}
void erase(RTLIL::SigSpec sig)
{
sig.expand();
for (auto &c : sig.chunks) {
if (c.wire == NULL)
continue;
assert(c.width == 1);
bitDef_t bit(c.wire, c.offset);
bits[bit].clear();
}
for (auto &bit : sig)
if (bit.wire != NULL)
bits[bit].clear();
}
void erase(RTLIL::SigSpec sig, T data)
{
sig.expand();
for (auto &c : sig.chunks) {
if (c.wire == NULL)
continue;
assert(c.width == 1);
bitDef_t bit(c.wire, c.offset);
bits[bit].erase(data);
}
for (auto &bit : sig)
if (bit.wire != NULL)
bits[bit].erase(data);
}
void erase(RTLIL::SigSpec sig, const std::set<T> &data)
{
sig.expand();
for (auto &c : sig.chunks) {
if (c.wire == NULL)
continue;
assert(c.width == 1);
bitDef_t bit(c.wire, c.offset);
bits[bit].erase(data.begin(), data.end());
}
for (auto &bit : sig)
if (bit.wire != NULL)
bits[bit].erase(data.begin(), data.end());
}
void find(RTLIL::SigSpec sig, std::set<T> &result)
{
sig.expand();
for (auto &c : sig.chunks) {
if (c.wire == NULL)
continue;
assert(c.width == 1);
bitDef_t bit(c.wire, c.offset);
for (auto &data : bits[bit])
result.insert(data);
}
for (auto &bit : sig)
if (bit.wire != NULL) {
auto &data = bits[bit];
result.insert(data.begin(), data.end());
}
}
std::set<T> find(RTLIL::SigSpec sig)
@ -258,25 +202,22 @@ struct SigSet
bool has(RTLIL::SigSpec sig)
{
sig.expand();
for (auto &c : sig.chunks) {
if (c.wire == NULL)
continue;
assert(c.width == 1);
bitDef_t bit(c.wire, c.offset);
if (bits.count(bit))
for (auto &bit : sig)
if (bit.wire != NULL && bits.count(bit))
return true;
}
return false;
}
};
struct SigMap
{
typedef std::pair<RTLIL::Wire*,int> bitDef_t;
struct bitDef_t : public std::pair<RTLIL::Wire*, int> {
bitDef_t() : std::pair<RTLIL::Wire*, int>(NULL, 0) { }
bitDef_t(const RTLIL::SigBit &bit) : std::pair<RTLIL::Wire*, int>(bit.wire, bit.offset) { }
};
struct shared_bit_data_t {
RTLIL::SigChunk chunk;
RTLIL::SigBit map_to;
std::set<bitDef_t> bits;
};
@ -304,7 +245,7 @@ struct SigMap
clear();
for (auto &bit : other.bits) {
bits[bit.first] = new shared_bit_data_t;
bits[bit.first]->chunk = bit.second->chunk;
bits[bit.first]->map_to = bit.second->map_to;
bits[bit.first]->bits = bit.second->bits;
}
}
@ -332,29 +273,25 @@ struct SigMap
void set(RTLIL::Module *module)
{
clear();
for (auto &it : module->connections)
for (auto &it : module->connections())
add(it.first, it.second);
}
// internal helper function
void register_bit(const RTLIL::SigChunk &c)
void register_bit(const RTLIL::SigBit &bit)
{
assert(c.width == 1);
bitDef_t bit(c.wire, c.offset);
if (c.wire && bits.count(bit) == 0) {
if (bit.wire && bits.count(bit) == 0) {
shared_bit_data_t *bd = new shared_bit_data_t;
bd->chunk = c;
bd->map_to = bit;
bd->bits.insert(bit);
bits[bit] = bd;
}
}
// internal helper function
void unregister_bit(const RTLIL::SigChunk &c)
void unregister_bit(const RTLIL::SigBit &bit)
{
assert(c.width == 1);
bitDef_t bit(c.wire, c.offset);
if (c.wire && bits.count(bit) > 0) {
if (bit.wire && bits.count(bit) > 0) {
shared_bit_data_t *bd = bits[bit];
bd->bits.erase(bit);
if (bd->bits.size() == 0)
@ -364,17 +301,13 @@ struct SigMap
}
// internal helper function
void merge_bit(const RTLIL::SigChunk &c1, const RTLIL::SigChunk &c2)
void merge_bit(const RTLIL::SigBit &bit1, const RTLIL::SigBit &bit2)
{
assert(c1.wire != NULL && c2.wire != NULL);
assert(c1.width == 1 && c2.width == 1);
log_assert(bit1.wire != NULL && bit2.wire != NULL);
bitDef_t b1(c1.wire, c1.offset);
bitDef_t b2(c2.wire, c2.offset);
shared_bit_data_t *bd1 = bits[b1];
shared_bit_data_t *bd2 = bits[b2];
assert(bd1 != NULL && bd2 != NULL);
shared_bit_data_t *bd1 = bits[bit1];
shared_bit_data_t *bd2 = bits[bit2];
log_assert(bd1 != NULL && bd2 != NULL);
if (bd1 == bd2)
return;
@ -388,7 +321,7 @@ struct SigMap
}
else
{
bd1->chunk = bd2->chunk;
bd1->map_to = bd2->map_to;
for (auto &bit : bd2->bits)
bits[bit] = bd1;
bd1->bits.insert(bd2->bits.begin(), bd2->bits.end());
@ -397,81 +330,87 @@ struct SigMap
}
// internal helper function
void set_bit(const RTLIL::SigChunk &c1, const RTLIL::SigChunk &c2)
void set_bit(const RTLIL::SigBit &bit1, const RTLIL::SigBit &bit2)
{
assert(c1.wire != NULL);
assert(c1.width == 1 && c2.width == 1);
bitDef_t bit(c1.wire, c1.offset);
assert(bits.count(bit) > 0);
bits[bit]->chunk = c2;
log_assert(bit1.wire != NULL);
log_assert(bits.count(bit1) > 0);
bits[bit1]->map_to = bit2;
}
// internal helper function
void map_bit(RTLIL::SigChunk &c)
void map_bit(RTLIL::SigBit &bit) const
{
assert(c.width == 1);
bitDef_t bit(c.wire, c.offset);
if (c.wire && bits.count(bit) > 0)
c = bits[bit]->chunk;
if (bit.wire && bits.count(bit) > 0)
bit = bits.at(bit)->map_to;
}
void add(RTLIL::SigSpec from, RTLIL::SigSpec to)
{
from.expand();
to.expand();
log_assert(SIZE(from) == SIZE(to));
assert(from.chunks.size() == to.chunks.size());
for (size_t i = 0; i < from.chunks.size(); i++)
for (int i = 0; i < SIZE(from); i++)
{
RTLIL::SigChunk &cf = from.chunks[i];
RTLIL::SigChunk &ct = to.chunks[i];
RTLIL::SigBit &bf = from[i];
RTLIL::SigBit &bt = to[i];
if (cf.wire == NULL)
if (bf.wire == NULL)
continue;
register_bit(cf);
register_bit(ct);
register_bit(bf);
register_bit(bt);
if (ct.wire != NULL)
merge_bit(cf, ct);
if (bt.wire != NULL)
merge_bit(bf, bt);
else
set_bit(cf, ct);
set_bit(bf, bt);
}
}
void add(RTLIL::SigSpec sig)
{
sig.expand();
for (size_t i = 0; i < sig.chunks.size(); i++)
{
RTLIL::SigChunk &c = sig.chunks[i];
if (c.wire != NULL) {
register_bit(c);
set_bit(c, c);
}
for (auto &bit : sig) {
register_bit(bit);
set_bit(bit, bit);
}
}
void del(RTLIL::SigSpec sig)
{
sig.expand();
for (auto &c : sig.chunks)
unregister_bit(c);
for (auto &bit : sig)
unregister_bit(bit);
}
void apply(RTLIL::SigSpec &sig)
void apply(RTLIL::SigBit &bit) const
{
sig.expand();
for (auto &c : sig.chunks)
map_bit(c);
sig.optimize();
map_bit(bit);
}
RTLIL::SigSpec operator()(RTLIL::SigSpec sig)
void apply(RTLIL::SigSpec &sig) const
{
for (auto &bit : sig)
map_bit(bit);
}
RTLIL::SigBit operator()(RTLIL::SigBit bit) const
{
apply(bit);
return bit;
}
RTLIL::SigSpec operator()(RTLIL::SigSpec sig) const
{
apply(sig);
return sig;
}
RTLIL::SigSpec operator()(RTLIL::Wire *wire) const
{
RTLIL::SigSpec sig(wire);
apply(sig);
return sig;
}
};
YOSYS_NAMESPACE_END
#endif /* SIGTOOLS_H */

210
kernel/utils.h Normal file
View file

@ -0,0 +1,210 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
// This file contains various c++ utility routines and helper classes that
// do not depend on any other components of yosys (except stuff like log_*).
#include "kernel/yosys.h"
#ifndef UTILS_H
#define UTILS_H
// ------------------------------------------------
// A map-like container, but you can save and restore the state
// ------------------------------------------------
template<typename Key, typename T, typename Compare = std::less<Key>>
struct stackmap
{
private:
std::vector<std::map<Key, T*, Compare>> backup_state;
std::map<Key, T, Compare> current_state;
static T empty_tuple;
public:
stackmap() { }
stackmap(const std::map<Key, T, Compare> &other) : current_state(other) { }
template<typename Other>
void operator=(const Other &other)
{
for (auto &it : current_state)
if (!backup_state.empty() && backup_state.back().count(it.first) == 0)
backup_state.back()[it.first] = new T(it.second);
current_state.clear();
for (auto &it : other)
set(it.first, it.second);
}
bool has(const Key &k)
{
return current_state.count(k) != 0;
}
void set(const Key &k, const T &v)
{
if (!backup_state.empty() && backup_state.back().count(k) == 0)
backup_state.back()[k] = current_state.count(k) ? new T(current_state.at(k)) : nullptr;
current_state[k] = v;
}
void unset(const Key &k)
{
if (!backup_state.empty() && backup_state.back().count(k) == 0)
backup_state.back()[k] = current_state.count(k) ? new T(current_state.at(k)) : nullptr;
current_state.erase(k);
}
const T &get(const Key &k)
{
if (current_state.count(k) == 0)
return empty_tuple;
return current_state.at(k);
}
void reset(const Key &k)
{
for (int i = SIZE(backup_state)-1; i >= 0; i--)
if (backup_state[i].count(k) != 0) {
if (backup_state[i].at(k) == nullptr)
current_state.erase(k);
else
current_state[k] = *backup_state[i].at(k);
return;
}
current_state.erase(k);
}
const std::map<Key, T, Compare> &stdmap()
{
return current_state;
}
void save()
{
backup_state.resize(backup_state.size()+1);
}
void restore()
{
log_assert(!backup_state.empty());
for (auto &it : backup_state.back())
if (it.second != nullptr) {
current_state[it.first] = *it.second;
delete it.second;
} else
current_state.erase(it.first);
backup_state.pop_back();
}
~stackmap()
{
while (!backup_state.empty())
restore();
}
};
// ------------------------------------------------
// A simple class for topological sorting
// ------------------------------------------------
template<typename T>
struct TopoSort
{
bool analyze_loops, found_loops;
std::map<T, std::set<T>> database;
std::set<std::set<T>> loops;
std::vector<T> sorted;
TopoSort()
{
analyze_loops = true;
found_loops = false;
}
void node(T n)
{
if (database.count(n) == 0)
database[n] = std::set<T>();
}
void edge(T left, T right)
{
node(left);
database[right].insert(left);
}
void sort_worker(const T &n, std::set<T> &marked_cells, std::set<T> &active_cells, std::vector<T> &active_stack)
{
if (active_cells.count(n)) {
found_loops = true;
if (analyze_loops) {
std::set<T> loop;
for (int i = SIZE(active_stack)-1; i >= 0; i--) {
loop.insert(active_stack[i]);
if (active_stack[i] == n)
break;
}
loops.insert(loop);
}
return;
}
if (marked_cells.count(n))
return;
if (!database.at(n).empty())
{
if (analyze_loops)
active_stack.push_back(n);
active_cells.insert(n);
for (auto &left_n : database.at(n))
sort_worker(left_n, marked_cells, active_cells, active_stack);
if (analyze_loops)
active_stack.pop_back();
active_cells.erase(n);
}
marked_cells.insert(n);
sorted.push_back(n);
}
bool sort()
{
loops.clear();
sorted.clear();
found_loops = false;
std::set<T> marked_cells;
std::set<T> active_cells;
std::vector<T> active_stack;
for (auto &it : database)
sort_worker(it.first, marked_cells, active_cells, active_stack);
log_assert(SIZE(sorted) == SIZE(database));
return !found_loops;
}
};
#endif

646
kernel/yosys.cc Normal file
View file

@ -0,0 +1,646 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include "kernel/yosys.h"
#ifdef YOSYS_ENABLE_READLINE
# include <readline/readline.h>
# include <readline/history.h>
#endif
#include <dlfcn.h>
#include <unistd.h>
#include <limits.h>
#include <errno.h>
YOSYS_NAMESPACE_BEGIN
int autoidx = 1;
RTLIL::Design *yosys_design = NULL;
#ifdef YOSYS_ENABLE_TCL
Tcl_Interp *yosys_tcl_interp = NULL;
#endif
std::string stringf(const char *fmt, ...)
{
std::string string;
va_list ap;
va_start(ap, fmt);
string = vstringf(fmt, ap);
va_end(ap);
return string;
}
std::string vstringf(const char *fmt, va_list ap)
{
std::string string;
char *str = NULL;
if (vasprintf(&str, fmt, ap) < 0)
str = NULL;
if (str != NULL) {
string = str;
free(str);
}
return string;
}
int SIZE(RTLIL::Wire *wire)
{
return wire->width;
}
void yosys_setup()
{
Pass::init_register();
yosys_design = new RTLIL::Design;
log_push();
}
void yosys_shutdown()
{
log_pop();
delete yosys_design;
yosys_design = NULL;
for (auto f : log_files)
if (f != stderr)
fclose(f);
log_errfile = NULL;
log_files.clear();
Pass::done_register();
#ifdef YOSYS_ENABLE_TCL
if (yosys_tcl_interp != NULL) {
Tcl_DeleteInterp(yosys_tcl_interp);
Tcl_Finalize();
yosys_tcl_interp = NULL;
}
#endif
for (auto &it : loaded_plugins)
dlclose(it.second);
loaded_plugins.clear();
loaded_plugin_aliases.clear();
}
RTLIL::IdString new_id(std::string file, int line, std::string func)
{
std::string str = "$auto$";
size_t pos = file.find_last_of('/');
str += pos != std::string::npos ? file.substr(pos+1) : file;
str += stringf(":%d:%s$%d", line, func.c_str(), autoidx++);
return str;
}
RTLIL::Design *yosys_get_design()
{
return yosys_design;
}
const char *create_prompt(RTLIL::Design *design, int recursion_counter)
{
static char buffer[100];
std::string str = "\n";
if (recursion_counter > 1)
str += stringf("(%d) ", recursion_counter);
str += "yosys";
if (!design->selected_active_module.empty())
str += stringf(" [%s]", RTLIL::unescape_id(design->selected_active_module).c_str());
if (!design->selection_stack.empty() && !design->selection_stack.back().full_selection) {
if (design->selected_active_module.empty())
str += "*";
else if (design->selection_stack.back().selected_modules.size() != 1 || design->selection_stack.back().selected_members.size() != 0 ||
design->selection_stack.back().selected_modules.count(design->selected_active_module) == 0)
str += "*";
}
snprintf(buffer, 100, "%s> ", str.c_str());
return buffer;
}
#ifdef YOSYS_ENABLE_TCL
static int tcl_yosys_cmd(ClientData, Tcl_Interp *interp, int argc, const char *argv[])
{
std::vector<std::string> args;
for (int i = 1; i < argc; i++)
args.push_back(argv[i]);
if (args.size() >= 1 && args[0] == "-import") {
for (auto &it : pass_register) {
std::string tcl_command_name = it.first;
if (tcl_command_name == "proc")
tcl_command_name = "procs";
Tcl_CmdInfo info;
if (Tcl_GetCommandInfo(interp, tcl_command_name.c_str(), &info) != 0) {
log("[TCL: yosys -import] Command name collision: found pre-existing command `%s' -> skip.\n", it.first.c_str());
} else {
std::string tcl_script = stringf("proc %s args { yosys %s {*}$args }", tcl_command_name.c_str(), it.first.c_str());
Tcl_Eval(interp, tcl_script.c_str());
}
}
return TCL_OK;
}
if (args.size() == 1) {
Pass::call(yosys_get_design(), args[0]);
return TCL_OK;
}
Pass::call(yosys_get_design(), args);
return TCL_OK;
}
extern Tcl_Interp *yosys_get_tcl_interp()
{
if (yosys_tcl_interp == NULL) {
yosys_tcl_interp = Tcl_CreateInterp();
Tcl_CreateCommand(yosys_tcl_interp, "yosys", tcl_yosys_cmd, NULL, NULL);
}
return yosys_tcl_interp;
}
struct TclPass : public Pass {
TclPass() : Pass("tcl", "execute a TCL script file") { }
virtual void help() {
log("\n");
log(" tcl <filename>\n");
log("\n");
log("This command executes the tcl commands in the specified file.\n");
log("Use 'yosys cmd' to run the yosys command 'cmd' from tcl.\n");
log("\n");
log("The tcl command 'yosys -import' can be used to import all yosys\n");
log("commands directly as tcl commands to the tcl shell. The yosys\n");
log("command 'proc' is wrapped using the tcl command 'procs' in order\n");
log("to avoid a name collision with the tcl builting command 'proc'.\n");
log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
if (args.size() < 2)
log_cmd_error("Missing script file.\n");
if (args.size() > 2)
extra_args(args, 1, design, false);
if (Tcl_EvalFile(yosys_get_tcl_interp(), args[1].c_str()) != TCL_OK)
log_cmd_error("TCL interpreter returned an error: %s\n", Tcl_GetStringResult(yosys_get_tcl_interp()));
}
} TclPass;
#endif
#if defined(__linux__)
std::string proc_self_dirname ()
{
char path [PATH_MAX];
ssize_t buflen = readlink("/proc/self/exe", path, sizeof(path));
if (buflen < 0) {
log_error("readlink(\"/proc/self/exe\") failed: %s\n", strerror(errno));
}
while (buflen > 0 && path[buflen-1] != '/')
buflen--;
return std::string(path, buflen);
}
#elif defined(__APPLE__)
#include <mach-o/dyld.h>
std::string proc_self_dirname ()
{
char * path = NULL;
uint32_t buflen = 0;
while (_NSGetExecutablePath(path, &buflen) != 0)
path = (char *) realloc((void *) path, buflen);
while (buflen > 0 && path[buflen-1] != '/')
buflen--;
return std::string(path, buflen);
}
#elif defined(EMSCRIPTEN)
std::string proc_self_dirname ()
{
return "/";
}
#else
#error Dont know how to determine process executable base path!
#endif
std::string proc_share_dirname ()
{
std::string proc_self_path = proc_self_dirname();
std::string proc_share_path = proc_self_path + "share/";
if (access(proc_share_path.c_str(), X_OK) == 0)
return proc_share_path;
proc_share_path = proc_self_path + "../share/yosys/";
if (access(proc_share_path.c_str(), X_OK) == 0)
return proc_share_path;
log_error("proc_share_dirname: unable to determine share/ directory!\n");
}
bool fgetline(FILE *f, std::string &buffer)
{
buffer = "";
char block[4096];
while (1) {
if (fgets(block, 4096, f) == NULL)
return false;
buffer += block;
if (buffer.size() > 0 && (buffer[buffer.size()-1] == '\n' || buffer[buffer.size()-1] == '\r')) {
while (buffer.size() > 0 && (buffer[buffer.size()-1] == '\n' || buffer[buffer.size()-1] == '\r'))
buffer.resize(buffer.size()-1);
return true;
}
}
}
static void handle_label(std::string &command, bool &from_to_active, const std::string &run_from, const std::string &run_to)
{
int pos = 0;
std::string label;
while (pos < SIZE(command) && (command[pos] == ' ' || command[pos] == '\t'))
pos++;
while (pos < SIZE(command) && command[pos] != ' ' && command[pos] != '\t' && command[pos] != '\r' && command[pos] != '\n')
label += command[pos++];
if (label.back() == ':' && SIZE(label) > 1)
{
label = label.substr(0, SIZE(label)-1);
command = command.substr(pos);
if (label == run_from)
from_to_active = true;
else if (label == run_to || (run_from == run_to && !run_from.empty()))
from_to_active = false;
}
}
void run_frontend(std::string filename, std::string command, RTLIL::Design *design, std::string *backend_command, std::string *from_to_label)
{
if (command == "auto") {
if (filename.size() > 2 && filename.substr(filename.size()-2) == ".v")
command = "verilog";
else if (filename.size() > 2 && filename.substr(filename.size()-3) == ".sv")
command = "verilog -sv";
else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".il")
command = "ilang";
else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".ys")
command = "script";
else if (filename == "-")
command = "script";
else
log_error("Can't guess frontend for input file `%s' (missing -f option)!\n", filename.c_str());
}
if (command == "script")
{
std::string run_from, run_to;
bool from_to_active = true;
if (from_to_label != NULL) {
size_t pos = from_to_label->find(':');
if (pos == std::string::npos) {
run_from = *from_to_label;
run_to = *from_to_label;
} else {
run_from = from_to_label->substr(0, pos);
run_to = from_to_label->substr(pos+1);
}
from_to_active = run_from.empty();
}
log("\n-- Executing script file `%s' --\n", filename.c_str());
FILE *f = stdin;
if (filename != "-")
f = fopen(filename.c_str(), "r");
if (f == NULL)
log_error("Can't open script file `%s' for reading: %s\n", filename.c_str(), strerror(errno));
FILE *backup_script_file = Frontend::current_script_file;
Frontend::current_script_file = f;
try {
std::string command;
while (fgetline(f, command)) {
while (!command.empty() && command[command.size()-1] == '\\') {
std::string next_line;
if (!fgetline(f, next_line))
break;
command.resize(command.size()-1);
command += next_line;
}
handle_label(command, from_to_active, run_from, run_to);
if (from_to_active)
Pass::call(design, command);
}
if (!command.empty()) {
handle_label(command, from_to_active, run_from, run_to);
if (from_to_active)
Pass::call(design, command);
}
}
catch (log_cmd_error_expection) {
Frontend::current_script_file = backup_script_file;
throw log_cmd_error_expection();
}
Frontend::current_script_file = backup_script_file;
if (filename != "-")
fclose(f);
if (backend_command != NULL && *backend_command == "auto")
*backend_command = "";
return;
}
if (filename == "-") {
log("\n-- Parsing stdin using frontend `%s' --\n", command.c_str());
} else {
log("\n-- Parsing `%s' using frontend `%s' --\n", filename.c_str(), command.c_str());
}
Frontend::frontend_call(design, NULL, filename, command);
}
void run_pass(std::string command, RTLIL::Design *design)
{
log("\n-- Running pass `%s' --\n", command.c_str());
Pass::call(design, command);
}
void run_backend(std::string filename, std::string command, RTLIL::Design *design)
{
if (command == "auto") {
if (filename.size() > 2 && filename.substr(filename.size()-2) == ".v")
command = "verilog";
else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".il")
command = "ilang";
else if (filename.size() > 5 && filename.substr(filename.size()-5) == ".blif")
command = "blif";
else if (filename == "-")
command = "ilang";
else if (filename.empty())
return;
else
log_error("Can't guess backend for output file `%s' (missing -b option)!\n", filename.c_str());
}
if (filename.empty())
filename = "-";
if (filename == "-") {
log("\n-- Writing to stdout using backend `%s' --\n", command.c_str());
} else {
log("\n-- Writing to `%s' using backend `%s' --\n", filename.c_str(), command.c_str());
}
Backend::backend_call(design, NULL, filename, command);
}
#ifdef YOSYS_ENABLE_READLINE
static char *readline_cmd_generator(const char *text, int state)
{
static std::map<std::string, Pass*>::iterator it;
static int len;
if (!state) {
it = pass_register.begin();
len = strlen(text);
}
for (; it != pass_register.end(); it++) {
if (it->first.substr(0, len) == text)
return strdup((it++)->first.c_str());
}
return NULL;
}
static char *readline_obj_generator(const char *text, int state)
{
static std::vector<char*> obj_names;
static size_t idx;
if (!state)
{
idx = 0;
obj_names.clear();
RTLIL::Design *design = yosys_get_design();
int len = strlen(text);
if (design->selected_active_module.empty())
{
for (auto &it : design->modules_)
if (RTLIL::unescape_id(it.first).substr(0, len) == text)
obj_names.push_back(strdup(RTLIL::id2cstr(it.first)));
}
else
if (design->modules_.count(design->selected_active_module) > 0)
{
RTLIL::Module *module = design->modules_.at(design->selected_active_module);
for (auto &it : module->wires_)
if (RTLIL::unescape_id(it.first).substr(0, len) == text)
obj_names.push_back(strdup(RTLIL::id2cstr(it.first)));
for (auto &it : module->memories)
if (RTLIL::unescape_id(it.first).substr(0, len) == text)
obj_names.push_back(strdup(RTLIL::id2cstr(it.first)));
for (auto &it : module->cells_)
if (RTLIL::unescape_id(it.first).substr(0, len) == text)
obj_names.push_back(strdup(RTLIL::id2cstr(it.first)));
for (auto &it : module->processes)
if (RTLIL::unescape_id(it.first).substr(0, len) == text)
obj_names.push_back(strdup(RTLIL::id2cstr(it.first)));
}
std::sort(obj_names.begin(), obj_names.end());
}
if (idx < obj_names.size())
return strdup(obj_names[idx++]);
idx = 0;
obj_names.clear();
return NULL;
}
static char **readline_completion(const char *text, int start, int)
{
if (start == 0)
return rl_completion_matches(text, readline_cmd_generator);
if (strncmp(rl_line_buffer, "read_", 5) && strncmp(rl_line_buffer, "write_", 6))
return rl_completion_matches(text, readline_obj_generator);
return NULL;
}
#endif
void shell(RTLIL::Design *design)
{
static int recursion_counter = 0;
recursion_counter++;
log_cmd_error_throw = true;
#ifdef YOSYS_ENABLE_READLINE
rl_readline_name = "yosys";
rl_attempted_completion_function = readline_completion;
rl_basic_word_break_characters = " \t\n";
#endif
char *command = NULL;
#ifdef YOSYS_ENABLE_READLINE
while ((command = readline(create_prompt(design, recursion_counter))) != NULL)
#else
char command_buffer[4096];
while ((command = fgets(command_buffer, 4096, stdin)) != NULL)
#endif
{
if (command[strspn(command, " \t\r\n")] == 0)
continue;
#ifdef YOSYS_ENABLE_READLINE
add_history(command);
#endif
char *p = command + strspn(command, " \t\r\n");
if (!strncmp(p, "exit", 4)) {
p += 4;
p += strspn(p, " \t\r\n");
if (*p == 0)
break;
}
try {
log_assert(design->selection_stack.size() == 1);
Pass::call(design, command);
} catch (log_cmd_error_expection) {
while (design->selection_stack.size() > 1)
design->selection_stack.pop_back();
log_reset_stack();
}
}
if (command == NULL)
printf("exit\n");
recursion_counter--;
log_cmd_error_throw = false;
}
struct ShellPass : public Pass {
ShellPass() : Pass("shell", "enter interactive command mode") { }
virtual void help() {
log("\n");
log(" shell\n");
log("\n");
log("This command enters the interactive command mode. This can be useful\n");
log("in a script to interrupt the script at a certain point and allow for\n");
log("interactive inspection or manual synthesis of the design at this point.\n");
log("\n");
log("The command prompt of the interactive shell indicates the current\n");
log("selection (see 'help select'):\n");
log("\n");
log(" yosys>\n");
log(" the entire design is selected\n");
log("\n");
log(" yosys*>\n");
log(" only part of the design is selected\n");
log("\n");
log(" yosys [modname]>\n");
log(" the entire module 'modname' is selected using 'select -module modname'\n");
log("\n");
log(" yosys [modname]*>\n");
log(" only part of current module 'modname' is selected\n");
log("\n");
log("When in interactive shell, some errors (e.g. invalid command arguments)\n");
log("do not terminate yosys but return to the command prompt.\n");
log("\n");
log("This command is the default action if nothing else has been specified\n");
log("on the command line.\n");
log("\n");
log("Press Ctrl-D or type 'exit' to leave the interactive shell.\n");
log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
extra_args(args, 1, design, false);
shell(design);
}
} ShellPass;
#ifdef YOSYS_ENABLE_READLINE
struct HistoryPass : public Pass {
HistoryPass() : Pass("history", "show last interactive commands") { }
virtual void help() {
log("\n");
log(" history\n");
log("\n");
log("This command prints all commands in the shell history buffer. This are\n");
log("all commands executed in an interactive session, but not the commands\n");
log("from executed scripts.\n");
log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
extra_args(args, 1, design, false);
for(HIST_ENTRY **list = history_list(); *list != NULL; list++)
log("%s\n", (*list)->line);
}
} HistoryPass;
#endif
struct ScriptPass : public Pass {
ScriptPass() : Pass("script", "execute commands from script file") { }
virtual void help() {
log("\n");
log(" script <filename> [<from_label>:<to_label>]\n");
log("\n");
log("This command executes the yosys commands in the specified file.\n");
log("\n");
log("The 2nd argument can be used to only execute the section of the\n");
log("file between the specified labels. An empty from label is synonymous\n");
log("for the beginning of the file and an empty to label is synonymous\n");
log("for the end of the file.\n");
log("\n");
log("If only one label is specified (without ':') then only the block\n");
log("marked with that label (until the next label) is executed.\n");
log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
if (args.size() < 2)
log_cmd_error("Missing script file.\n");
else if (args.size() == 2)
run_frontend(args[1], "script", design, NULL, NULL);
else if (args.size() == 3)
run_frontend(args[1], "script", design, NULL, &args[2]);
else
extra_args(args, 2, design, false);
}
} ScriptPass;
YOSYS_NAMESPACE_END

149
kernel/yosys.h Normal file
View file

@ -0,0 +1,149 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
// *** NOTE TO THE READER ***
//
// Maybe you have just opened this file in the hope to learn more about the
// Yosys API. Let me congratulate you on this great decision! ;)
//
// If you want to know how the design is represented by Yosys in the memory,
// you should read "kernel/rtlil.h".
//
// If you want to know how to register a command with Yosys, you could read
// "kernel/register.h", but it would be easier to just look at a simple
// example instead. A simple one would be "passes/cmds/log.cc".
//
// This header is very boring. It just defines some general things that
// belong nowhere else and includes the interesting headers.
//
// Find more information in the "CodingReadme" file.
#ifndef YOSYS_H
#define YOSYS_H
#include <map>
#include <set>
#include <vector>
#include <string>
#include <algorithm>
#include <functional>
#include <initializer_list>
#include <sstream>
#include <fstream>
#include <istream>
#include <ostream>
#include <iostream>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define PRIVATE_NAMESPACE_BEGIN namespace {
#define PRIVATE_NAMESPACE_END }
#if 0
# define YOSYS_NAMESPACE_BEGIN namespace Yosys {
# define YOSYS_NAMESPACE_END }
# define YOSYS_NAMESPACE_PREFIX Yosys::
# define USING_YOSYS_NAMESPACE using namespace Yosys;
#else
# define YOSYS_NAMESPACE_BEGIN
# define YOSYS_NAMESPACE_END
# define YOSYS_NAMESPACE_PREFIX
# define USING_YOSYS_NAMESPACE
#endif
#if __cplusplus >= 201103L
# define OVERRIDE override
# define FINAL final
#else
# define OVERRIDE
# define FINAL
#endif
YOSYS_NAMESPACE_BEGIN
namespace RTLIL {
struct IdString;
struct SigSpec;
struct Wire;
struct Cell;
}
std::string stringf(const char *fmt, ...);
std::string vstringf(const char *fmt, va_list ap);
template<typename T> int SIZE(const T &obj) { return obj.size(); }
int SIZE(RTLIL::Wire *wire);
YOSYS_NAMESPACE_END
#include "kernel/log.h"
#include "kernel/rtlil.h"
#include "kernel/register.h"
YOSYS_NAMESPACE_BEGIN
void yosys_setup();
void yosys_shutdown();
#ifdef YOSYS_ENABLE_TCL
#include <tcl.h>
Tcl_Interp *yosys_get_tcl_interp();
#endif
extern int autoidx;
extern RTLIL::Design *yosys_design;
RTLIL::IdString new_id(std::string file, int line, std::string func);
#define NEW_ID \
YOSYS_NAMESPACE_PREFIX new_id(__FILE__, __LINE__, __FUNCTION__)
#define ID(_str) \
([]() { static YOSYS_NAMESPACE_PREFIX RTLIL::IdString _id(_str); return _id; })()
RTLIL::Design *yosys_get_design();
std::string proc_self_dirname();
std::string proc_share_dirname();
const char *create_prompt(RTLIL::Design *design, int recursion_counter);
void run_frontend(std::string filename, std::string command, RTLIL::Design *design, std::string *backend_command, std::string *from_to_label);
void run_pass(std::string command, RTLIL::Design *design);
void run_backend(std::string filename, std::string command, RTLIL::Design *design);
void shell(RTLIL::Design *design);
// from kernel/version_*.o (cc source generated from Makefile)
extern const char *yosys_version_str;
// from passes/cmds/design.cc
extern std::map<std::string, RTLIL::Design*> saved_designs;
extern std::vector<RTLIL::Design*> pushed_designs;
// from passes/cmds/pluginc.cc
extern std::map<std::string, void*> loaded_plugins;
extern std::map<std::string, std::string> loaded_plugin_aliases;
void load_plugin(std::string filename, std::vector<std::string> aliases);
YOSYS_NAMESPACE_END
#endif

View file

@ -3,7 +3,8 @@ CC = clang
CXX = clang
CXXFLAGS = -MD -Wall -Wextra -ggdb
CXXFLAGS += -std=c++11 -O0
LDLIBS = -lminisat -lstdc++
LDLIBS = ../minisat/Options.cc ../minisat/SimpSolver.cc ../minisat/Solver.cc ../minisat/System.cc -lm -lstdc++
all: demo_vec demo_bit demo_cmp testbench puzzle3d
@ -17,10 +18,11 @@ test: all
./testbench
./demo_bit
./demo_vec
./demo_cmp
# ./demo_cmp
# ./puzzle3d
clean:
rm -f demo_bit demo_vec testbench puzzle3d *.o *.d
rm -f demo_bit demo_vec demo_cmp testbench puzzle3d *.o *.d
.PHONY: all test clean

View file

@ -25,15 +25,20 @@
#include <limits.h>
#include <stdint.h>
#include <signal.h>
#include <csignal>
#include <cinttypes>
#include <unistd.h>
#include <minisat/core/Solver.h>
#include "../minisat/Solver.h"
#include "../minisat/SimpSolver.h"
ezMiniSAT::ezMiniSAT() : minisatSolver(NULL)
{
minisatSolver = NULL;
foundContradiction = false;
freeze(TRUE);
freeze(FALSE);
}
ezMiniSAT::~ezMiniSAT()
@ -50,9 +55,28 @@ void ezMiniSAT::clear()
}
foundContradiction = false;
minisatVars.clear();
#if EZMINISAT_SIMPSOLVER && EZMINISAT_INCREMENTAL
cnfFrozenVars.clear();
#endif
ezSAT::clear();
}
#if EZMINISAT_SIMPSOLVER && EZMINISAT_INCREMENTAL
void ezMiniSAT::freeze(int id)
{
if (!mode_non_incremental())
cnfFrozenVars.insert(bind(id));
}
bool ezMiniSAT::eliminated(int idx)
{
idx = idx < 0 ? -idx : idx;
if (minisatSolver != NULL && idx > 0 && idx <= int(minisatVars.size()))
return minisatSolver->isEliminated(minisatVars.at(idx-1));
return false;
}
#endif
ezMiniSAT *ezMiniSAT::alarmHandlerThis = NULL;
clock_t ezMiniSAT::alarmHandlerTimeout = 0;
@ -67,6 +91,8 @@ void ezMiniSAT::alarmHandler(int)
bool ezMiniSAT::solver(const std::vector<int> &modelExpressions, std::vector<bool> &modelValues, const std::vector<int> &assumptions)
{
preSolverCallback();
solverTimoutStatus = false;
if (0) {
@ -90,22 +116,42 @@ contradiction:
for (auto id : modelExpressions)
modelIdx.push_back(bind(id));
if (minisatSolver == NULL)
minisatSolver = new Minisat::Solver;
if (minisatSolver == NULL) {
minisatSolver = new Solver;
minisatSolver->verbosity = EZMINISAT_VERBOSITY;
}
#if EZMINISAT_INCREMENTAL
std::vector<std::vector<int>> cnf;
consumeCnf(cnf);
#else
const std::vector<std::vector<int>> &cnf = this->cnf();
#endif
while (int(minisatVars.size()) < numCnfVariables())
minisatVars.push_back(minisatSolver->newVar());
#if EZMINISAT_SIMPSOLVER && EZMINISAT_INCREMENTAL
for (auto idx : cnfFrozenVars)
minisatSolver->setFrozen(minisatVars.at(idx > 0 ? idx-1 : -idx-1), true);
cnfFrozenVars.clear();
#endif
for (auto &clause : cnf) {
Minisat::vec<Minisat::Lit> ps;
for (auto idx : clause)
for (auto idx : clause) {
if (idx > 0)
ps.push(Minisat::mkLit(minisatVars.at(idx-1)));
else
ps.push(Minisat::mkLit(minisatVars.at(-idx-1), true));
#if EZMINISAT_SIMPSOLVER
if (minisatSolver->isEliminated(minisatVars.at(idx > 0 ? idx-1 : -idx-1))) {
fprintf(stderr, "Assert in %s:%d failed! Missing call to ezsat->freeze(): %s (lit=%d)\n",
__FILE__, __LINE__, cnfLiteralInfo(idx).c_str(), idx);
abort();
}
#endif
}
if (!minisatSolver->addClause(ps))
goto contradiction;
}
@ -115,20 +161,31 @@ contradiction:
Minisat::vec<Minisat::Lit> assumps;
for (auto idx : extraClauses)
for (auto idx : extraClauses) {
if (idx > 0)
assumps.push(Minisat::mkLit(minisatVars.at(idx-1)));
else
assumps.push(Minisat::mkLit(minisatVars.at(-idx-1), true));
#if EZMINISAT_SIMPSOLVER
if (minisatSolver->isEliminated(minisatVars.at(idx > 0 ? idx-1 : -idx-1))) {
fprintf(stderr, "Assert in %s:%d failed! Missing call to ezsat->freeze(): %s\n", __FILE__, __LINE__, cnfLiteralInfo(idx).c_str());
abort();
}
#endif
}
sighandler_t old_alarm_sighandler = NULL;
struct sigaction sig_action;
struct sigaction old_sig_action;
int old_alarm_timeout = 0;
if (solverTimeout > 0) {
sig_action.sa_handler = alarmHandler;
sigemptyset(&sig_action.sa_mask);
sig_action.sa_flags = SA_RESTART;
alarmHandlerThis = this;
alarmHandlerTimeout = clock() + solverTimeout*CLOCKS_PER_SEC;
old_alarm_timeout = alarm(0);
old_alarm_sighandler = signal(SIGALRM, alarmHandler);
sigaction(SIGALRM, &sig_action, &old_sig_action);
alarm(1);
}
@ -138,12 +195,18 @@ contradiction:
if (alarmHandlerTimeout == 0)
solverTimoutStatus = true;
alarm(0);
signal(SIGALRM, old_alarm_sighandler);
sigaction(SIGALRM, &old_sig_action, NULL);
alarm(old_alarm_timeout);
}
if (!foundSolution)
if (!foundSolution) {
#if !EZMINISAT_INCREMENTAL
delete minisatSolver;
minisatSolver = NULL;
minisatVars.clear();
#endif
return false;
}
modelValues.clear();
modelValues.resize(modelIdx.size());
@ -161,6 +224,11 @@ contradiction:
modelValues[i] = (value == Minisat::lbool(refvalue));
}
#if !EZMINISAT_INCREMENTAL
delete minisatSolver;
minisatSolver = NULL;
minisatVars.clear();
#endif
return true;
}

View file

@ -20,6 +20,10 @@
#ifndef EZMINISAT_H
#define EZMINISAT_H
#define EZMINISAT_SIMPSOLVER 1
#define EZMINISAT_VERBOSITY 0
#define EZMINISAT_INCREMENTAL 1
#include "ezsat.h"
#include <time.h>
@ -28,15 +32,25 @@
// don't force ezSAT users to use minisat headers..
namespace Minisat {
class Solver;
class SimpSolver;
}
class ezMiniSAT : public ezSAT
{
private:
Minisat::Solver *minisatSolver;
#if EZMINISAT_SIMPSOLVER
typedef Minisat::SimpSolver Solver;
#else
typedef Minisat::Solver Solver;
#endif
Solver *minisatSolver;
std::vector<int> minisatVars;
bool foundContradiction;
#if EZMINISAT_SIMPSOLVER && EZMINISAT_INCREMENTAL
std::set<int> cnfFrozenVars;
#endif
static ezMiniSAT *alarmHandlerThis;
static clock_t alarmHandlerTimeout;
static void alarmHandler(int);
@ -45,6 +59,10 @@ public:
ezMiniSAT();
virtual ~ezMiniSAT();
virtual void clear();
#if EZMINISAT_SIMPSOLVER && EZMINISAT_INCREMENTAL
virtual void freeze(int id);
virtual bool eliminated(int idx);
#endif
virtual bool solver(const std::vector<int> &modelExpressions, std::vector<bool> &modelValues, const std::vector<int> &assumptions);
};

View file

@ -19,21 +19,21 @@
#include "ezsat.h"
#include <cmath>
#include <algorithm>
#include <cassert>
#include <stdlib.h>
#include <assert.h>
const int ezSAT::TRUE = 1;
const int ezSAT::FALSE = 2;
ezSAT::ezSAT()
{
literal("TRUE");
literal("FALSE");
flag_keep_cnf = false;
flag_non_incremental = false;
assert(literal("TRUE") == TRUE);
assert(literal("FALSE") == FALSE);
non_incremental_solve_used_up = false;
cnfConsumed = false;
cnfVariableCount = 0;
@ -41,6 +41,12 @@ ezSAT::ezSAT()
solverTimeout = 0;
solverTimoutStatus = false;
literal("TRUE");
literal("FALSE");
assert(literal("TRUE") == TRUE);
assert(literal("FALSE") == FALSE);
}
ezSAT::~ezSAT()
@ -67,6 +73,20 @@ int ezSAT::literal(const std::string &name)
return literalsCache.at(name);
}
int ezSAT::frozen_literal()
{
int id = literal();
freeze(id);
return id;
}
int ezSAT::frozen_literal(const std::string &name)
{
int id = literal(name);
freeze(id);
return id;
}
int ezSAT::expression(OpId op, int a, int b, int c, int d, int e, int f)
{
std::vector<int> args(6);
@ -342,13 +362,19 @@ void ezSAT::clear()
cnfLiteralVariables.clear();
cnfExpressionVariables.clear();
cnfClauses.clear();
cnfAssumptions.clear();
}
void ezSAT::freeze(int)
{
}
bool ezSAT::eliminated(int)
{
return false;
}
void ezSAT::assume(int id)
{
cnfAssumptions.insert(id);
if (id < 0)
{
assert(0 < -id && -id <= int(expressions.size()));
@ -462,11 +488,32 @@ int ezSAT::bound(int id) const
return 0;
}
int ezSAT::bind(int id)
std::string ezSAT::cnfLiteralInfo(int idx) const
{
for (size_t i = 0; i < cnfLiteralVariables.size(); i++) {
if (cnfLiteralVariables[i] == idx)
return to_string(i+1);
if (cnfLiteralVariables[i] == -idx)
return "NOT " + to_string(i+1);
}
for (size_t i = 0; i < cnfExpressionVariables.size(); i++) {
if (cnfExpressionVariables[i] == idx)
return to_string(-i-1);
if (cnfExpressionVariables[i] == -idx)
return "NOT " + to_string(-i-1);
}
return "<unnamed>";
}
int ezSAT::bind(int id, bool auto_freeze)
{
if (id >= 0) {
assert(0 < id && id <= int(literals.size()));
cnfLiteralVariables.resize(literals.size());
if (eliminated(cnfLiteralVariables[id-1])) {
fprintf(stderr, "ezSAT: Missing freeze on literal `%s'.\n", to_string(id).c_str());
abort();
}
if (cnfLiteralVariables[id-1] == 0) {
cnfLiteralVariables[id-1] = ++cnfVariableCount;
if (id == TRUE)
@ -480,6 +527,17 @@ int ezSAT::bind(int id)
assert(0 < -id && -id <= int(expressions.size()));
cnfExpressionVariables.resize(expressions.size());
if (eliminated(cnfExpressionVariables[-id-1]))
{
cnfExpressionVariables[-id-1] = 0;
// this will recursively call bind(id). within the recursion
// the cnf is pre-set to 0. an idx is allocated there, then it
// is frozen, then it returns here with the new idx already set.
if (auto_freeze)
freeze(id);
}
if (cnfExpressionVariables[-id-1] == 0)
{
OpId op;
@ -497,7 +555,7 @@ int ezSAT::bind(int id)
newArgs.push_back(OR(AND(args[i], NOT(args[i+1])), AND(NOT(args[i]), args[i+1])));
args.swap(newArgs);
}
idx = bind(args.at(0));
idx = bind(args.at(0), false);
goto assign_idx;
}
@ -505,17 +563,17 @@ int ezSAT::bind(int id)
std::vector<int> invArgs;
for (auto arg : args)
invArgs.push_back(NOT(arg));
idx = bind(OR(expression(OpAnd, args), expression(OpAnd, invArgs)));
idx = bind(OR(expression(OpAnd, args), expression(OpAnd, invArgs)), false);
goto assign_idx;
}
if (op == OpITE) {
idx = bind(OR(AND(args[0], args[1]), AND(NOT(args[0]), args[2])));
idx = bind(OR(AND(args[0], args[1]), AND(NOT(args[0]), args[2])), false);
goto assign_idx;
}
for (int i = 0; i < int(args.size()); i++)
args[i] = bind(args[i]);
args[i] = bind(args[i], false);
switch (op)
{
@ -535,120 +593,45 @@ int ezSAT::bind(int id)
void ezSAT::consumeCnf()
{
cnfConsumed = true;
if (mode_keep_cnf())
cnfClausesBackup.insert(cnfClausesBackup.end(), cnfClauses.begin(), cnfClauses.end());
else
cnfConsumed = true;
cnfClauses.clear();
}
void ezSAT::consumeCnf(std::vector<std::vector<int>> &cnf)
{
cnfConsumed = true;
if (mode_keep_cnf())
cnfClausesBackup.insert(cnfClausesBackup.end(), cnfClauses.begin(), cnfClauses.end());
else
cnfConsumed = true;
cnf.swap(cnfClauses);
cnfClauses.clear();
}
static bool test_bit(uint32_t bitmask, int idx)
void ezSAT::getFullCnf(std::vector<std::vector<int>> &full_cnf) const
{
if (idx > 0)
return (bitmask & (1 << (+idx-1))) != 0;
else
return (bitmask & (1 << (-idx-1))) == 0;
assert(full_cnf.empty());
full_cnf.insert(full_cnf.end(), cnfClausesBackup.begin(), cnfClausesBackup.end());
full_cnf.insert(full_cnf.end(), cnfClauses.begin(), cnfClauses.end());
}
bool ezSAT::solver(const std::vector<int> &modelExpressions, std::vector<bool> &modelValues, const std::vector<int> &assumptions)
void ezSAT::preSolverCallback()
{
std::vector<int> extraClauses, modelIdx;
std::vector<int> values(numLiterals());
assert(!non_incremental_solve_used_up);
if (mode_non_incremental())
non_incremental_solve_used_up = true;
}
for (auto id : assumptions)
extraClauses.push_back(bind(id));
for (auto id : modelExpressions)
modelIdx.push_back(bind(id));
if (cnfVariableCount > 20) {
fprintf(stderr, "*************************************************************************************\n");
fprintf(stderr, "ERROR: You are trying to use the builtin solver of ezSAT with more than 20 variables!\n");
fprintf(stderr, "The builtin solver is a dumb brute force solver and only ment for testing and demo\n");
fprintf(stderr, "purposes. Use a real SAT solve like MiniSAT (e.g. using the ezMiniSAT class) instead.\n");
fprintf(stderr, "*************************************************************************************\n");
abort();
}
for (uint32_t bitmask = 0; bitmask < (1 << numCnfVariables()); bitmask++)
{
// printf("%07o:", int(bitmask));
// for (int i = 2; i < numLiterals(); i++)
// if (bound(i+1))
// printf(" %s=%d", to_string(i+1).c_str(), test_bit(bitmask, bound(i+1)));
// printf(" |");
// for (int idx = 1; idx <= numCnfVariables(); idx++)
// printf(" %3d", test_bit(bitmask, idx) ? idx : -idx);
// printf("\n");
for (auto idx : extraClauses)
if (!test_bit(bitmask, idx))
goto next;
for (auto &clause : cnfClauses) {
for (auto idx : clause)
if (test_bit(bitmask, idx))
goto next_clause;
// printf("failed clause:");
// for (auto idx2 : clause)
// printf(" %3d", idx2);
// printf("\n");
goto next;
next_clause:;
// printf("passed clause:");
// for (auto idx2 : clause)
// printf(" %3d", idx2);
// printf("\n");
}
modelValues.resize(modelIdx.size());
for (int i = 0; i < int(modelIdx.size()); i++)
modelValues[i] = test_bit(bitmask, modelIdx[i]);
// validate result using eval()
values[0] = TRUE, values[1] = FALSE;
for (int i = 2; i < numLiterals(); i++) {
int idx = bound(i+1);
values[i] = idx != 0 ? (test_bit(bitmask, idx) ? TRUE : FALSE) : 0;
}
for (auto id : cnfAssumptions) {
int result = eval(id, values);
if (result != TRUE) {
printInternalState(stderr);
fprintf(stderr, "Variables:");
for (int i = 0; i < numLiterals(); i++)
fprintf(stderr, " %s=%s", lookup_literal(i+1).c_str(), values[i] == TRUE ? "TRUE" : values[i] == FALSE ? "FALSE" : "UNDEF");
fprintf(stderr, "\nValidation of solver results failed: got `%d' (%s) for assumption '%d': %s\n",
result, result == FALSE ? "FALSE" : "UNDEF", id, to_string(id).c_str());
abort();
}
// printf("OK: %d -> %d\n", id, result);
}
for (auto id : assumptions) {
int result = eval(id, values);
if (result != TRUE) {
printInternalState(stderr);
fprintf(stderr, "Variables:");
for (int i = 0; i < numLiterals(); i++)
fprintf(stderr, " %s=%s", lookup_literal(i+1).c_str(), values[i] == TRUE ? "TRUE" : values[i] == FALSE ? "FALSE" : "UNDEF");
fprintf(stderr, "\nValidation of solver results failed: got `%d' (%s) for assumption '%d': %s\n",
result, result == FALSE ? "FALSE" : "UNDEF", id, to_string(id).c_str());
abort();
}
// printf("OK: %d -> %d\n", id, result);
}
return true;
next:;
}
return false;
bool ezSAT::solver(const std::vector<int>&, std::vector<bool>&, const std::vector<int>&)
{
preSolverCallback();
fprintf(stderr, "************************************************************************\n");
fprintf(stderr, "ERROR: You are trying to use the solve() method of the ezSAT base class!\n");
fprintf(stderr, "Use a dervied class like ezMiniSAT instead.\n");
fprintf(stderr, "************************************************************************\n");
abort();
}
std::vector<int> ezSAT::vec_const(const std::vector<bool> &bits)
@ -994,6 +977,96 @@ std::vector<int> ezSAT::vec_srl(const std::vector<int> &vec1, int shift)
return vec;
}
std::vector<int> ezSAT::vec_shift(const std::vector<int> &vec1, int shift, int extend_left, int extend_right)
{
std::vector<int> vec;
for (int i = 0; i < int(vec1.size()); i++) {
int j = i+shift;
if (j < 0)
vec.push_back(extend_right);
else if (j >= int(vec1.size()))
vec.push_back(extend_left);
else
vec.push_back(vec1[j]);
}
return vec;
}
static int my_clog2(int x)
{
int result = 0;
for (x--; x > 0; result++)
x >>= 1;
return result;
}
std::vector<int> ezSAT::vec_shift_right(const std::vector<int> &vec1, const std::vector<int> &vec2, bool vec2_signed, int extend_left, int extend_right)
{
int vec2_bits = std::min(my_clog2(vec1.size()) + (vec2_signed ? 1 : 0), int(vec2.size()));
std::vector<int> overflow_bits(vec2.begin() + vec2_bits, vec2.end());
int overflow_left = FALSE, overflow_right = FALSE;
if (vec2_signed) {
int overflow = FALSE;
for (auto bit : overflow_bits)
overflow = OR(overflow, XOR(bit, vec2[vec2_bits-1]));
overflow_left = AND(overflow, NOT(vec2.back()));
overflow_right = AND(overflow, vec2.back());
} else
overflow_left = vec_reduce_or(overflow_bits);
std::vector<int> buffer = vec1;
if (vec2_signed)
while (buffer.size() < vec1.size() + (1 << vec2_bits))
buffer.push_back(extend_left);
std::vector<int> overflow_pattern_left(buffer.size(), extend_left);
std::vector<int> overflow_pattern_right(buffer.size(), extend_right);
buffer = vec_ite(overflow_left, overflow_pattern_left, buffer);
if (vec2_signed)
buffer = vec_ite(overflow_right, overflow_pattern_left, buffer);
for (int i = vec2_bits-1; i >= 0; i--) {
std::vector<int> shifted_buffer;
if (vec2_signed && i == vec2_bits-1)
shifted_buffer = vec_shift(buffer, -(1 << i), extend_left, extend_right);
else
shifted_buffer = vec_shift(buffer, 1 << i, extend_left, extend_right);
buffer = vec_ite(vec2[i], shifted_buffer, buffer);
}
buffer.resize(vec1.size());
return buffer;
}
std::vector<int> ezSAT::vec_shift_left(const std::vector<int> &vec1, const std::vector<int> &vec2, bool vec2_signed, int extend_left, int extend_right)
{
// vec2_signed is not implemented in vec_shift_left() yet
assert(vec2_signed == false);
int vec2_bits = std::min(my_clog2(vec1.size()), int(vec2.size()));
std::vector<int> overflow_bits(vec2.begin() + vec2_bits, vec2.end());
int overflow = vec_reduce_or(overflow_bits);
std::vector<int> buffer = vec1;
std::vector<int> overflow_pattern_right(buffer.size(), extend_right);
buffer = vec_ite(overflow, overflow_pattern_right, buffer);
for (int i = 0; i < vec2_bits; i++) {
std::vector<int> shifted_buffer;
shifted_buffer = vec_shift(buffer, -(1 << i), extend_left, extend_right);
buffer = vec_ite(vec2[i], shifted_buffer, buffer);
}
buffer.resize(vec1.size());
return buffer;
}
void ezSAT::vec_append(std::vector<int> &vec, const std::vector<int> &vec1) const
{
for (auto bit : vec1)
@ -1124,17 +1197,32 @@ void ezSAT::printDIMACS(FILE *f, bool verbose) const
if (cnfExpressionVariables[i] != 0)
fprintf(f, "c %*d: %s\n", digits, cnfExpressionVariables[i], to_string(-i-1).c_str());
if (mode_keep_cnf()) {
fprintf(f, "c\n");
fprintf(f, "c %d clauses from backup, %d from current buffer\n",
int(cnfClausesBackup.size()), int(cnfClauses.size()));
}
fprintf(f, "c\n");
}
fprintf(f, "p cnf %d %d\n", cnfVariableCount, int(cnfClauses.size()));
std::vector<std::vector<int>> all_clauses;
getFullCnf(all_clauses);
assert(cnfClausesCount == int(all_clauses.size()));
fprintf(f, "p cnf %d %d\n", cnfVariableCount, cnfClausesCount);
int maxClauseLen = 0;
for (auto &clause : cnfClauses)
for (auto &clause : all_clauses)
maxClauseLen = std::max(int(clause.size()), maxClauseLen);
for (auto &clause : cnfClauses) {
if (!verbose)
maxClauseLen = std::min(maxClauseLen, 3);
for (auto &clause : all_clauses) {
for (auto idx : clause)
fprintf(f, " %*d", digits, idx);
fprintf(f, " %*d\n", (digits + 1)*int(maxClauseLen - clause.size()) + digits, 0);
if (maxClauseLen >= int(clause.size()))
fprintf(f, " %*d\n", (digits + 1)*int(maxClauseLen - clause.size()) + digits, 0);
else
fprintf(f, " %*d\n", digits, 0);
}
}

View file

@ -48,6 +48,11 @@ public:
static const int FALSE;
private:
bool flag_keep_cnf;
bool flag_non_incremental;
bool non_incremental_solve_used_up;
std::map<std::string, int> literalsCache;
std::vector<std::string> literals;
@ -57,8 +62,7 @@ private:
bool cnfConsumed;
int cnfVariableCount, cnfClausesCount;
std::vector<int> cnfLiteralVariables, cnfExpressionVariables;
std::vector<std::vector<int>> cnfClauses;
std::set<int> cnfAssumptions;
std::vector<std::vector<int>> cnfClauses, cnfClausesBackup;
void add_clause(const std::vector<int> &args);
void add_clause(const std::vector<int> &args, bool argsPolarity, int a = 0, int b = 0, int c = 0);
@ -68,6 +72,9 @@ private:
int bind_cnf_and(const std::vector<int> &args);
int bind_cnf_or(const std::vector<int> &args);
protected:
void preSolverCallback();
public:
int solverTimeout;
bool solverTimoutStatus;
@ -75,11 +82,19 @@ public:
ezSAT();
virtual ~ezSAT();
void keep_cnf() { flag_keep_cnf = true; }
void non_incremental() { flag_non_incremental = true; }
bool mode_keep_cnf() const { return flag_keep_cnf; }
bool mode_non_incremental() const { return flag_non_incremental; }
// manage expressions
int value(bool val);
int literal();
int literal(const std::string &name);
int frozen_literal();
int frozen_literal(const std::string &name);
int expression(OpId op, int a = 0, int b = 0, int c = 0, int d = 0, int e = 0, int f = 0);
int expression(OpId op, const std::vector<int> &args);
@ -141,10 +156,10 @@ public:
// manage CNF (usually only accessed by SAT solvers)
virtual void clear();
virtual void freeze(int id);
virtual bool eliminated(int idx);
void assume(int id);
int bind(int id);
const std::set<int> &assumed() const { return cnfAssumptions; }
int bind(int id, bool auto_freeze = true);
int bound(int id) const;
int numCnfVariables() const { return cnfVariableCount; }
@ -154,6 +169,11 @@ public:
void consumeCnf();
void consumeCnf(std::vector<std::vector<int>> &cnf);
// use this function to get the full CNF in keep_cnf mode
void getFullCnf(std::vector<std::vector<int>> &full_cnf) const;
std::string cnfLiteralInfo(int idx) const;
// simple helpers for build expressions easily
struct _V {
@ -165,7 +185,7 @@ public:
int get(ezSAT *that) {
if (name.empty())
return id;
return that->literal(name);
return that->frozen_literal(name);
}
};
@ -217,7 +237,7 @@ public:
std::vector<int> vec_iff(const std::vector<int> &vec1, const std::vector<int> &vec2);
std::vector<int> vec_ite(const std::vector<int> &vec1, const std::vector<int> &vec2, const std::vector<int> &vec3);
std::vector<int> vec_ite(int sel, const std::vector<int> &vec2, const std::vector<int> &vec3);
std::vector<int> vec_ite(int sel, const std::vector<int> &vec1, const std::vector<int> &vec2);
std::vector<int> vec_count(const std::vector<int> &vec, int numBits, bool clip = true);
std::vector<int> vec_add(const std::vector<int> &vec1, const std::vector<int> &vec2);
@ -245,6 +265,10 @@ public:
std::vector<int> vec_shr(const std::vector<int> &vec1, int shift, bool signExtend = false) { return vec_shl(vec1, -shift, signExtend); }
std::vector<int> vec_srr(const std::vector<int> &vec1, int shift) { return vec_srl(vec1, -shift); }
std::vector<int> vec_shift(const std::vector<int> &vec1, int shift, int extend_left, int extend_right);
std::vector<int> vec_shift_right(const std::vector<int> &vec1, const std::vector<int> &vec2, bool vec2_signed, int extend_left, int extend_right);
std::vector<int> vec_shift_left(const std::vector<int> &vec1, const std::vector<int> &vec2, bool vec2_signed, int extend_left, int extend_right);
void vec_append(std::vector<int> &vec, const std::vector<int> &vec1) const;
void vec_append_signed(std::vector<int> &vec, const std::vector<int> &vec1, int64_t value);
void vec_append_unsigned(std::vector<int> &vec, const std::vector<int> &vec1, uint64_t value);

View file

@ -260,8 +260,10 @@ int main()
std::vector<int> modelExpressions;
std::vector<bool> modelValues;
for (auto &it : blockinfo)
for (auto &it : blockinfo) {
ez.freeze(it.first);
modelExpressions.push_back(it.first);
}
int solution_counter = 0;
while (1)

View file

@ -38,11 +38,6 @@ struct xorshift128 {
bool test(ezSAT &sat, int assumption = 0)
{
for (auto id : sat.assumed())
printf("%s\n", sat.to_string(id).c_str());
if (assumption)
printf("%s\n", sat.to_string(assumption).c_str());
std::vector<int> modelExpressions;
std::vector<bool> modelValues;
@ -68,7 +63,8 @@ void test_simple()
{
printf("==== %s ====\n\n", __PRETTY_FUNCTION__);
ezSAT sat;
ezMiniSAT sat;
sat.non_incremental();
sat.assume(sat.OR("A", "B"));
sat.assume(sat.NOT(sat.AND("A", "B")));
test(sat);
@ -76,89 +72,6 @@ void test_simple()
// ------------------------------------------------------------------------------------------------------------
void test_basic_operators(ezSAT &sat, xorshift128 &rng, int iter, bool buildTrees, bool buildClusters, std::vector<bool> &log)
{
int vars[6] = {
sat.VAR("A"), sat.VAR("B"), sat.VAR("C"),
sat.NOT("A"), sat.NOT("B"), sat.NOT("C")
};
for (int i = 0; i < iter; i++) {
int assumption = 0, op = rng() % 6, to = rng() % 6;
int a = vars[rng() % 6], b = vars[rng() % 6], c = vars[rng() % 6];
// printf("--> %d %d:%s %d:%s %d:%s\n", op, a, sat.to_string(a).c_str(), b, sat.to_string(b).c_str(), c, sat.to_string(c).c_str());
switch (op)
{
case 0:
assumption = sat.NOT(a);
break;
case 1:
assumption = sat.AND(a, b);
break;
case 2:
assumption = sat.OR(a, b);
break;
case 3:
assumption = sat.XOR(a, b);
break;
case 4:
assumption = sat.IFF(a, b);
break;
case 5:
assumption = sat.ITE(a, b, c);
break;
}
// printf(" --> %d:%s\n", to, sat.to_string(assumption).c_str());
if (buildTrees)
vars[to] = assumption;
if (!buildClusters)
sat.clear();
sat.assume(assumption);
if (sat.numCnfVariables() < 15) {
printf("%d:\n", int(log.size()));
log.push_back(test(sat));
} else {
// printf("** skipping large problem **\n");
}
}
}
void test_basic_operators(ezSAT &sat, std::vector<bool> &log)
{
printf("-- %s --\n\n", __PRETTY_FUNCTION__);
xorshift128 rng;
test_basic_operators(sat, rng, 1000, false, false, log);
for (int i = 0; i < 100; i++)
test_basic_operators(sat, rng, 10, true, false, log);
for (int i = 0; i < 100; i++)
test_basic_operators(sat, rng, 10, false, true, log);
}
void test_basic_operators()
{
printf("==== %s ====\n\n", __PRETTY_FUNCTION__);
ezSAT sat;
ezMiniSAT miniSat;
std::vector<bool> logSat, logMiniSat;
test_basic_operators(sat, logSat);
test_basic_operators(miniSat, logMiniSat);
if (logSat != logMiniSat) {
printf("Differences between logSat and logMiniSat:");
for (int i = 0; i < int(std::max(logSat.size(), logMiniSat.size())); i++)
if (i >= int(logSat.size()) || i >= int(logMiniSat.size()) || logSat[i] != logMiniSat[i])
printf(" %d", i);
printf("\n");
abort();
} else {
printf("Completed %d tests with identical results with ezSAT and ezMiniSAT.\n\n", int(logSat.size()));
}
}
// ------------------------------------------------------------------------------------------------------------
void test_xorshift32_try(ezSAT &sat, uint32_t input_pattern)
{
uint32_t output_pattern = input_pattern;
@ -209,6 +122,8 @@ void test_xorshift32()
printf("==== %s ====\n\n", __PRETTY_FUNCTION__);
ezMiniSAT sat;
sat.keep_cnf();
xorshift128 rng;
std::vector<int> bits = sat.vec_var("i", 32);
@ -225,6 +140,9 @@ void test_xorshift32()
test_xorshift32_try(sat, rng());
test_xorshift32_try(sat, rng());
test_xorshift32_try(sat, rng());
sat.printDIMACS(stdout, true);
printf("\n");
}
// ------------------------------------------------------------------------------------------------------------
@ -243,7 +161,7 @@ void check(const char *expr1_str, bool expr1, const char *expr2_str, bool expr2)
void test_signed(int8_t a, int8_t b, int8_t c)
{
ezSAT sat;
ezMiniSAT sat;
std::vector<int> av = sat.vec_const_signed(a, 8);
std::vector<int> bv = sat.vec_const_signed(b, 8);
@ -262,7 +180,7 @@ void test_signed(int8_t a, int8_t b, int8_t c)
void test_unsigned(uint8_t a, uint8_t b, uint8_t c)
{
ezSAT sat;
ezMiniSAT sat;
if (b < c)
b ^= c, c ^= b, b ^= c;
@ -284,7 +202,7 @@ void test_unsigned(uint8_t a, uint8_t b, uint8_t c)
void test_count(uint32_t x)
{
ezSAT sat;
ezMiniSAT sat;
int count = 0;
for (int i = 0; i < 32; i++)
@ -338,10 +256,10 @@ void test_onehot()
printf("==== %s ====\n\n", __PRETTY_FUNCTION__);
ezMiniSAT ez;
int a = ez.literal("a");
int b = ez.literal("b");
int c = ez.literal("c");
int d = ez.literal("d");
int a = ez.frozen_literal("a");
int b = ez.frozen_literal("b");
int c = ez.frozen_literal("c");
int d = ez.frozen_literal("d");
std::vector<int> abcd;
abcd.push_back(a);
@ -392,10 +310,10 @@ void test_manyhot()
printf("==== %s ====\n\n", __PRETTY_FUNCTION__);
ezMiniSAT ez;
int a = ez.literal("a");
int b = ez.literal("b");
int c = ez.literal("c");
int d = ez.literal("d");
int a = ez.frozen_literal("a");
int b = ez.frozen_literal("b");
int c = ez.frozen_literal("c");
int d = ez.frozen_literal("d");
std::vector<int> abcd;
abcd.push_back(a);
@ -446,13 +364,13 @@ void test_ordered()
printf("==== %s ====\n\n", __PRETTY_FUNCTION__);
ezMiniSAT ez;
int a = ez.literal("a");
int b = ez.literal("b");
int c = ez.literal("c");
int a = ez.frozen_literal("a");
int b = ez.frozen_literal("b");
int c = ez.frozen_literal("c");
int x = ez.literal("x");
int y = ez.literal("y");
int z = ez.literal("z");
int x = ez.frozen_literal("x");
int y = ez.frozen_literal("y");
int z = ez.frozen_literal("z");
std::vector<int> abc;
abc.push_back(a);
@ -512,7 +430,6 @@ void test_ordered()
int main()
{
test_simple();
test_basic_operators();
test_xorshift32();
test_arith();
test_onehot();

View file

@ -0,0 +1,20 @@
--- SolverTypes.h
+++ SolverTypes.h
@@ -52,7 +52,7 @@ struct Lit {
int x;
// Use this as a constructor:
- friend Lit mkLit(Var var, bool sign = false);
+ friend Lit mkLit(Var var, bool sign);
bool operator == (Lit p) const { return x == p.x; }
bool operator != (Lit p) const { return x != p.x; }
@@ -60,7 +60,7 @@ struct Lit {
};
-inline Lit mkLit (Var var, bool sign) { Lit p; p.x = var + var + (int)sign; return p; }
+inline Lit mkLit (Var var, bool sign = false) { Lit p; p.x = var + var + (int)sign; return p; }
inline Lit operator ~(Lit p) { Lit q; q.x = p.x ^ 1; return q; }
inline Lit operator ^(Lit p, bool b) { Lit q; q.x = p.x ^ (unsigned int)b; return q; }
inline bool sign (Lit p) { return p.x & 1; }

View file

@ -0,0 +1,38 @@
--- ParseUtils.h
+++ ParseUtils.h
@@ -24,8 +24,6 @@ OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWA
#include <stdlib.h>
#include <stdio.h>
-#include <zlib.h>
-
#include "XAlloc.h"
namespace Minisat {
@@ -36,24 +34,16 @@ namespace Minisat {
class StreamBuffer {
- gzFile in;
unsigned char* buf;
int pos;
int size;
enum { buffer_size = 64*1024 };
- void assureLookahead() {
- if (pos >= size) {
- pos = 0;
- size = gzread(in, buf, buffer_size); } }
+ virtual void assureLookahead() = 0;
public:
- explicit StreamBuffer(gzFile i) : in(i), pos(0), size(0){
- buf = (unsigned char*)xrealloc(NULL, buffer_size);
- assureLookahead();
- }
- ~StreamBuffer() { free(buf); }
+ virtual ~StreamBuffer() { }
int operator * () const { return (pos >= size) ? EOF : buf[pos]; }
void operator ++ () { pos++; assureLookahead(); }

17
libs/minisat/00_UPDATE.sh Normal file
View file

@ -0,0 +1,17 @@
#!/bin/bash
rm -f LICENSE *.cc *.h
git clone --depth 1 https://github.com/niklasso/minisat minisat_upstream
rm minisat_upstream/minisat/*/Main.cc
mv minisat_upstream/LICENSE minisat_upstream/minisat/*/*.{h,cc} .
rm -rf minisat_upstream
sed -i -e 's,^#include *"minisat/[^/]\+/\?,#include ",' *.cc *.h
sed -i -e 's/Minisat::memUsedPeak()/Minisat::memUsedPeak(bool)/' System.cc
sed -i -e 's/PRI[iu]64/ & /' Options.h Solver.cc
sed -i -e '1 i #define __STDC_LIMIT_MACROS' *.cc
sed -i -e '1 i #define __STDC_FORMAT_MACROS' *.cc
patch -p0 < 00_PATCH_mkLit_default_arg.patch
patch -p0 < 00_PATCH_remove_zlib.patch

84
libs/minisat/Alg.h Normal file
View file

@ -0,0 +1,84 @@
/*******************************************************************************************[Alg.h]
Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
Copyright (c) 2007-2010, Niklas Sorensson
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
**************************************************************************************************/
#ifndef Minisat_Alg_h
#define Minisat_Alg_h
#include "Vec.h"
namespace Minisat {
//=================================================================================================
// Useful functions on vector-like types:
//=================================================================================================
// Removing and searching for elements:
//
template<class V, class T>
static inline void remove(V& ts, const T& t)
{
int j = 0;
for (; j < (int)ts.size() && ts[j] != t; j++);
assert(j < (int)ts.size());
for (; j < (int)ts.size()-1; j++) ts[j] = ts[j+1];
ts.pop();
}
template<class V, class T>
static inline bool find(V& ts, const T& t)
{
int j = 0;
for (; j < (int)ts.size() && ts[j] != t; j++);
return j < (int)ts.size();
}
//=================================================================================================
// Copying vectors with support for nested vector types:
//
// Base case:
template<class T>
static inline void copy(const T& from, T& to)
{
to = from;
}
// Recursive case:
template<class T>
static inline void copy(const vec<T>& from, vec<T>& to, bool append = false)
{
if (!append)
to.clear();
for (int i = 0; i < from.size(); i++){
to.push();
copy(from[i], to.last());
}
}
template<class T>
static inline void append(const vec<T>& from, vec<T>& to){ copy(from, to, true); }
//=================================================================================================
}
#endif

131
libs/minisat/Alloc.h Normal file
View file

@ -0,0 +1,131 @@
/*****************************************************************************************[Alloc.h]
Copyright (c) 2008-2010, Niklas Sorensson
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
**************************************************************************************************/
#ifndef Minisat_Alloc_h
#define Minisat_Alloc_h
#include "XAlloc.h"
#include "Vec.h"
namespace Minisat {
//=================================================================================================
// Simple Region-based memory allocator:
template<class T>
class RegionAllocator
{
T* memory;
uint32_t sz;
uint32_t cap;
uint32_t wasted_;
void capacity(uint32_t min_cap);
public:
// TODO: make this a class for better type-checking?
typedef uint32_t Ref;
enum { Ref_Undef = UINT32_MAX };
enum { Unit_Size = sizeof(T) };
explicit RegionAllocator(uint32_t start_cap = 1024*1024) : memory(NULL), sz(0), cap(0), wasted_(0){ capacity(start_cap); }
~RegionAllocator()
{
if (memory != NULL)
::free(memory);
}
uint32_t size () const { return sz; }
uint32_t wasted () const { return wasted_; }
Ref alloc (int size);
void free (int size) { wasted_ += size; }
// Deref, Load Effective Address (LEA), Inverse of LEA (AEL):
T& operator[](Ref r) { assert(r < sz); return memory[r]; }
const T& operator[](Ref r) const { assert(r < sz); return memory[r]; }
T* lea (Ref r) { assert(r < sz); return &memory[r]; }
const T* lea (Ref r) const { assert(r < sz); return &memory[r]; }
Ref ael (const T* t) { assert((void*)t >= (void*)&memory[0] && (void*)t < (void*)&memory[sz-1]);
return (Ref)(t - &memory[0]); }
void moveTo(RegionAllocator& to) {
if (to.memory != NULL) ::free(to.memory);
to.memory = memory;
to.sz = sz;
to.cap = cap;
to.wasted_ = wasted_;
memory = NULL;
sz = cap = wasted_ = 0;
}
};
template<class T>
void RegionAllocator<T>::capacity(uint32_t min_cap)
{
if (cap >= min_cap) return;
uint32_t prev_cap = cap;
while (cap < min_cap){
// NOTE: Multiply by a factor (13/8) without causing overflow, then add 2 and make the
// result even by clearing the least significant bit. The resulting sequence of capacities
// is carefully chosen to hit a maximum capacity that is close to the '2^32-1' limit when
// using 'uint32_t' as indices so that as much as possible of this space can be used.
uint32_t delta = ((cap >> 1) + (cap >> 3) + 2) & ~1;
cap += delta;
if (cap <= prev_cap)
throw OutOfMemoryException();
}
// printf(" .. (%p) cap = %u\n", this, cap);
assert(cap > 0);
memory = (T*)xrealloc(memory, sizeof(T)*cap);
}
template<class T>
typename RegionAllocator<T>::Ref
RegionAllocator<T>::alloc(int size)
{
// printf("ALLOC called (this = %p, size = %d)\n", this, size); fflush(stdout);
assert(size > 0);
capacity(sz + size);
uint32_t prev_sz = sz;
sz += size;
// Handle overflow:
if (sz < prev_sz)
throw OutOfMemoryException();
return prev_sz;
}
//=================================================================================================
}
#endif

87
libs/minisat/Dimacs.h Normal file
View file

@ -0,0 +1,87 @@
/****************************************************************************************[Dimacs.h]
Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
Copyright (c) 2007-2010, Niklas Sorensson
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
**************************************************************************************************/
#ifndef Minisat_Dimacs_h
#define Minisat_Dimacs_h
#include <stdio.h>
#include "ParseUtils.h"
#include "SolverTypes.h"
namespace Minisat {
//=================================================================================================
// DIMACS Parser:
template<class B, class Solver>
static void readClause(B& in, Solver& S, vec<Lit>& lits) {
int parsed_lit, var;
lits.clear();
for (;;){
parsed_lit = parseInt(in);
if (parsed_lit == 0) break;
var = abs(parsed_lit)-1;
while (var >= S.nVars()) S.newVar();
lits.push( (parsed_lit > 0) ? mkLit(var) : ~mkLit(var) );
}
}
template<class B, class Solver>
static void parse_DIMACS_main(B& in, Solver& S, bool strictp = false) {
vec<Lit> lits;
int vars = 0;
int clauses = 0;
int cnt = 0;
for (;;){
skipWhitespace(in);
if (*in == EOF) break;
else if (*in == 'p'){
if (eagerMatch(in, "p cnf")){
vars = parseInt(in);
clauses = parseInt(in);
// SATRACE'06 hack
// if (clauses > 4000000)
// S.eliminate(true);
}else{
printf("PARSE ERROR! Unexpected char: %c\n", *in), exit(3);
}
} else if (*in == 'c' || *in == 'p')
skipLine(in);
else{
cnt++;
readClause(in, S, lits);
S.addClause_(lits); }
}
if (strictp && cnt != clauses)
printf("PARSE ERROR! DIMACS header mismatch: wrong number of clauses\n");
}
// Inserts problem into solver.
//
template<class Solver>
static void parse_DIMACS(gzFile input_stream, Solver& S, bool strictp = false) {
StreamBuffer in(input_stream);
parse_DIMACS_main(in, S, strictp); }
//=================================================================================================
}
#endif

168
libs/minisat/Heap.h Normal file
View file

@ -0,0 +1,168 @@
/******************************************************************************************[Heap.h]
Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
Copyright (c) 2007-2010, Niklas Sorensson
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
**************************************************************************************************/
#ifndef Minisat_Heap_h
#define Minisat_Heap_h
#include "Vec.h"
#include "IntMap.h"
namespace Minisat {
//=================================================================================================
// A heap implementation with support for decrease/increase key.
template<class K, class Comp, class MkIndex = MkIndexDefault<K> >
class Heap {
vec<K> heap; // Heap of Keys
IntMap<K,int,MkIndex> indices; // Each Key's position (index) in the Heap
Comp lt; // The heap is a minimum-heap with respect to this comparator
// Index "traversal" functions
static inline int left (int i) { return i*2+1; }
static inline int right (int i) { return (i+1)*2; }
static inline int parent(int i) { return (i-1) >> 1; }
void percolateUp(int i)
{
K x = heap[i];
int p = parent(i);
while (i != 0 && lt(x, heap[p])){
heap[i] = heap[p];
indices[heap[p]] = i;
i = p;
p = parent(p);
}
heap [i] = x;
indices[x] = i;
}
void percolateDown(int i)
{
K x = heap[i];
while (left(i) < heap.size()){
int child = right(i) < heap.size() && lt(heap[right(i)], heap[left(i)]) ? right(i) : left(i);
if (!lt(heap[child], x)) break;
heap[i] = heap[child];
indices[heap[i]] = i;
i = child;
}
heap [i] = x;
indices[x] = i;
}
public:
Heap(const Comp& c, MkIndex _index = MkIndex()) : indices(_index), lt(c) {}
int size () const { return heap.size(); }
bool empty () const { return heap.size() == 0; }
bool inHeap (K k) const { return indices.has(k) && indices[k] >= 0; }
int operator[](int index) const { assert(index < heap.size()); return heap[index]; }
void decrease (K k) { assert(inHeap(k)); percolateUp (indices[k]); }
void increase (K k) { assert(inHeap(k)); percolateDown(indices[k]); }
// Safe variant of insert/decrease/increase:
void update(K k)
{
if (!inHeap(k))
insert(k);
else {
percolateUp(indices[k]);
percolateDown(indices[k]); }
}
void insert(K k)
{
indices.reserve(k, -1);
assert(!inHeap(k));
indices[k] = heap.size();
heap.push(k);
percolateUp(indices[k]);
}
void remove(K k)
{
assert(inHeap(k));
int k_pos = indices[k];
indices[k] = -1;
if (k_pos < heap.size()-1){
heap[k_pos] = heap.last();
indices[heap[k_pos]] = k_pos;
heap.pop();
percolateDown(k_pos);
}else
heap.pop();
}
K removeMin()
{
K x = heap[0];
heap[0] = heap.last();
indices[heap[0]] = 0;
indices[x] = -1;
heap.pop();
if (heap.size() > 1) percolateDown(0);
return x;
}
// Rebuild the heap from scratch, using the elements in 'ns':
void build(const vec<K>& ns) {
for (int i = 0; i < heap.size(); i++)
indices[heap[i]] = -1;
heap.clear();
for (int i = 0; i < ns.size(); i++){
// TODO: this should probably call reserve instead of relying on it being reserved already.
assert(indices.has(ns[i]));
indices[ns[i]] = i;
heap.push(ns[i]); }
for (int i = heap.size() / 2 - 1; i >= 0; i--)
percolateDown(i);
}
void clear(bool dispose = false)
{
// TODO: shouldn't the 'indices' map also be dispose-cleared?
for (int i = 0; i < heap.size(); i++)
indices[heap[i]] = -1;
heap.clear(dispose);
}
};
//=================================================================================================
}
#endif

106
libs/minisat/IntMap.h Normal file
View file

@ -0,0 +1,106 @@
/****************************************************************************************[IntMap.h]
Copyright (c) 2011, Niklas Sorensson
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
**************************************************************************************************/
#ifndef Minisat_IntMap_h
#define Minisat_IntMap_h
#include "Vec.h"
namespace Minisat {
template<class T> struct MkIndexDefault {
typename vec<T>::Size operator()(T t) const { return (typename vec<T>::Size)t; }
};
template<class K, class V, class MkIndex = MkIndexDefault<K> >
class IntMap {
vec<V> map;
MkIndex index;
public:
explicit IntMap(MkIndex _index = MkIndex()) : index(_index){}
bool has (K k) const { return index(k) < map.size(); }
const V& operator[](K k) const { assert(has(k)); return map[index(k)]; }
V& operator[](K k) { assert(has(k)); return map[index(k)]; }
const V* begin () const { return &map[0]; }
const V* end () const { return &map[map.size()]; }
V* begin () { return &map[0]; }
V* end () { return &map[map.size()]; }
void reserve(K key, V pad) { map.growTo(index(key)+1, pad); }
void reserve(K key) { map.growTo(index(key)+1); }
void insert (K key, V val, V pad){ reserve(key, pad); operator[](key) = val; }
void insert (K key, V val) { reserve(key); operator[](key) = val; }
void clear (bool dispose = false) { map.clear(dispose); }
void moveTo (IntMap& to) { map.moveTo(to.map); to.index = index; }
void copyTo (IntMap& to) const { map.copyTo(to.map); to.index = index; }
};
template<class K, class MkIndex = MkIndexDefault<K> >
class IntSet
{
IntMap<K, char, MkIndex> in_set;
vec<K> xs;
public:
// Size operations:
int size (void) const { return xs.size(); }
void clear (bool free = false){
if (free)
in_set.clear(true);
else
for (int i = 0; i < xs.size(); i++)
in_set[xs[i]] = 0;
xs.clear(free);
}
// Allow inspecting the internal vector:
const vec<K>&
toVec () const { return xs; }
// Vector interface:
K operator [] (int index) const { return xs[index]; }
void insert (K k) { in_set.reserve(k, 0); if (!in_set[k]) { in_set[k] = 1; xs.push(k); } }
bool has (K k) { in_set.reserve(k, 0); return in_set[k]; }
};
#if 0
template<class K, class V, V nil, class MkIndex = MkIndexDefault<K> >
class IntMapNil {
vec<V> map;
V nil;
public:
IntMap(){}
void reserve(K);
V& find (K);
const V& operator[](K k) const;
};
#endif
//=================================================================================================
} // namespace Minisat
#endif

42
libs/minisat/IntTypes.h Normal file
View file

@ -0,0 +1,42 @@
/**************************************************************************************[IntTypes.h]
Copyright (c) 2009-2010, Niklas Sorensson
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
**************************************************************************************************/
#ifndef Minisat_IntTypes_h
#define Minisat_IntTypes_h
#ifdef __sun
// Not sure if there are newer versions that support C99 headers. The
// needed features are implemented in the headers below though:
# include <sys/int_types.h>
# include <sys/int_fmtio.h>
# include <sys/int_limits.h>
#else
# include <stdint.h>
# include <inttypes.h>
#endif
#include <limits.h>
//=================================================================================================
#endif

21
libs/minisat/LICENSE Normal file
View file

@ -0,0 +1,21 @@
MiniSat -- Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
Copyright (c) 2007-2010 Niklas Sorensson
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

193
libs/minisat/Map.h Normal file
View file

@ -0,0 +1,193 @@
/*******************************************************************************************[Map.h]
Copyright (c) 2006-2010, Niklas Sorensson
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
**************************************************************************************************/
#ifndef Minisat_Map_h
#define Minisat_Map_h
#include "IntTypes.h"
#include "Vec.h"
namespace Minisat {
//=================================================================================================
// Default hash/equals functions
//
template<class K> struct Hash { uint32_t operator()(const K& k) const { return hash(k); } };
template<class K> struct Equal { bool operator()(const K& k1, const K& k2) const { return k1 == k2; } };
template<class K> struct DeepHash { uint32_t operator()(const K* k) const { return hash(*k); } };
template<class K> struct DeepEqual { bool operator()(const K* k1, const K* k2) const { return *k1 == *k2; } };
static inline uint32_t hash(uint32_t x){ return x; }
static inline uint32_t hash(uint64_t x){ return (uint32_t)x; }
static inline uint32_t hash(int32_t x) { return (uint32_t)x; }
static inline uint32_t hash(int64_t x) { return (uint32_t)x; }
//=================================================================================================
// Some primes
//
static const int nprimes = 25;
static const int primes [nprimes] = { 31, 73, 151, 313, 643, 1291, 2593, 5233, 10501, 21013, 42073, 84181, 168451, 337219, 674701, 1349473, 2699299, 5398891, 10798093, 21596719, 43193641, 86387383, 172775299, 345550609, 691101253 };
//=================================================================================================
// Hash table implementation of Maps
//
template<class K, class D, class H = Hash<K>, class E = Equal<K> >
class Map {
public:
struct Pair { K key; D data; };
private:
H hash;
E equals;
vec<Pair>* table;
int cap;
int size;
// Don't allow copying (error prone):
Map<K,D,H,E>& operator = (Map<K,D,H,E>& other);
Map (Map<K,D,H,E>& other);
bool checkCap(int new_size) const { return new_size > cap; }
int32_t index (const K& k) const { return hash(k) % cap; }
void _insert (const K& k, const D& d) {
vec<Pair>& ps = table[index(k)];
ps.push(); ps.last().key = k; ps.last().data = d; }
void rehash () {
const vec<Pair>* old = table;
int old_cap = cap;
int newsize = primes[0];
for (int i = 1; newsize <= cap && i < nprimes; i++)
newsize = primes[i];
table = new vec<Pair>[newsize];
cap = newsize;
for (int i = 0; i < old_cap; i++){
for (int j = 0; j < old[i].size(); j++){
_insert(old[i][j].key, old[i][j].data); }}
delete [] old;
// printf(" --- rehashing, old-cap=%d, new-cap=%d\n", cap, newsize);
}
public:
Map () : table(NULL), cap(0), size(0) {}
Map (const H& h, const E& e) : hash(h), equals(e), table(NULL), cap(0), size(0){}
~Map () { delete [] table; }
// PRECONDITION: the key must already exist in the map.
const D& operator [] (const K& k) const
{
assert(size != 0);
const D* res = NULL;
const vec<Pair>& ps = table[index(k)];
for (int i = 0; i < ps.size(); i++)
if (equals(ps[i].key, k))
res = &ps[i].data;
assert(res != NULL);
return *res;
}
// PRECONDITION: the key must already exist in the map.
D& operator [] (const K& k)
{
assert(size != 0);
D* res = NULL;
vec<Pair>& ps = table[index(k)];
for (int i = 0; i < ps.size(); i++)
if (equals(ps[i].key, k))
res = &ps[i].data;
assert(res != NULL);
return *res;
}
// PRECONDITION: the key must *NOT* exist in the map.
void insert (const K& k, const D& d) { if (checkCap(size+1)) rehash(); _insert(k, d); size++; }
bool peek (const K& k, D& d) const {
if (size == 0) return false;
const vec<Pair>& ps = table[index(k)];
for (int i = 0; i < ps.size(); i++)
if (equals(ps[i].key, k)){
d = ps[i].data;
return true; }
return false;
}
bool has (const K& k) const {
if (size == 0) return false;
const vec<Pair>& ps = table[index(k)];
for (int i = 0; i < ps.size(); i++)
if (equals(ps[i].key, k))
return true;
return false;
}
// PRECONDITION: the key must exist in the map.
void remove(const K& k) {
assert(table != NULL);
vec<Pair>& ps = table[index(k)];
int j = 0;
for (; j < ps.size() && !equals(ps[j].key, k); j++);
assert(j < ps.size());
ps[j] = ps.last();
ps.pop();
size--;
}
void clear () {
cap = size = 0;
delete [] table;
table = NULL;
}
int elems() const { return size; }
int bucket_count() const { return cap; }
// NOTE: the hash and equality objects are not moved by this method:
void moveTo(Map& other){
delete [] other.table;
other.table = table;
other.cap = cap;
other.size = size;
table = NULL;
size = cap = 0;
}
// NOTE: given a bit more time, I could make a more C++-style iterator out of this:
const vec<Pair>& bucket(int i) const { return table[i]; }
};
//=================================================================================================
}
#endif

94
libs/minisat/Options.cc Normal file
View file

@ -0,0 +1,94 @@
#define __STDC_FORMAT_MACROS
#define __STDC_LIMIT_MACROS
/**************************************************************************************[Options.cc]
Copyright (c) 2008-2010, Niklas Sorensson
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
**************************************************************************************************/
#include "Sort.h"
#include "Options.h"
#include "ParseUtils.h"
using namespace Minisat;
void Minisat::parseOptions(int& argc, char** argv, bool strict)
{
int i, j;
for (i = j = 1; i < argc; i++){
const char* str = argv[i];
if (match(str, "--") && match(str, Option::getHelpPrefixString()) && match(str, "help")){
if (*str == '\0')
printUsageAndExit(argc, argv);
else if (match(str, "-verb"))
printUsageAndExit(argc, argv, true);
} else {
bool parsed_ok = false;
for (int k = 0; !parsed_ok && k < Option::getOptionList().size(); k++){
parsed_ok = Option::getOptionList()[k]->parse(argv[i]);
// fprintf(stderr, "checking %d: %s against flag <%s> (%s)\n", i, argv[i], Option::getOptionList()[k]->name, parsed_ok ? "ok" : "skip");
}
if (!parsed_ok){
if (strict && match(argv[i], "-"))
fprintf(stderr, "ERROR! Unknown flag \"%s\". Use '--%shelp' for help.\n", argv[i], Option::getHelpPrefixString()), exit(1);
else
argv[j++] = argv[i];
}
}
}
argc -= (i - j);
}
void Minisat::setUsageHelp (const char* str){ Option::getUsageString() = str; }
void Minisat::setHelpPrefixStr (const char* str){ Option::getHelpPrefixString() = str; }
void Minisat::printUsageAndExit (int /*argc*/, char** argv, bool verbose)
{
const char* usage = Option::getUsageString();
if (usage != NULL)
fprintf(stderr, usage, argv[0]);
sort(Option::getOptionList(), Option::OptionLt());
const char* prev_cat = NULL;
const char* prev_type = NULL;
for (int i = 0; i < Option::getOptionList().size(); i++){
const char* cat = Option::getOptionList()[i]->category;
const char* type = Option::getOptionList()[i]->type_name;
if (cat != prev_cat)
fprintf(stderr, "\n%s OPTIONS:\n\n", cat);
else if (type != prev_type)
fprintf(stderr, "\n");
Option::getOptionList()[i]->help(verbose);
prev_cat = Option::getOptionList()[i]->category;
prev_type = Option::getOptionList()[i]->type_name;
}
fprintf(stderr, "\nHELP OPTIONS:\n\n");
fprintf(stderr, " --%shelp Print help message.\n", Option::getHelpPrefixString());
fprintf(stderr, " --%shelp-verb Print verbose help message.\n", Option::getHelpPrefixString());
fprintf(stderr, "\n");
exit(0);
}

386
libs/minisat/Options.h Normal file
View file

@ -0,0 +1,386 @@
/***************************************************************************************[Options.h]
Copyright (c) 2008-2010, Niklas Sorensson
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
**************************************************************************************************/
#ifndef Minisat_Options_h
#define Minisat_Options_h
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include "IntTypes.h"
#include "Vec.h"
#include "ParseUtils.h"
namespace Minisat {
//==================================================================================================
// Top-level option parse/help functions:
extern void parseOptions (int& argc, char** argv, bool strict = false);
extern void printUsageAndExit(int argc, char** argv, bool verbose = false);
extern void setUsageHelp (const char* str);
extern void setHelpPrefixStr (const char* str);
//==================================================================================================
// Options is an abstract class that gives the interface for all types options:
class Option
{
protected:
const char* name;
const char* description;
const char* category;
const char* type_name;
static vec<Option*>& getOptionList () { static vec<Option*> options; return options; }
static const char*& getUsageString() { static const char* usage_str; return usage_str; }
static const char*& getHelpPrefixString() { static const char* help_prefix_str = ""; return help_prefix_str; }
struct OptionLt {
bool operator()(const Option* x, const Option* y) {
int test1 = strcmp(x->category, y->category);
return test1 < 0 || (test1 == 0 && strcmp(x->type_name, y->type_name) < 0);
}
};
Option(const char* name_,
const char* desc_,
const char* cate_,
const char* type_) :
name (name_)
, description(desc_)
, category (cate_)
, type_name (type_)
{
getOptionList().push(this);
}
public:
virtual ~Option() {}
virtual bool parse (const char* str) = 0;
virtual void help (bool verbose = false) = 0;
friend void parseOptions (int& argc, char** argv, bool strict);
friend void printUsageAndExit (int argc, char** argv, bool verbose);
friend void setUsageHelp (const char* str);
friend void setHelpPrefixStr (const char* str);
};
//==================================================================================================
// Range classes with specialization for floating types:
struct IntRange {
int begin;
int end;
IntRange(int b, int e) : begin(b), end(e) {}
};
struct Int64Range {
int64_t begin;
int64_t end;
Int64Range(int64_t b, int64_t e) : begin(b), end(e) {}
};
struct DoubleRange {
double begin;
double end;
bool begin_inclusive;
bool end_inclusive;
DoubleRange(double b, bool binc, double e, bool einc) : begin(b), end(e), begin_inclusive(binc), end_inclusive(einc) {}
};
//==================================================================================================
// Double options:
class DoubleOption : public Option
{
protected:
DoubleRange range;
double value;
public:
DoubleOption(const char* c, const char* n, const char* d, double def = double(), DoubleRange r = DoubleRange(-HUGE_VAL, false, HUGE_VAL, false))
: Option(n, d, c, "<double>"), range(r), value(def) {
// FIXME: set LC_NUMERIC to "C" to make sure that strtof/strtod parses decimal point correctly.
}
operator double (void) const { return value; }
operator double& (void) { return value; }
DoubleOption& operator=(double x) { value = x; return *this; }
virtual bool parse(const char* str){
const char* span = str;
if (!match(span, "-") || !match(span, name) || !match(span, "="))
return false;
char* end;
double tmp = strtod(span, &end);
if (end == NULL)
return false;
else if (tmp >= range.end && (!range.end_inclusive || tmp != range.end)){
fprintf(stderr, "ERROR! value <%s> is too large for option \"%s\".\n", span, name);
exit(1);
}else if (tmp <= range.begin && (!range.begin_inclusive || tmp != range.begin)){
fprintf(stderr, "ERROR! value <%s> is too small for option \"%s\".\n", span, name);
exit(1); }
value = tmp;
// fprintf(stderr, "READ VALUE: %g\n", value);
return true;
}
virtual void help (bool verbose = false){
fprintf(stderr, " -%-12s = %-8s %c%4.2g .. %4.2g%c (default: %g)\n",
name, type_name,
range.begin_inclusive ? '[' : '(',
range.begin,
range.end,
range.end_inclusive ? ']' : ')',
value);
if (verbose){
fprintf(stderr, "\n %s\n", description);
fprintf(stderr, "\n");
}
}
};
//==================================================================================================
// Int options:
class IntOption : public Option
{
protected:
IntRange range;
int32_t value;
public:
IntOption(const char* c, const char* n, const char* d, int32_t def = int32_t(), IntRange r = IntRange(INT32_MIN, INT32_MAX))
: Option(n, d, c, "<int32>"), range(r), value(def) {}
operator int32_t (void) const { return value; }
operator int32_t& (void) { return value; }
IntOption& operator= (int32_t x) { value = x; return *this; }
virtual bool parse(const char* str){
const char* span = str;
if (!match(span, "-") || !match(span, name) || !match(span, "="))
return false;
char* end;
int32_t tmp = strtol(span, &end, 10);
if (end == NULL)
return false;
else if (tmp > range.end){
fprintf(stderr, "ERROR! value <%s> is too large for option \"%s\".\n", span, name);
exit(1);
}else if (tmp < range.begin){
fprintf(stderr, "ERROR! value <%s> is too small for option \"%s\".\n", span, name);
exit(1); }
value = tmp;
return true;
}
virtual void help (bool verbose = false){
fprintf(stderr, " -%-12s = %-8s [", name, type_name);
if (range.begin == INT32_MIN)
fprintf(stderr, "imin");
else
fprintf(stderr, "%4d", range.begin);
fprintf(stderr, " .. ");
if (range.end == INT32_MAX)
fprintf(stderr, "imax");
else
fprintf(stderr, "%4d", range.end);
fprintf(stderr, "] (default: %d)\n", value);
if (verbose){
fprintf(stderr, "\n %s\n", description);
fprintf(stderr, "\n");
}
}
};
// Leave this out for visual C++ until Microsoft implements C99 and gets support for strtoll.
#ifndef _MSC_VER
class Int64Option : public Option
{
protected:
Int64Range range;
int64_t value;
public:
Int64Option(const char* c, const char* n, const char* d, int64_t def = int64_t(), Int64Range r = Int64Range(INT64_MIN, INT64_MAX))
: Option(n, d, c, "<int64>"), range(r), value(def) {}
operator int64_t (void) const { return value; }
operator int64_t& (void) { return value; }
Int64Option& operator= (int64_t x) { value = x; return *this; }
virtual bool parse(const char* str){
const char* span = str;
if (!match(span, "-") || !match(span, name) || !match(span, "="))
return false;
char* end;
int64_t tmp = strtoll(span, &end, 10);
if (end == NULL)
return false;
else if (tmp > range.end){
fprintf(stderr, "ERROR! value <%s> is too large for option \"%s\".\n", span, name);
exit(1);
}else if (tmp < range.begin){
fprintf(stderr, "ERROR! value <%s> is too small for option \"%s\".\n", span, name);
exit(1); }
value = tmp;
return true;
}
virtual void help (bool verbose = false){
fprintf(stderr, " -%-12s = %-8s [", name, type_name);
if (range.begin == INT64_MIN)
fprintf(stderr, "imin");
else
fprintf(stderr, "%4" PRIi64 , range.begin);
fprintf(stderr, " .. ");
if (range.end == INT64_MAX)
fprintf(stderr, "imax");
else
fprintf(stderr, "%4" PRIi64 , range.end);
fprintf(stderr, "] (default: %" PRIi64 ")\n", value);
if (verbose){
fprintf(stderr, "\n %s\n", description);
fprintf(stderr, "\n");
}
}
};
#endif
//==================================================================================================
// String option:
class StringOption : public Option
{
const char* value;
public:
StringOption(const char* c, const char* n, const char* d, const char* def = NULL)
: Option(n, d, c, "<string>"), value(def) {}
operator const char* (void) const { return value; }
operator const char*& (void) { return value; }
StringOption& operator= (const char* x) { value = x; return *this; }
virtual bool parse(const char* str){
const char* span = str;
if (!match(span, "-") || !match(span, name) || !match(span, "="))
return false;
value = span;
return true;
}
virtual void help (bool verbose = false){
fprintf(stderr, " -%-10s = %8s\n", name, type_name);
if (verbose){
fprintf(stderr, "\n %s\n", description);
fprintf(stderr, "\n");
}
}
};
//==================================================================================================
// Bool option:
class BoolOption : public Option
{
bool value;
public:
BoolOption(const char* c, const char* n, const char* d, bool v)
: Option(n, d, c, "<bool>"), value(v) {}
operator bool (void) const { return value; }
operator bool& (void) { return value; }
BoolOption& operator=(bool b) { value = b; return *this; }
virtual bool parse(const char* str){
const char* span = str;
if (match(span, "-")){
bool b = !match(span, "no-");
if (strcmp(span, name) == 0){
value = b;
return true; }
}
return false;
}
virtual void help (bool verbose = false){
fprintf(stderr, " -%s, -no-%s", name, name);
for (uint32_t i = 0; i < 32 - strlen(name)*2; i++)
fprintf(stderr, " ");
fprintf(stderr, " ");
fprintf(stderr, "(default: %s)\n", value ? "on" : "off");
if (verbose){
fprintf(stderr, "\n %s\n", description);
fprintf(stderr, "\n");
}
}
};
//=================================================================================================
}
#endif

119
libs/minisat/ParseUtils.h Normal file
View file

@ -0,0 +1,119 @@
/************************************************************************************[ParseUtils.h]
Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
Copyright (c) 2007-2010, Niklas Sorensson
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
**************************************************************************************************/
#ifndef Minisat_ParseUtils_h
#define Minisat_ParseUtils_h
#include <stdlib.h>
#include <stdio.h>
#include "XAlloc.h"
namespace Minisat {
//-------------------------------------------------------------------------------------------------
// A simple buffered character stream class:
class StreamBuffer {
unsigned char* buf;
int pos;
int size;
enum { buffer_size = 64*1024 };
virtual void assureLookahead() = 0;
public:
virtual ~StreamBuffer() { }
int operator * () const { return (pos >= size) ? EOF : buf[pos]; }
void operator ++ () { pos++; assureLookahead(); }
int position () const { return pos; }
};
//-------------------------------------------------------------------------------------------------
// End-of-file detection functions for StreamBuffer and char*:
static inline bool isEof(StreamBuffer& in) { return *in == EOF; }
static inline bool isEof(const char* in) { return *in == '\0'; }
//-------------------------------------------------------------------------------------------------
// Generic parse functions parametrized over the input-stream type.
template<class B>
static void skipWhitespace(B& in) {
while ((*in >= 9 && *in <= 13) || *in == 32)
++in; }
template<class B>
static void skipLine(B& in) {
for (;;){
if (isEof(in)) return;
if (*in == '\n') { ++in; return; }
++in; } }
template<class B>
static int parseInt(B& in) {
int val = 0;
bool neg = false;
skipWhitespace(in);
if (*in == '-') neg = true, ++in;
else if (*in == '+') ++in;
if (*in < '0' || *in > '9') fprintf(stderr, "PARSE ERROR! Unexpected char: %c\n", *in), exit(3);
while (*in >= '0' && *in <= '9')
val = val*10 + (*in - '0'),
++in;
return neg ? -val : val; }
// String matching: in case of a match the input iterator will be advanced the corresponding
// number of characters.
template<class B>
static bool match(B& in, const char* str) {
int i;
for (i = 0; str[i] != '\0'; i++)
if (in[i] != str[i])
return false;
in += i;
return true;
}
// String matching: consumes characters eagerly, but does not require random access iterator.
template<class B>
static bool eagerMatch(B& in, const char* str) {
for (; *str != '\0'; ++str, ++in)
if (*str != *in)
return false;
return true; }
//=================================================================================================
}
#endif

69
libs/minisat/Queue.h Normal file
View file

@ -0,0 +1,69 @@
/*****************************************************************************************[Queue.h]
Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
Copyright (c) 2007-2010, Niklas Sorensson
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
**************************************************************************************************/
#ifndef Minisat_Queue_h
#define Minisat_Queue_h
#include "Vec.h"
namespace Minisat {
//=================================================================================================
template<class T>
class Queue {
vec<T> buf;
int first;
int end;
public:
typedef T Key;
Queue() : buf(1), first(0), end(0) {}
void clear (bool dealloc = false) { buf.clear(dealloc); buf.growTo(1); first = end = 0; }
int size () const { return (end >= first) ? end - first : end - first + buf.size(); }
const T& operator [] (int index) const { assert(index >= 0); assert(index < size()); return buf[(first + index) % buf.size()]; }
T& operator [] (int index) { assert(index >= 0); assert(index < size()); return buf[(first + index) % buf.size()]; }
T peek () const { assert(first != end); return buf[first]; }
void pop () { assert(first != end); first++; if (first == buf.size()) first = 0; }
void insert(T elem) { // INVARIANT: buf[end] is always unused
buf[end++] = elem;
if (end == buf.size()) end = 0;
if (first == end){ // Resize:
vec<T> tmp((buf.size()*3 + 1) >> 1);
//**/printf("queue alloc: %d elems (%.1f MB)\n", tmp.size(), tmp.size() * sizeof(T) / 1000000.0);
int i = 0;
for (int j = first; j < buf.size(); j++) tmp[i++] = buf[j];
for (int j = 0 ; j < end ; j++) tmp[i++] = buf[j];
first = 0;
end = buf.size();
tmp.moveTo(buf);
}
}
};
//=================================================================================================
}
#endif

67
libs/minisat/Rnd.h Normal file
View file

@ -0,0 +1,67 @@
/*******************************************************************************************[Rnd.h]
Copyright (c) 2012, Niklas Sorensson
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
**************************************************************************************************/
#ifndef Minisat_Rnd_h
#define Minisat_Rnd_h
#include "Vec.h"
namespace Minisat {
// Generate a random double:
static inline double drand(double& seed)
{
seed *= 1389796;
int q = (int)(seed / 2147483647);
seed -= (double)q * 2147483647;
return seed / 2147483647;
}
// Generate a random integer:
static inline int irand(double& seed, int size) { return (int)(drand(seed) * size); }
// Randomly shuffle the contents of a vector:
template<class T>
static void randomShuffle(double& seed, vec<T>& xs)
{
for (int i = 0; i < xs.size(); i++){
int pick = i + irand(seed, xs.size() - i);
T tmp = xs[i];
xs[i] = xs[pick];
xs[pick] = tmp;
}
}
// Randomly shuffle a vector of a vector (ugly)
template<class T>
static void randomShuffle(double& seed, vec<vec<T> >& xs)
{
for (int i = 0; i < xs.size(); i++){
int pick = i + irand(seed, xs.size() - i);
vec<T> tmp; xs[i].moveTo(tmp);
xs[pick].moveTo(xs[i]);
tmp.moveTo(xs[pick]);
}
}
//=================================================================================================
} // namespace Minisat
#endif

727
libs/minisat/SimpSolver.cc Normal file
View file

@ -0,0 +1,727 @@
#define __STDC_FORMAT_MACROS
#define __STDC_LIMIT_MACROS
/***********************************************************************************[SimpSolver.cc]
Copyright (c) 2006, Niklas Een, Niklas Sorensson
Copyright (c) 2007-2010, Niklas Sorensson
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
**************************************************************************************************/
#include "Sort.h"
#include "SimpSolver.h"
#include "System.h"
using namespace Minisat;
//=================================================================================================
// Options:
static const char* _cat = "SIMP";
static BoolOption opt_use_asymm (_cat, "asymm", "Shrink clauses by asymmetric branching.", false);
static BoolOption opt_use_rcheck (_cat, "rcheck", "Check if a clause is already implied. (costly)", false);
static BoolOption opt_use_elim (_cat, "elim", "Perform variable elimination.", true);
static IntOption opt_grow (_cat, "grow", "Allow a variable elimination step to grow by a number of clauses.", 0);
static IntOption opt_clause_lim (_cat, "cl-lim", "Variables are not eliminated if it produces a resolvent with a length above this limit. -1 means no limit", 20, IntRange(-1, INT32_MAX));
static IntOption opt_subsumption_lim (_cat, "sub-lim", "Do not check if subsumption against a clause larger than this. -1 means no limit.", 1000, IntRange(-1, INT32_MAX));
static DoubleOption opt_simp_garbage_frac(_cat, "simp-gc-frac", "The fraction of wasted memory allowed before a garbage collection is triggered during simplification.", 0.5, DoubleRange(0, false, HUGE_VAL, false));
//=================================================================================================
// Constructor/Destructor:
SimpSolver::SimpSolver() :
grow (opt_grow)
, clause_lim (opt_clause_lim)
, subsumption_lim (opt_subsumption_lim)
, simp_garbage_frac (opt_simp_garbage_frac)
, use_asymm (opt_use_asymm)
, use_rcheck (opt_use_rcheck)
, use_elim (opt_use_elim)
, extend_model (true)
, merges (0)
, asymm_lits (0)
, eliminated_vars (0)
, elimorder (1)
, use_simplification (true)
, occurs (ClauseDeleted(ca))
, elim_heap (ElimLt(n_occ))
, bwdsub_assigns (0)
, n_touched (0)
{
vec<Lit> dummy(1,lit_Undef);
ca.extra_clause_field = true; // NOTE: must happen before allocating the dummy clause below.
bwdsub_tmpunit = ca.alloc(dummy);
remove_satisfied = false;
}
SimpSolver::~SimpSolver()
{
}
Var SimpSolver::newVar(lbool upol, bool dvar) {
Var v = Solver::newVar(upol, dvar);
frozen .insert(v, (char)false);
eliminated.insert(v, (char)false);
if (use_simplification){
n_occ .insert( mkLit(v), 0);
n_occ .insert(~mkLit(v), 0);
occurs .init (v);
touched .insert(v, 0);
elim_heap .insert(v);
}
return v; }
void SimpSolver::releaseVar(Lit l)
{
assert(!isEliminated(var(l)));
if (!use_simplification && var(l) >= max_simp_var)
// Note: Guarantees that no references to this variable is
// left in model extension datastructure. Could be improved!
Solver::releaseVar(l);
else
// Otherwise, don't allow variable to be reused.
Solver::addClause(l);
}
lbool SimpSolver::solve_(bool do_simp, bool turn_off_simp)
{
vec<Var> extra_frozen;
lbool result = l_True;
do_simp &= use_simplification;
if (do_simp){
// Assumptions must be temporarily frozen to run variable elimination:
for (int i = 0; i < assumptions.size(); i++){
Var v = var(assumptions[i]);
// If an assumption has been eliminated, remember it.
assert(!isEliminated(v));
if (!frozen[v]){
// Freeze and store.
setFrozen(v, true);
extra_frozen.push(v);
} }
result = lbool(eliminate(turn_off_simp));
}
if (result == l_True)
result = Solver::solve_();
else if (verbosity >= 1)
printf("===============================================================================\n");
if (result == l_True && extend_model)
extendModel();
if (do_simp)
// Unfreeze the assumptions that were frozen:
for (int i = 0; i < extra_frozen.size(); i++)
setFrozen(extra_frozen[i], false);
return result;
}
bool SimpSolver::addClause_(vec<Lit>& ps)
{
#ifndef NDEBUG
for (int i = 0; i < ps.size(); i++)
assert(!isEliminated(var(ps[i])));
#endif
int nclauses = clauses.size();
if (use_rcheck && implied(ps))
return true;
if (!Solver::addClause_(ps))
return false;
if (use_simplification && clauses.size() == nclauses + 1){
CRef cr = clauses.last();
const Clause& c = ca[cr];
// NOTE: the clause is added to the queue immediately and then
// again during 'gatherTouchedClauses()'. If nothing happens
// in between, it will only be checked once. Otherwise, it may
// be checked twice unnecessarily. This is an unfortunate
// consequence of how backward subsumption is used to mimic
// forward subsumption.
subsumption_queue.insert(cr);
for (int i = 0; i < c.size(); i++){
occurs[var(c[i])].push(cr);
n_occ[c[i]]++;
touched[var(c[i])] = 1;
n_touched++;
if (elim_heap.inHeap(var(c[i])))
elim_heap.increase(var(c[i]));
}
}
return true;
}
void SimpSolver::removeClause(CRef cr)
{
const Clause& c = ca[cr];
if (use_simplification)
for (int i = 0; i < c.size(); i++){
n_occ[c[i]]--;
updateElimHeap(var(c[i]));
occurs.smudge(var(c[i]));
}
Solver::removeClause(cr);
}
bool SimpSolver::strengthenClause(CRef cr, Lit l)
{
Clause& c = ca[cr];
assert(decisionLevel() == 0);
assert(use_simplification);
// FIX: this is too inefficient but would be nice to have (properly implemented)
// if (!find(subsumption_queue, &c))
subsumption_queue.insert(cr);
if (c.size() == 2){
removeClause(cr);
c.strengthen(l);
}else{
detachClause(cr, true);
c.strengthen(l);
attachClause(cr);
remove(occurs[var(l)], cr);
n_occ[l]--;
updateElimHeap(var(l));
}
return c.size() == 1 ? enqueue(c[0]) && propagate() == CRef_Undef : true;
}
// Returns FALSE if clause is always satisfied ('out_clause' should not be used).
bool SimpSolver::merge(const Clause& _ps, const Clause& _qs, Var v, vec<Lit>& out_clause)
{
merges++;
out_clause.clear();
bool ps_smallest = _ps.size() < _qs.size();
const Clause& ps = ps_smallest ? _qs : _ps;
const Clause& qs = ps_smallest ? _ps : _qs;
for (int i = 0; i < qs.size(); i++){
if (var(qs[i]) != v){
for (int j = 0; j < ps.size(); j++)
if (var(ps[j]) == var(qs[i])){
if (ps[j] == ~qs[i])
return false;
else
goto next;
}
out_clause.push(qs[i]);
}
next:;
}
for (int i = 0; i < ps.size(); i++)
if (var(ps[i]) != v)
out_clause.push(ps[i]);
return true;
}
// Returns FALSE if clause is always satisfied.
bool SimpSolver::merge(const Clause& _ps, const Clause& _qs, Var v, int& size)
{
merges++;
bool ps_smallest = _ps.size() < _qs.size();
const Clause& ps = ps_smallest ? _qs : _ps;
const Clause& qs = ps_smallest ? _ps : _qs;
const Lit* __ps = (const Lit*)ps;
const Lit* __qs = (const Lit*)qs;
size = ps.size()-1;
for (int i = 0; i < qs.size(); i++){
if (var(__qs[i]) != v){
for (int j = 0; j < ps.size(); j++)
if (var(__ps[j]) == var(__qs[i])){
if (__ps[j] == ~__qs[i])
return false;
else
goto next;
}
size++;
}
next:;
}
return true;
}
void SimpSolver::gatherTouchedClauses()
{
if (n_touched == 0) return;
int i,j;
for (i = j = 0; i < subsumption_queue.size(); i++)
if (ca[subsumption_queue[i]].mark() == 0)
ca[subsumption_queue[i]].mark(2);
for (i = 0; i < nVars(); i++)
if (touched[i]){
const vec<CRef>& cs = occurs.lookup(i);
for (j = 0; j < cs.size(); j++)
if (ca[cs[j]].mark() == 0){
subsumption_queue.insert(cs[j]);
ca[cs[j]].mark(2);
}
touched[i] = 0;
}
for (i = 0; i < subsumption_queue.size(); i++)
if (ca[subsumption_queue[i]].mark() == 2)
ca[subsumption_queue[i]].mark(0);
n_touched = 0;
}
bool SimpSolver::implied(const vec<Lit>& c)
{
assert(decisionLevel() == 0);
trail_lim.push(trail.size());
for (int i = 0; i < c.size(); i++)
if (value(c[i]) == l_True){
cancelUntil(0);
return true;
}else if (value(c[i]) != l_False){
assert(value(c[i]) == l_Undef);
uncheckedEnqueue(~c[i]);
}
bool result = propagate() != CRef_Undef;
cancelUntil(0);
return result;
}
// Backward subsumption + backward subsumption resolution
bool SimpSolver::backwardSubsumptionCheck(bool verbose)
{
int cnt = 0;
int subsumed = 0;
int deleted_literals = 0;
assert(decisionLevel() == 0);
while (subsumption_queue.size() > 0 || bwdsub_assigns < trail.size()){
// Empty subsumption queue and return immediately on user-interrupt:
if (asynch_interrupt){
subsumption_queue.clear();
bwdsub_assigns = trail.size();
break; }
// Check top-level assignments by creating a dummy clause and placing it in the queue:
if (subsumption_queue.size() == 0 && bwdsub_assigns < trail.size()){
Lit l = trail[bwdsub_assigns++];
ca[bwdsub_tmpunit][0] = l;
ca[bwdsub_tmpunit].calcAbstraction();
subsumption_queue.insert(bwdsub_tmpunit); }
CRef cr = subsumption_queue.peek(); subsumption_queue.pop();
Clause& c = ca[cr];
if (c.mark()) continue;
if (verbose && verbosity >= 2 && cnt++ % 1000 == 0)
printf("subsumption left: %10d (%10d subsumed, %10d deleted literals)\r", subsumption_queue.size(), subsumed, deleted_literals);
assert(c.size() > 1 || value(c[0]) == l_True); // Unit-clauses should have been propagated before this point.
// Find best variable to scan:
Var best = var(c[0]);
for (int i = 1; i < c.size(); i++)
if (occurs[var(c[i])].size() < occurs[best].size())
best = var(c[i]);
// Search all candidates:
vec<CRef>& _cs = occurs.lookup(best);
CRef* cs = (CRef*)_cs;
for (int j = 0; j < _cs.size(); j++)
if (c.mark())
break;
else if (!ca[cs[j]].mark() && cs[j] != cr && (subsumption_lim == -1 || ca[cs[j]].size() < subsumption_lim)){
Lit l = c.subsumes(ca[cs[j]]);
if (l == lit_Undef)
subsumed++, removeClause(cs[j]);
else if (l != lit_Error){
deleted_literals++;
if (!strengthenClause(cs[j], ~l))
return false;
// Did current candidate get deleted from cs? Then check candidate at index j again:
if (var(l) == best)
j--;
}
}
}
return true;
}
bool SimpSolver::asymm(Var v, CRef cr)
{
Clause& c = ca[cr];
assert(decisionLevel() == 0);
if (c.mark() || satisfied(c)) return true;
trail_lim.push(trail.size());
Lit l = lit_Undef;
for (int i = 0; i < c.size(); i++)
if (var(c[i]) != v && value(c[i]) != l_False)
uncheckedEnqueue(~c[i]);
else
l = c[i];
if (propagate() != CRef_Undef){
cancelUntil(0);
asymm_lits++;
if (!strengthenClause(cr, l))
return false;
}else
cancelUntil(0);
return true;
}
bool SimpSolver::asymmVar(Var v)
{
assert(use_simplification);
const vec<CRef>& cls = occurs.lookup(v);
if (value(v) != l_Undef || cls.size() == 0)
return true;
for (int i = 0; i < cls.size(); i++)
if (!asymm(v, cls[i]))
return false;
return backwardSubsumptionCheck();
}
static void mkElimClause(vec<uint32_t>& elimclauses, Lit x)
{
elimclauses.push(toInt(x));
elimclauses.push(1);
}
static void mkElimClause(vec<uint32_t>& elimclauses, Var v, Clause& c)
{
int first = elimclauses.size();
int v_pos = -1;
// Copy clause to elimclauses-vector. Remember position where the
// variable 'v' occurs:
for (int i = 0; i < c.size(); i++){
elimclauses.push(toInt(c[i]));
if (var(c[i]) == v)
v_pos = i + first;
}
assert(v_pos != -1);
// Swap the first literal with the 'v' literal, so that the literal
// containing 'v' will occur first in the clause:
uint32_t tmp = elimclauses[v_pos];
elimclauses[v_pos] = elimclauses[first];
elimclauses[first] = tmp;
// Store the length of the clause last:
elimclauses.push(c.size());
}
bool SimpSolver::eliminateVar(Var v)
{
assert(!frozen[v]);
assert(!isEliminated(v));
assert(value(v) == l_Undef);
// Split the occurrences into positive and negative:
//
const vec<CRef>& cls = occurs.lookup(v);
vec<CRef> pos, neg;
for (int i = 0; i < cls.size(); i++)
(find(ca[cls[i]], mkLit(v)) ? pos : neg).push(cls[i]);
// Check wether the increase in number of clauses stays within the allowed ('grow'). Moreover, no
// clause must exceed the limit on the maximal clause size (if it is set):
//
int cnt = 0;
int clause_size = 0;
for (int i = 0; i < pos.size(); i++)
for (int j = 0; j < neg.size(); j++)
if (merge(ca[pos[i]], ca[neg[j]], v, clause_size) &&
(++cnt > cls.size() + grow || (clause_lim != -1 && clause_size > clause_lim)))
return true;
// Delete and store old clauses:
eliminated[v] = true;
setDecisionVar(v, false);
eliminated_vars++;
if (pos.size() > neg.size()){
for (int i = 0; i < neg.size(); i++)
mkElimClause(elimclauses, v, ca[neg[i]]);
mkElimClause(elimclauses, mkLit(v));
}else{
for (int i = 0; i < pos.size(); i++)
mkElimClause(elimclauses, v, ca[pos[i]]);
mkElimClause(elimclauses, ~mkLit(v));
}
for (int i = 0; i < cls.size(); i++)
removeClause(cls[i]);
// Produce clauses in cross product:
vec<Lit>& resolvent = add_tmp;
for (int i = 0; i < pos.size(); i++)
for (int j = 0; j < neg.size(); j++)
if (merge(ca[pos[i]], ca[neg[j]], v, resolvent) && !addClause_(resolvent))
return false;
// Free occurs list for this variable:
occurs[v].clear(true);
// Free watchers lists for this variable, if possible:
if (watches[ mkLit(v)].size() == 0) watches[ mkLit(v)].clear(true);
if (watches[~mkLit(v)].size() == 0) watches[~mkLit(v)].clear(true);
return backwardSubsumptionCheck();
}
bool SimpSolver::substitute(Var v, Lit x)
{
assert(!frozen[v]);
assert(!isEliminated(v));
assert(value(v) == l_Undef);
if (!ok) return false;
eliminated[v] = true;
setDecisionVar(v, false);
const vec<CRef>& cls = occurs.lookup(v);
vec<Lit>& subst_clause = add_tmp;
for (int i = 0; i < cls.size(); i++){
Clause& c = ca[cls[i]];
subst_clause.clear();
for (int j = 0; j < c.size(); j++){
Lit p = c[j];
subst_clause.push(var(p) == v ? x ^ sign(p) : p);
}
removeClause(cls[i]);
if (!addClause_(subst_clause))
return ok = false;
}
return true;
}
void SimpSolver::extendModel()
{
int i, j;
Lit x;
for (i = elimclauses.size()-1; i > 0; i -= j){
for (j = elimclauses[i--]; j > 1; j--, i--)
if (modelValue(toLit(elimclauses[i])) != l_False)
goto next;
x = toLit(elimclauses[i]);
model[var(x)] = lbool(!sign(x));
next:;
}
}
bool SimpSolver::eliminate(bool turn_off_elim)
{
if (!simplify())
return false;
else if (!use_simplification)
return true;
// Main simplification loop:
//
while (n_touched > 0 || bwdsub_assigns < trail.size() || elim_heap.size() > 0){
gatherTouchedClauses();
// printf(" ## (time = %6.2f s) BWD-SUB: queue = %d, trail = %d\n", cpuTime(), subsumption_queue.size(), trail.size() - bwdsub_assigns);
if ((subsumption_queue.size() > 0 || bwdsub_assigns < trail.size()) &&
!backwardSubsumptionCheck(true)){
ok = false; goto cleanup; }
// Empty elim_heap and return immediately on user-interrupt:
if (asynch_interrupt){
assert(bwdsub_assigns == trail.size());
assert(subsumption_queue.size() == 0);
assert(n_touched == 0);
elim_heap.clear();
goto cleanup; }
// printf(" ## (time = %6.2f s) ELIM: vars = %d\n", cpuTime(), elim_heap.size());
for (int cnt = 0; !elim_heap.empty(); cnt++){
Var elim = elim_heap.removeMin();
if (asynch_interrupt) break;
if (isEliminated(elim) || value(elim) != l_Undef) continue;
if (verbosity >= 2 && cnt % 100 == 0)
printf("elimination left: %10d\r", elim_heap.size());
if (use_asymm){
// Temporarily freeze variable. Otherwise, it would immediately end up on the queue again:
bool was_frozen = frozen[elim];
frozen[elim] = true;
if (!asymmVar(elim)){
ok = false; goto cleanup; }
frozen[elim] = was_frozen; }
// At this point, the variable may have been set by assymetric branching, so check it
// again. Also, don't eliminate frozen variables:
if (use_elim && value(elim) == l_Undef && !frozen[elim] && !eliminateVar(elim)){
ok = false; goto cleanup; }
checkGarbage(simp_garbage_frac);
}
assert(subsumption_queue.size() == 0);
}
cleanup:
// If no more simplification is needed, free all simplification-related data structures:
if (turn_off_elim){
touched .clear(true);
occurs .clear(true);
n_occ .clear(true);
elim_heap.clear(true);
subsumption_queue.clear(true);
use_simplification = false;
remove_satisfied = true;
ca.extra_clause_field = false;
max_simp_var = nVars();
// Force full cleanup (this is safe and desirable since it only happens once):
rebuildOrderHeap();
garbageCollect();
}else{
// Cheaper cleanup:
checkGarbage();
}
if (verbosity >= 1 && elimclauses.size() > 0)
printf("| Eliminated clauses: %10.2f Mb |\n",
double(elimclauses.size() * sizeof(uint32_t)) / (1024*1024));
return ok;
}
//=================================================================================================
// Garbage Collection methods:
void SimpSolver::relocAll(ClauseAllocator& to)
{
if (!use_simplification) return;
// All occurs lists:
//
for (int i = 0; i < nVars(); i++){
occurs.clean(i);
vec<CRef>& cs = occurs[i];
for (int j = 0; j < cs.size(); j++)
ca.reloc(cs[j], to);
}
// Subsumption queue:
//
for (int i = subsumption_queue.size(); i > 0; i--){
CRef cr = subsumption_queue.peek(); subsumption_queue.pop();
if (ca[cr].mark()) continue;
ca.reloc(cr, to);
subsumption_queue.insert(cr);
}
// Temporary clause:
//
ca.reloc(bwdsub_tmpunit, to);
}
void SimpSolver::garbageCollect()
{
// Initialize the next region to a size corresponding to the estimated utilization degree. This
// is not precise but should avoid some unnecessary reallocations for the new region:
ClauseAllocator to(ca.size() - ca.wasted());
to.extra_clause_field = ca.extra_clause_field; // NOTE: this is important to keep (or lose) the extra fields.
relocAll(to);
Solver::relocAll(to);
if (verbosity >= 2)
printf("| Garbage collection: %12d bytes => %12d bytes |\n",
ca.size()*ClauseAllocator::Unit_Size, to.size()*ClauseAllocator::Unit_Size);
to.moveTo(ca);
}

222
libs/minisat/SimpSolver.h Normal file
View file

@ -0,0 +1,222 @@
/************************************************************************************[SimpSolver.h]
Copyright (c) 2006, Niklas Een, Niklas Sorensson
Copyright (c) 2007-2010, Niklas Sorensson
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
**************************************************************************************************/
#ifndef Minisat_SimpSolver_h
#define Minisat_SimpSolver_h
#include "Queue.h"
#include "Solver.h"
namespace Minisat {
//=================================================================================================
class SimpSolver : public Solver {
public:
// Constructor/Destructor:
//
SimpSolver();
~SimpSolver();
// Problem specification:
//
Var newVar (lbool upol = l_Undef, bool dvar = true);
void releaseVar(Lit l);
bool addClause (const vec<Lit>& ps);
bool addEmptyClause(); // Add the empty clause to the solver.
bool addClause (Lit p); // Add a unit clause to the solver.
bool addClause (Lit p, Lit q); // Add a binary clause to the solver.
bool addClause (Lit p, Lit q, Lit r); // Add a ternary clause to the solver.
bool addClause (Lit p, Lit q, Lit r, Lit s); // Add a quaternary clause to the solver.
bool addClause_( vec<Lit>& ps);
bool substitute(Var v, Lit x); // Replace all occurences of v with x (may cause a contradiction).
// Variable mode:
//
void setFrozen (Var v, bool b); // If a variable is frozen it will not be eliminated.
bool isEliminated(Var v) const;
// Alternative freeze interface (may replace 'setFrozen()'):
void freezeVar (Var v); // Freeze one variable so it will not be eliminated.
void thaw (); // Thaw all frozen variables.
// Solving:
//
bool solve (const vec<Lit>& assumps, bool do_simp = true, bool turn_off_simp = false);
lbool solveLimited(const vec<Lit>& assumps, bool do_simp = true, bool turn_off_simp = false);
bool solve ( bool do_simp = true, bool turn_off_simp = false);
bool solve (Lit p , bool do_simp = true, bool turn_off_simp = false);
bool solve (Lit p, Lit q, bool do_simp = true, bool turn_off_simp = false);
bool solve (Lit p, Lit q, Lit r, bool do_simp = true, bool turn_off_simp = false);
bool eliminate (bool turn_off_elim = false); // Perform variable elimination based simplification.
// Memory managment:
//
virtual void garbageCollect();
// Generate a (possibly simplified) DIMACS file:
//
#if 0
void toDimacs (const char* file, const vec<Lit>& assumps);
void toDimacs (const char* file);
void toDimacs (const char* file, Lit p);
void toDimacs (const char* file, Lit p, Lit q);
void toDimacs (const char* file, Lit p, Lit q, Lit r);
#endif
// Mode of operation:
//
int grow; // Allow a variable elimination step to grow by a number of clauses (default to zero).
int clause_lim; // Variables are not eliminated if it produces a resolvent with a length above this limit.
// -1 means no limit.
int subsumption_lim; // Do not check if subsumption against a clause larger than this. -1 means no limit.
double simp_garbage_frac; // A different limit for when to issue a GC during simplification (Also see 'garbage_frac').
bool use_asymm; // Shrink clauses by asymmetric branching.
bool use_rcheck; // Check if a clause is already implied. Prett costly, and subsumes subsumptions :)
bool use_elim; // Perform variable elimination.
bool extend_model; // Flag to indicate whether the user needs to look at the full model.
// Statistics:
//
int merges;
int asymm_lits;
int eliminated_vars;
protected:
// Helper structures:
//
struct ElimLt {
const LMap<int>& n_occ;
explicit ElimLt(const LMap<int>& no) : n_occ(no) {}
// TODO: are 64-bit operations here noticably bad on 32-bit platforms? Could use a saturating
// 32-bit implementation instead then, but this will have to do for now.
uint64_t cost (Var x) const { return (uint64_t)n_occ[mkLit(x)] * (uint64_t)n_occ[~mkLit(x)]; }
bool operator()(Var x, Var y) const { return cost(x) < cost(y); }
// TODO: investigate this order alternative more.
// bool operator()(Var x, Var y) const {
// int c_x = cost(x);
// int c_y = cost(y);
// return c_x < c_y || c_x == c_y && x < y; }
};
struct ClauseDeleted {
const ClauseAllocator& ca;
explicit ClauseDeleted(const ClauseAllocator& _ca) : ca(_ca) {}
bool operator()(const CRef& cr) const { return ca[cr].mark() == 1; } };
// Solver state:
//
int elimorder;
bool use_simplification;
Var max_simp_var; // Max variable at the point simplification was turned off.
vec<uint32_t> elimclauses;
VMap<char> touched;
OccLists<Var, vec<CRef>, ClauseDeleted>
occurs;
LMap<int> n_occ;
Heap<Var,ElimLt> elim_heap;
Queue<CRef> subsumption_queue;
VMap<char> frozen;
vec<Var> frozen_vars;
VMap<char> eliminated;
int bwdsub_assigns;
int n_touched;
// Temporaries:
//
CRef bwdsub_tmpunit;
// Main internal methods:
//
lbool solve_ (bool do_simp = true, bool turn_off_simp = false);
bool asymm (Var v, CRef cr);
bool asymmVar (Var v);
void updateElimHeap (Var v);
void gatherTouchedClauses ();
bool merge (const Clause& _ps, const Clause& _qs, Var v, vec<Lit>& out_clause);
bool merge (const Clause& _ps, const Clause& _qs, Var v, int& size);
bool backwardSubsumptionCheck (bool verbose = false);
bool eliminateVar (Var v);
void extendModel ();
void removeClause (CRef cr);
bool strengthenClause (CRef cr, Lit l);
bool implied (const vec<Lit>& c);
void relocAll (ClauseAllocator& to);
};
//=================================================================================================
// Implementation of inline methods:
inline bool SimpSolver::isEliminated (Var v) const { return eliminated[v]; }
inline void SimpSolver::updateElimHeap(Var v) {
assert(use_simplification);
// if (!frozen[v] && !isEliminated(v) && value(v) == l_Undef)
if (elim_heap.inHeap(v) || (!frozen[v] && !isEliminated(v) && value(v) == l_Undef))
elim_heap.update(v); }
inline bool SimpSolver::addClause (const vec<Lit>& ps) { ps.copyTo(add_tmp); return addClause_(add_tmp); }
inline bool SimpSolver::addEmptyClause() { add_tmp.clear(); return addClause_(add_tmp); }
inline bool SimpSolver::addClause (Lit p) { add_tmp.clear(); add_tmp.push(p); return addClause_(add_tmp); }
inline bool SimpSolver::addClause (Lit p, Lit q) { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); return addClause_(add_tmp); }
inline bool SimpSolver::addClause (Lit p, Lit q, Lit r) { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); add_tmp.push(r); return addClause_(add_tmp); }
inline bool SimpSolver::addClause (Lit p, Lit q, Lit r, Lit s){ add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); add_tmp.push(r); add_tmp.push(s); return addClause_(add_tmp); }
inline void SimpSolver::setFrozen (Var v, bool b) { frozen[v] = (char)b; if (use_simplification && !b) { updateElimHeap(v); } }
inline void SimpSolver::freezeVar(Var v){
if (!frozen[v]){
frozen[v] = 1;
frozen_vars.push(v);
} }
inline void SimpSolver::thaw(){
for (int i = 0; i < frozen_vars.size(); i++){
Var v = frozen_vars[i];
frozen[v] = 0;
if (use_simplification)
updateElimHeap(v);
}
frozen_vars.clear(); }
inline bool SimpSolver::solve ( bool do_simp, bool turn_off_simp) { budgetOff(); assumptions.clear(); return solve_(do_simp, turn_off_simp) == l_True; }
inline bool SimpSolver::solve (Lit p , bool do_simp, bool turn_off_simp) { budgetOff(); assumptions.clear(); assumptions.push(p); return solve_(do_simp, turn_off_simp) == l_True; }
inline bool SimpSolver::solve (Lit p, Lit q, bool do_simp, bool turn_off_simp) { budgetOff(); assumptions.clear(); assumptions.push(p); assumptions.push(q); return solve_(do_simp, turn_off_simp) == l_True; }
inline bool SimpSolver::solve (Lit p, Lit q, Lit r, bool do_simp, bool turn_off_simp) { budgetOff(); assumptions.clear(); assumptions.push(p); assumptions.push(q); assumptions.push(r); return solve_(do_simp, turn_off_simp) == l_True; }
inline bool SimpSolver::solve (const vec<Lit>& assumps, bool do_simp, bool turn_off_simp){
budgetOff(); assumps.copyTo(assumptions); return solve_(do_simp, turn_off_simp) == l_True; }
inline lbool SimpSolver::solveLimited (const vec<Lit>& assumps, bool do_simp, bool turn_off_simp){
assumps.copyTo(assumptions); return solve_(do_simp, turn_off_simp); }
//=================================================================================================
}
#endif

1068
libs/minisat/Solver.cc Normal file

File diff suppressed because it is too large Load diff

409
libs/minisat/Solver.h Normal file
View file

@ -0,0 +1,409 @@
/****************************************************************************************[Solver.h]
Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
Copyright (c) 2007-2010, Niklas Sorensson
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
**************************************************************************************************/
#ifndef Minisat_Solver_h
#define Minisat_Solver_h
#include "Vec.h"
#include "Heap.h"
#include "Alg.h"
#include "IntMap.h"
#include "Options.h"
#include "SolverTypes.h"
namespace Minisat {
//=================================================================================================
// Solver -- the main class:
class Solver {
public:
// Constructor/Destructor:
//
Solver();
virtual ~Solver();
// Problem specification:
//
Var newVar (lbool upol = l_Undef, bool dvar = true); // Add a new variable with parameters specifying variable mode.
void releaseVar(Lit l); // Make literal true and promise to never refer to variable again.
bool addClause (const vec<Lit>& ps); // Add a clause to the solver.
bool addEmptyClause(); // Add the empty clause, making the solver contradictory.
bool addClause (Lit p); // Add a unit clause to the solver.
bool addClause (Lit p, Lit q); // Add a binary clause to the solver.
bool addClause (Lit p, Lit q, Lit r); // Add a ternary clause to the solver.
bool addClause (Lit p, Lit q, Lit r, Lit s); // Add a quaternary clause to the solver.
bool addClause_( vec<Lit>& ps); // Add a clause to the solver without making superflous internal copy. Will
// change the passed vector 'ps'.
// Solving:
//
bool simplify (); // Removes already satisfied clauses.
bool solve (const vec<Lit>& assumps); // Search for a model that respects a given set of assumptions.
lbool solveLimited (const vec<Lit>& assumps); // Search for a model that respects a given set of assumptions (With resource constraints).
bool solve (); // Search without assumptions.
bool solve (Lit p); // Search for a model that respects a single assumption.
bool solve (Lit p, Lit q); // Search for a model that respects two assumptions.
bool solve (Lit p, Lit q, Lit r); // Search for a model that respects three assumptions.
bool okay () const; // FALSE means solver is in a conflicting state
bool implies (const vec<Lit>& assumps, vec<Lit>& out);
// Iterate over clauses and top-level assignments:
ClauseIterator clausesBegin() const;
ClauseIterator clausesEnd() const;
TrailIterator trailBegin() const;
TrailIterator trailEnd () const;
void toDimacs (FILE* f, const vec<Lit>& assumps); // Write CNF to file in DIMACS-format.
void toDimacs (const char *file, const vec<Lit>& assumps);
void toDimacs (FILE* f, Clause& c, vec<Var>& map, Var& max);
// Convenience versions of 'toDimacs()':
void toDimacs (const char* file);
void toDimacs (const char* file, Lit p);
void toDimacs (const char* file, Lit p, Lit q);
void toDimacs (const char* file, Lit p, Lit q, Lit r);
// Variable mode:
//
void setPolarity (Var v, lbool b); // Declare which polarity the decision heuristic should use for a variable. Requires mode 'polarity_user'.
void setDecisionVar (Var v, bool b); // Declare if a variable should be eligible for selection in the decision heuristic.
// Read state:
//
lbool value (Var x) const; // The current value of a variable.
lbool value (Lit p) const; // The current value of a literal.
lbool modelValue (Var x) const; // The value of a variable in the last model. The last call to solve must have been satisfiable.
lbool modelValue (Lit p) const; // The value of a literal in the last model. The last call to solve must have been satisfiable.
int nAssigns () const; // The current number of assigned literals.
int nClauses () const; // The current number of original clauses.
int nLearnts () const; // The current number of learnt clauses.
int nVars () const; // The current number of variables.
int nFreeVars () const;
void printStats () const; // Print some current statistics to standard output.
// Resource constraints:
//
void setConfBudget(int64_t x);
void setPropBudget(int64_t x);
void budgetOff();
void interrupt(); // Trigger a (potentially asynchronous) interruption of the solver.
void clearInterrupt(); // Clear interrupt indicator flag.
// Memory managment:
//
virtual void garbageCollect();
void checkGarbage(double gf);
void checkGarbage();
// Extra results: (read-only member variable)
//
vec<lbool> model; // If problem is satisfiable, this vector contains the model (if any).
LSet conflict; // If problem is unsatisfiable (possibly under assumptions),
// this vector represent the final conflict clause expressed in the assumptions.
// Mode of operation:
//
int verbosity;
double var_decay;
double clause_decay;
double random_var_freq;
double random_seed;
bool luby_restart;
int ccmin_mode; // Controls conflict clause minimization (0=none, 1=basic, 2=deep).
int phase_saving; // Controls the level of phase saving (0=none, 1=limited, 2=full).
bool rnd_pol; // Use random polarities for branching heuristics.
bool rnd_init_act; // Initialize variable activities with a small random value.
double garbage_frac; // The fraction of wasted memory allowed before a garbage collection is triggered.
int min_learnts_lim; // Minimum number to set the learnts limit to.
int restart_first; // The initial restart limit. (default 100)
double restart_inc; // The factor with which the restart limit is multiplied in each restart. (default 1.5)
double learntsize_factor; // The intitial limit for learnt clauses is a factor of the original clauses. (default 1 / 3)
double learntsize_inc; // The limit for learnt clauses is multiplied with this factor each restart. (default 1.1)
int learntsize_adjust_start_confl;
double learntsize_adjust_inc;
// Statistics: (read-only member variable)
//
uint64_t solves, starts, decisions, rnd_decisions, propagations, conflicts;
uint64_t dec_vars, num_clauses, num_learnts, clauses_literals, learnts_literals, max_literals, tot_literals;
protected:
// Helper structures:
//
struct VarData { CRef reason; int level; };
static inline VarData mkVarData(CRef cr, int l){ VarData d = {cr, l}; return d; }
struct Watcher {
CRef cref;
Lit blocker;
Watcher(CRef cr, Lit p) : cref(cr), blocker(p) {}
bool operator==(const Watcher& w) const { return cref == w.cref; }
bool operator!=(const Watcher& w) const { return cref != w.cref; }
};
struct WatcherDeleted
{
const ClauseAllocator& ca;
WatcherDeleted(const ClauseAllocator& _ca) : ca(_ca) {}
bool operator()(const Watcher& w) const { return ca[w.cref].mark() == 1; }
};
struct VarOrderLt {
const IntMap<Var, double>& activity;
bool operator () (Var x, Var y) const { return activity[x] > activity[y]; }
VarOrderLt(const IntMap<Var, double>& act) : activity(act) { }
};
struct ShrinkStackElem {
uint32_t i;
Lit l;
ShrinkStackElem(uint32_t _i, Lit _l) : i(_i), l(_l){}
};
// Solver state:
//
vec<CRef> clauses; // List of problem clauses.
vec<CRef> learnts; // List of learnt clauses.
vec<Lit> trail; // Assignment stack; stores all assigments made in the order they were made.
vec<int> trail_lim; // Separator indices for different decision levels in 'trail'.
vec<Lit> assumptions; // Current set of assumptions provided to solve by the user.
VMap<double> activity; // A heuristic measurement of the activity of a variable.
VMap<lbool> assigns; // The current assignments.
VMap<char> polarity; // The preferred polarity of each variable.
VMap<lbool> user_pol; // The users preferred polarity of each variable.
VMap<char> decision; // Declares if a variable is eligible for selection in the decision heuristic.
VMap<VarData> vardata; // Stores reason and level for each variable.
OccLists<Lit, vec<Watcher>, WatcherDeleted, MkIndexLit>
watches; // 'watches[lit]' is a list of constraints watching 'lit' (will go there if literal becomes true).
Heap<Var,VarOrderLt>order_heap; // A priority queue of variables ordered with respect to the variable activity.
bool ok; // If FALSE, the constraints are already unsatisfiable. No part of the solver state may be used!
double cla_inc; // Amount to bump next clause with.
double var_inc; // Amount to bump next variable with.
int qhead; // Head of queue (as index into the trail -- no more explicit propagation queue in MiniSat).
int simpDB_assigns; // Number of top-level assignments since last execution of 'simplify()'.
int64_t simpDB_props; // Remaining number of propagations that must be made before next execution of 'simplify()'.
double progress_estimate;// Set by 'search()'.
bool remove_satisfied; // Indicates whether possibly inefficient linear scan for satisfied clauses should be performed in 'simplify'.
Var next_var; // Next variable to be created.
ClauseAllocator ca;
vec<Var> released_vars;
vec<Var> free_vars;
// Temporaries (to reduce allocation overhead). Each variable is prefixed by the method in which it is
// used, exept 'seen' wich is used in several places.
//
VMap<char> seen;
vec<ShrinkStackElem>analyze_stack;
vec<Lit> analyze_toclear;
vec<Lit> add_tmp;
double max_learnts;
double learntsize_adjust_confl;
int learntsize_adjust_cnt;
// Resource constraints:
//
int64_t conflict_budget; // -1 means no budget.
int64_t propagation_budget; // -1 means no budget.
bool asynch_interrupt;
// Main internal methods:
//
void insertVarOrder (Var x); // Insert a variable in the decision order priority queue.
Lit pickBranchLit (); // Return the next decision variable.
void newDecisionLevel (); // Begins a new decision level.
void uncheckedEnqueue (Lit p, CRef from = CRef_Undef); // Enqueue a literal. Assumes value of literal is undefined.
bool enqueue (Lit p, CRef from = CRef_Undef); // Test if fact 'p' contradicts current state, enqueue otherwise.
CRef propagate (); // Perform unit propagation. Returns possibly conflicting clause.
void cancelUntil (int level); // Backtrack until a certain level.
void analyze (CRef confl, vec<Lit>& out_learnt, int& out_btlevel); // (bt = backtrack)
void analyzeFinal (Lit p, LSet& out_conflict); // COULD THIS BE IMPLEMENTED BY THE ORDINARIY "analyze" BY SOME REASONABLE GENERALIZATION?
bool litRedundant (Lit p); // (helper method for 'analyze()')
lbool search (int nof_conflicts); // Search for a given number of conflicts.
lbool solve_ (); // Main solve method (assumptions given in 'assumptions').
void reduceDB (); // Reduce the set of learnt clauses.
void removeSatisfied (vec<CRef>& cs); // Shrink 'cs' to contain only non-satisfied clauses.
void rebuildOrderHeap ();
// Maintaining Variable/Clause activity:
//
void varDecayActivity (); // Decay all variables with the specified factor. Implemented by increasing the 'bump' value instead.
void varBumpActivity (Var v, double inc); // Increase a variable with the current 'bump' value.
void varBumpActivity (Var v); // Increase a variable with the current 'bump' value.
void claDecayActivity (); // Decay all clauses with the specified factor. Implemented by increasing the 'bump' value instead.
void claBumpActivity (Clause& c); // Increase a clause with the current 'bump' value.
// Operations on clauses:
//
void attachClause (CRef cr); // Attach a clause to watcher lists.
void detachClause (CRef cr, bool strict = false); // Detach a clause to watcher lists.
void removeClause (CRef cr); // Detach and free a clause.
bool isRemoved (CRef cr) const; // Test if a clause has been removed.
bool locked (const Clause& c) const; // Returns TRUE if a clause is a reason for some implication in the current state.
bool satisfied (const Clause& c) const; // Returns TRUE if a clause is satisfied in the current state.
// Misc:
//
int decisionLevel () const; // Gives the current decisionlevel.
uint32_t abstractLevel (Var x) const; // Used to represent an abstraction of sets of decision levels.
CRef reason (Var x) const;
int level (Var x) const;
double progressEstimate () const; // DELETE THIS ?? IT'S NOT VERY USEFUL ...
bool withinBudget () const;
void relocAll (ClauseAllocator& to);
// Static helpers:
//
// Returns a random float 0 <= x < 1. Seed must never be 0.
static inline double drand(double& seed) {
seed *= 1389796;
int q = (int)(seed / 2147483647);
seed -= (double)q * 2147483647;
return seed / 2147483647; }
// Returns a random integer 0 <= x < size. Seed must never be 0.
static inline int irand(double& seed, int size) {
return (int)(drand(seed) * size); }
};
//=================================================================================================
// Implementation of inline methods:
inline CRef Solver::reason(Var x) const { return vardata[x].reason; }
inline int Solver::level (Var x) const { return vardata[x].level; }
inline void Solver::insertVarOrder(Var x) {
if (!order_heap.inHeap(x) && decision[x]) order_heap.insert(x); }
inline void Solver::varDecayActivity() { var_inc *= (1 / var_decay); }
inline void Solver::varBumpActivity(Var v) { varBumpActivity(v, var_inc); }
inline void Solver::varBumpActivity(Var v, double inc) {
if ( (activity[v] += inc) > 1e100 ) {
// Rescale:
for (int i = 0; i < nVars(); i++)
activity[i] *= 1e-100;
var_inc *= 1e-100; }
// Update order_heap with respect to new activity:
if (order_heap.inHeap(v))
order_heap.decrease(v); }
inline void Solver::claDecayActivity() { cla_inc *= (1 / clause_decay); }
inline void Solver::claBumpActivity (Clause& c) {
if ( (c.activity() += cla_inc) > 1e20 ) {
// Rescale:
for (int i = 0; i < learnts.size(); i++)
ca[learnts[i]].activity() *= 1e-20;
cla_inc *= 1e-20; } }
inline void Solver::checkGarbage(void){ return checkGarbage(garbage_frac); }
inline void Solver::checkGarbage(double gf){
if (ca.wasted() > ca.size() * gf)
garbageCollect(); }
// NOTE: enqueue does not set the ok flag! (only public methods do)
inline bool Solver::enqueue (Lit p, CRef from) { return value(p) != l_Undef ? value(p) != l_False : (uncheckedEnqueue(p, from), true); }
inline bool Solver::addClause (const vec<Lit>& ps) { ps.copyTo(add_tmp); return addClause_(add_tmp); }
inline bool Solver::addEmptyClause () { add_tmp.clear(); return addClause_(add_tmp); }
inline bool Solver::addClause (Lit p) { add_tmp.clear(); add_tmp.push(p); return addClause_(add_tmp); }
inline bool Solver::addClause (Lit p, Lit q) { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); return addClause_(add_tmp); }
inline bool Solver::addClause (Lit p, Lit q, Lit r) { add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); add_tmp.push(r); return addClause_(add_tmp); }
inline bool Solver::addClause (Lit p, Lit q, Lit r, Lit s){ add_tmp.clear(); add_tmp.push(p); add_tmp.push(q); add_tmp.push(r); add_tmp.push(s); return addClause_(add_tmp); }
inline bool Solver::isRemoved (CRef cr) const { return ca[cr].mark() == 1; }
inline bool Solver::locked (const Clause& c) const { return value(c[0]) == l_True && reason(var(c[0])) != CRef_Undef && ca.lea(reason(var(c[0]))) == &c; }
inline void Solver::newDecisionLevel() { trail_lim.push(trail.size()); }
inline int Solver::decisionLevel () const { return trail_lim.size(); }
inline uint32_t Solver::abstractLevel (Var x) const { return 1 << (level(x) & 31); }
inline lbool Solver::value (Var x) const { return assigns[x]; }
inline lbool Solver::value (Lit p) const { return assigns[var(p)] ^ sign(p); }
inline lbool Solver::modelValue (Var x) const { return model[x]; }
inline lbool Solver::modelValue (Lit p) const { return model[var(p)] ^ sign(p); }
inline int Solver::nAssigns () const { return trail.size(); }
inline int Solver::nClauses () const { return num_clauses; }
inline int Solver::nLearnts () const { return num_learnts; }
inline int Solver::nVars () const { return next_var; }
// TODO: nFreeVars() is not quite correct, try to calculate right instead of adapting it like below:
inline int Solver::nFreeVars () const { return (int)dec_vars - (trail_lim.size() == 0 ? trail.size() : trail_lim[0]); }
inline void Solver::setPolarity (Var v, lbool b){ user_pol[v] = b; }
inline void Solver::setDecisionVar(Var v, bool b)
{
if ( b && !decision[v]) dec_vars++;
else if (!b && decision[v]) dec_vars--;
decision[v] = b;
insertVarOrder(v);
}
inline void Solver::setConfBudget(int64_t x){ conflict_budget = conflicts + x; }
inline void Solver::setPropBudget(int64_t x){ propagation_budget = propagations + x; }
inline void Solver::interrupt(){ asynch_interrupt = true; }
inline void Solver::clearInterrupt(){ asynch_interrupt = false; }
inline void Solver::budgetOff(){ conflict_budget = propagation_budget = -1; }
inline bool Solver::withinBudget() const {
return !asynch_interrupt &&
(conflict_budget < 0 || conflicts < (uint64_t)conflict_budget) &&
(propagation_budget < 0 || propagations < (uint64_t)propagation_budget); }
// FIXME: after the introduction of asynchronous interrruptions the solve-versions that return a
// pure bool do not give a safe interface. Either interrupts must be possible to turn off here, or
// all calls to solve must return an 'lbool'. I'm not yet sure which I prefer.
inline bool Solver::solve () { budgetOff(); assumptions.clear(); return solve_() == l_True; }
inline bool Solver::solve (Lit p) { budgetOff(); assumptions.clear(); assumptions.push(p); return solve_() == l_True; }
inline bool Solver::solve (Lit p, Lit q) { budgetOff(); assumptions.clear(); assumptions.push(p); assumptions.push(q); return solve_() == l_True; }
inline bool Solver::solve (Lit p, Lit q, Lit r) { budgetOff(); assumptions.clear(); assumptions.push(p); assumptions.push(q); assumptions.push(r); return solve_() == l_True; }
inline bool Solver::solve (const vec<Lit>& assumps){ budgetOff(); assumps.copyTo(assumptions); return solve_() == l_True; }
inline lbool Solver::solveLimited (const vec<Lit>& assumps){ assumps.copyTo(assumptions); return solve_(); }
inline bool Solver::okay () const { return ok; }
inline ClauseIterator Solver::clausesBegin() const { return ClauseIterator(ca, &clauses[0]); }
inline ClauseIterator Solver::clausesEnd () const { return ClauseIterator(ca, &clauses[clauses.size()]); }
inline TrailIterator Solver::trailBegin () const { return TrailIterator(&trail[0]); }
inline TrailIterator Solver::trailEnd () const {
return TrailIterator(&trail[decisionLevel() == 0 ? trail.size() : trail_lim[0]]); }
inline void Solver::toDimacs (const char* file){ vec<Lit> as; toDimacs(file, as); }
inline void Solver::toDimacs (const char* file, Lit p){ vec<Lit> as; as.push(p); toDimacs(file, as); }
inline void Solver::toDimacs (const char* file, Lit p, Lit q){ vec<Lit> as; as.push(p); as.push(q); toDimacs(file, as); }
inline void Solver::toDimacs (const char* file, Lit p, Lit q, Lit r){ vec<Lit> as; as.push(p); as.push(q); as.push(r); toDimacs(file, as); }
//=================================================================================================
// Debug etc:
//=================================================================================================
}
#endif

478
libs/minisat/SolverTypes.h Normal file
View file

@ -0,0 +1,478 @@
/***********************************************************************************[SolverTypes.h]
Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
Copyright (c) 2007-2010, Niklas Sorensson
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
**************************************************************************************************/
#ifndef Minisat_SolverTypes_h
#define Minisat_SolverTypes_h
#include <assert.h>
#include "IntTypes.h"
#include "Alg.h"
#include "Vec.h"
#include "IntMap.h"
#include "Map.h"
#include "Alloc.h"
namespace Minisat {
//=================================================================================================
// Variables, literals, lifted booleans, clauses:
// NOTE! Variables are just integers. No abstraction here. They should be chosen from 0..N,
// so that they can be used as array indices.
typedef int Var;
#if defined(MINISAT_CONSTANTS_AS_MACROS)
#define var_Undef (-1)
#else
const Var var_Undef = -1;
#endif
struct Lit {
int x;
// Use this as a constructor:
friend Lit mkLit(Var var, bool sign);
bool operator == (Lit p) const { return x == p.x; }
bool operator != (Lit p) const { return x != p.x; }
bool operator < (Lit p) const { return x < p.x; } // '<' makes p, ~p adjacent in the ordering.
};
inline Lit mkLit (Var var, bool sign = false) { Lit p; p.x = var + var + (int)sign; return p; }
inline Lit operator ~(Lit p) { Lit q; q.x = p.x ^ 1; return q; }
inline Lit operator ^(Lit p, bool b) { Lit q; q.x = p.x ^ (unsigned int)b; return q; }
inline bool sign (Lit p) { return p.x & 1; }
inline int var (Lit p) { return p.x >> 1; }
// Mapping Literals to and from compact integers suitable for array indexing:
inline int toInt (Var v) { return v; }
inline int toInt (Lit p) { return p.x; }
inline Lit toLit (int i) { Lit p; p.x = i; return p; }
//const Lit lit_Undef = mkLit(var_Undef, false); // }- Useful special constants.
//const Lit lit_Error = mkLit(var_Undef, true ); // }
const Lit lit_Undef = { -2 }; // }- Useful special constants.
const Lit lit_Error = { -1 }; // }
struct MkIndexLit { vec<Lit>::Size operator()(Lit l) const { return vec<Lit>::Size(l.x); } };
template<class T> class VMap : public IntMap<Var, T>{};
template<class T> class LMap : public IntMap<Lit, T, MkIndexLit>{};
class LSet : public IntSet<Lit, MkIndexLit>{};
//=================================================================================================
// Lifted booleans:
//
// NOTE: this implementation is optimized for the case when comparisons between values are mostly
// between one variable and one constant. Some care had to be taken to make sure that gcc
// does enough constant propagation to produce sensible code, and this appears to be somewhat
// fragile unfortunately.
class lbool {
uint8_t value;
public:
explicit lbool(uint8_t v) : value(v) { }
lbool() : value(0) { }
explicit lbool(bool x) : value(!x) { }
bool operator == (lbool b) const { return ((b.value&2) & (value&2)) | (!(b.value&2)&(value == b.value)); }
bool operator != (lbool b) const { return !(*this == b); }
lbool operator ^ (bool b) const { return lbool((uint8_t)(value^(uint8_t)b)); }
lbool operator && (lbool b) const {
uint8_t sel = (this->value << 1) | (b.value << 3);
uint8_t v = (0xF7F755F4 >> sel) & 3;
return lbool(v); }
lbool operator || (lbool b) const {
uint8_t sel = (this->value << 1) | (b.value << 3);
uint8_t v = (0xFCFCF400 >> sel) & 3;
return lbool(v); }
friend int toInt (lbool l);
friend lbool toLbool(int v);
};
inline int toInt (lbool l) { return l.value; }
inline lbool toLbool(int v) { return lbool((uint8_t)v); }
#if defined(MINISAT_CONSTANTS_AS_MACROS)
#define l_True (lbool((uint8_t)0)) // gcc does not do constant propagation if these are real constants.
#define l_False (lbool((uint8_t)1))
#define l_Undef (lbool((uint8_t)2))
#else
const lbool l_True ((uint8_t)0);
const lbool l_False((uint8_t)1);
const lbool l_Undef((uint8_t)2);
#endif
//=================================================================================================
// Clause -- a simple class for representing a clause:
class Clause;
typedef RegionAllocator<uint32_t>::Ref CRef;
class Clause {
struct {
unsigned mark : 2;
unsigned learnt : 1;
unsigned has_extra : 1;
unsigned reloced : 1;
unsigned size : 27; } header;
union { Lit lit; float act; uint32_t abs; CRef rel; } data[0];
friend class ClauseAllocator;
// NOTE: This constructor cannot be used directly (doesn't allocate enough memory).
Clause(const vec<Lit>& ps, bool use_extra, bool learnt) {
header.mark = 0;
header.learnt = learnt;
header.has_extra = use_extra;
header.reloced = 0;
header.size = ps.size();
for (int i = 0; i < ps.size(); i++)
data[i].lit = ps[i];
if (header.has_extra){
if (header.learnt)
data[header.size].act = 0;
else
calcAbstraction();
}
}
// NOTE: This constructor cannot be used directly (doesn't allocate enough memory).
Clause(const Clause& from, bool use_extra){
header = from.header;
header.has_extra = use_extra; // NOTE: the copied clause may lose the extra field.
for (int i = 0; i < from.size(); i++)
data[i].lit = from[i];
if (header.has_extra){
if (header.learnt)
data[header.size].act = from.data[header.size].act;
else
data[header.size].abs = from.data[header.size].abs;
}
}
public:
void calcAbstraction() {
assert(header.has_extra);
uint32_t abstraction = 0;
for (int i = 0; i < size(); i++)
abstraction |= 1 << (var(data[i].lit) & 31);
data[header.size].abs = abstraction; }
int size () const { return header.size; }
void shrink (int i) { assert(i <= size()); if (header.has_extra) data[header.size-i] = data[header.size]; header.size -= i; }
void pop () { shrink(1); }
bool learnt () const { return header.learnt; }
bool has_extra () const { return header.has_extra; }
uint32_t mark () const { return header.mark; }
void mark (uint32_t m) { header.mark = m; }
const Lit& last () const { return data[header.size-1].lit; }
bool reloced () const { return header.reloced; }
CRef relocation () const { return data[0].rel; }
void relocate (CRef c) { header.reloced = 1; data[0].rel = c; }
// NOTE: somewhat unsafe to change the clause in-place! Must manually call 'calcAbstraction' afterwards for
// subsumption operations to behave correctly.
Lit& operator [] (int i) { return data[i].lit; }
Lit operator [] (int i) const { return data[i].lit; }
operator const Lit* (void) const { return (Lit*)data; }
float& activity () { assert(header.has_extra); return data[header.size].act; }
uint32_t abstraction () const { assert(header.has_extra); return data[header.size].abs; }
Lit subsumes (const Clause& other) const;
void strengthen (Lit p);
};
//=================================================================================================
// ClauseAllocator -- a simple class for allocating memory for clauses:
const CRef CRef_Undef = RegionAllocator<uint32_t>::Ref_Undef;
class ClauseAllocator
{
RegionAllocator<uint32_t> ra;
static uint32_t clauseWord32Size(int size, bool has_extra){
return (sizeof(Clause) + (sizeof(Lit) * (size + (int)has_extra))) / sizeof(uint32_t); }
public:
enum { Unit_Size = RegionAllocator<uint32_t>::Unit_Size };
bool extra_clause_field;
ClauseAllocator(uint32_t start_cap) : ra(start_cap), extra_clause_field(false){}
ClauseAllocator() : extra_clause_field(false){}
void moveTo(ClauseAllocator& to){
to.extra_clause_field = extra_clause_field;
ra.moveTo(to.ra); }
CRef alloc(const vec<Lit>& ps, bool learnt = false)
{
assert(sizeof(Lit) == sizeof(uint32_t));
assert(sizeof(float) == sizeof(uint32_t));
bool use_extra = learnt | extra_clause_field;
CRef cid = ra.alloc(clauseWord32Size(ps.size(), use_extra));
new (lea(cid)) Clause(ps, use_extra, learnt);
return cid;
}
CRef alloc(const Clause& from)
{
bool use_extra = from.learnt() | extra_clause_field;
CRef cid = ra.alloc(clauseWord32Size(from.size(), use_extra));
new (lea(cid)) Clause(from, use_extra);
return cid; }
uint32_t size () const { return ra.size(); }
uint32_t wasted () const { return ra.wasted(); }
// Deref, Load Effective Address (LEA), Inverse of LEA (AEL):
Clause& operator[](CRef r) { return (Clause&)ra[r]; }
const Clause& operator[](CRef r) const { return (Clause&)ra[r]; }
Clause* lea (CRef r) { return (Clause*)ra.lea(r); }
const Clause* lea (CRef r) const { return (Clause*)ra.lea(r);; }
CRef ael (const Clause* t){ return ra.ael((uint32_t*)t); }
void free(CRef cid)
{
Clause& c = operator[](cid);
ra.free(clauseWord32Size(c.size(), c.has_extra()));
}
void reloc(CRef& cr, ClauseAllocator& to)
{
Clause& c = operator[](cr);
if (c.reloced()) { cr = c.relocation(); return; }
cr = to.alloc(c);
c.relocate(cr);
}
};
//=================================================================================================
// Simple iterator classes (for iterating over clauses and top-level assignments):
class ClauseIterator {
const ClauseAllocator& ca;
const CRef* crefs;
public:
ClauseIterator(const ClauseAllocator& _ca, const CRef* _crefs) : ca(_ca), crefs(_crefs){}
void operator++(){ crefs++; }
const Clause& operator*() const { return ca[*crefs]; }
// NOTE: does not compare that references use the same clause-allocator:
bool operator==(const ClauseIterator& ci) const { return crefs == ci.crefs; }
bool operator!=(const ClauseIterator& ci) const { return crefs != ci.crefs; }
};
class TrailIterator {
const Lit* lits;
public:
TrailIterator(const Lit* _lits) : lits(_lits){}
void operator++() { lits++; }
Lit operator*() const { return *lits; }
bool operator==(const TrailIterator& ti) const { return lits == ti.lits; }
bool operator!=(const TrailIterator& ti) const { return lits != ti.lits; }
};
//=================================================================================================
// OccLists -- a class for maintaining occurence lists with lazy deletion:
template<class K, class Vec, class Deleted, class MkIndex = MkIndexDefault<K> >
class OccLists
{
IntMap<K, Vec, MkIndex> occs;
IntMap<K, char, MkIndex> dirty;
vec<K> dirties;
Deleted deleted;
public:
OccLists(const Deleted& d, MkIndex _index = MkIndex()) :
occs(_index),
dirty(_index),
deleted(d){}
void init (const K& idx){ occs.reserve(idx); occs[idx].clear(); dirty.reserve(idx, 0); }
Vec& operator[](const K& idx){ return occs[idx]; }
Vec& lookup (const K& idx){ if (dirty[idx]) clean(idx); return occs[idx]; }
void cleanAll ();
void clean (const K& idx);
void smudge (const K& idx){
if (dirty[idx] == 0){
dirty[idx] = 1;
dirties.push(idx);
}
}
void clear(bool free = true){
occs .clear(free);
dirty .clear(free);
dirties.clear(free);
}
};
template<class K, class Vec, class Deleted, class MkIndex>
void OccLists<K,Vec,Deleted,MkIndex>::cleanAll()
{
for (int i = 0; i < dirties.size(); i++)
// Dirties may contain duplicates so check here if a variable is already cleaned:
if (dirty[dirties[i]])
clean(dirties[i]);
dirties.clear();
}
template<class K, class Vec, class Deleted, class MkIndex>
void OccLists<K,Vec,Deleted,MkIndex>::clean(const K& idx)
{
Vec& vec = occs[idx];
int i, j;
for (i = j = 0; i < vec.size(); i++)
if (!deleted(vec[i]))
vec[j++] = vec[i];
vec.shrink(i - j);
dirty[idx] = 0;
}
//=================================================================================================
// CMap -- a class for mapping clauses to values:
template<class T>
class CMap
{
struct CRefHash {
uint32_t operator()(CRef cr) const { return (uint32_t)cr; } };
typedef Map<CRef, T, CRefHash> HashTable;
HashTable map;
public:
// Size-operations:
void clear () { map.clear(); }
int size () const { return map.elems(); }
// Insert/Remove/Test mapping:
void insert (CRef cr, const T& t){ map.insert(cr, t); }
void growTo (CRef cr, const T& t){ map.insert(cr, t); } // NOTE: for compatibility
void remove (CRef cr) { map.remove(cr); }
bool has (CRef cr, T& t) { return map.peek(cr, t); }
// Vector interface (the clause 'c' must already exist):
const T& operator [] (CRef cr) const { return map[cr]; }
T& operator [] (CRef cr) { return map[cr]; }
// Iteration (not transparent at all at the moment):
int bucket_count() const { return map.bucket_count(); }
const vec<typename HashTable::Pair>& bucket(int i) const { return map.bucket(i); }
// Move contents to other map:
void moveTo(CMap& other){ map.moveTo(other.map); }
// TMP debug:
void debug(){
printf(" --- size = %d, bucket_count = %d\n", size(), map.bucket_count()); }
};
/*_________________________________________________________________________________________________
|
| subsumes : (other : const Clause&) -> Lit
|
| Description:
| Checks if clause subsumes 'other', and at the same time, if it can be used to simplify 'other'
| by subsumption resolution.
|
| Result:
| lit_Error - No subsumption or simplification
| lit_Undef - Clause subsumes 'other'
| p - The literal p can be deleted from 'other'
|________________________________________________________________________________________________@*/
inline Lit Clause::subsumes(const Clause& other) const
{
//if (other.size() < size() || (extra.abst & ~other.extra.abst) != 0)
//if (other.size() < size() || (!learnt() && !other.learnt() && (extra.abst & ~other.extra.abst) != 0))
assert(!header.learnt); assert(!other.header.learnt);
assert(header.has_extra); assert(other.header.has_extra);
if (other.header.size < header.size || (data[header.size].abs & ~other.data[other.header.size].abs) != 0)
return lit_Error;
Lit ret = lit_Undef;
const Lit* c = (const Lit*)(*this);
const Lit* d = (const Lit*)other;
for (unsigned i = 0; i < header.size; i++) {
// search for c[i] or ~c[i]
for (unsigned j = 0; j < other.header.size; j++)
if (c[i] == d[j])
goto ok;
else if (ret == lit_Undef && c[i] == ~d[j]){
ret = c[i];
goto ok;
}
// did not find it
return lit_Error;
ok:;
}
return ret;
}
inline void Clause::strengthen(Lit p)
{
remove(*this, p);
calcAbstraction();
}
//=================================================================================================
}
#endif

98
libs/minisat/Sort.h Normal file
View file

@ -0,0 +1,98 @@
/******************************************************************************************[Sort.h]
Copyright (c) 2003-2007, Niklas Een, Niklas Sorensson
Copyright (c) 2007-2010, Niklas Sorensson
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
**************************************************************************************************/
#ifndef Minisat_Sort_h
#define Minisat_Sort_h
#include "Vec.h"
//=================================================================================================
// Some sorting algorithms for vec's
namespace Minisat {
template<class T>
struct LessThan_default {
bool operator () (T x, T y) { return x < y; }
};
template <class T, class LessThan>
void selectionSort(T* array, int size, LessThan lt)
{
int i, j, best_i;
T tmp;
for (i = 0; i < size-1; i++){
best_i = i;
for (j = i+1; j < size; j++){
if (lt(array[j], array[best_i]))
best_i = j;
}
tmp = array[i]; array[i] = array[best_i]; array[best_i] = tmp;
}
}
template <class T> static inline void selectionSort(T* array, int size) {
selectionSort(array, size, LessThan_default<T>()); }
template <class T, class LessThan>
void sort(T* array, int size, LessThan lt)
{
if (size <= 15)
selectionSort(array, size, lt);
else{
T pivot = array[size / 2];
T tmp;
int i = -1;
int j = size;
for(;;){
do i++; while(lt(array[i], pivot));
do j--; while(lt(pivot, array[j]));
if (i >= j) break;
tmp = array[i]; array[i] = array[j]; array[j] = tmp;
}
sort(array , i , lt);
sort(&array[i], size-i, lt);
}
}
template <class T> static inline void sort(T* array, int size) {
sort(array, size, LessThan_default<T>()); }
//=================================================================================================
// For 'vec's:
template <class T, class LessThan> void sort(vec<T>& v, LessThan lt) {
sort((T*)v, v.size(), lt); }
template <class T> void sort(vec<T>& v) {
sort(v, LessThan_default<T>()); }
//=================================================================================================
}
#endif

171
libs/minisat/System.cc Normal file
View file

@ -0,0 +1,171 @@
#define __STDC_FORMAT_MACROS
#define __STDC_LIMIT_MACROS
/***************************************************************************************[System.cc]
Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
Copyright (c) 2007-2010, Niklas Sorensson
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
**************************************************************************************************/
#include <signal.h>
#include <stdio.h>
#include "System.h"
#if defined(__linux__)
#include <stdlib.h>
using namespace Minisat;
static inline int memReadStat(int field)
{
char name[256];
pid_t pid = getpid();
int value;
sprintf(name, "/proc/%d/statm", pid);
FILE* in = fopen(name, "rb");
if (in == NULL) return 0;
for (; field >= 0; field--)
if (fscanf(in, "%d", &value) != 1)
printf("ERROR! Failed to parse memory statistics from \"/proc\".\n"), exit(1);
fclose(in);
return value;
}
static inline int memReadPeak(void)
{
char name[256];
pid_t pid = getpid();
sprintf(name, "/proc/%d/status", pid);
FILE* in = fopen(name, "rb");
if (in == NULL) return 0;
// Find the correct line, beginning with "VmPeak:":
int peak_kb = 0;
while (!feof(in) && fscanf(in, "VmPeak: %d kB", &peak_kb) != 1)
while (!feof(in) && fgetc(in) != '\n')
;
fclose(in);
return peak_kb;
}
double Minisat::memUsed() { return (double)memReadStat(0) * (double)getpagesize() / (1024*1024); }
double Minisat::memUsedPeak(bool strictlyPeak) {
double peak = memReadPeak() / (double)1024;
return peak == 0 && !strictlyPeak ? memUsed() : peak; }
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__gnu_hurd__)
double Minisat::memUsed() {
struct rusage ru;
getrusage(RUSAGE_SELF, &ru);
return (double)ru.ru_maxrss / 1024; }
double Minisat::memUsedPeak(bool) { return memUsed(); }
#elif defined(__APPLE__)
#include <malloc/malloc.h>
double Minisat::memUsed() {
malloc_statistics_t t;
malloc_zone_statistics(NULL, &t);
return (double)t.max_size_in_use / (1024*1024); }
double Minisat::memUsedPeak(bool) { return memUsed(); }
#else
double Minisat::memUsed() { return 0; }
double Minisat::memUsedPeak(bool) { return 0; }
#endif
void Minisat::setX86FPUPrecision()
{
#if defined(__linux__) && defined(_FPU_EXTENDED) && defined(_FPU_DOUBLE) && defined(_FPU_GETCW)
// Only correct FPU precision on Linux architectures that needs and supports it:
fpu_control_t oldcw, newcw;
_FPU_GETCW(oldcw); newcw = (oldcw & ~_FPU_EXTENDED) | _FPU_DOUBLE; _FPU_SETCW(newcw);
printf("WARNING: for repeatability, setting FPU to use double precision\n");
#endif
}
#if !defined(_MSC_VER) && !defined(__MINGW32__)
void Minisat::limitMemory(uint64_t max_mem_mb)
{
// FIXME: OpenBSD does not support RLIMIT_AS. Not sure how well RLIMIT_DATA works instead.
#if defined(__OpenBSD__)
#define RLIMIT_AS RLIMIT_DATA
#endif
// Set limit on virtual memory:
if (max_mem_mb != 0){
rlim_t new_mem_lim = (rlim_t)max_mem_mb * 1024*1024;
rlimit rl;
getrlimit(RLIMIT_AS, &rl);
if (rl.rlim_max == RLIM_INFINITY || new_mem_lim < rl.rlim_max){
rl.rlim_cur = new_mem_lim;
if (setrlimit(RLIMIT_AS, &rl) == -1)
printf("WARNING! Could not set resource limit: Virtual memory.\n");
}
}
#if defined(__OpenBSD__)
#undef RLIMIT_AS
#endif
}
#else
void Minisat::limitMemory(uint64_t /*max_mem_mb*/)
{
printf("WARNING! Memory limit not supported on this architecture.\n");
}
#endif
#if !defined(_MSC_VER) && !defined(__MINGW32__)
void Minisat::limitTime(uint32_t max_cpu_time)
{
if (max_cpu_time != 0){
rlimit rl;
getrlimit(RLIMIT_CPU, &rl);
if (rl.rlim_max == RLIM_INFINITY || (rlim_t)max_cpu_time < rl.rlim_max){
rl.rlim_cur = max_cpu_time;
if (setrlimit(RLIMIT_CPU, &rl) == -1)
printf("WARNING! Could not set resource limit: CPU-time.\n");
}
}
}
#else
void Minisat::limitTime(uint32_t /*max_cpu_time*/)
{
printf("WARNING! CPU-time limit not supported on this architecture.\n");
}
#endif
void Minisat::sigTerm(void handler(int))
{
signal(SIGINT, handler);
signal(SIGTERM,handler);
#ifdef SIGXCPU
signal(SIGXCPU,handler);
#endif
}

72
libs/minisat/System.h Normal file
View file

@ -0,0 +1,72 @@
/****************************************************************************************[System.h]
Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson
Copyright (c) 2007-2010, Niklas Sorensson
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
**************************************************************************************************/
#ifndef Minisat_System_h
#define Minisat_System_h
#if defined(__linux__)
#include <fpu_control.h>
#endif
#include "IntTypes.h"
//-------------------------------------------------------------------------------------------------
namespace Minisat {
static inline double cpuTime(void); // CPU-time in seconds.
extern double memUsed(); // Memory in mega bytes (returns 0 for unsupported architectures).
extern double memUsedPeak(bool strictlyPeak = false); // Peak-memory in mega bytes (returns 0 for unsupported architectures).
extern void setX86FPUPrecision(); // Make sure double's are represented with the same precision
// in memory and registers.
extern void limitMemory(uint64_t max_mem_mb); // Set a limit on total memory usage. The exact
// semantics varies depending on architecture.
extern void limitTime(uint32_t max_cpu_time); // Set a limit on maximum CPU time. The exact
// semantics varies depending on architecture.
extern void sigTerm(void handler(int)); // Set up handling of available termination signals.
}
//-------------------------------------------------------------------------------------------------
// Implementation of inline functions:
#if defined(_MSC_VER) || defined(__MINGW32__)
#include <time.h>
static inline double Minisat::cpuTime(void) { return (double)clock() / CLOCKS_PER_SEC; }
#else
#include <sys/time.h>
#include <sys/resource.h>
#include <unistd.h>
static inline double Minisat::cpuTime(void) {
struct rusage ru;
getrusage(RUSAGE_SELF, &ru);
return (double)ru.ru_utime.tv_sec + (double)ru.ru_utime.tv_usec / 1000000; }
#endif
#endif

134
libs/minisat/Vec.h Normal file
View file

@ -0,0 +1,134 @@
/*******************************************************************************************[Vec.h]
Copyright (c) 2003-2007, Niklas Een, Niklas Sorensson
Copyright (c) 2007-2010, Niklas Sorensson
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
**************************************************************************************************/
#ifndef Minisat_Vec_h
#define Minisat_Vec_h
#include <assert.h>
#include <limits>
#include <new>
#include "IntTypes.h"
#include "XAlloc.h"
namespace Minisat {
//=================================================================================================
// Automatically resizable arrays
//
// NOTE! Don't use this vector on datatypes that cannot be re-located in memory (with realloc)
template<class T, class _Size = int>
class vec {
public:
typedef _Size Size;
private:
T* data;
Size sz;
Size cap;
// Don't allow copying (error prone):
vec<T>& operator=(vec<T>& other);
vec (vec<T>& other);
static inline Size max(Size x, Size y){ return (x > y) ? x : y; }
public:
// Constructors:
vec() : data(NULL), sz(0), cap(0) { }
explicit vec(Size size) : data(NULL), sz(0), cap(0) { growTo(size); }
vec(Size size, const T& pad) : data(NULL), sz(0), cap(0) { growTo(size, pad); }
~vec() { clear(true); }
// Pointer to first element:
operator T* (void) { return data; }
// Size operations:
Size size (void) const { return sz; }
void shrink (Size nelems) { assert(nelems <= sz); for (Size i = 0; i < nelems; i++) sz--, data[sz].~T(); }
void shrink_ (Size nelems) { assert(nelems <= sz); sz -= nelems; }
int capacity (void) const { return cap; }
void capacity (Size min_cap);
void growTo (Size size);
void growTo (Size size, const T& pad);
void clear (bool dealloc = false);
// Stack interface:
void push (void) { if (sz == cap) capacity(sz+1); new (&data[sz]) T(); sz++; }
//void push (const T& elem) { if (sz == cap) capacity(sz+1); data[sz++] = elem; }
void push (const T& elem) { if (sz == cap) capacity(sz+1); new (&data[sz++]) T(elem); }
void push_ (const T& elem) { assert(sz < cap); data[sz++] = elem; }
void pop (void) { assert(sz > 0); sz--, data[sz].~T(); }
// NOTE: it seems possible that overflow can happen in the 'sz+1' expression of 'push()', but
// in fact it can not since it requires that 'cap' is equal to INT_MAX. This in turn can not
// happen given the way capacities are calculated (below). Essentially, all capacities are
// even, but INT_MAX is odd.
const T& last (void) const { return data[sz-1]; }
T& last (void) { return data[sz-1]; }
// Vector interface:
const T& operator [] (Size index) const { return data[index]; }
T& operator [] (Size index) { return data[index]; }
// Duplicatation (preferred instead):
void copyTo(vec<T>& copy) const { copy.clear(); copy.growTo(sz); for (Size i = 0; i < sz; i++) copy[i] = data[i]; }
void moveTo(vec<T>& dest) { dest.clear(true); dest.data = data; dest.sz = sz; dest.cap = cap; data = NULL; sz = 0; cap = 0; }
};
template<class T, class _Size>
void vec<T,_Size>::capacity(Size min_cap) {
if (cap >= min_cap) return;
Size add = max((min_cap - cap + 1) & ~1, ((cap >> 1) + 2) & ~1); // NOTE: grow by approximately 3/2
const Size size_max = std::numeric_limits<Size>::max();
if ( ((size_max <= std::numeric_limits<int>::max()) && (add > size_max - cap))
|| (((data = (T*)::realloc(data, (cap += add) * sizeof(T))) == NULL) && errno == ENOMEM) )
throw OutOfMemoryException();
}
template<class T, class _Size>
void vec<T,_Size>::growTo(Size size, const T& pad) {
if (sz >= size) return;
capacity(size);
for (Size i = sz; i < size; i++) data[i] = pad;
sz = size; }
template<class T, class _Size>
void vec<T,_Size>::growTo(Size size) {
if (sz >= size) return;
capacity(size);
for (Size i = sz; i < size; i++) new (&data[i]) T();
sz = size; }
template<class T, class _Size>
void vec<T,_Size>::clear(bool dealloc) {
if (data != NULL){
for (Size i = 0; i < sz; i++) data[i].~T();
sz = 0;
if (dealloc) free(data), data = NULL, cap = 0; } }
//=================================================================================================
}
#endif

45
libs/minisat/XAlloc.h Normal file
View file

@ -0,0 +1,45 @@
/****************************************************************************************[XAlloc.h]
Copyright (c) 2009-2010, Niklas Sorensson
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or
substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
**************************************************************************************************/
#ifndef Minisat_XAlloc_h
#define Minisat_XAlloc_h
#include <errno.h>
#include <stdlib.h>
namespace Minisat {
//=================================================================================================
// Simple layer on top of malloc/realloc to catch out-of-memory situtaions and provide some typing:
class OutOfMemoryException{};
static inline void* xrealloc(void *ptr, size_t size)
{
void* mem = realloc(ptr, size);
if (mem == NULL && errno == ENOMEM){
throw OutOfMemoryException();
}else
return mem;
}
//=================================================================================================
}
#endif

View file

@ -1,185 +1,270 @@
/*
Copyright (c) 2011, Micael Hildenborg
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of Micael Hildenborg nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
Contributors:
Gustav
Several members in the gamedev.se forum.
Gregory Petrosyan
*/
#include "sha1.h"
namespace sha1
{
namespace // local
{
// Rotate an integer value to left.
inline unsigned int rol(const unsigned int value,
const unsigned int steps)
{
return ((value << steps) | (value >> (32 - steps)));
}
// Sets the first 16 integers in the buffert to zero.
// Used for clearing the W buffert.
inline void clearWBuffert(unsigned int* buffert)
{
for (int pos = 16; --pos >= 0;)
{
buffert[pos] = 0;
}
}
void innerHash(unsigned int* result, unsigned int* w)
{
unsigned int a = result[0];
unsigned int b = result[1];
unsigned int c = result[2];
unsigned int d = result[3];
unsigned int e = result[4];
int round = 0;
#define sha1macro(func,val) \
{ \
const unsigned int t = rol(a, 5) + (func) + e + val + w[round]; \
e = d; \
d = c; \
c = rol(b, 30); \
b = a; \
a = t; \
}
while (round < 16)
{
sha1macro((b & c) | (~b & d), 0x5a827999)
++round;
}
while (round < 20)
{
w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
sha1macro((b & c) | (~b & d), 0x5a827999)
++round;
}
while (round < 40)
{
w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
sha1macro(b ^ c ^ d, 0x6ed9eba1)
++round;
}
while (round < 60)
{
w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
sha1macro((b & c) | (b & d) | (c & d), 0x8f1bbcdc)
++round;
}
while (round < 80)
{
w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1);
sha1macro(b ^ c ^ d, 0xca62c1d6)
++round;
}
#undef sha1macro
result[0] += a;
result[1] += b;
result[2] += c;
result[3] += d;
result[4] += e;
}
} // namespace
void calc(const void* src, const int bytelength, unsigned char* hash)
{
// Init the result array.
unsigned int result[5] = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 };
// Cast the void src pointer to be the byte array we can work with.
const unsigned char* sarray = (const unsigned char*) src;
// The reusable round buffer
unsigned int w[80];
// Loop through all complete 64byte blocks.
const int endOfFullBlocks = bytelength - 64;
int endCurrentBlock;
int currentBlock = 0;
while (currentBlock <= endOfFullBlocks)
{
endCurrentBlock = currentBlock + 64;
// Init the round buffer with the 64 byte block data.
for (int roundPos = 0; currentBlock < endCurrentBlock; currentBlock += 4)
{
// This line will swap endian on big endian and keep endian on little endian.
w[roundPos++] = (unsigned int) sarray[currentBlock + 3]
| (((unsigned int) sarray[currentBlock + 2]) << 8)
| (((unsigned int) sarray[currentBlock + 1]) << 16)
| (((unsigned int) sarray[currentBlock]) << 24);
}
innerHash(result, w);
}
// Handle the last and not full 64 byte block if existing.
endCurrentBlock = bytelength - currentBlock;
clearWBuffert(w);
int lastBlockBytes = 0;
for (;lastBlockBytes < endCurrentBlock; ++lastBlockBytes)
{
w[lastBlockBytes >> 2] |= (unsigned int) sarray[lastBlockBytes + currentBlock] << ((3 - (lastBlockBytes & 3)) << 3);
}
w[lastBlockBytes >> 2] |= 0x80 << ((3 - (lastBlockBytes & 3)) << 3);
if (endCurrentBlock >= 56)
{
innerHash(result, w);
clearWBuffert(w);
}
w[15] = bytelength << 3;
innerHash(result, w);
// Store hash in result pointer, and make sure we get in in the correct order on both endian models.
for (int hashByte = 20; --hashByte >= 0;)
{
hash[hashByte] = (result[hashByte >> 2] >> (((3 - hashByte) & 0x3) << 3)) & 0xff;
}
}
void toHexString(const unsigned char* hash, char* hexstring)
{
const char hexDigits[] = { "0123456789abcdef" };
for (int hashByte = 20; --hashByte >= 0;)
{
hexstring[hashByte << 1] = hexDigits[(hash[hashByte] >> 4) & 0xf];
hexstring[(hashByte << 1) + 1] = hexDigits[hash[hashByte] & 0xf];
}
hexstring[40] = 0;
}
} // namespace sha1
/*
sha1.cpp - source code of
============
SHA-1 in C++
============
100% Public Domain.
Original C Code
-- Steve Reid <steve@edmweb.com>
Small changes to fit into bglibs
-- Bruce Guenter <bruce@untroubled.org>
Translation to simpler C++ Code
-- Volker Grabsch <vog@notjusthosting.com>
*/
#include "sha1.h"
#include <sstream>
#include <iomanip>
#include <fstream>
/* Help macros */
#define SHA1_ROL(value, bits) (((value) << (bits)) | (((value) & 0xffffffff) >> (32 - (bits))))
#define SHA1_BLK(i) (block[i&15] = SHA1_ROL(block[(i+13)&15] ^ block[(i+8)&15] ^ block[(i+2)&15] ^ block[i&15],1))
/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
#define SHA1_R0(v,w,x,y,z,i) z += ((w&(x^y))^y) + block[i] + 0x5a827999 + SHA1_ROL(v,5); w=SHA1_ROL(w,30);
#define SHA1_R1(v,w,x,y,z,i) z += ((w&(x^y))^y) + SHA1_BLK(i) + 0x5a827999 + SHA1_ROL(v,5); w=SHA1_ROL(w,30);
#define SHA1_R2(v,w,x,y,z,i) z += (w^x^y) + SHA1_BLK(i) + 0x6ed9eba1 + SHA1_ROL(v,5); w=SHA1_ROL(w,30);
#define SHA1_R3(v,w,x,y,z,i) z += (((w|x)&y)|(w&x)) + SHA1_BLK(i) + 0x8f1bbcdc + SHA1_ROL(v,5); w=SHA1_ROL(w,30);
#define SHA1_R4(v,w,x,y,z,i) z += (w^x^y) + SHA1_BLK(i) + 0xca62c1d6 + SHA1_ROL(v,5); w=SHA1_ROL(w,30);
SHA1::SHA1()
{
reset();
}
void SHA1::update(const std::string &s)
{
std::istringstream is(s);
update(is);
}
void SHA1::update(std::istream &is)
{
std::string rest_of_buffer;
read(is, rest_of_buffer, BLOCK_BYTES - buffer.size());
buffer += rest_of_buffer;
while (is)
{
uint32 block[BLOCK_INTS];
buffer_to_block(buffer, block);
transform(block);
read(is, buffer, BLOCK_BYTES);
}
}
/*
* Add padding and return the message digest.
*/
std::string SHA1::final()
{
/* Total number of hashed bits */
uint64 total_bits = (transforms*BLOCK_BYTES + buffer.size()) * 8;
/* Padding */
buffer += 0x80;
unsigned int orig_size = buffer.size();
while (buffer.size() < BLOCK_BYTES)
{
buffer += (char)0x00;
}
uint32 block[BLOCK_INTS];
buffer_to_block(buffer, block);
if (orig_size > BLOCK_BYTES - 8)
{
transform(block);
for (unsigned int i = 0; i < BLOCK_INTS - 2; i++)
{
block[i] = 0;
}
}
/* Append total_bits, split this uint64 into two uint32 */
block[BLOCK_INTS - 1] = total_bits;
block[BLOCK_INTS - 2] = (total_bits >> 32);
transform(block);
/* Hex std::string */
std::ostringstream result;
for (unsigned int i = 0; i < DIGEST_INTS; i++)
{
result << std::hex << std::setfill('0') << std::setw(8);
result << (digest[i] & 0xffffffff);
}
/* Reset for next run */
reset();
return result.str();
}
std::string SHA1::from_file(const std::string &filename)
{
std::ifstream stream(filename.c_str(), std::ios::binary);
SHA1 checksum;
checksum.update(stream);
return checksum.final();
}
void SHA1::reset()
{
/* SHA1 initialization constants */
digest[0] = 0x67452301;
digest[1] = 0xefcdab89;
digest[2] = 0x98badcfe;
digest[3] = 0x10325476;
digest[4] = 0xc3d2e1f0;
/* Reset counters */
transforms = 0;
buffer = "";
}
/*
* Hash a single 512-bit block. This is the core of the algorithm.
*/
void SHA1::transform(uint32 block[BLOCK_BYTES])
{
/* Copy digest[] to working vars */
uint32 a = digest[0];
uint32 b = digest[1];
uint32 c = digest[2];
uint32 d = digest[3];
uint32 e = digest[4];
/* 4 rounds of 20 operations each. Loop unrolled. */
SHA1_R0(a,b,c,d,e, 0);
SHA1_R0(e,a,b,c,d, 1);
SHA1_R0(d,e,a,b,c, 2);
SHA1_R0(c,d,e,a,b, 3);
SHA1_R0(b,c,d,e,a, 4);
SHA1_R0(a,b,c,d,e, 5);
SHA1_R0(e,a,b,c,d, 6);
SHA1_R0(d,e,a,b,c, 7);
SHA1_R0(c,d,e,a,b, 8);
SHA1_R0(b,c,d,e,a, 9);
SHA1_R0(a,b,c,d,e,10);
SHA1_R0(e,a,b,c,d,11);
SHA1_R0(d,e,a,b,c,12);
SHA1_R0(c,d,e,a,b,13);
SHA1_R0(b,c,d,e,a,14);
SHA1_R0(a,b,c,d,e,15);
SHA1_R1(e,a,b,c,d,16);
SHA1_R1(d,e,a,b,c,17);
SHA1_R1(c,d,e,a,b,18);
SHA1_R1(b,c,d,e,a,19);
SHA1_R2(a,b,c,d,e,20);
SHA1_R2(e,a,b,c,d,21);
SHA1_R2(d,e,a,b,c,22);
SHA1_R2(c,d,e,a,b,23);
SHA1_R2(b,c,d,e,a,24);
SHA1_R2(a,b,c,d,e,25);
SHA1_R2(e,a,b,c,d,26);
SHA1_R2(d,e,a,b,c,27);
SHA1_R2(c,d,e,a,b,28);
SHA1_R2(b,c,d,e,a,29);
SHA1_R2(a,b,c,d,e,30);
SHA1_R2(e,a,b,c,d,31);
SHA1_R2(d,e,a,b,c,32);
SHA1_R2(c,d,e,a,b,33);
SHA1_R2(b,c,d,e,a,34);
SHA1_R2(a,b,c,d,e,35);
SHA1_R2(e,a,b,c,d,36);
SHA1_R2(d,e,a,b,c,37);
SHA1_R2(c,d,e,a,b,38);
SHA1_R2(b,c,d,e,a,39);
SHA1_R3(a,b,c,d,e,40);
SHA1_R3(e,a,b,c,d,41);
SHA1_R3(d,e,a,b,c,42);
SHA1_R3(c,d,e,a,b,43);
SHA1_R3(b,c,d,e,a,44);
SHA1_R3(a,b,c,d,e,45);
SHA1_R3(e,a,b,c,d,46);
SHA1_R3(d,e,a,b,c,47);
SHA1_R3(c,d,e,a,b,48);
SHA1_R3(b,c,d,e,a,49);
SHA1_R3(a,b,c,d,e,50);
SHA1_R3(e,a,b,c,d,51);
SHA1_R3(d,e,a,b,c,52);
SHA1_R3(c,d,e,a,b,53);
SHA1_R3(b,c,d,e,a,54);
SHA1_R3(a,b,c,d,e,55);
SHA1_R3(e,a,b,c,d,56);
SHA1_R3(d,e,a,b,c,57);
SHA1_R3(c,d,e,a,b,58);
SHA1_R3(b,c,d,e,a,59);
SHA1_R4(a,b,c,d,e,60);
SHA1_R4(e,a,b,c,d,61);
SHA1_R4(d,e,a,b,c,62);
SHA1_R4(c,d,e,a,b,63);
SHA1_R4(b,c,d,e,a,64);
SHA1_R4(a,b,c,d,e,65);
SHA1_R4(e,a,b,c,d,66);
SHA1_R4(d,e,a,b,c,67);
SHA1_R4(c,d,e,a,b,68);
SHA1_R4(b,c,d,e,a,69);
SHA1_R4(a,b,c,d,e,70);
SHA1_R4(e,a,b,c,d,71);
SHA1_R4(d,e,a,b,c,72);
SHA1_R4(c,d,e,a,b,73);
SHA1_R4(b,c,d,e,a,74);
SHA1_R4(a,b,c,d,e,75);
SHA1_R4(e,a,b,c,d,76);
SHA1_R4(d,e,a,b,c,77);
SHA1_R4(c,d,e,a,b,78);
SHA1_R4(b,c,d,e,a,79);
/* Add the working vars back into digest[] */
digest[0] += a;
digest[1] += b;
digest[2] += c;
digest[3] += d;
digest[4] += e;
/* Count the number of transformations */
transforms++;
}
void SHA1::buffer_to_block(const std::string &buffer, uint32 block[BLOCK_BYTES])
{
/* Convert the std::string (byte buffer) to a uint32 array (MSB) */
for (unsigned int i = 0; i < BLOCK_INTS; i++)
{
block[i] = (buffer[4*i+3] & 0xff)
| (buffer[4*i+2] & 0xff)<<8
| (buffer[4*i+1] & 0xff)<<16
| (buffer[4*i+0] & 0xff)<<24;
}
}
void SHA1::read(std::istream &is, std::string &s, int max)
{
char sbuf[max];
is.read(sbuf, max);
s.assign(sbuf, is.gcount());
}
std::string sha1(const std::string &string)
{
SHA1 checksum;
checksum.update(string);
return checksum.final();
}

View file

@ -1,49 +1,57 @@
/*
Copyright (c) 2011, Micael Hildenborg
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of Micael Hildenborg nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef SHA1_DEFINED
#define SHA1_DEFINED
namespace sha1
{
/**
@param src points to any kind of data to be hashed.
@param bytelength the number of bytes to hash from the src pointer.
@param hash should point to a buffer of at least 20 bytes of size for storing the sha1 result in.
*/
void calc(const void* src, const int bytelength, unsigned char* hash);
/**
@param hash is 20 bytes of sha1 hash. This is the same data that is the result from the calc function.
@param hexstring should point to a buffer of at least 41 bytes of size for storing the hexadecimal representation of the hash. A zero will be written at position 40, so the buffer will be a valid zero ended string.
*/
void toHexString(const unsigned char* hash, char* hexstring);
} // namespace sha1
#endif // SHA1_DEFINED
/*
sha1.h - header of
============
SHA-1 in C++
============
100% Public Domain.
Original C Code
-- Steve Reid <steve@edmweb.com>
Small changes to fit into bglibs
-- Bruce Guenter <bruce@untroubled.org>
Translation to simpler C++ Code
-- Volker Grabsch <vog@notjusthosting.com>
*/
#ifndef SHA1_HPP
#define SHA1_HPP
#include <iostream>
#include <string>
class SHA1
{
public:
SHA1();
void update(const std::string &s);
void update(std::istream &is);
std::string final();
static std::string from_file(const std::string &filename);
private:
typedef unsigned long int uint32; /* just needs to be at least 32bit */
typedef unsigned long long uint64; /* just needs to be at least 64bit */
static const unsigned int DIGEST_INTS = 5; /* number of 32bit integers per SHA1 digest */
static const unsigned int BLOCK_INTS = 16; /* number of 32bit integers per SHA1 block */
static const unsigned int BLOCK_BYTES = BLOCK_INTS * 4;
uint32 digest[DIGEST_INTS];
std::string buffer;
uint64 transforms;
void reset();
void transform(uint32 block[BLOCK_BYTES]);
static void buffer_to_block(const std::string &buffer, uint32 block[BLOCK_BYTES]);
static void read(std::istream &is, std::string &s, int max);
};
std::string sha1(const std::string &string);
#endif /* SHA1_HPP */

View file

@ -26,8 +26,8 @@
#include <stdio.h>
#ifdef _YOSYS_
# include "kernel/log.h"
# define my_printf log
# include "kernel/yosys.h"
# define my_printf YOSYS_NAMESPACE_PREFIX log
#else
# define my_printf printf
#endif

View file

@ -1,5 +0,0 @@
Makefile
moc_mainwindow.cpp
moc_svgview.cpp
qrc_svgviewer.cpp
svgviewer

View file

@ -1,215 +0,0 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg width="20cm" height="15cm" viewBox="0 0 800 600"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink/"
baseProfile="tiny" version="1.2">
<title>Spheres</title>
<desc>Semi-transparent bubbles on a colored background.</desc>
<defs>
<!-- Create radial gradients for each bubble. -->
<radialGradient id="blueBubble" gradientUnits="userSpaceOnUse"
cx="0" cy="0" r="100" fx="-50" fy="-50">
<stop offset="0%" stop-color="white" stop-opacity="1" />
<stop offset="25%" stop-color="#cdcdff" stop-opacity=".65" />
<stop offset="100%" stop-color="#cdaacd" stop-opacity=".75" />
</radialGradient>
<radialGradient id="redBubble" gradientUnits="userSpaceOnUse"
cx="0" cy="0" r="100" fx="-50" fy="-50">
<stop offset="0%" stop-color="white" stop-opacity="1" />
<stop offset="25%" stop-color="#ffcdcd" stop-opacity=".65" />
<stop offset="100%" stop-color="#bbbb99" stop-opacity=".75" />
</radialGradient>
<radialGradient id="greenBubble" gradientUnits="userSpaceOnUse"
cx="0" cy="0" r="100" fx="-50" fy="-50">
<stop offset="0%" stop-color="white" stop-opacity="1" />
<stop offset="25%" stop-color="#cdffcd" stop-opacity=".65" />
<stop offset="100%" stop-color="#99aaaa" stop-opacity=".75" />
</radialGradient>
<radialGradient id="yellowBubble" gradientUnits="userSpaceOnUse"
cx="0" cy="0" r="100" fx="-50" fy="-50">
<stop offset="0%" stop-color="white" stop-opacity="1" />
<stop offset="25%" stop-color="#ffffcd" stop-opacity=".65" />
<stop offset="100%" stop-color="#bbbbaa" stop-opacity=".75" />
</radialGradient>
<radialGradient id="background" gradientUnits="userSpaceOnUse"
cx="0" cy="0" r="400" fx="250" fy="250">
<stop offset="0%" stop-color="#ffffee" />
<stop offset="100%" stop-color="#ccccaa" />
</radialGradient>
<linearGradient id="surface" gradientUnits="userSpaceOnUse"
x1="-100" y1="200" x2="400" y2="200">
<stop offset="0%" stop-color="#ffffcc" />
<stop offset="100%" stop-color="#bbbb88" />
</linearGradient>
<!-- Create radial gradients for each circle to make them look like
spheres. -->
<radialGradient id="blueSphere" gradientUnits="userSpaceOnUse"
cx="0" cy="0" r="100" fx="-50" fy="-50">
<stop offset="0%" stop-color="white" />
<stop offset="75%" stop-color="blue" />
<stop offset="100%" stop-color="#222244" />
</radialGradient>
<radialGradient id="redSphere" gradientUnits="userSpaceOnUse"
cx="0" cy="0" r="100" fx="-50" fy="-50">
<stop offset="0%" stop-color="white" />
<stop offset="75%" stop-color="red" />
<stop offset="100%" stop-color="#442222" />
</radialGradient>
<radialGradient id="greenSphere" gradientUnits="userSpaceOnUse"
cx="0" cy="0" r="100" fx="-50" fy="-50">
<stop offset="0%" stop-color="white" />
<stop offset="75%" stop-color="green" />
<stop offset="100%" stop-color="#113311" />
</radialGradient>
<radialGradient id="yellowSphere" gradientUnits="userSpaceOnUse"
cx="0" cy="0" r="100" fx="-50" fy="-50">
<stop offset="0%" stop-color="white" />
<stop offset="75%" stop-color="yellow" />
<stop offset="100%" stop-color="#444422" />
</radialGradient>
<radialGradient id="shadowGrad" gradientUnits="userSpaceOnUse"
cx="0" cy="0" r="100" fx="-50" fy="50">
<stop offset="0%" stop-color="black" stop-opacity="1.0" />
<stop offset="100%" stop-color="black" stop-opacity="0.0" />
</radialGradient>
<!-- Define a shadow for each sphere. -->
<circle id="shadow" fill="url(#shadowGrad)" cx="0" cy="0" r="100" />
<g id="bubble">
<circle fill="black" cx="0" cy="0" r="50" />
<circle fill="#a6ce39" cx="0" cy="0" r="33" />
<path fill="black" d="M 37,50 L 50,37 L 12,-1 L 22,-11 L 10,-24 L -24,10
L -11,22 L -1,12 Z" />
<circle cx="0" cy="0" r="100" />
</g>
</defs>
<g>
<rect fill="url(#background)" x="0" y="0" width="800" height="600" />
</g>
<g transform="translate(200,700)">
<use xlink:href="#bubble" fill="url(#blueBubble)" />
<animateTransform attributeName="transform" type="translate" additive="sum"
values="0,0; 0,-800" begin="1s" dur="10s" fill="freeze" repeatCount="indefinite" />
</g>
<g transform="translate(315,700)">
<g transform="scale(0.5,0.5)">
<use xlink:href="#bubble" fill="url(#redBubble)" />
</g>
<animateTransform attributeName="transform" type="translate" additive="sum"
values="0,0; 0,-800" begin="3s" dur="7s" fill="freeze" repeatCount="indefinite" />
</g>
<g transform="translate(80,700)">
<g transform="scale(0.65,0.65)">
<use xlink:href="#bubble" fill="url(#greenBubble)" />
</g>
<animateTransform attributeName="transform" type="translate" additive="sum"
values="0,0; 0,-800" begin="5s" dur="9s" fill="freeze" repeatCount="indefinite" />
</g>
<g transform="translate(255,700)">
<g transform="scale(0.3,0.3)">
<use xlink:href="#bubble" fill="url(#yellowBubble)" />
</g>
<animateTransform attributeName="transform" type="translate" additive="sum"
values="0,0; 0,-800" begin="2s" dur="6s" fill="freeze" repeatCount="indefinite" />
</g>
<g transform="translate(565,700)">
<g transform="scale(0.4,0.4)">
<use xlink:href="#bubble" fill="url(#blueBubble)" />
</g>
<animateTransform attributeName="transform" type="translate" additive="sum"
values="0,0; 0,-800" begin="4s" dur="8s" fill="freeze" repeatCount="indefinite" />
</g>
<g transform="translate(715,700)">
<g transform="scale(0.6,0.6)">
<use xlink:href="#bubble" fill="url(#redBubble)" />
</g>
<animateTransform attributeName="transform" type="translate" additive="sum"
values="0,0; 0,-800" begin="1s" dur="4s" fill="freeze" repeatCount="indefinite" />
</g>
<g transform="translate(645,700)">
<g transform="scale(0.375,0.375)">
<use xlink:href="#bubble" fill="url(#greenBubble)" />
</g>
<animateTransform attributeName="transform" type="translate" additive="sum"
values="0,0; 0,-800" begin="0s" dur="11s" fill="freeze" repeatCount="indefinite" />
</g>
<g transform="translate(555,700)">
<g transform="scale(0.9,0.9)">
<use xlink:href="#bubble" fill="url(#yellowBubble)" />
</g>
<animateTransform attributeName="transform" type="translate" additive="sum"
values="0,0; 0,-800" begin="3s" dur="7.5s" fill="freeze" repeatCount="indefinite" />
</g>
<g transform="translate(360,700)">
<g transform="scale(0.5,0.5)">
<use xlink:href="#bubble" fill="url(#blueBubble)" />
</g>
<animateTransform attributeName="transform" type="translate" additive="sum"
values="0,0; 0,-800" begin="3s" dur="6s" fill="freeze" repeatCount="indefinite" />
</g>
<g transform="translate(215,700)">
<g transform="scale(0.45,0.45)">
<use xlink:href="#bubble" fill="url(#redBubble)" />
</g>
<animateTransform attributeName="transform" type="translate" additive="sum"
values="0,0; 0,-800" begin="5.5s" dur="7s" fill="freeze" repeatCount="indefinite" />
</g>
<g transform="translate(420,700)">
<g transform="scale(0.75,0.75)">
<use xlink:href="#bubble" fill="url(#greenBubble)" />
</g>
<animateTransform attributeName="transform" type="translate" additive="sum"
values="0,0; 0,-800" begin="1s" dur="9s" fill="freeze" repeatCount="indefinite" />
</g>
<g transform="translate(815,700)">
<g transform="scale(0.6,0.6)">
<use xlink:href="#bubble" fill="url(#yellowBubble)" />
</g>
<animateTransform attributeName="transform" type="translate" additive="sum"
values="0,0; 0,-800" begin="2s" dur="9.5s" fill="freeze" repeatCount="indefinite" />
</g>
<g transform="translate(225,375)" >
<g transform="scale(1.0,0.5)" >
<path d="M 0 0 L 350 0 L 450 450 L -100 450 z"
fill="url(#surface)" stroke="none" />
</g>
</g>
<g transform="translate(200,0)" >
<g transform="translate(200,490) scale(2.0,1.0) rotate(45)" >
<rect fill="#a6ce39" x="-69" y="-69" width="138" height="138" />
<circle fill="black" cx="0" cy="0" r="50" />
<circle fill="#a6ce39" cx="0" cy="0" r="33" />
<path fill="black" d="M 37,50 L 50,37 L 12,-1 L 22,-11 L 10,-24 L -24,10
L -11,22 L -1,12 Z" />
<animateTransform attributeName="transform" type="rotate" additive="sum" values="0; 360"
begin="0s" dur="10s" fill="freeze" repeatCount="indefinite" />
</g>
<g transform="translate(200,375)">
<use xlink:href="#shadow" transform="translate(25,55) scale(1.0,0.5)" />
<circle fill="url(#blueSphere)" cx="0" cy="0" r="100" />
</g>
<g transform="translate(315,440)">
<g transform="scale(0.5,0.5)">
<use xlink:href="#shadow" transform="translate(25,55) scale(1.0,0.5)" />
<circle fill="url(#redSphere)" cx="0" cy="0" r="100" />
</g>
</g>
<g transform="translate(80,475)">
<g transform="scale(0.65,0.65)">
<use xlink:href="#shadow" transform="translate(25,55) scale(1.0,0.5)" />
<circle fill="url(#greenSphere)" cx="0" cy="0" r="100" />
</g>
</g>
<g transform="translate(255,525)">
<g transform="scale(0.3,0.3)">
<use xlink:href="#shadow" transform="translate(25,55) scale(1.0,0.5)" />
<circle fill="url(#yellowSphere)" cx="0" cy="0" r="100" />
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 9.9 KiB

View file

@ -1,77 +0,0 @@
<?xml version="1.0" standalone="no"?>
<svg width="10cm" height="10cm" viewBox="0 0 1000 1000"
xmlns="http://www.w3.org/2000/svg" version="1.2" baseProfile="tiny">
<title>Example cubic02 - cubic Bezier commands in path data</title>
<desc>Picture showing examples of "C" and "S" commands,
along with annotations showing the control points
and end points</desc>
<rect fill="none" stroke="blue" stroke-width="1" x="1" y="1" width="998" height="998" />
<!-- Path 1 -->
<polyline fill="none" stroke="#888888" stroke-width="2" points="100,200 100,100" />
<polyline fill="none" stroke="#888888" stroke-width="2" points="400,100 400,200" />
<path fill="none" stroke="red" stroke-width="5" d="M100,200 C100,100 400,100 400,200" />
<circle fill="none" stroke="#888888" stroke-width="2" cx="100" cy="200" r="10" />
<circle fill="none" stroke="#888888" stroke-width="2" cx="400" cy="200" r="10" />
<circle class="CtlPoint" cx="100" cy="100" r="10" />
<circle class="CtlPoint" cx="400" cy="100" r="10" />
<text text-anchor="middle" font-size="22" font-family="Verdana" x="250" y="275">M100,200 C100,100 400,100 400,200</text>
<!-- Path 2 -->
<polyline fill="none" stroke="#888888" stroke-width="2" points="100,500 25,400" />
<polyline fill="none" stroke="#888888" stroke-width="2" points="475,400 400,500" />
<path fill="none" stroke="red" stroke-width="5" d="M100,500 C25,400 475,400 400,500" />
<circle fill="none" stroke="#888888" stroke-width="2" cx="100" cy="500" r="10" />
<circle fill="none" stroke="#888888" stroke-width="2" cx="400" cy="500" r="10" />
<circle fill="#888888" stroke="none" cx="25" cy="400" r="10" />
<circle fill="#888888" stroke="none" cx="475" cy="400" r="10" />
<text text-anchor="middle" font-size="22" font-family="Verdana" x="250" y="575">M100,500 C25,400 475,400 400,500</text>
<!-- Path 3 -->
<polyline fill="none" stroke="#888888" stroke-width="2" points="100,800 175,700" />
<polyline fill="none" stroke="#888888" stroke-width="2" points="325,700 400,800" />
<path fill="none" stroke="red" stroke-width="5" d="M100,800 C175,700 325,700 400,800" />
<circle fill="none" stroke="#888888" stroke-width="2" cx="100" cy="800" r="10" />
<circle fill="none" stroke="#888888" stroke-width="2" cx="400" cy="800" r="10" />
<circle fill="#888888" stroke="none" cx="175" cy="700" r="10" />
<circle fill="#888888" stroke="none" cx="325" cy="700" r="10" />
<text text-anchor="middle" font-size="22" font-family="Verdana" x="250" y="875">M100,800 C175,700 325,700 400,800</text>
<!-- Path 4 -->
<polyline fill="none" stroke="#888888" stroke-width="2" points="600,200 675,100" />
<polyline fill="none" stroke="#888888" stroke-width="2" points="975,100 900,200" />
<path fill="none" stroke="red" stroke-width="5" d="M600,200 C675,100 975,100 900,200" />
<circle fill="none" stroke="#888888" stroke-width="2" cx="600" cy="200" r="10" />
<circle fill="none" stroke="#888888" stroke-width="2" cx="900" cy="200" r="10" />
<circle fill="#888888" stroke="none" cx="675" cy="100" r="10" />
<circle fill="#888888" stroke="none" cx="975" cy="100" r="10" />
<text text-anchor="middle" font-size="22" font-family="Verdana" x="750" y="275">M600,200 C675,100 975,100 900,200</text>
<!-- Path 5 -->
<polyline fill="none" stroke="#888888" stroke-width="2" points="600,500 600,350" />
<polyline fill="none" stroke="#888888" stroke-width="2" points="900,650 900,500" />
<path fill="none" stroke="red" stroke-width="5" d="M600,500 C600,350 900,650 900,500" />
<circle fill="none" stroke="#888888" stroke-width="2" cx="600" cy="500" r="10" />
<circle fill="none" stroke="#888888" stroke-width="2" cx="900" cy="500" r="10" />
<circle fill="#888888" stroke="none" cx="600" cy="350" r="10" />
<circle fill="#888888" stroke="none" cx="900" cy="650" r="10" />
<text text-anchor="middle" font-size="22" font-family="Verdana" x="750" y="575">M600,500 C600,350 900,650 900,500</text>
<!-- Path 6 (C and S command) -->
<polyline fill="none" stroke="#888888" stroke-width="2" points="600,800 625,700" />
<polyline fill="none" stroke="#888888" stroke-width="2" points="725,700 750,800" />
<polyline fill="none" stroke="#888888" stroke-width="2" points="750,800 775,900" />
<polyline fill="none" stroke="#888888" stroke-width="2" points="875,900 900,800" />
<path fill="none" stroke="red" stroke-width="5" d="M600,800 C625,700 725,700 750,800
S875,900 900,800" />
<circle fill="none" stroke="#888888" stroke-width="2" cx="600" cy="800" r="10" />
<circle fill="none" stroke="#888888" stroke-width="2" cx="750" cy="800" r="10" />
<circle fill="none" stroke="#888888" stroke-width="2" cx="900" cy="800" r="10" />
<circle fill="#888888" stroke="none" cx="625" cy="700" r="10" />
<circle fill="#888888" stroke="none" cx="725" cy="700" r="10" />
<circle fill="#888888" stroke="none" cx="875" cy="900" r="10" />
<circle fill="none" stroke="blue" stroke-width="4" cx="775" cy="900" r="9" />
<text text-anchor="middle" font-size="22" font-family="Verdana" x="750" y="945">M600,800 C625,700 725,700 750,800</text>
<text text-anchor="middle" font-size="22" font-family="Verdana" x="750" y="975">S875,900 900,800</text>
</svg>

Before

Width:  |  Height:  |  Size: 5.2 KiB

Some files were not shown because too many files have changed in this diff Show more