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:
commit
d3c67ad9b6
513 changed files with 34858 additions and 12079 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -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
149
CHANGELOG
|
@ -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
194
CodingReadme
Normal 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
261
Makefile
|
@ -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
176
README
|
@ -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)
|
||||
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
|
||||
OBJS += backends/autotest/autotest.o
|
||||
|
|
@ -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;
|
||||
|
|
@ -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 ¶m : 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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
@ -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
|
||||
|
|
|
@ -2,4 +2,5 @@
|
|||
OBJS += frontends/ast/ast.o
|
||||
OBJS += frontends/ast/simplify.o
|
||||
OBJS += frontends/ast/genrtlil.o
|
||||
OBJS += frontends/ast/dpicall.o
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
140
frontends/ast/dpicall.cc
Normal 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
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(¤t_process->root_case.switches);
|
||||
case_stack.clear();
|
||||
case_stack.push_back(¤t_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;
|
||||
};
|
||||
|
|
3
frontends/liberty/Makefile.inc
Normal file
3
frontends/liberty/Makefile.inc
Normal file
|
@ -0,0 +1,3 @@
|
|||
|
||||
OBJS += frontends/liberty/liberty.o
|
||||
|
578
frontends/liberty/liberty.cc
Normal file
578
frontends/liberty/liberty.cc
Normal 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
|
||||
|
16
frontends/verific/Makefile.inc
Normal file
16
frontends/verific/Makefile.inc
Normal 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
|
||||
|
31
frontends/verific/build_amd64.txt
Normal file
31
frontends/verific/build_amd64.txt
Normal 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
|
||||
|
18
frontends/verific/test_navre.ys
Normal file
18
frontends/verific/test_navre.ys
Normal 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
|
949
frontends/verific/verific.cc
Normal file
949
frontends/verific/verific.cc
Normal 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
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
1
frontends/vhdl2verilog/Makefile.inc
Normal file
1
frontends/vhdl2verilog/Makefile.inc
Normal file
|
@ -0,0 +1 @@
|
|||
OBJS += frontends/vhdl2verilog/vhdl2verilog.o
|
196
frontends/vhdl2verilog/vhdl2verilog.cc
Normal file
196
frontends/vhdl2verilog/vhdl2verilog.cc
Normal 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
|
||||
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
651
kernel/driver.cc
651
kernel/driver.cc
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
205
kernel/log.cc
205
kernel/log.cc
|
@ -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
|
||||
|
||||
|
|
120
kernel/log.h
120
kernel/log.h
|
@ -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
231
kernel/macc.h
Normal 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
455
kernel/modtools.h
Normal 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
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
2355
kernel/rtlil.cc
2355
kernel/rtlil.cc
File diff suppressed because it is too large
Load diff
938
kernel/rtlil.h
938
kernel/rtlil.h
File diff suppressed because it is too large
Load diff
641
kernel/satgen.h
641
kernel/satgen.h
|
@ -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
|
||||
|
||||
|
|
|
@ -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
210
kernel/utils.h
Normal 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
646
kernel/yosys.cc
Normal 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
149
kernel/yosys.h
Normal 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
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
|
|
20
libs/minisat/00_PATCH_mkLit_default_arg.patch
Normal file
20
libs/minisat/00_PATCH_mkLit_default_arg.patch
Normal 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; }
|
38
libs/minisat/00_PATCH_remove_zlib.patch
Normal file
38
libs/minisat/00_PATCH_remove_zlib.patch
Normal 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
17
libs/minisat/00_UPDATE.sh
Normal 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
84
libs/minisat/Alg.h
Normal 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
131
libs/minisat/Alloc.h
Normal 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
87
libs/minisat/Dimacs.h
Normal 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
168
libs/minisat/Heap.h
Normal 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
106
libs/minisat/IntMap.h
Normal 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
42
libs/minisat/IntTypes.h
Normal 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
21
libs/minisat/LICENSE
Normal 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
193
libs/minisat/Map.h
Normal 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
94
libs/minisat/Options.cc
Normal 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
386
libs/minisat/Options.h
Normal 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
119
libs/minisat/ParseUtils.h
Normal 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
69
libs/minisat/Queue.h
Normal 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
67
libs/minisat/Rnd.h
Normal 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
727
libs/minisat/SimpSolver.cc
Normal 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
222
libs/minisat/SimpSolver.h
Normal 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
1068
libs/minisat/Solver.cc
Normal file
File diff suppressed because it is too large
Load diff
409
libs/minisat/Solver.h
Normal file
409
libs/minisat/Solver.h
Normal 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
478
libs/minisat/SolverTypes.h
Normal 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
98
libs/minisat/Sort.h
Normal 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
171
libs/minisat/System.cc
Normal 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
72
libs/minisat/System.h
Normal 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
134
libs/minisat/Vec.h
Normal 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
45
libs/minisat/XAlloc.h
Normal 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
|
|
@ -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();
|
||||
}
|
||||
|
|
106
libs/sha1/sha1.h
106
libs/sha1/sha1.h
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
5
libs/svgviewer/.gitignore
vendored
5
libs/svgviewer/.gitignore
vendored
|
@ -1,5 +0,0 @@
|
|||
Makefile
|
||||
moc_mainwindow.cpp
|
||||
moc_svgview.cpp
|
||||
qrc_svgviewer.cpp
|
||||
svgviewer
|
|
@ -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 |
|
@ -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
Loading…
Add table
Reference in a new issue