This commit is contained in:
Ahmed Irfan 2015-04-03 16:38:07 +02:00
commit bdf6b2b19a
266 changed files with 18483 additions and 4711 deletions

8
.gitignore vendored
View File

@ -11,9 +11,17 @@
/qtcreator.creator.user
/Makefile.conf
/abc
/viz.js
/yosys
/yosys.exe
/yosys.js
/yosys-abc
/yosys-abc.exe
/yosys-config
/yosys-filterlib
/yosys-filterlib.exe
/kernel/version_*.cc
/share
/yosys-win32-mxebin-*
/yosys-win32-vcxsrc-*
/yosysjs-*

132
CHANGELOG
View File

@ -1,15 +1,133 @@
List of changes and major improvements between releases
List of major changes and improvements between releases
=======================================================
Yosys 0.3.0 .. Yoys 0.3.0+
--------------------------
Yosys 0.4 .. Yosys 0.5
----------------------
... TBD ...
* API changes
- Added log_warning()
- Added eval_select_args() and eval_select_op()
- Added cell->known(), cell->input(portname), cell->output(portname)
- Skip blackbox modules in design->selected_modules()
- Replaced std::map<> and std::set<> with dict<> and pool<>
- New SigSpec::extend() is what used to be SigSpec::extend_u0()
- Added YS_OVERRIDE, YS_FINAL, YS_ATTRIBUTE, YS_NORETURN
* Cell library changes
- Added flip-flops with enable ($dffe etc.)
- Added $equiv cells for equivalence checking framework
* Various
- Updated ABC to hg rev 61ad5f908c03
- Added clock domain partitioning to ABC pass
- Improved plugin building (see "yosys-config --build")
- Added ENABLE_NDEBUG Makefile flag for high-performance builds
- Added "yosys -d", "yosys -L" and other driver improvements
- Added support for multi-bit (array) cell ports to "write_edif"
- Now printing most output to stdout, not stderr
- Added "onehot" attribute (set by "fsm_map")
- Various performance improvements
- Vastly improved Xilinx flow
- Added "make unsintall"
* Equivalence checking
- Added equivalence checking commands:
equiv_make equiv_simple equiv_status
equiv_induct equiv_miter
equiv_add equiv_remove
* Block RAM support:
- Added "memory_bram" command
- Added BRAM support to Xilinx flow
* Other New Commands and Options
- Added "dff2dffe"
- Added "fsm -encfile"
- Added "dfflibmap -prepare"
- Added "write_blid -unbuf -undef -blackbox"
- Added "write_smt2" for writing SMT-LIBv2 files
- Added "test_cell -w -muxdiv"
- Added "select -read"
Yosys 0.2.0 .. Yoys 0.3.0
Yosys 0.3.0 .. Yosys 0.4
------------------------
* Platform Support
- Added support for mxe-based cross-builds for win32
- Added sourcecode-export as VisualStudio project
- Added experimental EMCC (JavaScript) support
* Verilog Frontend
- Added -sv option for SystemVerilog (and automatic *.sv file support)
- Added support for real-valued constants and constant expressions
- Added support for non-standard "via_celltype" attribute on task/func
- Added support for non-standard "module mod_name(...);" syntax
- Added support for non-standard """ macro bodies
- Added support for array with more than one dimension
- Added support for $readmemh and $readmemb
- Added support for DPI functions
* Changes in internal cell library
- Added $shift and $shiftx cell types
- Added $alu, $lcu, $fa and $macc cell types
- Removed $bu0 and $safe_pmux cell types
- $mem/$memwr WR_EN input is now a per-data-bit enable signal
- Added $_NAND_ $_NOR_ $_XNOR_ $_AOI3_ $_OAI3_ $_AOI4_ $_OAI4_
- Renamed ports of $lut cells (from I->O to A->Y)
- Renamed $_INV_ to $_NOT_
* Changes for simple synthesis flows
- There is now a "synth" command with a recommended default script
- Many improvements in synthesis of arithmetic functions to gates
- Multiplieres and adders with many operands are using carry-save adder trees
- Remaining adders are now implemented using BrentKung carry look-ahead adders
- Various new high-level optimizations on RTL netlist
- Various improvements in FSM optimization
- Updated ABC to hg 5b5af75f1dda (from 2014-11-07)
* Changes in internal APIs and RTLIL
- Added log_id() and log_cell() helper functions
- Added function-like cell creation helpers
- Added GetSize() function (like .size() but with int)
- Major refactoring of RTLIL::Module and related classes
- Major refactoring of RTLIL::SigSpec and related classes
- Now RTLIL::IdString is essentially an int
- Added macros for code coverage counters
- Added some Makefile magic for pretty make logs
- Added "kernel/yosys.h" with all the core definitions
- Chanded a lot of code from FILE* to c++ streams
- Added RTLIL::Monitor API and "trace" command
- Added "Yosys" C++ namespace
* Changes relevant to SAT solving
- Added ezSAT::keep_cnf() and ezSAT::non_incremental()
- Added native ezSAT support for vector shift ops
- Updated MiniSAT to git 37dc6c67e2 (from 2013-09-25)
* New commands (or large improvements to commands)
- Added "synth" command with default script
- Added "share" (finally some real resource sharing)
- Added "memory_share" (reduce number of ports on memories)
- Added "wreduce" and "alumacc" commands
- Added "opt -keepdc -fine -full -fast"
- Added some "test_*" commands
* Various other changes
- Added %D and %c select operators
- Added support for labels in yosys scripts
- Added support for here-documents in yosys scripts
- Support "+/" prefix for files from proc_share_dir
- Added "autoidx" statement to ilang language
- Switched from "yosys-svgviewer" to "xdot"
- Renamed "stdcells.v" to "techmap.v"
- Various bug fixes and small improvements
- Improved welcome and bye messages
Yosys 0.2.0 .. Yosys 0.3.0
--------------------------
* Driver program and overall behavior:
@ -59,8 +177,8 @@ Yosys 0.2.0 .. Yoys 0.3.0
- Various build fixes for OSX (Darwin) and OpenBSD
Yosys 0.1.0 .. Yoys 0.2.0
-------------------------
Yosys 0.1.0 .. Yosys 0.2.0
--------------------------
* Changes to the driver program:
- Added "yosys -h" and "yosys -H"

View File

@ -1,31 +1,209 @@
This file contains some very brief documentation on things like programming APIs.
Also consult the Yosys manual and the section about programming in the presentation.
(Both can be downloaded as PDF from the yosys webpage.)
--snip-- only the lines below this mark are included in the yosys manual --snip--
Getting Started
===============
Reading List
------------
Outline of a Yosys command
--------------------------
To write Yosys C++ code you need to know at least the following classes in kernel/rtlil.h:
Here is a the C++ code for a "hello_world" Yosys command (hello.cc):
#include "kernel/yosys.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct HelloWorldPass : public Pass {
HelloWorldPass() : Pass("hello_world") { }
virtual void execute(vector<string>, Design*) {
log("Hello World!\n");
}
} HelloWorldPass;
PRIVATE_NAMESPACE_END
This can be built into a Yosys module using the following command:
yosys-config --exec --cxx --cxxflags --ldflags -o hello.so -shared hello.cc --ldlibs
Or short:
yosys-config --build hello.so hello.cc
And then executed using the following command:
yosys -m hello.so -p hello_world
Yosys Data Structures
---------------------
Here is a short list of data structures that you should make yourself familiar
with before you write C++ code for Yosys. The following data structures are all
defined when "kernel/yosys.h" is included and USING_YOSYS_NAMESPACE is used.
1. Yosys Container Classes
Yosys uses dict<K, T> and pool<T> as main container classes. dict<K, T> is
essentially a replacement for std::unordered_map<K, T> and pool<T> is a
replacement for std::unordered_set<T>. The main characteristics are:
- dict<K, T> and pool<T> are about 2x faster than the std containers
- references to elements in a dict<K, T> or pool<T> are invalidated by
insert and remove operations (similar to std::vector<T> on push_back()).
- some iterators are invalidated by erase(). specifically, iterators
that have not passed the erased element yet are invalidated. (erase()
itself returns valid iterator to the next element.)
- no iterators are invalidated by insert(). elements are inserted at
begin(). i.e. only a new iterator that starts at begin() will see the
inserted elements.
- the method .count(key, iterator) is like .count(key) but only
considers elements that can be reached via the iterator.
- iterators can be compared. it1 < it2 means that the position of t2
can be reached via t1 but not vice versa.
- the method .sort() can be used to sort the elements in the container
the container stays sorted until elements are added or removed.
- dict<K, T> and pool<T> will have the same order of iteration across
all compilers, standard libraries and architectures.
In addition to dict<K, T> and pool<T> there is also an idict<K> that
creates a bijective map from K to the integers. For example:
idict<string, 42> si;
log("%d\n", si("hello")); // will print 42
log("%d\n", si("world")); // will print 43
log("%d\n", si.at("world")); // will print 43
log("%d\n", si.at("dummy")); // will throw exception
log("%s\n", si[42].c_str())); // will print hello
log("%s\n", si[43].c_str())); // will print world
log("%s\n", si[44].c_str())); // will throw exception
It is not possible to remove elements from an idict.
2. Standard STL data types
In Yosys we use std::vector<T> and std::string whenever applicable. When
dict<K, T> and pool<T> are not suitable then std::map<K, T> and std::set<T>
are used instead.
The types std::vector<T> and std::string are also available as vector<T>
and string in the Yosys namespace.
3. RTLIL objects
The current design (essentially a collection of modules, each defined by a
netlist) is stored in memory using RTLIL object (declared in kernel/rtlil.h,
automatically included by kernel/yosys.h). You should glance over at least
the declarations for the following types in kernel/rtlil.h:
RTLIL::IdString
This is a handle for an identifier (e.g. cell or wire name).
It feels a lot like a std::string, but is only a single int
in size. (The actual string is stored in a global lookup
table.)
RTLIL::SigBit
A single signal bit. I.e. either a constant state (0, 1,
x, z) or a single bit from a wire.
RTLIL::SigSpec
Essentially a vector of SigBits.
RTLIL::Wire
RTLIL::Cell
The building blocks of the netlist in a module.
RTLIL::Module
RTLIL::SigSpec
RTLIL::Design
The module is a container with connected cells and wires
in it. The design is a container with modules in it.
All this types are also available without the RTLIL:: prefix in the Yosys
namespace.
4. SigMap and other Helper Classes
There are a couple of additional helper classes that are in wide use
in Yosys. Most importantly there is SigMap (declared in kernel/sigtools.h).
When a design has many wires in it that are connected to each other, then a
single signal bit can have multiple valid names. The SigMap object can be used
to map SigSpecs or SigBits to unique SigSpecs and SigBits that consistently
only use one wire from such a group of connected wires. For example:
SigBit a = module->addWire(NEW_ID);
SigBit b = module->addWire(NEW_ID);
module->connect(a, b);
log("%d\n", a == b); // will print 0
SigMap sigmap(module);
log("%d\n", sigmap(a) == sigmap(b)); // will print 1
Using the RTLIL Netlist Format
------------------------------
In the RTLIL netlist format the cell ports contain SigSpecs that point to the
Wires. There are no references in the other direction. This has two direct
consequences:
(1) It is very easy to go from cells to wires but hard to go in the other way.
(2) There is no danger in removing cells from the netlists, but removing wires
can break the netlist format when there are still references to the wire
somewhere in the netlist.
The solution to (1) is easy: Create custom indexes that allow you to make fast
lookups for the wire-to-cell direction. You can either use existing generic
index structures to do that (such as the ModIndex class) or write your own
index. For many application it is simplest to construct a custom index. For
example:
SigMap sigmap(module);
dict<SigBit, Cell*> sigbit_to_driver_index;
for (auto cell : module->cells())
for (auto &conn : cell->connections())
if (cell->output(conn.first))
for (auto bit : sigmap(conn.second))
sigbit_to_driver_index[bit] = cell;
Regarding (2): There is a general theme in Yosys that you don't remove wires
from the design. You can rename them, unconnect them, but you do not actually remove
the Wire object from the module. Instead you let the "clean" command take care
of the dangling wires. On the other hand it is safe to remove cells (as long as
you make sure this does not invalidate a custom index you are using in your code).
Example Code
------------
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
manual/CHAPTER_Prog/stubnets.cc
manual/PRESENTATION_Prog/my_cmd.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
style. 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.
@ -58,15 +236,58 @@ 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.
gcc 4.6 are 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)
warnings for implicit type casts, always use "GetSize(foobar)" instead
of "foobar.size()". (GetSize() is defined in kernel/yosys.h)
Use range-based for loops whenever applicable.
--snap-- only the lines above this mark are included in the yosys manual --snap--
Creating the Visual Studio Template Project
===========================================
1. Create an empty Visual C++ Win32 Console App project
Microsoft Visual Studio Express 2013 for Windows Desktop
Open New Project Wizard (File -> New Project..)
Project Name: YosysVS
Solution Name: YosysVS
[X] Create directory for solution
[ ] Add to source control
[X] Console applications
[X] Empty Projcect
[ ] SDL checks
2. Open YosysVS Project Properties
Select Configuration: All Configurations
C/C++ -> General -> Additional Include Directories
Add: ..\yosys
C/C++ -> Preprocessor -> Preprocessor Definitions
Add: _YOSYS_;_CRT_SECURE_NO_WARNINGS
3. Resulting file system tree:
YosysVS/
YosysVS/YosysVS
YosysVS/YosysVS/YosysVS.vcxproj
YosysVS/YosysVS/YosysVS.vcxproj.filters
YosysVS/YosysVS.sdf
YosysVS/YosysVS.sln
YosysVS/YosysVS.v12.suo
4. Zip YosysVS as YosysVS-Tpl-v1.zip
Checklist for adding internal cell types
========================================
@ -96,50 +317,45 @@ Update the CHANGELOG file:
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
Update and check documentation:
cd ~yosys
make update-manual
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
cd ~yosys
vi README CodingReadme
- is the information provided in those file still up to date
Also with default config setting:
Then with default config setting:
cd ~yosys
make vgtest
cd ~yosys
./yosys -p 'proc; show' tests/simple/fiedler-cooley.v
./yosys -p 'proc; opt; show' tests/simple/fiedler-cooley.v
./yosys -p 'synth; show' tests/simple/fiedler-cooley.v
./yosys -p 'synth_xilinx -top up3down5; show' tests/simple/fiedler-cooley.v
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
cd ~yosys/techlibs/xilinx/example_basys3
bash run.sh
Finally if a current verific library is available:
Test building plugins with various of the standard passes:
yosys-config --build test.so equiv_simple.cc
- also check the code examples in CodingReadme
And if a version of the verific library is currently available:
cd ~yosys
cat frontends/verific/build_amd64.txt
@ -149,12 +365,22 @@ Finally if a current verific library is available:
../../yosys test_navre.ys
Release candiate:
Finally run all tests with "make config-{clang,gcc,gcc-4.6}":
- 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
cd ~yosys
make clean
make test
make vloghtb
make install
cd ~yosys-bigsim
make clean
make full
cd ~vloghammer
make purge gen_issues gen_samples
make SYN_LIST="yosys" SIM_LIST="icarus yosim verilator" REPORT_FULL=1 world
chromium-browser report.html
Release:
@ -166,7 +392,6 @@ Release:
- push tag to github
- post changelog on github
- post short release note on reddit
- delete -rc branch from github
Updating the website:
@ -183,12 +408,3 @@ Updating the website:
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+"

201
Makefile
View File

@ -3,6 +3,7 @@ CONFIG := clang
# CONFIG := gcc
# CONFIG := gcc-4.6
# CONFIG := emcc
# CONFIG := mxe
# features (the more the better)
ENABLE_TCL := 1
@ -10,41 +11,53 @@ ENABLE_ABC := 1
ENABLE_PLUGINS := 1
ENABLE_READLINE := 1
ENABLE_VERIFIC := 0
ENABLE_COVER := 1
# other configuration flags
ENABLE_GPROF := 0
ENABLE_NDEBUG := 0
DESTDIR := /usr/local
INSTALL_SUDO :=
TARGET_BINDIR := $(DESTDIR)/bin
TARGET_DATDIR := $(DESTDIR)/share/yosys
EXE =
OBJS =
GENFILES =
EXTRA_OBJS =
EXTRA_TARGETS =
TARGETS = yosys yosys-config
TARGETS = yosys$(EXE) yosys-config
PRETTY = 1
SMALL = 0
all: top-all
CXXFLAGS = -Wall -Wextra -ggdb -I"$(shell pwd)" -MD -DYOSYS_SRC='"$(shell pwd)"' -D_YOSYS_ -fPIC -I${DESTDIR}/include
LDFLAGS = -L${DESTDIR}/lib
YOSYS_SRC := $(shell pwd)
CXXFLAGS = -Wall -Wextra -ggdb -I"$(YOSYS_SRC)" -MD -D_YOSYS_ -fPIC -I$(DESTDIR)/include
LDFLAGS = -L$(DESTDIR)/lib
LDLIBS = -lstdc++ -lm
QMAKE = qmake-qt4
SED = sed
BISON = bison
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
# add macports/homebrew include and library path to search directories, don't use '-rdynamic' and '-lrt':
CXXFLAGS += -I/opt/local/include -I/usr/local/opt/readline/include
LDFLAGS += -L/opt/local/lib -L/usr/local/opt/readline/lib
# add homebrew's libffi include and library path
CXXFLAGS += $(shell PKG_CONFIG_PATH=$$(brew list libffi | grep pkgconfig | xargs dirname) pkg-config --silence-errors --cflags libffi)
LDFLAGS += $(shell PKG_CONFIG_PATH=$$(brew list libffi | grep pkgconfig | xargs dirname) pkg-config --silence-errors --libs libffi)
# use bison installed by homebrew if available
BISON = $(shell (brew list bison | grep -m1 "bin/bison") || echo bison)
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; })
YOSYS_VER := 0.5+$(shell test -d .git && { git log --author=clifford@clifford.at --oneline c3c9fbfb8c678.. | wc -l; })
GIT_REV := $(shell git rev-parse --short HEAD 2> /dev/null || echo UNKNOWN)
OBJS = kernel/version_$(GIT_REV).o
@ -54,8 +67,9 @@ 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 = 4d547a5e065b
ABCREV = 61ad5f908c03
ABCPULL = 1
ABCMKARGS = # CC="$(CXX)" CXX="$(CXX)"
define newline
@ -81,8 +95,42 @@ 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))
CXXFLAGS := -std=c++11 $(filter-out -fPIC -ggdb,$(CXXFLAGS))
EMCCFLAGS := -Os -Wno-warn-absolute-paths
EMCCFLAGS += --memory-init-file 0 --embed-file share -s NO_EXIT_RUNTIME=1
EMCCFLAGS += -s EXPORTED_FUNCTIONS="['_main','_run','_prompt','_errmsg']"
EMCCFLAGS += -s DISABLE_EXCEPTION_CATCHING=0 -s ALLOW_MEMORY_GROWTH=1
# https://github.com/kripken/emscripten/blob/master/src/settings.js
CXXFLAGS += $(EMCCFLAGS)
LDFLAGS += $(EMCCFLAGS)
LDLIBS =
EXE = .js
TARGETS := $(filter-out yosys-config,$(TARGETS))
EXTRA_TARGETS += yosysjs-$(YOSYS_VER).zip
viz.js:
wget -O viz.js.part https://github.com/mdaines/viz.js/releases/download/0.0.3/viz.js
mv viz.js.part viz.js
yosysjs-$(YOSYS_VER).zip: yosys.js viz.js misc/yosysjs/*
rm -rf yosysjs-$(YOSYS_VER) yosysjs-$(YOSYS_VER).zip
mkdir -p yosysjs-$(YOSYS_VER)
cp viz.js misc/yosysjs/* yosys.js yosysjs-$(YOSYS_VER)/
zip -r yosysjs-$(YOSYS_VER).zip yosysjs-$(YOSYS_VER)
yosys.html: misc/yosys.html
$(P) cp misc/yosys.html yosys.html
else ifeq ($(CONFIG),mxe)
CXX = /usr/local/src/mxe/usr/bin/i686-pc-mingw32-gcc
CXXFLAGS += -std=gnu++0x -Os -D_POSIX_SOURCE
CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS))
LDFLAGS := $(filter-out -rdynamic,$(LDFLAGS)) -s
LDLIBS := $(filter-out -lrt,$(LDLIBS))
ABCMKARGS += ARCHFLAGS="-DSIZEOF_VOID_P=4 -DSIZEOF_LONG=4 -DSIZEOF_INT=4 -DWIN32_NO_DLL -x c++ -fpermissive -w"
ABCMKARGS += LIBS="lib/x86/pthreadVC2.lib -s" READLINE=0 CC="$(CXX)" CXX="$(CXX)"
EXE = .exe
else ifneq ($(CONFIG),none)
$(error Invalid CONFIG setting '$(CONFIG)'. Valid values: clang, gcc, gcc-4.6, emcc, none)
@ -91,6 +139,9 @@ endif
ifeq ($(ENABLE_READLINE),1)
CXXFLAGS += -DYOSYS_ENABLE_READLINE
LDLIBS += -lreadline
ifeq ($(CONFIG),mxe)
LDLIBS += -lpdcurses
endif
endif
ifeq ($(ENABLE_PLUGINS),1)
@ -99,7 +150,7 @@ LDLIBS += $(shell pkg-config --silence-errors --libs libffi || echo -lffi) -ldl
endif
ifeq ($(ENABLE_TCL),1)
TCL_VERSION ?= tcl8.5
TCL_VERSION ?= tcl$(shell echo 'puts [info tclversion]' | tclsh)
TCL_INCLUDE ?= /usr/include/$(TCL_VERSION)
CXXFLAGS += -I$(TCL_INCLUDE) -DYOSYS_ENABLE_TCL
LDLIBS += -l$(TCL_VERSION)
@ -110,9 +161,13 @@ CXXFLAGS += -pg
LDFLAGS += -pg
endif
ifeq ($(ENABLE_NDEBUG),1)
CXXFLAGS := -O3 -DNDEBUG $(filter-out -Os,$(CXXFLAGS))
endif
ifeq ($(ENABLE_ABC),1)
CXXFLAGS += -DYOSYS_ENABLE_ABC
TARGETS += yosys-abc
TARGETS += yosys-abc$(EXE)
endif
ifeq ($(ENABLE_VERIFIC),1)
@ -122,11 +177,26 @@ CXXFLAGS += $(patsubst %,-I$(VERIFIC_DIR)/%,$(VERIFIC_COMPONENTS)) -DYOSYS_ENABL
LDLIBS += $(patsubst %,$(VERIFIC_DIR)/%/*-linux.a,$(VERIFIC_COMPONENTS))
endif
ifeq ($(ENABLE_COVER),1)
CXXFLAGS += -DYOSYS_ENABLE_COVER
endif
define add_share_file
EXTRA_TARGETS += $(subst //,/,$(1)/$(notdir $(2)))
$(subst //,/,$(1)/$(notdir $(2))): $(2)
$$(P) mkdir -p $(1)
$$(Q) cp $(2) $(subst //,/,$(1)/$(notdir $(2)))
endef
define add_include_file
$(eval $(call add_share_file,$(dir share/include/$(1)),$(1)))
endef
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_UPDATE = $(eval P_STATUS=$(shell echo $(OBJS) yosys$(EXE) | gawk 'BEGIN { RS = " "; I = $(P_STATUS)+0; } $$1 == "$@" && NR > I { I = NR; } END { print I; }'))
P_SHOW = [$(shell gawk "BEGIN { N=$(words $(OBJS) yosys$(EXE)); printf \"%3d\", $(P_OFFSET)+90*$(P_STATUS)/N; exit; }")%]
P = @echo "$(if $(findstring $@,$(TARGETS) $(EXTRA_TARGETS)),$(eval P_OFFSET = 10))$(call P_UPDATE)$(call P_SHOW) Building $@";
Q = @
S = -s
@ -137,7 +207,26 @@ Q =
S =
endif
$(eval $(call add_include_file,kernel/yosys.h))
$(eval $(call add_include_file,kernel/hashlib.h))
$(eval $(call add_include_file,kernel/log.h))
$(eval $(call add_include_file,kernel/rtlil.h))
$(eval $(call add_include_file,kernel/register.h))
$(eval $(call add_include_file,kernel/celltypes.h))
$(eval $(call add_include_file,kernel/consteval.h))
$(eval $(call add_include_file,kernel/sigtools.h))
$(eval $(call add_include_file,kernel/modtools.h))
$(eval $(call add_include_file,kernel/macc.h))
$(eval $(call add_include_file,kernel/utils.h))
$(eval $(call add_include_file,kernel/satgen.h))
$(eval $(call add_include_file,libs/ezsat/ezsat.h))
$(eval $(call add_include_file,libs/ezsat/ezminisat.h))
$(eval $(call add_include_file,libs/sha1/sha1.h))
$(eval $(call add_include_file,passes/fsm/fsmdata.h))
$(eval $(call add_include_file,backends/ilang/ilang_backend.h))
OBJS += kernel/driver.o kernel/register.o kernel/rtlil.o kernel/log.o kernel/calc.o kernel/yosys.o
kernel/log.o: CXXFLAGS += -DYOSYS_SRC='"$(YOSYS_SRC)"'
OBJS += libs/bigint/BigIntegerAlgorithms.o libs/bigint/BigInteger.o libs/bigint/BigIntegerUtils.o
OBJS += libs/bigint/BigUnsigned.o libs/bigint/BigUnsignedInABase.o
@ -192,8 +281,8 @@ top-all: $(TARGETS) $(EXTRA_TARGETS)
@echo " Build successful."
@echo ""
yosys: $(OBJS)
$(P) $(CXX) -o yosys $(LDFLAGS) $(OBJS) $(LDLIBS)
yosys$(EXE): $(OBJS)
$(P) $(CXX) -o yosys$(EXE) $(LDFLAGS) $(OBJS) $(LDLIBS)
%.o: %.cc
$(P) $(CXX) -o $@ -c $(CXXFLAGS) $<
@ -203,15 +292,16 @@ yosys: $(OBJS)
kernel/version_$(GIT_REV).cc: Makefile
$(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
$(Q) echo "namespace Yosys { extern const char *yosys_version_str; const char *yosys_version_str=\"Yosys $(YOSYS_VER) (git sha1 $(GIT_REV), $(notdir $(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
$(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
yosys-config: misc/yosys-config.in
$(P) $(SED) -e 's,@CXXFLAGS@,$(subst -I"$(YOSYS_SRC)",-I"$(TARGET_DATDIR)/include",$(CXXFLAGS)),;' \
-e 's,@CXX@,$(CXX),;' -e 's,@LDFLAGS@,$(LDFLAGS),;' -e 's,@LDLIBS@,$(LDLIBS),;' \
-e 's,@BINDIR@,$(TARGET_BINDIR),;' -e 's,@DATDIR@,$(TARGET_DATDIR),;' < misc/yosys-config.in > yosys-config
$(Q) chmod +x yosys-config
abc/abc-$(ABCREV):
abc/abc-$(ABCREV)$(EXE):
$(P)
ifneq ($(ABCREV),default)
$(Q) if ( cd abc 2> /dev/null && hg identify; ) | grep -q +; then \
@ -219,20 +309,20 @@ ifneq ($(ABCREV),default)
fi
$(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:"; \
echo "Pulling ABC from bitbucket.org:"; set -x; \
test -d abc || hg clone https://bitbucket.org/alanmi/abc abc; \
cd abc && hg pull && hg update -r $(ABCREV); \
cd abc && $(MAKE) DEP= clean && hg pull && hg update -r $(ABCREV); \
fi
endif
$(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: "
$(Q) cd abc && $(MAKE) $(S) $(ABCMKARGS) PROG="abc-$(ABCREV)$(EXE)" MSG_PREFIX="$(eval P_OFFSET = 5)$(call P_SHOW)$(eval P_OFFSET = 10) ABC: "
ifeq ($(ABCREV),default)
.PHONY: abc/abc-$(ABCREV)
.PHONY: abc/abc-$(ABCREV)$(EXE)
endif
yosys-abc: abc/abc-$(ABCREV)
$(P) cp abc/abc-$(ABCREV) yosys-abc
yosys-abc$(EXE): abc/abc-$(ABCREV)$(EXE)
$(P) cp abc/abc-$(ABCREV)$(EXE) yosys-abc$(EXE)
test: $(TARGETS) $(EXTRA_TARGETS)
+cd tests/simple && bash run-test.sh
@ -243,6 +333,7 @@ test: $(TARGETS) $(EXTRA_TARGETS)
+cd tests/fsm && bash run-test.sh
+cd tests/techmap && bash run-test.sh
+cd tests/memories && bash run-test.sh
+cd tests/bram && bash run-test.sh
+cd tests/various && bash run-test.sh
+cd tests/sat && bash run-test.sh
@echo ""
@ -252,7 +343,7 @@ test: $(TARGETS) $(EXTRA_TARGETS)
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 )
$(VALGRIND) ./yosys -p 'setattr -mod -unset top; synth' $$( ls tests/simple/*.v | grep -v repwhile.v )
@echo ""
@echo " Passed \"make vgtest\"."
@echo ""
@ -269,6 +360,13 @@ install: $(TARGETS) $(EXTRA_TARGETS)
$(INSTALL_SUDO) mkdir -p $(DESTDIR)/share/yosys
$(INSTALL_SUDO) cp -r share/. $(DESTDIR)/share/yosys/.
uninstall:
$(INSTALL_SUDO) rm -vf $(addprefix $(DESTDIR)/bin/,$(notdir $(TARGETS)))
$(INSTALL_SUDO) rm -rvf $(DESTDIR)/share/yosys/
update-manual: $(TARGETS) $(EXTRA_TARGETS)
cd manual && ../yosys -p 'help -write-tex-command-reference-manual'
manual: $(TARGETS) $(EXTRA_TARGETS)
cd manual && bash appnotes.sh
cd manual && bash presentation.sh
@ -277,13 +375,13 @@ manual: $(TARGETS) $(EXTRA_TARGETS)
clean:
rm -rf share
cd manual && bash clean.sh
rm -f $(OBJS) $(GENFILES) $(TARGETS) $(EXTRA_TARGETS)
rm -f $(OBJS) $(GENFILES) $(TARGETS) $(EXTRA_TARGETS) $(EXTRA_OBJS)
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]*
$(MAKE) -C abc DEP= clean
rm -f yosys-abc$(EXE) abc/abc-[0-9a-f]*
mrproper: clean
git clean -xdf
@ -295,6 +393,29 @@ qtcreator:
{ echo .; find backends frontends kernel libs passes -type f \( -name '*.h' -o -name '*.hh' \) -printf '%h\n' | sort -u; } > qtcreator.includes
touch qtcreator.config qtcreator.creator
vcxsrc: $(GENFILES) $(EXTRA_TARGETS)
rm -rf yosys-win32-vcxsrc-$(YOSYS_VER){,.zip}
set -e; for f in `ls $(filter %.cc %.cpp,$(GENFILES)) $(addsuffix .cc,$(basename $(OBJS))) $(addsuffix .cpp,$(basename $(OBJS))) 2> /dev/null`; do \
echo "Analyse: $$f" >&2; cpp -std=gnu++0x -MM -I. -D_YOSYS_ $$f; done | sed 's,.*:,,; s,//*,/,g; s,/[^/]*/\.\./,/,g; y, \\,\n\n,;' | grep '^[^/]' | sort -u | grep -v kernel/version_ > srcfiles.txt
bash misc/create_vcxsrc.sh yosys-win32-vcxsrc $(YOSYS_VER) $(GIT_REV)
echo "namespace Yosys { extern const char *yosys_version_str; const char *yosys_version_str=\"Yosys (Version Information Unavailable)\"; }" > kernel/version.cc
zip yosys-win32-vcxsrc-$(YOSYS_VER)/genfiles.zip $(GENFILES) kernel/version.cc
zip -r yosys-win32-vcxsrc-$(YOSYS_VER).zip yosys-win32-vcxsrc-$(YOSYS_VER)/
rm -f srcfiles.txt kernel/version.cc
ifeq ($(CONFIG),mxe)
mxebin: $(TARGETS) $(EXTRA_TARGETS)
rm -rf yosys-win32-mxebin-$(YOSYS_VER){,.zip}
mkdir -p yosys-win32-mxebin-$(YOSYS_VER)
cp -r yosys.exe share/ yosys-win32-mxebin-$(YOSYS_VER)/
ifeq ($(ENABLE_ABC),1)
cp -r yosys-abc.exe abc/lib/x86/pthreadVC2.dll yosys-win32-mxebin-$(YOSYS_VER)/
endif
echo -en 'This is Yosys $(YOSYS_VER) for Win32.\r\n' > yosys-win32-mxebin-$(YOSYS_VER)/readme.txt
echo -en 'Documentation at http://www.clifford.at/yosys/.\r\n' >> yosys-win32-mxebin-$(YOSYS_VER)/readme.txt
zip -r yosys-win32-mxebin-$(YOSYS_VER).zip yosys-win32-mxebin-$(YOSYS_VER)/
endif
config-clean: clean
rm -f Makefile.conf
@ -314,6 +435,12 @@ config-emcc: clean
echo 'ENABLE_PLUGINS := 0' >> Makefile.conf
echo 'ENABLE_READLINE := 0' >> Makefile.conf
config-mxe: clean
echo 'CONFIG := mxe' > Makefile.conf
echo 'ENABLE_TCL := 0' >> Makefile.conf
echo 'ENABLE_PLUGINS := 0' >> Makefile.conf
echo 'ENABLE_READLINE := 0' >> Makefile.conf
config-gprof: clean
echo 'CONFIG := gcc' > Makefile.conf
echo 'ENABLE_GPROF := 1' >> Makefile.conf
@ -321,6 +448,12 @@ config-gprof: clean
config-sudo:
echo "INSTALL_SUDO := sudo" >> Makefile.conf
echo-yosys-ver:
@echo "$(YOSYS_VER)"
echo-git-rev:
@echo "$(GIT_REV)"
-include libs/*/*.d
-include frontends/*/*.d
-include passes/*/*.d

65
README
View File

@ -3,7 +3,7 @@
| |
| yosys -- Yosys Open SYnthesis Suite |
| |
| Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> |
| Copyright (C) 2012 - 2015 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 |
@ -55,12 +55,13 @@ 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:
$ yosys_deps="build-essential clang bison flex libreadline-dev
tcl8.5-dev libffi-dev git mercurial graphviz xdot"
$ yosys_deps="build-essential clang bison flex libreadline-dev gawk
tcl-dev libffi-dev git mercurial graphviz xdot pkg-config"
$ sudo apt-get install $yosys_deps
There are also pre-compiled packages for Yosys on Ubuntu. Visit the Yosys
download page to learn more about this:
There are also pre-compiled Yosys binary packages for Ubuntu and Win32 as well
as a source distribution for Visual Studio. Visit the Yosys download page for
more information:
http://www.clifford.at/yosys/download.html
@ -248,11 +249,19 @@ Verilog Attributes and non-standard features
is strongly recommended instead).
- The "nomem2reg" attribute on modules or arrays prohibits the
automatic early conversion of arrays to separate registers.
automatic early conversion of arrays to separate registers. This
is potentially dangerous. Usually the front-end has good reasons
for converting an array to a list of registers. Prohibiting this
step will likely result in incorrect synthesis results.
- The "mem2reg" attribute on modules or arrays forces the early
conversion of arrays to separate registers.
- The "nomeminit" attribute on modules or arrays prohibits the
creation of initialized memories. This effectively puts "mem2reg"
on all memories that are written to in an "initial" block and
are not ROMs.
- The "nolatches" attribute on modules or always-blocks
prohibits the generation of logic-loops for latches. Instead
all not explicitly assigned values default to x-bits. This does
@ -264,6 +273,9 @@ Verilog Attributes and non-standard features
temporary variable within an always block. This is mostly used internally
by yosys to synthesize verilog functions and access arrays.
- The "onehot" attribute on wires mark them as onehot state register. This
is used for example for memory port sharing and set by the fsm_map pass.
- The "blackbox" attribute on modules is used to mark empty stub modules
that have the same ports as the real thing but do not contain information
on the internal configuration. This modules are only used by the synthesis
@ -273,6 +285,11 @@ Verilog Attributes and non-standard features
- The "keep" attribute on cells and wires is used to mark objects that should
never be removed by the optimizer. This is used for example for cells that
have hidden connections that are not part of the netlist, such as IO pads.
Setting the "keep" attribute on a module has the same effect as setting it
on all instances of the module.
- The "keep_hierarchy" attribute on cells and modules keeps the "flatten"
command from flattening the indicated cells and modules.
- The "init" attribute on wires is set by the frontend when a register is
initialized "FPGA-style" with 'reg foo = val'. It can be used during synthesis
@ -289,7 +306,7 @@ Verilog Attributes and non-standard features
by adding an empty {* *} statement.)
- Modules can be declared with "module mod_name(...);" (with three dots
instead of a list of moudle ports). With this syntax it is sufficient
instead of a list of module ports). With this syntax it is sufficient
to simply declare a module port as 'input' or 'output' in the module
body.
@ -354,40 +371,8 @@ from SystemVerilog:
- The "assert" statement from SystemVerilog is supported in its most basic
form. In module context: "assert property (<expression>);" and within an
always block: "assert(<expression>);". It is transformed to a $assert cell
that is supported by the "sat" and "write_btor" commands.
always block: "assert(<expression>);". It is transformed to a $assert cell.
- The keywords "always_comb", "always_ff" and "always_latch", "logic" and
"bit" are supported.
Roadmap / Large-scale TODOs
===========================
- Technology mapping for real-world applications
- Improve Xilinx FGPA synthesis (RAMB, CARRY4, SLR, etc.)
- Implement SAT-based formal equivialence checker
- Write equiv pass based on hint-based register mapping
- Re-implement Verilog frontend (far future)
- cleaner (easier to use, harder to use wrong) AST format
- pipeline of well structured AST transformations
- true contextual name lookup
Other Unsorted TODOs
====================
- Implement missing Verilog 2005 features:
- 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)
- Check standard vs. implementation to identify missing features
- Miscellaneous TODO items:
- Add brief source code documentation to most passes and kernel code
- Implement mux-to-tribuf pass and rebalance mixed mux/tribuf trees

View File

@ -28,6 +28,9 @@
#include "kernel/log.h"
#include <string>
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct BlifDumperConfig
{
bool icells_mode;
@ -35,11 +38,14 @@ struct BlifDumperConfig
bool impltf_mode;
bool gates_mode;
bool param_mode;
bool attr_mode;
bool blackbox_mode;
std::string buf_type, buf_in, buf_out;
std::string true_type, true_out, false_type, false_out;
std::map<RTLIL::IdString, std::pair<RTLIL::IdString, RTLIL::IdString>> unbuf_types;
std::string true_type, true_out, false_type, false_out, undef_type, undef_out;
BlifDumperConfig() : icells_mode(false), conn_mode(false), impltf_mode(false), gates_mode(false), param_mode(false) { }
BlifDumperConfig() : icells_mode(false), conn_mode(false), impltf_mode(false), gates_mode(false), param_mode(false), attr_mode(false), blackbox_mode(false) { }
};
struct BlifDumper
@ -69,8 +75,11 @@ struct BlifDumper
const char *cstr(RTLIL::SigBit sig)
{
if (sig.wire == NULL)
return sig == RTLIL::State::S1 ? "$true" : "$false";
if (sig.wire == NULL) {
if (sig == RTLIL::State::S0) return config->false_type == "-" ? config->false_out.c_str() : "$false";
if (sig == RTLIL::State::S1) return config->true_type == "-" ? config->true_out.c_str() : "$true";
return config->undef_type == "-" ? config->undef_out.c_str() : "$undef";
}
std::string str = RTLIL::unescape_id(sig.wire->name);
for (size_t i = 0; i < str.size(); i++)
@ -95,6 +104,26 @@ struct BlifDumper
return "subckt";
}
void dump_params(const char *command, dict<IdString, Const> &params)
{
for (auto &param : params) {
f << stringf("%s %s ", command, 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());
}
}
void dump()
{
f << stringf("\n");
@ -126,23 +155,44 @@ struct BlifDumper
}
f << stringf("\n");
if (module->get_bool_attribute("\\blackbox")) {
f << stringf(".blackbox\n");
f << stringf(".end\n");
return;
}
if (!config->impltf_mode) {
if (!config->false_type.empty())
f << stringf(".%s %s %s=$false\n", subckt_or_gate(config->false_type),
config->false_type.c_str(), config->false_out.c_str());
else
if (!config->false_type.empty()) {
if (config->false_type != "-")
f << stringf(".%s %s %s=$false\n", subckt_or_gate(config->false_type),
config->false_type.c_str(), config->false_out.c_str());
} else
f << stringf(".names $false\n");
if (!config->true_type.empty())
f << stringf(".%s %s %s=$true\n", subckt_or_gate(config->true_type),
config->true_type.c_str(), config->true_out.c_str());
else
if (!config->true_type.empty()) {
if (config->true_type != "-")
f << stringf(".%s %s %s=$true\n", subckt_or_gate(config->true_type),
config->true_type.c_str(), config->true_out.c_str());
} else
f << stringf(".names $true\n1\n");
if (!config->undef_type.empty()) {
if (config->undef_type != "-")
f << stringf(".%s %s %s=$undef\n", subckt_or_gate(config->undef_type),
config->undef_type.c_str(), config->undef_out.c_str());
} else
f << stringf(".names $undef\n");
}
for (auto &cell_it : module->cells_)
{
RTLIL::Cell *cell = cell_it.second;
if (config->unbuf_types.count(cell->type)) {
auto portnames = config->unbuf_types.at(cell->type);
f << stringf(".names %s %s\n1 1\n",
cstr(cell->getPort(portnames.first)), cstr(cell->getPort(portnames.second)));
continue;
}
if (!config->icells_mode && cell->type == "$_NOT_") {
f << stringf(".names %s %s\n0 1\n",
cstr(cell->getPort("\\A")), cstr(cell->getPort("\\Y")));
@ -191,21 +241,21 @@ struct BlifDumper
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++) {
for (int i = width-1; i >= 0; 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');
RTLIL::SigSpec mask = cell->parameters.at("\\LUT");
for (int i = 0; i < (1 << width); i++)
if (mask[i] == RTLIL::S1) {
for (int j = width-1; j >= 0; j--) {
f << ((i>>j)&1 ? '1' : '0');
}
f << " 1\n";
}
f << stringf(" %c\n", mask[i]);
}
continue;
}
@ -220,23 +270,10 @@ struct BlifDumper
}
f << stringf("\n");
if (config->attr_mode)
dump_params(".attr", cell->attributes);
if (config->param_mode)
for (auto &param : cell->parameters) {
f << stringf(".param %s ", RTLIL::id2cstr(param.first));
if (param.second.flags & RTLIL::CONST_FLAG_STRING) {
std::string str = param.second.decode_string();
f << stringf("\"");
for (char ch : str)
if (ch == '"' || ch == '\\')
f << stringf("\\%c", ch);
else if (ch < 32 || ch >= 127)
f << stringf("\\%03o", ch);
else
f << stringf("%c", ch);
f << stringf("\"\n");
} else
f << stringf("%s\n", param.second.as_string().c_str());
}
dump_params(".param", cell->parameters);
}
for (auto &conn : module->connections())
@ -276,9 +313,17 @@ struct BlifBackend : public Backend {
log(" -buf <cell-type> <in-port> <out-port>\n");
log(" use cells of type <cell-type> with the specified port names for buffers\n");
log("\n");
log(" -unbuf <cell-type> <in-port> <out-port>\n");
log(" replace buffer cells with the specified name and port names with\n");
log(" a .names statement that models a buffer\n");
log("\n");
log(" -true <cell-type> <out-port>\n");
log(" -false <cell-type> <out-port>\n");
log(" use the specified cell types to drive nets that are constant 1 or 0\n");
log(" -undef <cell-type> <out-port>\n");
log(" use the specified cell types to drive nets that are constant 1, 0, or\n");
log(" undefined. when '-' is used as <cell-type>, then <out-port> specifies\n");
log(" the wire name to be used for the constant signal and no cell driving\n");
log(" that wire is generated.\n");
log("\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");
@ -296,11 +341,17 @@ struct BlifBackend : public Backend {
log(" do not generate buffers for connected wires. instead use the\n");
log(" non-standard .conn statement.\n");
log("\n");
log(" -attr\n");
log(" use the non-standard .attr statement to write cell attributes\n");
log("\n");
log(" -param\n");
log(" use the non-standard .param statement to write module parameters\n");
log(" use the non-standard .param statement to write cell parameters\n");
log("\n");
log(" -blackbox\n");
log(" write blackbox cells with .blackbox statement.\n");
log("\n");
log(" -impltf\n");
log(" do not write definitions for the $true and $false wires.\n");
log(" do not write definitions for the $true, $false and $undef wires.\n");
log("\n");
}
virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
@ -326,6 +377,13 @@ struct BlifBackend : public Backend {
config.buf_out = args[++argidx];
continue;
}
if (args[argidx] == "-unbuf" && argidx+3 < args.size()) {
RTLIL::IdString unbuf_type = RTLIL::escape_id(args[++argidx]);
RTLIL::IdString unbuf_in = RTLIL::escape_id(args[++argidx]);
RTLIL::IdString unbuf_out = RTLIL::escape_id(args[++argidx]);
config.unbuf_types[unbuf_type] = std::pair<RTLIL::IdString, RTLIL::IdString>(unbuf_in, unbuf_out);
continue;
}
if (args[argidx] == "-true" && argidx+2 < args.size()) {
config.true_type = args[++argidx];
config.true_out = args[++argidx];
@ -336,6 +394,11 @@ struct BlifBackend : public Backend {
config.false_out = args[++argidx];
continue;
}
if (args[argidx] == "-undef" && argidx+2 < args.size()) {
config.undef_type = args[++argidx];
config.undef_out = args[++argidx];
continue;
}
if (args[argidx] == "-icells") {
config.icells_mode = true;
continue;
@ -352,6 +415,14 @@ struct BlifBackend : public Backend {
config.param_mode = true;
continue;
}
if (args[argidx] == "-attr") {
config.attr_mode = true;
continue;
}
if (args[argidx] == "-blackbox") {
config.blackbox_mode = true;
continue;
}
if (args[argidx] == "-impltf") {
config.impltf_mode = true;
continue;
@ -372,7 +443,7 @@ struct BlifBackend : public Backend {
for (auto module_it : design->modules_)
{
RTLIL::Module *module = module_it.second;
if (module->get_bool_attribute("\\blackbox"))
if (module->get_bool_attribute("\\blackbox") && !config.blackbox_mode)
continue;
if (module->processes.size() != 0)
@ -397,3 +468,4 @@ struct BlifBackend : public Backend {
}
} BlifBackend;
PRIVATE_NAMESPACE_END

View File

@ -30,6 +30,9 @@
#include <string>
#include <math.h>
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct BtorDumperConfig
{
bool subckt_mode;
@ -476,7 +479,7 @@ struct BtorDumper
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();
bool l2_signed YS_ATTRIBUTE(unused) = cell->parameters.at(RTLIL::IdString("\\B_SIGNED")).as_bool();
int l1_width = cell->parameters.at(RTLIL::IdString("\\A_WIDTH")).as_int();
int l2_width = cell->parameters.at(RTLIL::IdString("\\B_WIDTH")).as_int();
@ -817,7 +820,7 @@ struct BtorDumper
int input_width = cell->parameters.at(RTLIL::IdString("\\A_WIDTH")).as_int();
log_assert(input->size() == input_width);
int input_line = dump_sigspec(input, input_width);
const RTLIL::SigSpec* output = &cell->getPort(RTLIL::IdString("\\Y"));
const RTLIL::SigSpec* output YS_ATTRIBUTE(unused) = &cell->getPort(RTLIL::IdString("\\Y"));
int output_width = cell->parameters.at(RTLIL::IdString("\\Y_WIDTH")).as_int();
log_assert(output->size() == output_width);
int offset = cell->parameters.at(RTLIL::IdString("\\OFFSET")).as_int();
@ -1057,3 +1060,4 @@ struct BtorBackend : public Backend {
}
} BtorBackend;
PRIVATE_NAMESPACE_END

View File

@ -27,6 +27,9 @@
#include "kernel/log.h"
#include <string>
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
#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()
@ -108,7 +111,7 @@ struct EdifBackend : public Backend {
log_header("Executing EDIF backend.\n");
std::string top_module_name;
std::map<RTLIL::IdString, std::set<RTLIL::IdString>> lib_cell_ports;
std::map<RTLIL::IdString, std::map<RTLIL::IdString, int>> lib_cell_ports;
CellTypes ct(design);
EdifNames edif_names;
@ -147,12 +150,8 @@ struct EdifBackend : public Backend {
RTLIL::Cell *cell = cell_it.second;
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.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);
}
for (auto p : cell->connections())
lib_cell_ports[cell->type][p.first] = GetSize(p.second);
}
}
}
@ -195,12 +194,15 @@ struct EdifBackend : public Backend {
for (auto &port_it : cell_it.second) {
const char *dir = "INOUT";
if (ct.cell_known(cell_it.first)) {
if (!ct.cell_output(cell_it.first, port_it))
if (!ct.cell_output(cell_it.first, port_it.first))
dir = "INPUT";
else if (!ct.cell_input(cell_it.first, port_it))
else if (!ct.cell_input(cell_it.first, port_it.first))
dir = "OUTPUT";
}
*f << stringf(" (port %s (direction %s))\n", EDIF_DEF(port_it), dir);
if (port_it.second == 1)
*f << stringf(" (port %s (direction %s))\n", EDIF_DEF(port_it.first), dir);
else
*f << stringf(" (port (array %s %d) (direction %s))\n", EDIF_DEF(port_it.first), port_it.second, dir);
}
*f << stringf(" )\n");
*f << stringf(" )\n");
@ -300,12 +302,12 @@ struct EdifBackend : public Backend {
char digit_str[2] = { "0123456789abcdef"[digit_value], 0 };
hex_string = std::string(digit_str) + hex_string;
}
*f << stringf("\n (property %s (string \"%s\"))", EDIF_DEF(p.first), hex_string.c_str());
*f << stringf("\n (property %s (string \"%d'h%s\"))", EDIF_DEF(p.first), GetSize(p.second.bits), hex_string.c_str());
}
*f << stringf(")\n");
for (auto &p : cell->connections()) {
RTLIL::SigSpec sig = sigmap(p.second);
for (int i = 0; i < SIZE(sig); i++)
for (int i = 0; i < GetSize(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
@ -345,3 +347,4 @@ struct EdifBackend : public Backend {
}
} EdifBackend;
PRIVATE_NAMESPACE_END

View File

@ -26,7 +26,9 @@
#include "kernel/yosys.h"
#include <errno.h>
USING_YOSYS_NAMESPACE
using namespace ILANG_BACKEND;
YOSYS_NAMESPACE_BEGIN
void ILANG_BACKEND::dump_const(std::ostream &f, const RTLIL::Const &data, int width, int offset, bool autoint)
{
@ -101,7 +103,7 @@ void ILANG_BACKEND::dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig, boo
dump_sigchunk(f, sig.as_chunk(), autoint);
} else {
f << stringf("{ ");
for (auto it = sig.chunks().rbegin(); it != sig.chunks().rend(); it++) {
for (auto it = sig.chunks().rbegin(); it != sig.chunks().rend(); ++it) {
dump_sigchunk(f, *it, false);
f << stringf(" ");
}
@ -111,11 +113,9 @@ void ILANG_BACKEND::dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig, boo
void ILANG_BACKEND::dump_wire(std::ostream &f, std::string indent, const RTLIL::Wire *wire)
{
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);
for (auto &it : wire->attributes) {
f << stringf("%s" "attribute %s ", indent.c_str(), it.first.c_str());
dump_const(f, it.second);
f << stringf("\n");
}
f << stringf("%s" "wire ", indent.c_str());
@ -136,11 +136,9 @@ void ILANG_BACKEND::dump_wire(std::ostream &f, std::string indent, const RTLIL::
void ILANG_BACKEND::dump_memory(std::ostream &f, std::string indent, const RTLIL::Memory *memory)
{
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);
for (auto &it : memory->attributes) {
f << stringf("%s" "attribute %s ", indent.c_str(), it.first.c_str());
dump_const(f, it.second);
f << stringf("\n");
}
f << stringf("%s" "memory ", indent.c_str());
@ -148,29 +146,27 @@ void ILANG_BACKEND::dump_memory(std::ostream &f, std::string indent, const RTLIL
f << stringf("width %d ", memory->width);
if (memory->size != 0)
f << stringf("size %d ", memory->size);
if (memory->start_offset != 0)
f << stringf("offset %d ", memory->start_offset);
f << stringf("%s\n", memory->name.c_str());
}
void ILANG_BACKEND::dump_cell(std::ostream &f, std::string indent, const RTLIL::Cell *cell)
{
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);
for (auto &it : cell->attributes) {
f << stringf("%s" "attribute %s ", indent.c_str(), it.first.c_str());
dump_const(f, it.second);
f << stringf("\n");
}
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);
for (auto &it : cell->parameters) {
f << stringf("%s parameter%s %s ", indent.c_str(), (it.second.flags & RTLIL::CONST_FLAG_SIGNED) != 0 ? " signed" : "", it.first.c_str());
dump_const(f, it.second);
f << stringf("\n");
}
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);
for (auto &it : cell->connections()) {
f << stringf("%s connect %s ", indent.c_str(), it.first.c_str());
dump_sigspec(f, it.second);
f << stringf("\n");
}
f << stringf("%s" "end\n", indent.c_str());
@ -178,7 +174,7 @@ void ILANG_BACKEND::dump_cell(std::ostream &f, std::string indent, const RTLIL::
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++)
for (auto it = cs->actions.begin(); it != cs->actions.end(); ++it)
{
f << stringf("%s" "assign ", indent.c_str());
dump_sigspec(f, it->first);
@ -187,13 +183,13 @@ void ILANG_BACKEND::dump_proc_case_body(std::ostream &f, std::string indent, con
f << stringf("\n");
}
for (auto it = cs->switches.begin(); it != cs->switches.end(); it++)
for (auto it = cs->switches.begin(); it != cs->switches.end(); ++it)
dump_proc_switch(f, indent, *it);
}
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++) {
for (auto it = sw->attributes.begin(); it != sw->attributes.end(); ++it) {
f << stringf("%s" "attribute %s ", indent.c_str(), it->first.c_str());
dump_const(f, it->second);
f << stringf("\n");
@ -203,7 +199,7 @@ void ILANG_BACKEND::dump_proc_switch(std::ostream &f, std::string indent, const
dump_sigspec(f, sw->signal);
f << stringf("\n");
for (auto it = sw->cases.begin(); it != sw->cases.end(); it++)
for (auto it = sw->cases.begin(); it != sw->cases.end(); ++it)
{
f << stringf("%s case ", indent.c_str());
for (size_t i = 0; i < (*it)->compare.size(); i++) {
@ -235,7 +231,7 @@ void ILANG_BACKEND::dump_proc_sync(std::ostream &f, std::string indent, const RT
case RTLIL::STi: f << stringf("init\n"); break;
}
for (auto it = sy->actions.begin(); it != sy->actions.end(); it++) {
for (auto it = sy->actions.begin(); it != sy->actions.end(); ++it) {
f << stringf("%s update ", indent.c_str());
dump_sigspec(f, it->first);
f << stringf(" ");
@ -246,14 +242,14 @@ void ILANG_BACKEND::dump_proc_sync(std::ostream &f, std::string indent, const RT
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++) {
for (auto it = proc->attributes.begin(); it != proc->attributes.end(); ++it) {
f << stringf("%s" "attribute %s ", indent.c_str(), it->first.c_str());
dump_const(f, it->second);
f << stringf("\n");
}
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++)
for (auto it = proc->syncs.begin(); it != proc->syncs.end(); ++it)
dump_proc_sync(f, indent + " ", *it);
f << stringf("%s" "end\n", indent.c_str());
}
@ -274,7 +270,7 @@ void ILANG_BACKEND::dump_module(std::ostream &f, std::string indent, RTLIL::Modu
if (print_header)
{
for (auto it = module->attributes.begin(); it != module->attributes.end(); it++) {
for (auto it = module->attributes.begin(); it != module->attributes.end(); ++it) {
f << stringf("%s" "attribute %s ", indent.c_str(), it->first.c_str());
dump_const(f, it->second);
f << stringf("\n");
@ -285,56 +281,36 @@ void ILANG_BACKEND::dump_module(std::ostream &f, std::string indent, RTLIL::Modu
if (print_body)
{
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)
f << stringf("\n");
dump_wire(f, indent + " ", it);
}
for (auto it : sorted_memories)
if (!only_selected || design->selected(module, it)) {
for (auto it : module->memories)
if (!only_selected || design->selected(module, it.second)) {
if (only_selected)
f << stringf("\n");
dump_memory(f, indent + " ", it);
dump_memory(f, indent + " ", it.second);
}
for (auto it : sorted_cells)
for (auto it : module->cells())
if (!only_selected || design->selected(module, it)) {
if (only_selected)
f << stringf("\n");
dump_cell(f, indent + " ", it);
}
for (auto it : sorted_processes)
if (!only_selected || design->selected(module, it)) {
for (auto it : module->processes)
if (!only_selected || design->selected(module, it.second)) {
if (only_selected)
f << stringf("\n");
dump_proc(f, indent + " ", it);
dump_proc(f, indent + " ", it.second);
}
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;
@ -360,11 +336,13 @@ void ILANG_BACKEND::dump_module(std::ostream &f, std::string indent, RTLIL::Modu
void ILANG_BACKEND::dump_design(std::ostream &f, RTLIL::Design *design, bool only_selected, bool flag_m, bool flag_n)
{
#ifndef NDEBUG
int init_autoidx = autoidx;
#endif
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))
@ -380,7 +358,7 @@ void ILANG_BACKEND::dump_design(std::ostream &f, RTLIL::Design *design, bool onl
f << stringf("autoidx %d\n", autoidx);
}
for (auto it = design->modules_.begin(); it != design->modules_.end(); it++) {
for (auto it = design->modules_.begin(); it != design->modules_.end(); ++it) {
if (!only_selected || design->selected(it->second)) {
if (only_selected)
f << stringf("\n");
@ -391,6 +369,9 @@ void ILANG_BACKEND::dump_design(std::ostream &f, RTLIL::Design *design, bool onl
log_assert(init_autoidx == autoidx);
}
YOSYS_NAMESPACE_END
PRIVATE_NAMESPACE_BEGIN
struct IlangBackend : public Backend {
IlangBackend() : Backend("ilang", "write design to ilang file") { }
virtual void help()
@ -423,6 +404,8 @@ struct IlangBackend : public Backend {
}
extra_args(f, filename, args, argidx);
design->sort();
log("Output filename: %s\n", filename.c_str());
*f << stringf("# Generated by %s\n", yosys_version_str);
ILANG_BACKEND::dump_design(*f, design, selected, true, false);
@ -447,10 +430,10 @@ struct DumpPass : public Pass {
log(" -n\n");
log(" only dump the module headers if the entire module is selected\n");
log("\n");
log(" -outfile <filename>\n");
log(" -o <filename>\n");
log(" write to the specified file.\n");
log("\n");
log(" -append <filename>\n");
log(" -a <filename>\n");
log(" like -outfile but append instead of overwrite\n");
log("\n");
}
@ -463,12 +446,12 @@ struct DumpPass : public Pass {
for (argidx = 1; argidx < args.size(); argidx++)
{
std::string arg = args[argidx];
if (arg == "-outfile" && argidx+1 < args.size()) {
if ((arg == "-o" || arg == "-outfile") && argidx+1 < args.size()) {
filename = args[++argidx];
append = false;
continue;
}
if (arg == "-append" && argidx+1 < args.size()) {
if ((arg == "-a" || arg == "-append") && argidx+1 < args.size()) {
filename = args[++argidx];
append = true;
continue;
@ -510,3 +493,4 @@ struct DumpPass : public Pass {
}
} DumpPass;
PRIVATE_NAMESPACE_END

View File

@ -24,6 +24,8 @@
#include "kernel/log.h"
#include <string>
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
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)
{
@ -215,3 +217,4 @@ struct IntersynthBackend : public Backend {
}
} IntersynthBackend;
PRIVATE_NAMESPACE_END

View File

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

407
backends/json/json.cc Normal file
View File

@ -0,0 +1,407 @@
/*
* 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/rtlil.h"
#include "kernel/register.h"
#include "kernel/sigtools.h"
#include "kernel/celltypes.h"
#include "kernel/log.h"
#include <string>
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct JsonWriter
{
std::ostream &f;
bool use_selection;
Design *design;
Module *module;
SigMap sigmap;
int sigidcounter;
dict<SigBit, string> sigids;
JsonWriter(std::ostream &f, bool use_selection) : f(f), use_selection(use_selection) { }
string get_string(string str)
{
string newstr = "\"";
for (char c : str) {
if (c == '\\')
newstr += c;
newstr += c;
}
return newstr + "\"";
}
string get_name(IdString name)
{
return get_string(RTLIL::unescape_id(name));
}
string get_bits(SigSpec sig)
{
bool first = true;
string str = "[";
for (auto bit : sigmap(sig)) {
str += first ? " " : ", ";
first = false;
if (sigids.count(bit) == 0) {
string &s = sigids[bit];
if (bit.wire == nullptr) {
if (bit == State::S0) s = "\"0\"";
else if (bit == State::S1) s = "\"1\"";
else if (bit == State::Sz) s = "\"z\"";
else s = "\"x\"";
} else
s = stringf("%d", sigidcounter++);
}
str += sigids[bit];
}
return str + " ]";
}
void write_parameters(const dict<IdString, Const> &parameters)
{
bool first = true;
for (auto &param : parameters) {
f << stringf("%s\n", first ? "" : ",");
f << stringf(" %s: ", get_name(param.first).c_str());
if ((param.second.flags & RTLIL::ConstFlags::CONST_FLAG_STRING) != 0)
f << get_string(param.second.decode_string());
else if (GetSize(param.second.bits) > 32)
f << get_string(param.second.as_string());
else
f << stringf("%d", param.second.as_int());
first = false;
}
}
void write_module(Module *module_)
{
module = module_;
log_assert(module->design == design);
sigmap.set(module);
sigids.clear();
// reserve 0 and 1 to avoid confusion with "0" and "1"
sigidcounter = 2;
f << stringf(" %s: {\n", get_name(module->name).c_str());
f << stringf(" \"ports\": {");
bool first = true;
for (auto n : module->ports) {
Wire *w = module->wire(n);
if (use_selection && !module->selected(w))
continue;
f << stringf("%s\n", first ? "" : ",");
f << stringf(" %s: {\n", get_name(n).c_str());
f << stringf(" \"direction\": \"%s\",\n", w->port_input ? w->port_output ? "inout" : "input" : "output");
f << stringf(" \"bits\": %s\n", get_bits(w).c_str());
f << stringf(" }");
first = false;
}
f << stringf("\n },\n");
f << stringf(" \"cells\": {");
first = true;
for (auto c : module->cells()) {
if (use_selection && !module->selected(c))
continue;
f << stringf("%s\n", first ? "" : ",");
f << stringf(" %s: {\n", get_name(c->name).c_str());
f << stringf(" \"hide_name\": %s,\n", c->name[0] == '$' ? "1" : "0");
f << stringf(" \"type\": %s,\n", get_name(c->type).c_str());
f << stringf(" \"parameters\": {");
write_parameters(c->parameters);
f << stringf("\n },\n");
f << stringf(" \"attributes\": {");
write_parameters(c->attributes);
f << stringf("\n },\n");
f << stringf(" \"connections\": {");
bool first2 = true;
for (auto &conn : c->connections()) {
f << stringf("%s\n", first2 ? "" : ",");
f << stringf(" %s: %s", get_name(conn.first).c_str(), get_bits(conn.second).c_str());
first2 = false;
}
f << stringf("\n }\n");
f << stringf(" }");
first = false;
}
f << stringf("\n },\n");
f << stringf(" \"netnames\": {");
first = true;
for (auto w : module->wires()) {
if (use_selection && !module->selected(w))
continue;
f << stringf("%s\n", first ? "" : ",");
f << stringf(" %s: {\n", get_name(w->name).c_str());
f << stringf(" \"hide_name\": %s,\n", w->name[0] == '$' ? "1" : "0");
f << stringf(" \"bits\": %s,\n", get_bits(w).c_str());
f << stringf(" \"attributes\": {");
write_parameters(w->attributes);
f << stringf("\n }\n");
f << stringf(" }");
first = false;
}
f << stringf("\n }\n");
f << stringf(" }");
}
void write_design(Design *design_)
{
design = design_;
f << stringf("{\n");
f << stringf(" \"creator\": %s,\n", get_string(yosys_version_str).c_str());
f << stringf(" \"modules\": {\n");
vector<Module*> modules = use_selection ? design->selected_modules() : design->modules();
bool first_module = true;
for (auto mod : modules) {
if (!first_module)
f << stringf(",\n");
write_module(mod);
first_module = false;
}
f << stringf("\n }\n");
f << stringf("}\n");
}
};
struct JsonBackend : public Backend {
JsonBackend() : Backend("json", "write design to a JSON file") { }
virtual void help()
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" write_json [options] [filename]\n");
log("\n");
log("Write a JSON netlist of the current design.\n");
log("\n");
log("The general syntax of the JSON output created by this command is as follows:\n");
log("\n");
log(" {\n");
log(" \"modules\": {\n");
log(" <module_name>: {\n");
log(" \"ports\": {\n");
log(" <port_name>: <port_details>,\n");
log(" ...\n");
log(" },\n");
log(" \"cells\": {\n");
log(" <cell_name>: <cell_details>,\n");
log(" ...\n");
log(" },\n");
log(" \"netnames\": {\n");
log(" <net_name>: <net_details>,\n");
log(" ...\n");
log(" }\n");
log(" }\n");
log(" }\n");
log(" }\n");
log("\n");
log("Where <port_details> is:\n");
log("\n");
log(" {\n");
log(" \"direction\": <\"input\" | \"output\" | \"inout\">,\n");
log(" \"bits\": <bit_vector>\n");
log(" }\n");
log("\n");
log("And <cell_details> is:\n");
log("\n");
log(" {\n");
log(" \"hide_name\": <1 | 0>,\n");
log(" \"type\": <cell_type>,\n");
log(" \"parameters\": {\n");
log(" <parameter_name>: <parameter_value>,\n");
log(" ...\n");
log(" },\n");
log(" \"attributes\": {\n");
log(" <attribute_name>: <attribute_value>,\n");
log(" ...\n");
log(" },\n");
log(" \"connections\": {\n");
log(" <port_name>: <bit_vector>,\n");
log(" ...\n");
log(" },\n");
log(" }\n");
log("\n");
log("And <net_details> is:\n");
log("\n");
log(" {\n");
log(" \"hide_name\": <1 | 0>,\n");
log(" \"bits\": <bit_vector>\n");
log(" }\n");
log("\n");
log("The \"hide_name\" fields are set to 1 when the name of this cell or net is\n");
log("automatically created and is likely not of interest for a regular user.\n");
log("\n");
log("Module and cell ports and nets can be single bit wide or vectors of multiple\n");
log("bits. Each individual signal bit is assigned a unique integer. The <bit_vector>\n");
log("values referenced above are vectors of this integers. Signal bits that are\n");
log("connected to a constant driver are denoted as string \"0\" or \"1\" instead of\n");
log("a number.\n");
log("\n");
log("For example the following verilog code:\n");
log("\n");
log(" module test(input x, y);\n");
log(" (* keep *) foo #(.P(42), .Q(1337))\n");
log(" foo_inst (.A({x, y}), .B({y, x}), .C({4'd10, {4{x}}}));\n");
log(" endmodule\n");
log("\n");
log("Translates to the following JSON output:\n");
log("\n");
log(" {\n");
log(" \"modules\": {\n");
log(" \"test\": {\n");
log(" \"ports\": {\n");
log(" \"x\": {\n");
log(" \"direction\": \"input\",\n");
log(" \"bits\": [ 2 ]\n");
log(" },\n");
log(" \"y\": {\n");
log(" \"direction\": \"input\",\n");
log(" \"bits\": [ 3 ]\n");
log(" }\n");
log(" },\n");
log(" \"cells\": {\n");
log(" \"foo_inst\": {\n");
log(" \"hide_name\": 0,\n");
log(" \"type\": \"foo\",\n");
log(" \"parameters\": {\n");
log(" \"Q\": 1337,\n");
log(" \"P\": 42\n");
log(" },\n");
log(" \"attributes\": {\n");
log(" \"keep\": 1,\n");
log(" \"src\": \"test.v:2\"\n");
log(" },\n");
log(" \"connections\": {\n");
log(" \"C\": [ 2, 2, 2, 2, \"0\", \"1\", \"0\", \"1\" ],\n");
log(" \"B\": [ 2, 3 ],\n");
log(" \"A\": [ 3, 2 ]\n");
log(" }\n");
log(" }\n");
log(" },\n");
log(" \"netnames\": {\n");
log(" \"y\": {\n");
log(" \"hide_name\": 0,\n");
log(" \"bits\": [ 3 ],\n");
log(" \"attributes\": {\n");
log(" \"src\": \"test.v:1\"\n");
log(" }\n");
log(" },\n");
log(" \"x\": {\n");
log(" \"hide_name\": 0,\n");
log(" \"bits\": [ 2 ],\n");
log(" \"attributes\": {\n");
log(" \"src\": \"test.v:1\"\n");
log(" }\n");
log(" }\n");
log(" }\n");
log(" }\n");
log(" }\n");
log(" }\n");
log("\n");
log("Future version of Yosys might add support for additional fields in the JSON\n");
log("format. A program processing this format must ignore all unkown fields.\n");
log("\n");
}
virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
{
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
// if (args[argidx] == "-verbose") {
// verbose = true;
// continue;
// }
break;
}
extra_args(f, filename, args, argidx);
log_header("Executing JSON backend.\n");
JsonWriter json_writer(*f, false);
json_writer.write_design(design);
}
} JsonBackend;
struct JsonPass : public Pass {
JsonPass() : Pass("json", "write design in JSON format") { }
virtual void help()
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" json [options] [selection]\n");
log("\n");
log("Write a JSON netlist of all selected objects.\n");
log("\n");
log(" -o <filename>\n");
log(" write to the specified file.\n");
log("\n");
log("See 'help write_json' for a description of the JSON format used.\n");
log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
std::string filename;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
if (args[argidx] == "-o" && argidx+1 < args.size()) {
filename = args[++argidx];
continue;
}
break;
}
extra_args(args, argidx, design);
std::ostream *f;
std::stringstream buf;
if (!filename.empty()) {
std::ofstream *ff = new std::ofstream;
ff->open(filename.c_str(), 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 = &buf;
}
JsonWriter json_writer(*f, true);
json_writer.write_design(design);
if (!filename.empty()) {
delete f;
} else {
log("%s", buf.str().c_str());
}
}
} JsonPass;
PRIVATE_NAMESPACE_END

1
backends/smt2/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
test_cells

View File

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

711
backends/smt2/smt2.cc Normal file
View File

@ -0,0 +1,711 @@
/*
* 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/rtlil.h"
#include "kernel/register.h"
#include "kernel/sigtools.h"
#include "kernel/celltypes.h"
#include "kernel/log.h"
#include <string>
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct Smt2Worker
{
CellTypes ct;
SigMap sigmap;
RTLIL::Module *module;
bool bvmode, verbose;
int idcounter;
std::vector<std::string> decls, trans;
std::map<RTLIL::SigBit, RTLIL::Cell*> bit_driver;
std::set<RTLIL::Cell*> exported_cells;
pool<Cell*> recursive_cells, registers;
std::map<RTLIL::SigBit, std::pair<int, int>> fcache;
std::map<int, int> bvsizes;
Smt2Worker(RTLIL::Module *module, bool bvmode, bool verbose) :
ct(module->design), sigmap(module), module(module), bvmode(bvmode), verbose(verbose), idcounter(0)
{
decls.push_back(stringf("(declare-sort |%s_s| 0)\n", log_id(module)));
for (auto cell : module->cells())
for (auto &conn : cell->connections()) {
bool is_input = ct.cell_input(cell->type, conn.first);
bool is_output = ct.cell_output(cell->type, conn.first);
if (is_output && !is_input)
for (auto bit : sigmap(conn.second)) {
if (bit_driver.count(bit))
log_error("Found multiple drivers for %s.\n", log_signal(bit));
bit_driver[bit] = cell;
}
else if (is_output || !is_input)
log_error("Unsupported or unknown directionality on port %s of cell %s.%s (%s).\n",
log_id(conn.first), log_id(module), log_id(cell), log_id(cell->type));
}
}
void register_bool(RTLIL::SigBit bit, int id)
{
if (verbose) log("%*s-> register_bool: %s %d\n", 2+2*GetSize(recursive_cells), "",
log_signal(bit), id);
sigmap.apply(bit);
log_assert(fcache.count(bit) == 0);
fcache[bit] = std::pair<int, int>(id, -1);
}
void register_bv(RTLIL::SigSpec sig, int id)
{
if (verbose) log("%*s-> register_bv: %s %d\n", 2+2*GetSize(recursive_cells), "",
log_signal(sig), id);
log_assert(bvmode);
sigmap.apply(sig);
log_assert(bvsizes.count(id) == 0);
bvsizes[id] = GetSize(sig);
for (int i = 0; i < GetSize(sig); i++) {
log_assert(fcache.count(sig[i]) == 0);
fcache[sig[i]] = std::pair<int, int>(id, i);
}
}
void register_boolvec(RTLIL::SigSpec sig, int id)
{
if (verbose) log("%*s-> register_boolvec: %s %d\n", 2+2*GetSize(recursive_cells), "",
log_signal(sig), id);
log_assert(bvmode);
sigmap.apply(sig);
register_bool(sig[0], id);
for (int i = 1; i < GetSize(sig); i++)
sigmap.add(sig[i], RTLIL::State::S0);
}
std::string get_bool(RTLIL::SigBit bit, const char *state_name = "state")
{
sigmap.apply(bit);
if (bit.wire == nullptr)
return bit == RTLIL::State::S1 ? "true" : "false";
if (bit_driver.count(bit))
export_cell(bit_driver.at(bit));
sigmap.apply(bit);
if (fcache.count(bit) == 0) {
if (verbose) log("%*s-> external bool: %s\n", 2+2*GetSize(recursive_cells), "",
log_signal(bit));
decls.push_back(stringf("(declare-fun |%s#%d| (|%s_s|) Bool) ; %s\n",
log_id(module), idcounter, log_id(module), log_signal(bit)));
register_bool(bit, idcounter++);
}
auto f = fcache.at(bit);
if (f.second >= 0)
return stringf("(= ((_ extract %d %d) (|%s#%d| %s)) #b1)", f.second, f.second, log_id(module), f.first, state_name);
return stringf("(|%s#%d| %s)", log_id(module), f.first, state_name);
}
std::string get_bool(RTLIL::SigSpec sig, const char *state_name = "state")
{
return get_bool(sig.to_single_sigbit(), state_name);
}
std::string get_bv(RTLIL::SigSpec sig, const char *state_name = "state")
{
log_assert(bvmode);
sigmap.apply(sig);
std::vector<std::string> subexpr;
SigSpec orig_sig;
while (orig_sig != sig) {
for (auto bit : sig)
if (bit_driver.count(bit))
export_cell(bit_driver.at(bit));
orig_sig = sig;
sigmap.apply(sig);
}
for (int i = 0, j = 1; i < GetSize(sig); i += j, j = 1)
{
if (sig[i].wire == nullptr) {
while (i+j < GetSize(sig) && sig[i+j].wire == nullptr) j++;
subexpr.push_back("#b");
for (int k = i+j-1; k >= i; k--)
subexpr.back() += sig[k] == RTLIL::State::S1 ? "1" : "0";
continue;
}
if (fcache.count(sig[i]) && fcache.at(sig[i]).second == -1) {
subexpr.push_back(stringf("(ite %s #b1 #b0)", get_bool(sig[i], state_name).c_str()));
continue;
}
if (fcache.count(sig[i])) {
auto t1 = fcache.at(sig[i]);
while (i+j < GetSize(sig)) {
if (fcache.count(sig[i+j]) == 0)
break;
auto t2 = fcache.at(sig[i+j]);
if (t1.first != t2.first)
break;
if (t1.second+j != t2.second)
break;
j++;
}
if (t1.second == 0 && j == bvsizes.at(t1.first))
subexpr.push_back(stringf("(|%s#%d| %s)", log_id(module), t1.first, state_name));
else
subexpr.push_back(stringf("((_ extract %d %d) (|%s#%d| %s))",
t1.second + j - 1, t1.second, log_id(module), t1.first, state_name));
continue;
}
std::set<RTLIL::SigBit> seen_bits = { sig[i] };
while (i+j < GetSize(sig) && sig[i+j].wire && !fcache.count(sig[i+j]) && !seen_bits.count(sig[i+j]))
seen_bits.insert(sig[i+j]), j++;
if (verbose) log("%*s-> external bv: %s\n", 2+2*GetSize(recursive_cells), "",
log_signal(sig.extract(i, j)));
for (auto bit : sig.extract(i, j))
log_assert(bit_driver.count(bit) == 0);
decls.push_back(stringf("(declare-fun |%s#%d| (|%s_s|) (_ BitVec %d)) ; %s\n",
log_id(module), idcounter, log_id(module), j, log_signal(sig.extract(i, j))));
subexpr.push_back(stringf("(|%s#%d| %s)", log_id(module), idcounter, state_name));
register_bv(sig.extract(i, j), idcounter++);
}
if (GetSize(subexpr) > 1) {
std::string expr = "(concat";
for (int i = GetSize(subexpr)-1; i >= 0; i--)
expr += " " + subexpr[i];
return expr + ")";
} else {
log_assert(GetSize(subexpr) == 1);
return subexpr[0];
}
}
void export_gate(RTLIL::Cell *cell, std::string expr)
{
RTLIL::SigBit bit = sigmap(cell->getPort("\\Y").to_single_sigbit());
std::string processed_expr;
for (char ch : expr) {
if (ch == 'A') processed_expr += get_bool(cell->getPort("\\A"));
else if (ch == 'B') processed_expr += get_bool(cell->getPort("\\B"));
else if (ch == 'C') processed_expr += get_bool(cell->getPort("\\C"));
else if (ch == 'D') processed_expr += get_bool(cell->getPort("\\D"));
else if (ch == 'S') processed_expr += get_bool(cell->getPort("\\S"));
else processed_expr += ch;
}
if (verbose) log("%*s-> import cell: %s\n", 2+2*GetSize(recursive_cells), "",
log_id(cell));
decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) Bool %s) ; %s\n",
log_id(module), idcounter, log_id(module), processed_expr.c_str(), log_signal(bit)));
register_bool(bit, idcounter++);
recursive_cells.erase(cell);
}
void export_bvop(RTLIL::Cell *cell, std::string expr, char type = 0)
{
RTLIL::SigSpec sig_a, sig_b;
RTLIL::SigSpec sig_y = sigmap(cell->getPort("\\Y"));
bool is_signed = cell->getParam("\\A_SIGNED").as_bool();
int width = GetSize(sig_y);
if (type == 's' || type == 'd' || type == 'b') {
width = std::max(width, GetSize(cell->getPort("\\A")));
width = std::max(width, GetSize(cell->getPort("\\B")));
}
if (cell->hasPort("\\A")) {
sig_a = cell->getPort("\\A");
sig_a.extend_u0(width, is_signed);
}
if (cell->hasPort("\\B")) {
sig_b = cell->getPort("\\B");
sig_b.extend_u0(width, is_signed && !(type == 's'));
}
std::string processed_expr;
for (char ch : expr) {
if (ch == 'A') processed_expr += get_bv(sig_a);
else if (ch == 'B') processed_expr += get_bv(sig_b);
else if (ch == 'L') processed_expr += is_signed ? "a" : "l";
else if (ch == 'U') processed_expr += is_signed ? "s" : "u";
else processed_expr += ch;
}
if (width != GetSize(sig_y) && type != 'b')
processed_expr = stringf("((_ extract %d 0) %s)", GetSize(sig_y)-1, processed_expr.c_str());
if (verbose) log("%*s-> import cell: %s\n", 2+2*GetSize(recursive_cells), "",
log_id(cell));
if (type == 'b') {
decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) Bool %s) ; %s\n",
log_id(module), idcounter, log_id(module), processed_expr.c_str(), log_signal(sig_y)));
register_boolvec(sig_y, idcounter++);
} else {
decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) (_ BitVec %d) %s) ; %s\n",
log_id(module), idcounter, log_id(module), GetSize(sig_y), processed_expr.c_str(), log_signal(sig_y)));
register_bv(sig_y, idcounter++);
}
recursive_cells.erase(cell);
}
void export_reduce(RTLIL::Cell *cell, std::string expr, bool identity_val)
{
RTLIL::SigSpec sig_y = sigmap(cell->getPort("\\Y"));
std::string processed_expr;
for (char ch : expr)
if (ch == 'A' || ch == 'B') {
RTLIL::SigSpec sig = sigmap(cell->getPort(stringf("\\%c", ch)));
for (auto bit : sig)
processed_expr += " " + get_bool(bit);
if (GetSize(sig) == 1)
processed_expr += identity_val ? " true" : " false";
} else
processed_expr += ch;
if (verbose) log("%*s-> import cell: %s\n", 2+2*GetSize(recursive_cells), "",
log_id(cell));
decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) Bool %s) ; %s\n",
log_id(module), idcounter, log_id(module), processed_expr.c_str(), log_signal(sig_y)));
register_boolvec(sig_y, idcounter++);
recursive_cells.erase(cell);
}
void export_cell(RTLIL::Cell *cell)
{
if (verbose) log("%*s=> export_cell %s (%s) [%s]\n", 2+2*GetSize(recursive_cells), "",
log_id(cell), log_id(cell->type), exported_cells.count(cell) ? "old" : "new");
if (recursive_cells.count(cell))
log_error("Found logic loop in module %s! See cell %s.\n", log_id(module), log_id(cell));
if (exported_cells.count(cell))
return;
exported_cells.insert(cell);
recursive_cells.insert(cell);
if (cell->type == "$_DFF_P_" || cell->type == "$_DFF_N_")
{
registers.insert(cell);
decls.push_back(stringf("(declare-fun |%s#%d| (|%s_s|) Bool) ; %s\n",
log_id(module), idcounter, log_id(module), log_signal(cell->getPort("\\Q"))));
register_bool(cell->getPort("\\Q"), idcounter++);
recursive_cells.erase(cell);
return;
}
if (cell->type == "$_BUF_") return export_gate(cell, "A");
if (cell->type == "$_NOT_") return export_gate(cell, "(not A)");
if (cell->type == "$_AND_") return export_gate(cell, "(and A B)");
if (cell->type == "$_NAND_") return export_gate(cell, "(not (and A B))");
if (cell->type == "$_OR_") return export_gate(cell, "(or A B)");
if (cell->type == "$_NOR_") return export_gate(cell, "(not (or A B))");
if (cell->type == "$_XOR_") return export_gate(cell, "(xor A B)");
if (cell->type == "$_XNOR_") return export_gate(cell, "(not (xor A B))");
if (cell->type == "$_MUX_") return export_gate(cell, "(ite S B A)");
if (cell->type == "$_AOI3_") return export_gate(cell, "(not (or (and A B) C))");
if (cell->type == "$_OAI3_") return export_gate(cell, "(not (and (or A B) C))");
if (cell->type == "$_AOI4_") return export_gate(cell, "(not (or (and A B) (and C D)))");
if (cell->type == "$_OAI4_") return export_gate(cell, "(not (and (or A B) (or C D)))");
// FIXME: $lut
if (!bvmode)
log_error("Unsupported cell type %s for cell %s.%s. (Maybe this cell type would be supported in -bv mode?)\n",
log_id(cell->type), log_id(module), log_id(cell));
if (cell->type == "$dff")
{
registers.insert(cell);
decls.push_back(stringf("(declare-fun |%s#%d| (|%s_s|) (_ BitVec %d)) ; %s\n",
log_id(module), idcounter, log_id(module), GetSize(cell->getPort("\\Q")), log_signal(cell->getPort("\\Q"))));
register_bv(cell->getPort("\\Q"), idcounter++);
recursive_cells.erase(cell);
return;
}
if (cell->type == "$and") return export_bvop(cell, "(bvand A B)");
if (cell->type == "$or") return export_bvop(cell, "(bvor A B)");
if (cell->type == "$xor") return export_bvop(cell, "(bvxor A B)");
if (cell->type == "$xnor") return export_bvop(cell, "(bvxnor A B)");
if (cell->type == "$shl") return export_bvop(cell, "(bvshl A B)", 's');
if (cell->type == "$shr") return export_bvop(cell, "(bvlshr A B)", 's');
if (cell->type == "$sshl") return export_bvop(cell, "(bvshl A B)", 's');
if (cell->type == "$sshr") return export_bvop(cell, "(bvLshr A B)", 's');
// FIXME: $shift $shiftx
if (cell->type == "$lt") return export_bvop(cell, "(bvUlt A B)", 'b');
if (cell->type == "$le") return export_bvop(cell, "(bvUle A B)", 'b');
if (cell->type == "$ge") return export_bvop(cell, "(bvUge A B)", 'b');
if (cell->type == "$gt") return export_bvop(cell, "(bvUgt A B)", 'b');
if (cell->type == "$ne") return export_bvop(cell, "(distinct A B)", 'b');
if (cell->type == "$nex") return export_bvop(cell, "(distinct A B)", 'b');
if (cell->type == "$eq") return export_bvop(cell, "(= A B)", 'b');
if (cell->type == "$eqx") return export_bvop(cell, "(= A B)", 'b');
if (cell->type == "$not") return export_bvop(cell, "(bvnot A)");
if (cell->type == "$pos") return export_bvop(cell, "A");
if (cell->type == "$neg") return export_bvop(cell, "(bvneg A)");
if (cell->type == "$add") return export_bvop(cell, "(bvadd A B)");
if (cell->type == "$sub") return export_bvop(cell, "(bvsub A B)");
if (cell->type == "$mul") return export_bvop(cell, "(bvmul A B)");
if (cell->type == "$div") return export_bvop(cell, "(bvUdiv A B)", 'd');
if (cell->type == "$mod") return export_bvop(cell, "(bvUrem A B)", 'd');
if (cell->type == "$reduce_and") return export_reduce(cell, "(and A)", true);
if (cell->type == "$reduce_or") return export_reduce(cell, "(or A)", false);
if (cell->type == "$reduce_xor") return export_reduce(cell, "(xor A)", false);
if (cell->type == "$reduce_xnor") return export_reduce(cell, "(not (xor A))", false);
if (cell->type == "$reduce_bool") return export_reduce(cell, "(or A)", false);
if (cell->type == "$logic_not") return export_reduce(cell, "(not (or A))", false);
if (cell->type == "$logic_and") return export_reduce(cell, "(and (or A) (or B))", false);
if (cell->type == "$logic_or") return export_reduce(cell, "(or A B)", false);
if (cell->type == "$mux" || cell->type == "$pmux")
{
int width = GetSize(cell->getPort("\\Y"));
std::string processed_expr = get_bv(cell->getPort("\\A"));
RTLIL::SigSpec sig_b = cell->getPort("\\B");
RTLIL::SigSpec sig_s = cell->getPort("\\S");
get_bv(sig_b);
get_bv(sig_s);
for (int i = 0; i < GetSize(sig_s); i++)
processed_expr = stringf("(ite %s %s %s)", get_bool(sig_s[i]).c_str(),
get_bv(sig_b.extract(i*width, width)).c_str(), processed_expr.c_str());
if (verbose) log("%*s-> import cell: %s\n", 2+2*GetSize(recursive_cells), "",
log_id(cell));
RTLIL::SigSpec sig = sigmap(cell->getPort("\\Y"));
decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) (_ BitVec %d) %s) ; %s\n",
log_id(module), idcounter, log_id(module), width, processed_expr.c_str(), log_signal(sig)));
register_bv(sig, idcounter++);
recursive_cells.erase(cell);
return;
}
// FIXME: $slice $concat
log_error("Unsupported cell type %s for cell %s.%s.\n",
log_id(cell->type), log_id(module), log_id(cell));
}
void run()
{
if (verbose) log("=> export logic driving outputs\n");
for (auto wire : module->wires())
if (wire->port_id || wire->get_bool_attribute("\\keep")) {
RTLIL::SigSpec sig = sigmap(wire);
if (bvmode && GetSize(sig) > 1) {
decls.push_back(stringf("(define-fun |%s_n %s| ((state |%s_s|)) (_ BitVec %d) %s)\n",
log_id(module), log_id(wire), log_id(module), GetSize(sig), get_bv(sig).c_str()));
} else {
for (int i = 0; i < GetSize(sig); i++)
if (GetSize(sig) > 1)
decls.push_back(stringf("(define-fun |%s_n %s %d| ((state |%s_s|)) Bool %s)\n",
log_id(module), log_id(wire), i, log_id(module), get_bool(sig[i]).c_str()));
else
decls.push_back(stringf("(define-fun |%s_n %s| ((state |%s_s|)) Bool %s)\n",
log_id(module), log_id(wire), log_id(module), get_bool(sig[i]).c_str()));
}
}
if (verbose) log("=> export logic associated with the initial state\n");
vector<string> init_list;
for (auto wire : module->wires())
if (wire->attributes.count("\\init")) {
RTLIL::SigSpec sig = sigmap(wire);
Const val = wire->attributes.at("\\init");
val.bits.resize(GetSize(sig));
if (bvmode && GetSize(sig) > 1) {
init_list.push_back(stringf("(= %s #b%s) ; %s", get_bv(sig).c_str(), val.as_string().c_str(), log_id(wire)));
} else {
for (int i = 0; i < GetSize(sig); i++)
init_list.push_back(stringf("(= %s %s) ; %s", get_bool(sig[i]).c_str(), val.bits[i] == State::S1 ? "true" : "false", log_id(wire)));
}
}
if (verbose) log("=> export logic driving asserts\n");
vector<int> assert_list, assume_list;
for (auto cell : module->cells())
if (cell->type.in("$assert", "$assume")) {
string name_a = get_bool(cell->getPort("\\A"));
string name_en = get_bool(cell->getPort("\\EN"));
decls.push_back(stringf("(define-fun |%s#%d| ((state |%s_s|)) Bool (or %s (not %s))) ; %s\n",
log_id(module), idcounter, log_id(module), name_a.c_str(), name_en.c_str(), log_id(cell)));
if (cell->type == "$assert")
assert_list.push_back(idcounter++);
else
assume_list.push_back(idcounter++);
}
for (int iter = 1; !registers.empty(); iter++)
{
pool<Cell*> this_regs;
this_regs.swap(registers);
if (verbose) log("=> export logic driving registers [iteration %d]\n", iter);
for (auto cell : this_regs) {
if (cell->type == "$_DFF_P_" || cell->type == "$_DFF_N_") {
std::string expr_d = get_bool(cell->getPort("\\D"));
std::string expr_q = get_bool(cell->getPort("\\Q"), "next_state");
trans.push_back(stringf(" (= %s %s) ; %s %s\n", expr_d.c_str(), expr_q.c_str(), log_id(cell), log_signal(cell->getPort("\\Q"))));
}
if (cell->type == "$dff") {
std::string expr_d = get_bv(cell->getPort("\\D"));
std::string expr_q = get_bv(cell->getPort("\\Q"), "next_state");
trans.push_back(stringf(" (= %s %s) ; %s %s\n", expr_d.c_str(), expr_q.c_str(), log_id(cell), log_signal(cell->getPort("\\Q"))));
}
}
}
string assert_expr = assert_list.empty() ? "true" : "(and";
if (!assert_list.empty()) {
for (int i : assert_list)
assert_expr += stringf(" (|%s#%d| state)", log_id(module), i);
assert_expr += ")";
}
decls.push_back(stringf("(define-fun |%s_a| ((state |%s_s|)) Bool %s)\n",
log_id(module), log_id(module), assert_expr.c_str()));
string assume_expr = assume_list.empty() ? "true" : "(and";
if (!assume_list.empty()) {
for (int i : assume_list)
assume_expr += stringf(" (|%s#%d| state)", log_id(module), i);
assume_expr += ")";
}
decls.push_back(stringf("(define-fun |%s_u| ((state |%s_s|)) Bool %s)\n",
log_id(module), log_id(module), assume_expr.c_str()));
string init_expr = init_list.empty() ? "true" : "(and";
if (!init_list.empty()) {
for (auto &str : init_list)
init_expr += stringf("\n\t%s", str.c_str());
init_expr += "\n)";
}
decls.push_back(stringf("(define-fun |%s_i| ((state |%s_s|)) Bool %s)\n",
log_id(module), log_id(module), init_expr.c_str()));
}
void write(std::ostream &f)
{
for (auto it : decls)
f << it;
f << stringf("(define-fun |%s_t| ((state |%s_s|) (next_state |%s_s|)) Bool ", log_id(module), log_id(module), log_id(module));
if (GetSize(trans) > 1) {
f << "(and\n";
for (auto it : trans)
f << it;
f << "))";
} else
if (GetSize(trans) == 1)
f << "\n" + trans.front() + ")";
else
f << "true)";
f << stringf(" ; end of module %s\n", log_id(module));
}
};
struct Smt2Backend : public Backend {
Smt2Backend() : Backend("smt2", "write design to SMT-LIBv2 file") { }
virtual void help()
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" write_smt2 [options] [filename]\n");
log("\n");
log("Write a SMT-LIBv2 [1] description of the current design. For a module with name\n");
log("'<mod>' this will declare the sort '<mod>_s' (state of the module) and the\n");
log("functions operating on that state.\n");
log("\n");
log("The '<mod>_s' sort represents a module state. Additional '<mod>_n' functions\n");
log("are provided that can be used to access the values of the signals in the module.\n");
log("Only ports, and signals with the 'keep' attribute set are made available via\n");
log("such functions. Without the -bv option, multi-bit wires are exported as\n");
log("separate functions of type Bool for the individual bits. With the -bv option\n");
log("multi-bit wires are exported as single functions of type BitVec.\n");
log("\n");
log("The '<mod>_t' function evaluates to 'true' when the given pair of states\n");
log("describes a valid state transition.\n");
log("\n");
log("The '<mod>_a' function evaluates to 'true' when the given state satisfies\n");
log("the asserts in the module.\n");
log("\n");
log("The '<mod>_u' function evaluates to 'true' when the given state satisfies\n");
log("the assumptions in the module.\n");
log("\n");
log("The '<mod>_i' function evaluates to 'true' when the given state conforms\n");
log("to the initial state.\n");
log("\n");
log(" -verbose\n");
log(" this will print the recursive walk used to export the modules.\n");
log("\n");
log(" -bv\n");
log(" enable support for BitVec (FixedSizeBitVectors theory). with this\n");
log(" option set multi-bit wires are represented using the BitVec sort and\n");
log(" support for coarse grain cells (incl. arithmetic) is enabled.\n");
log("\n");
log(" -tpl <template_file>\n");
log(" use the given template file. the line containing only the token '%%%%'\n");
log(" is replaced with the regular output of this command.\n");
log("\n");
log("[1] For more information on SMT-LIBv2 visit http://smt-lib.org/ or read David\n");
log("R. Cok's tutorial: http://www.grammatech.com/resources/smt/SMTLIBTutorial.pdf\n");
log("\n");
log("---------------------------------------------------------------------------\n");
log("\n");
log("Example:\n");
log("\n");
log("Consider the following module (test.v). We want to prove that the output can\n");
log("never transition from a non-zero value to a zero value.\n");
log("\n");
log(" module test(input clk, output reg [3:0] y);\n");
log(" always @(posedge clk)\n");
log(" y <= (y << 1) | ^y;\n");
log(" endmodule\n");
log("\n");
log("For this proof we create the following template (test.tpl).\n");
log("\n");
log(" ; we need QF_UFBV for this poof\n");
log(" (set-logic QF_UFBV)\n");
log("\n");
log(" ; insert the auto-generated code here\n");
log(" %%%%\n");
log("\n");
log(" ; declare two state variables s1 and s2\n");
log(" (declare-fun s1 () test_s)\n");
log(" (declare-fun s2 () test_s)\n");
log("\n");
log(" ; state s2 is the successor of state s1\n");
log(" (assert (test_t s1 s2))\n");
log("\n");
log(" ; we are looking for a model with y non-zero in s1\n");
log(" (assert (distinct (|test_n y| s1) #b0000))\n");
log("\n");
log(" ; we are looking for a model with y zero in s2\n");
log(" (assert (= (|test_n y| s2) #b0000))\n");
log("\n");
log(" ; is there such a model?\n");
log(" (check-sat)\n");
log("\n");
log("The following yosys script will create a 'test.smt2' file for our proof:\n");
log("\n");
log(" read_verilog test.v\n");
log(" hierarchy -check; proc; opt; check -assert\n");
log(" write_smt2 -bv -tpl test.tpl test.smt2\n");
log("\n");
log("Running 'cvc4 test.smt2' will print 'unsat' because y can never transition\n");
log("from non-zero to zero in the test design.\n");
log("\n");
}
virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
{
std::ifstream template_f;
bool bvmode = false, verbose = false;
log_header("Executing SMT2 backend.\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
if (args[argidx] == "-tpl" && argidx+1 < args.size()) {
template_f.open(args[++argidx]);
if (template_f.fail())
log_error("Can't open template file `%s'.\n", args[argidx].c_str());
continue;
}
if (args[argidx] == "-bv") {
bvmode = true;
continue;
}
if (args[argidx] == "-verbose") {
verbose = true;
continue;
}
break;
}
extra_args(f, filename, args, argidx);
if (template_f.is_open()) {
std::string line;
while (std::getline(template_f, line)) {
int indent = 0;
while (indent < GetSize(line) && (line[indent] == ' ' || line[indent] == '\t'))
indent++;
if (line.substr(indent, 2) == "%%")
break;
*f << line << std::endl;
}
}
*f << stringf("; SMT-LIBv2 description generated by %s\n", yosys_version_str);
for (auto module : design->modules())
{
if (module->get_bool_attribute("\\blackbox") || module->has_memories_warn() || module->has_processes_warn())
continue;
log("Creating SMT-LIBv2 representation of module %s.\n", log_id(module));
Smt2Worker worker(module, bvmode, verbose);
worker.run();
worker.write(*f);
}
*f << stringf("; end of yosys output\n");
if (template_f.is_open()) {
std::string line;
while (std::getline(template_f, line))
*f << line << std::endl;
}
}
} Smt2Backend;
PRIVATE_NAMESPACE_END

View File

@ -0,0 +1,55 @@
#!/bin/bash
set -ex
rm -rf test_cells
mkdir test_cells
cd test_cells
../../../yosys -p 'test_cell -muxdiv -w test all /$alu /$macc /$fa /$lcu /$lut /$shift /$shiftx'
cat > miter.tpl <<- EOT
; #model# (set-option :produce-models true)
(set-logic QF_UFBV)
%%
(declare-fun s () miter_s)
(assert (|miter_n trigger| s))
(check-sat)
; #model# (get-value ((|miter_n in_A| s) (|miter_n in_B| s) (|miter_n gold_Y| s) (|miter_n gate_Y| s) (|miter_n trigger| s)))
EOT
for x in $(set +x; ls test_*.il | sort -R); do
x=${x%.il}
cat > $x.ys <<- EOT
read_ilang $x.il
copy gold gate
cd gate
techmap; opt; abc;;
cd ..
miter -equiv -flatten -make_outputs gold gate miter
hierarchy -check -top miter
dump
write_smt2 -bv -tpl miter.tpl $x.smt2
EOT
../../../yosys -q $x.ys
if ! cvc4 $x.smt2 > $x.result; then
cat $x.result
exit 1
fi
if ! grep unsat $x.result; then
echo "Proof failed! Extracting model..."
sed -i 's/^; #model# //' $x.smt2
cvc4 $x.smt2
exit 1
fi
done
set +x
echo ""
echo " All tests passed."
echo ""
exit 0

View File

@ -24,6 +24,9 @@
#include "kernel/log.h"
#include <string>
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
static void print_spice_net(std::ostream &f, RTLIL::SigBit s, std::string &neg, std::string &pos, std::string &ncpf, int &nc_counter)
{
if (s.wire) {
@ -55,7 +58,7 @@ static void print_spice_module(std::ostream &f, RTLIL::Module *module, RTLIL::De
if (design->modules_.count(cell->type) == 0)
{
log("Warning: no (blackbox) module for cell type `%s' (%s.%s) found! Guessing order of ports.\n",
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()) {
RTLIL::SigSpec sig = sigmap(conn.second);
@ -81,7 +84,7 @@ static void print_spice_module(std::ostream &f, RTLIL::Module *module, RTLIL::De
RTLIL::SigSpec sig(RTLIL::State::Sz, wire->width);
if (cell->hasPort(wire->name)) {
sig = sigmap(cell->getPort(wire->name));
sig.extend(wire->width, false);
sig.extend_u0(wire->width, false);
}
port_sigs.push_back(sig);
}
@ -231,3 +234,4 @@ struct SpiceBackend : public Backend {
}
} SpiceBackend;
PRIVATE_NAMESPACE_END

View File

@ -26,7 +26,6 @@
*
*/
#include "verilog_backend.h"
#include "kernel/register.h"
#include "kernel/celltypes.h"
#include "kernel/log.h"
@ -35,7 +34,8 @@
#include <set>
#include <map>
namespace {
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
bool norename, noattr, attr2comment, noexpr;
int auto_name_counter, auto_name_offset, auto_name_digits;
@ -51,16 +51,17 @@ void reset_auto_counter_id(RTLIL::IdString id, bool may_rename)
if (*str == '$' && may_rename && !norename)
auto_name_map[id] = auto_name_counter++;
if (str[0] != '_' && str[1] != 0)
if (str[0] != '\\' || str[1] != '_' || str[2] == 0)
return;
for (int i = 0; str[i] != 0; i++) {
if (str[i] == '_')
for (int i = 2; str[i] != 0; i++) {
if (str[i] == '_' && str[i+1] == 0)
continue;
if (str[i] < '0' || str[i] > '9')
return;
}
int num = atoi(str+1);
int num = atoi(str+2);
if (num >= auto_name_offset)
auto_name_offset = num + 1;
}
@ -73,22 +74,22 @@ void reset_auto_counter(RTLIL::Module *module)
reset_auto_counter_id(module->name, false);
for (auto it = module->wires_.begin(); it != module->wires_.end(); it++)
for (auto it = module->wires_.begin(); it != module->wires_.end(); ++it)
reset_auto_counter_id(it->second->name, true);
for (auto it = module->cells_.begin(); it != module->cells_.end(); it++) {
for (auto it = module->cells_.begin(); it != module->cells_.end(); ++it) {
reset_auto_counter_id(it->second->name, true);
reset_auto_counter_id(it->second->type, false);
}
for (auto it = module->processes.begin(); it != module->processes.end(); it++)
for (auto it = module->processes.begin(); it != module->processes.end(); ++it)
reset_auto_counter_id(it->second->name, false);
auto_name_digits = 1;
for (size_t i = 10; i < auto_name_offset + auto_name_map.size(); i = i*10)
auto_name_digits++;
for (auto it = auto_name_map.begin(); it != auto_name_map.end(); it++)
for (auto it = auto_name_map.begin(); it != auto_name_map.end(); ++it)
log(" renaming `%s' to `_%0*d_'.\n", it->first.c_str(), auto_name_digits, auto_name_offset + it->second);
}
@ -150,7 +151,7 @@ bool is_reg_wire(RTLIL::SigSpec sig, std::string &reg_name)
return true;
}
void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int offset = 0, bool no_decimal = false, bool set_signed = false)
void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int offset = 0, bool no_decimal = false, bool set_signed = false, bool escape_comment = false)
{
if (width < 0)
width = data.bits.size() - offset;
@ -166,7 +167,7 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o
if (data.bits[i] == RTLIL::S1)
val |= 1 << (i - offset);
}
f << stringf("32'%sd%d", set_signed ? "s" : "", val);
f << stringf("32'%sd %d", set_signed ? "s" : "", val);
} else {
dump_bits:
f << stringf("%d'%sb", width, set_signed ? "s" : "");
@ -198,6 +199,8 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o
f << stringf("\\\"");
else if (str[i] == '\\')
f << stringf("\\\\");
else if (str[i] == '/' && escape_comment && i > 0 && str[i-1] == '*')
f << stringf("\\/");
else
f << str[i];
}
@ -236,7 +239,7 @@ void dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig)
dump_sigchunk(f, sig.as_chunk());
} else {
f << stringf("{ ");
for (auto it = sig.chunks().rbegin(); it != sig.chunks().rend(); it++) {
for (auto it = sig.chunks().rbegin(); it != sig.chunks().rend(); ++it) {
if (it != sig.chunks().rbegin())
f << stringf(", ");
dump_sigchunk(f, *it, true);
@ -245,14 +248,19 @@ void dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig)
}
}
void dump_attributes(std::ostream &f, std::string indent, std::map<RTLIL::IdString, RTLIL::Const> &attributes, char term = '\n')
void dump_attributes(std::ostream &f, std::string indent, dict<RTLIL::IdString, RTLIL::Const> &attributes, char term = '\n', bool modattr = false)
{
if (noattr)
return;
for (auto it = attributes.begin(); it != attributes.end(); it++) {
for (auto it = attributes.begin(); it != attributes.end(); ++it) {
f << stringf("%s" "%s %s", indent.c_str(), attr2comment ? "/*" : "(*", id(it->first).c_str());
f << stringf(" = ");
dump_const(f, it->second);
if (modattr && (it->second == Const(0, 1) || it->second == Const(0)))
f << stringf(" 0 ");
else if (modattr && (it->second == Const(1, 1) || it->second == Const(1)))
f << stringf(" 1 ");
else
dump_const(f, it->second, -1, 0, false, false, attr2comment);
f << stringf(" %s%c", attr2comment ? "*/" : "*)", term);
}
}
@ -315,7 +323,7 @@ std::string cellname(RTLIL::Cell *cell)
if (!norename && cell->name[0] == '$' && reg_ct.count(cell->type) && cell->hasPort("\\Q"))
{
RTLIL::SigSpec sig = cell->getPort("\\Q");
if (SIZE(sig) != 1 || sig.is_fully_const())
if (GetSize(sig) != 1 || sig.is_fully_const())
goto no_special_reg_name;
RTLIL::Wire *wire = sig[0].wire;
@ -663,10 +671,60 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
return true;
}
if (cell->type == "$dff" || cell->type == "$adff")
if (cell->type == "$dffsr")
{
RTLIL::SigSpec sig_clk, sig_arst, val_arst;
bool pol_clk, pol_arst = false;
SigSpec sig_clk = cell->getPort("\\CLK");
SigSpec sig_set = cell->getPort("\\SET");
SigSpec sig_clr = cell->getPort("\\CLR");
SigSpec sig_d = cell->getPort("\\D");
SigSpec sig_q = cell->getPort("\\Q");
int width = cell->parameters["\\WIDTH"].as_int();
bool pol_clk = cell->parameters["\\CLK_POLARITY"].as_bool();
bool pol_set = cell->parameters["\\SET_POLARITY"].as_bool();
bool pol_clr = cell->parameters["\\CLR_POLARITY"].as_bool();
std::string reg_name = cellname(cell);
bool out_is_reg_wire = is_reg_wire(sig_q, reg_name);
if (!out_is_reg_wire)
f << stringf("%s" "reg [%d:0] %s;\n", indent.c_str(), width-1, reg_name.c_str());
for (int i = 0; i < width; i++) {
f << stringf("%s" "always @(%sedge ", indent.c_str(), pol_clk ? "pos" : "neg");
dump_sigspec(f, sig_clk);
f << stringf(", %sedge ", pol_set ? "pos" : "neg");
dump_sigspec(f, sig_set);
f << stringf(", %sedge ", pol_clr ? "pos" : "neg");
dump_sigspec(f, sig_clr);
f << stringf(")\n");
f << stringf("%s" " if (%s", indent.c_str(), pol_clr ? "" : "!");
dump_sigspec(f, sig_clr);
f << stringf(") %s[%d] <= 1'b0;\n", reg_name.c_str(), i);
f << stringf("%s" " else if (%s", indent.c_str(), pol_set ? "" : "!");
dump_sigspec(f, sig_set);
f << stringf(") %s[%d] <= 1'b1;\n", reg_name.c_str(), i);
f << stringf("%s" " else %s[%d] <= ", indent.c_str(), reg_name.c_str(), i);
dump_sigspec(f, sig_d[i]);
f << stringf(";\n");
}
if (!out_is_reg_wire) {
f << stringf("%s" "assign ", indent.c_str());
dump_sigspec(f, sig_q);
f << stringf(" = %s;\n", reg_name.c_str());
}
return true;
}
if (cell->type == "$dff" || cell->type == "$adff" || cell->type == "$dffe")
{
RTLIL::SigSpec sig_clk, sig_arst, sig_en, val_arst;
bool pol_clk, pol_arst = false, pol_en = false;
sig_clk = cell->getPort("\\CLK");
pol_clk = cell->parameters["\\CLK_POLARITY"].as_bool();
@ -677,6 +735,11 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
val_arst = RTLIL::SigSpec(cell->parameters["\\ARST_VALUE"]);
}
if (cell->type == "$dffe") {
sig_en = cell->getPort("\\EN");
pol_en = cell->parameters["\\EN_POLARITY"].as_bool();
}
std::string reg_name = cellname(cell);
bool out_is_reg_wire = is_reg_wire(cell->getPort("\\Q"), reg_name);
@ -701,6 +764,12 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
f << stringf("%s" " else\n", indent.c_str());
}
if (cell->type == "$dffe") {
f << stringf("%s" " if (%s", indent.c_str(), pol_en ? "" : "!");
dump_sigspec(f, sig_en);
f << stringf(")\n");
}
f << stringf("%s" " %s <= ", indent.c_str(), reg_name.c_str());
dump_cell_expr_port(f, cell, "D", false);
f << stringf(";\n");
@ -715,7 +784,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
}
// FIXME: $_SR_[PN][PN]_, $_DLATCH_[PN]_, $_DLATCHSR_[PN][PN][PN]_
// FIXME: $sr, $dffsr, $dlatch, $memrd, $memwr, $mem, $fsm
// FIXME: $sr, $dlatch, $memrd, $memwr, $mem, $fsm
return false;
}
@ -732,12 +801,12 @@ void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell)
if (cell->parameters.size() > 0) {
f << stringf(" #(");
for (auto it = cell->parameters.begin(); it != cell->parameters.end(); it++) {
for (auto it = cell->parameters.begin(); it != cell->parameters.end(); ++it) {
if (it != cell->parameters.begin())
f << stringf(",");
f << stringf("\n%s .%s(", indent.c_str(), id(it->first).c_str());
bool is_signed = (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0;
dump_const(f, it->second, -1, 0, !is_signed, is_signed);
dump_const(f, it->second, -1, 0, false, is_signed);
f << stringf(")");
}
f << stringf("\n%s" ")", indent.c_str());
@ -754,7 +823,7 @@ void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell)
for (int i = 1; true; i++) {
char str[16];
snprintf(str, 16, "$%d", i);
for (auto it = cell->connections().begin(); it != cell->connections().end(); it++) {
for (auto it = cell->connections().begin(); it != cell->connections().end(); ++it) {
if (it->first != str)
continue;
if (!first_arg)
@ -768,7 +837,7 @@ void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell)
break;
found_numbered_port:;
}
for (auto it = cell->connections().begin(); it != cell->connections().end(); it++) {
for (auto it = cell->connections().begin(); it != cell->connections().end(); ++it) {
if (numbered_ports.count(it->first))
continue;
if (!first_arg)
@ -800,7 +869,7 @@ void dump_case_body(std::ostream &f, std::string indent, RTLIL::CaseRule *cs, bo
if (!omit_trailing_begin && number_of_stmts >= 2)
f << stringf("%s" "begin\n", indent.c_str());
for (auto it = cs->actions.begin(); it != cs->actions.end(); it++) {
for (auto it = cs->actions.begin(); it != cs->actions.end(); ++it) {
if (it->first.size() == 0)
continue;
f << stringf("%s ", indent.c_str());
@ -810,7 +879,7 @@ void dump_case_body(std::ostream &f, std::string indent, RTLIL::CaseRule *cs, bo
f << stringf(";\n");
}
for (auto it = cs->switches.begin(); it != cs->switches.end(); it++)
for (auto it = cs->switches.begin(); it != cs->switches.end(); ++it)
dump_proc_switch(f, indent + " ", *it);
if (!omit_trailing_begin && number_of_stmts == 0)
@ -824,7 +893,7 @@ void dump_proc_switch(std::ostream &f, std::string indent, RTLIL::SwitchRule *sw
{
if (sw->signal.size() == 0) {
f << stringf("%s" "begin\n", indent.c_str());
for (auto it = sw->cases.begin(); it != sw->cases.end(); it++) {
for (auto it = sw->cases.begin(); it != sw->cases.end(); ++it) {
if ((*it)->compare.size() == 0)
dump_case_body(f, indent + " ", *it);
}
@ -836,7 +905,7 @@ void dump_proc_switch(std::ostream &f, std::string indent, RTLIL::SwitchRule *sw
dump_sigspec(f, sw->signal);
f << stringf(")\n");
for (auto it = sw->cases.begin(); it != sw->cases.end(); it++) {
for (auto it = sw->cases.begin(); it != sw->cases.end(); ++it) {
f << stringf("%s ", indent.c_str());
if ((*it)->compare.size() == 0)
f << stringf("default");
@ -856,11 +925,11 @@ void dump_proc_switch(std::ostream &f, std::string indent, RTLIL::SwitchRule *sw
void case_body_find_regs(RTLIL::CaseRule *cs)
{
for (auto it = cs->switches.begin(); it != cs->switches.end(); it++)
for (auto it = cs->switches.begin(); it != cs->switches.end(); ++it)
for (auto it2 = (*it)->cases.begin(); it2 != (*it)->cases.end(); it2++)
case_body_find_regs(*it2);
for (auto it = cs->actions.begin(); it != cs->actions.end(); it++) {
for (auto it = cs->actions.begin(); it != cs->actions.end(); ++it) {
for (auto &c : it->first.chunks())
if (c.wire != NULL)
reg_wires.insert(c.wire->name);
@ -871,7 +940,7 @@ void dump_process(std::ostream &f, std::string indent, RTLIL::Process *proc, boo
{
if (find_regs) {
case_body_find_regs(&proc->root_case);
for (auto it = proc->syncs.begin(); it != proc->syncs.end(); it++)
for (auto it = proc->syncs.begin(); it != proc->syncs.end(); ++it)
for (auto it2 = (*it)->actions.begin(); it2 != (*it)->actions.end(); it2++) {
for (auto &c : it2->first.chunks())
if (c.wire != NULL)
@ -925,7 +994,7 @@ void dump_process(std::ostream &f, std::string indent, RTLIL::Process *proc, boo
}
}
for (auto it = sync->actions.begin(); it != sync->actions.end(); it++) {
for (auto it = sync->actions.begin(); it != sync->actions.end(); ++it) {
if (it->first.size() == 0)
continue;
f << stringf("%s ", indent.c_str());
@ -946,7 +1015,7 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module)
active_module = module;
f << stringf("\n");
for (auto it = module->processes.begin(); it != module->processes.end(); it++)
for (auto it = module->processes.begin(); it != module->processes.end(); ++it)
dump_process(f, indent + " ", it->second, true);
if (!noexpr)
@ -979,12 +1048,12 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module)
}
}
dump_attributes(f, indent, module->attributes);
dump_attributes(f, indent, module->attributes, '\n', true);
f << stringf("%s" "module %s(", indent.c_str(), id(module->name, false).c_str());
bool keep_running = true;
for (int port_id = 1; keep_running; port_id++) {
keep_running = false;
for (auto it = module->wires_.begin(); it != module->wires_.end(); it++) {
for (auto it = module->wires_.begin(); it != module->wires_.end(); ++it) {
RTLIL::Wire *wire = it->second;
if (wire->port_id == port_id) {
if (port_id != 1)
@ -997,27 +1066,25 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module)
}
f << stringf(");\n");
for (auto it = module->wires_.begin(); it != module->wires_.end(); it++)
for (auto it = module->wires_.begin(); it != module->wires_.end(); ++it)
dump_wire(f, indent + " ", it->second);
for (auto it = module->memories.begin(); it != module->memories.end(); it++)
for (auto it = module->memories.begin(); it != module->memories.end(); ++it)
dump_memory(f, indent + " ", it->second);
for (auto it = module->cells_.begin(); it != module->cells_.end(); it++)
for (auto it = module->cells_.begin(); it != module->cells_.end(); ++it)
dump_cell(f, indent + " ", it->second);
for (auto it = module->processes.begin(); it != module->processes.end(); it++)
for (auto it = module->processes.begin(); it != module->processes.end(); ++it)
dump_process(f, indent + " ", it->second);
for (auto it = module->connections().begin(); it != module->connections().end(); it++)
for (auto it = module->connections().begin(); it != module->connections().end(); ++it)
dump_conn(f, indent + " ", it->first, it->second);
f << stringf("%s" "endmodule\n", indent.c_str());
active_module = NULL;
}
} /* namespace */
struct VerilogBackend : public Backend {
VerilogBackend() : Backend("verilog", "write design to verilog file") { }
virtual void help()
@ -1122,8 +1189,10 @@ struct VerilogBackend : public Backend {
}
extra_args(f, filename, args, argidx);
design->sort();
*f << stringf("/* Generated by %s */\n", yosys_version_str);
for (auto it = design->modules_.begin(); it != design->modules_.end(); it++) {
for (auto it = design->modules_.begin(); it != design->modules_.end(); ++it) {
if (it->second->get_bool_attribute("\\blackbox") != blackboxes)
continue;
if (selected && !design->selected_whole_module(it->first)) {
@ -1139,3 +1208,4 @@ struct VerilogBackend : public Backend {
}
} VerilogBackend;
PRIVATE_NAMESPACE_END

View File

@ -1,38 +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.
*
* ---
*
* A simple and straightforward verilog backend.
*
* Note that RTLIL processes can't always be mapped easily to a Verilog
* process. Therefore this frontend should only be used to export a
* Verilog netlist (i.e. after the "proc" pass has converted all processes
* to logic networks and registers).
*
*/
#ifndef VERILOG_BACKEND_H
#define VERILOG_BACKEND_H
#include "kernel/yosys.h"
namespace VERILOG_BACKEND {
void verilog_backend(std::ostream &f, std::vector<std::string> args, RTLIL::Design *design);
}
#endif

View File

@ -26,13 +26,18 @@
*
*/
#include "kernel/log.h"
#include "kernel/yosys.h"
#include "libs/sha1/sha1.h"
#include "ast.h"
#include <sstream>
#include <stdarg.h>
#include <math.h>
#if defined(__APPLE__)
# include <cmath>
#else
# include <math.h>
#endif
YOSYS_NAMESPACE_BEGIN
@ -48,12 +53,12 @@ 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, flag_autowire;
bool flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, flag_nolatches, flag_nomeminit, 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;
const std::map<RTLIL::SigBit, RTLIL::SigBit> *genRTLIL_subst_ptr = NULL;
const dict<RTLIL::SigBit, RTLIL::SigBit> *genRTLIL_subst_ptr = NULL;
RTLIL::SigSpec ignoreThisSignalsInInitial;
AstNode *current_top_block, *current_block, *current_block_child;
AstNode *current_always, *current_top_block, *current_block, *current_block_child;
AstModule *current_module;
}
@ -85,6 +90,7 @@ std::string AST::type2str(AstNodeType type)
X(AST_IDENTIFIER)
X(AST_PREFIX)
X(AST_ASSERT)
X(AST_ASSUME)
X(AST_FCALL)
X(AST_TO_BITS)
X(AST_TO_SIGNED)
@ -127,6 +133,7 @@ std::string AST::type2str(AstNodeType type)
X(AST_TERNARY)
X(AST_MEMRD)
X(AST_MEMWR)
X(AST_MEMINIT)
X(AST_TCALL)
X(AST_ASSIGN)
X(AST_CELL)
@ -175,6 +182,10 @@ bool AstNode::get_bool_attribute(RTLIL::IdString id)
// (the optional child arguments make it easier to create AST trees)
AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2)
{
static unsigned int hashidx_count = 123456789;
hashidx_count = mkhash_xorshift(hashidx_count);
hashidx_ = hashidx_count;
this->type = type;
filename = current_filename;
linenum = get_line_num();
@ -267,7 +278,7 @@ void AstNode::dumpAst(FILE *f, std::string indent)
bits[i-1] == RTLIL::S1 ? '1' :
bits[i-1] == RTLIL::Sx ? 'x' :
bits[i-1] == RTLIL::Sz ? 'z' : '?');
fprintf(f, "'(%zd)", bits.size());
fprintf(f, "'(%d)", GetSize(bits));
}
if (is_input)
fprintf(f, " input");
@ -471,7 +482,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent)
else if (bits.size() == 32)
fprintf(f, "%d", RTLIL::Const(bits).as_int());
else
fprintf(f, "%zd'b %s", bits.size(), RTLIL::Const(bits).as_string().c_str());
fprintf(f, "%d'b %s", GetSize(bits), RTLIL::Const(bits).as_string().c_str());
break;
case AST_REALVALUE:
@ -701,6 +712,8 @@ AstNode *AstNode::mkconst_bits(const std::vector<RTLIL::State> &v, bool is_signe
AstNode *AstNode::mkconst_str(const std::vector<RTLIL::State> &v)
{
AstNode *node = mkconst_str(RTLIL::Const(v).decode_string());
while (GetSize(node->bits) < GetSize(v))
node->bits.push_back(RTLIL::State::S0);
log_assert(node->bits == v);
return node;
}
@ -946,6 +959,7 @@ static AstModule* process_module(AstNode *ast, bool defer)
current_module->ast = ast_before_simplify;
current_module->nolatches = flag_nolatches;
current_module->nomeminit = flag_nomeminit;
current_module->nomem2reg = flag_nomem2reg;
current_module->mem2reg = flag_mem2reg;
current_module->lib = flag_lib;
@ -957,13 +971,14 @@ static AstModule* process_module(AstNode *ast, bool defer)
}
// create AstModule instances for all modules in the AST tree and add them to 'design'
void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool dump_vlog, bool nolatches, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool ignore_redef, bool defer, bool autowire)
void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool dump_vlog, bool nolatches, bool nomeminit, 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;
flag_dump_ast2 = dump_ast2;
flag_dump_vlog = dump_vlog;
flag_nolatches = nolatches;
flag_nomeminit = nomeminit;
flag_nomem2reg = nomem2reg;
flag_mem2reg = mem2reg;
flag_lib = lib;
@ -1011,7 +1026,7 @@ 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)
RTLIL::IdString AstModule::derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters)
{
std::string stripped_name = name.str();
@ -1025,6 +1040,7 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, std::map<RTLIL::IdStrin
flag_dump_ast2 = false;
flag_dump_vlog = false;
flag_nolatches = nolatches;
flag_nomeminit = nomeminit;
flag_nomem2reg = nomem2reg;
flag_mem2reg = mem2reg;
flag_lib = lib;
@ -1091,6 +1107,7 @@ RTLIL::Module *AstModule::clone() const
new_mod->ast = ast->clone();
new_mod->nolatches = nolatches;
new_mod->nomeminit = nomeminit;
new_mod->nomem2reg = nomem2reg;
new_mod->mem2reg = mem2reg;
new_mod->lib = lib;

View File

@ -64,6 +64,7 @@ namespace AST
AST_IDENTIFIER,
AST_PREFIX,
AST_ASSERT,
AST_ASSUME,
AST_FCALL,
AST_TO_BITS,
@ -107,6 +108,7 @@ namespace AST
AST_TERNARY,
AST_MEMRD,
AST_MEMWR,
AST_MEMINIT,
AST_TCALL,
AST_ASSIGN,
@ -142,6 +144,10 @@ namespace AST
// The AST is built using instances of this struct
struct AstNode
{
// for dict<> and pool<>
unsigned int hashidx_;
unsigned int hash() const { return hashidx_; }
// this nodes type
AstNodeType type;
@ -204,11 +210,13 @@ 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 in_param);
AstNode *readmem(bool is_readmemh, std::string mem_filename, AstNode *memory, int start_addr, int finish_addr);
void expand_genblock(std::string index_var, std::string prefix, std::map<std::string, std::string> &name_map);
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 mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg_places,
dict<AstNode*, uint32_t> &mem2reg_flags, dict<AstNode*, uint32_t> &proc_flags, uint32_t &status_flags);
void mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block);
bool mem2reg_check(pool<AstNode*> &mem2reg_set);
void meminfo(int &mem_width, int &mem_size, int &addr_bits);
// additional functionality for evaluating constant functions
@ -229,7 +237,7 @@ namespace AST
// 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, const std::map<RTLIL::SigBit, RTLIL::SigBit> *new_subst_ptr = NULL);
RTLIL::SigSpec genWidthRTLIL(int width, const dict<RTLIL::SigBit, RTLIL::SigBit> *new_subst_ptr = NULL);
// compare AST nodes
bool operator==(const AstNode &other) const;
@ -258,15 +266,15 @@ namespace AST
};
// process an AST tree (ast must point to an AST_DESIGN node) and generate RTLIL code
void process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool dump_vlog, bool nolatches, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool ignore_redef, bool defer, bool autowire);
void process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool dump_vlog, bool nolatches, bool nomeminit, 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, autowire;
bool nolatches, nomeminit, nomem2reg, mem2reg, lib, noopt, icells, autowire;
virtual ~AstModule();
virtual RTLIL::IdString derive(RTLIL::Design *design, std::map<RTLIL::IdString, RTLIL::Const> parameters);
virtual RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters);
virtual RTLIL::Module *clone() const;
};
@ -288,12 +296,12 @@ namespace AST
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, flag_autowire;
extern bool flag_dump_ast1, flag_dump_ast2, flag_nolatches, flag_nomeminit, 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 const std::map<RTLIL::SigBit, RTLIL::SigBit> *genRTLIL_subst_ptr;
extern const dict<RTLIL::SigBit, RTLIL::SigBit> *genRTLIL_subst_ptr;
extern RTLIL::SigSpec ignoreThisSignalsInInitial;
extern AST::AstNode *current_top_block, *current_block, *current_block_child;
extern AST::AstNode *current_always, *current_top_block, *current_block, *current_block_child;
extern AST::AstModule *current_module;
struct ProcessGenerator;
}

View File

@ -24,6 +24,8 @@
#include <dlfcn.h>
#include <ffi.h>
YOSYS_NAMESPACE_BEGIN
typedef void (*ffi_fptr) ();
static ffi_fptr resolve_fn (std::string symbol_name)
@ -73,8 +75,8 @@ AST::AstNode *AST::dpi_call(const std::string &rtype, const std::string &fname,
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++) {
log_assert(GetSize(args) == GetSize(argtypes));
for (int i = 0; i < GetSize(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);
@ -129,12 +131,18 @@ AST::AstNode *AST::dpi_call(const std::string &rtype, const std::string &fname,
return newNode;
}
YOSYS_NAMESPACE_END
#else /* YOSYS_ENABLE_PLUGINS */
YOSYS_NAMESPACE_BEGIN
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());
}
YOSYS_NAMESPACE_END
#endif /* YOSYS_ENABLE_PLUGINS */

View File

@ -73,7 +73,7 @@ static RTLIL::SigSpec uniop2rtlil(AstNode *that, std::string type, int result_wi
static void widthExtend(AstNode *that, RTLIL::SigSpec &sig, int width, bool is_signed)
{
if (width <= sig.size()) {
sig.extend(width, is_signed);
sig.extend_u0(width, is_signed);
return;
}
@ -254,7 +254,7 @@ struct AST_INTERNAL::ProcessGenerator
// create initial assignments for the temporary signals
if ((flag_nolatches || always->get_bool_attribute("\\nolatches") || current_module->get_bool_attribute("\\nolatches")) && !found_clocked_sync) {
subst_rvalue_map = subst_lvalue_from.to_sigbit_map(RTLIL::SigSpec(RTLIL::State::Sx, SIZE(subst_lvalue_from)));
subst_rvalue_map = subst_lvalue_from.to_sigbit_dict(RTLIL::SigSpec(RTLIL::State::Sx, GetSize(subst_lvalue_from)));
} else {
addChunkActions(current_case->actions, subst_lvalue_to, subst_lvalue_from);
}
@ -289,8 +289,8 @@ struct AST_INTERNAL::ProcessGenerator
{
RTLIL::SigSpec new_lhs, new_rhs;
log_assert(SIZE(lhs) == SIZE(rhs));
for (int i = 0; i < SIZE(lhs); i++) {
log_assert(GetSize(lhs) == GetSize(rhs));
for (int i = 0; i < GetSize(lhs); i++) {
if (lhs[i].wire == nullptr)
continue;
new_lhs.append(lhs[i]);
@ -306,7 +306,7 @@ struct AST_INTERNAL::ProcessGenerator
{
std::vector<RTLIL::SigChunk> chunks = sig.chunks();
for (int i = 0; i < SIZE(chunks); i++)
for (int i = 0; i < GetSize(chunks); i++)
{
RTLIL::SigChunk &chunk = chunks[i];
if (chunk.wire == NULL)
@ -430,7 +430,7 @@ struct AST_INTERNAL::ProcessGenerator
lvalue.replace(subst_lvalue_map.stdmap());
if (ast->type == AST_ASSIGN_EQ) {
for (int i = 0; i < SIZE(unmapped_lvalue); i++)
for (int i = 0; i < GetSize(unmapped_lvalue); i++)
subst_rvalue_map.set(unmapped_lvalue[i], rvalue[i]);
}
@ -472,7 +472,7 @@ struct AST_INTERNAL::ProcessGenerator
subst_lvalue_map.save();
subst_rvalue_map.save();
for (int i = 0; i < SIZE(this_case_eq_lvalue); i++)
for (int i = 0; i < GetSize(this_case_eq_lvalue); i++)
subst_lvalue_map.set(this_case_eq_lvalue[i], this_case_eq_ltemp[i]);
RTLIL::CaseRule *backup_case = current_case;
@ -507,7 +507,7 @@ struct AST_INTERNAL::ProcessGenerator
sw->cases.push_back(default_case);
}
for (int i = 0; i < SIZE(this_case_eq_lvalue); i++)
for (int i = 0; i < GetSize(this_case_eq_lvalue); i++)
subst_rvalue_map.set(this_case_eq_lvalue[i], this_case_eq_ltemp[i]);
this_case_eq_lvalue.replace(subst_lvalue_map.stdmap());
@ -567,9 +567,11 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
if (id_ast->children.size() > 1 && id_ast->children[1]->range_valid) {
this_width = id_ast->children[1]->range_left - id_ast->children[1]->range_right + 1;
} else
if (id_ast->children[0]->type == AST_CONSTANT) {
if (id_ast->children[0]->type != AST_CONSTANT)
while (id_ast->simplify(true, false, false, 1, -1, false, true)) { }
if (id_ast->children[0]->type == AST_CONSTANT)
this_width = id_ast->children[0]->bits.size();
} else
else
log_error("Failed to detect width for parameter %s at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
if (children.size() != 0)
range = children[0];
@ -839,14 +841,15 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
memory->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
memory->name = str;
memory->width = children[0]->range_left - children[0]->range_right + 1;
memory->start_offset = children[0]->range_right;
memory->size = children[1]->range_left - children[1]->range_right;
if (children[1]->range_right < children[1]->range_left) {
memory->start_offset = children[1]->range_right;
memory->size = children[1]->range_left - children[1]->range_right + 1;
} else {
memory->start_offset = children[1]->range_left;
memory->size = children[1]->range_right - children[1]->range_left + 1;
}
current_module->memories[memory->name] = memory;
if (memory->size < 0)
memory->size *= -1;
memory->size += std::min(children[1]->range_left, children[1]->range_right) + 1;
for (auto &attr : attributes) {
if (attr.second->type != AST_CONSTANT)
log_error("Attribute `%s' with non-constant value at %s:%d!\n",
@ -869,7 +872,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
case AST_REALVALUE:
{
RTLIL::SigSpec sig = realAsConst(width_hint);
log("Warning: converting real value %e to binary %s at %s:%d.\n",
log_warning("converting real value %e to binary %s at %s:%d.\n",
realvalue, log_signal(sig), filename.c_str(), linenum);
return sig;
}
@ -890,7 +893,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
wire->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
wire->name = str;
if (flag_autowire)
log("Warning: Identifier `%s' is implicitly declared at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
log_warning("Identifier `%s' is implicitly declared at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
else
log_error("Identifier `%s' is implicitly declared at %s:%d and `default_nettype is set to none.\n", str.c_str(), filename.c_str(), linenum);
}
@ -941,7 +944,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
shift_val = current_module->Sub(NEW_ID, RTLIL::SigSpec(source_width - width), shift_val, fake_ast->children[1]->is_signed);
fake_ast->children[1]->is_signed = true;
}
if (SIZE(shift_val) >= 32)
if (GetSize(shift_val) >= 32)
fake_ast->children[1]->is_signed = true;
RTLIL::SigSpec sig = binop2rtlil(fake_ast, "$shiftx", width, fake_ast->children[0]->genRTLIL(), shift_val);
delete left_at_zero_ast;
@ -955,10 +958,10 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
chunk.offset = (id2ast->range_left - id2ast->range_right + 1) - (chunk.offset + chunk.width);
if (chunk.offset >= source_width || chunk.offset + chunk.width < 0) {
if (chunk.width == 1)
log("Warning: Range select out of bounds on signal `%s' at %s:%d: Setting result bit to undef.\n",
log_warning("Range select out of bounds on signal `%s' at %s:%d: Setting result bit to undef.\n",
str.c_str(), filename.c_str(), linenum);
else
log("Warning: Range select out of bounds on signal `%s' at %s:%d: Setting all %d result bits to undef.\n",
log_warning("Range select out of bounds on signal `%s' at %s:%d: Setting all %d result bits to undef.\n",
str.c_str(), filename.c_str(), linenum, chunk.width);
chunk = RTLIL::SigChunk(RTLIL::State::Sx, chunk.width);
} else {
@ -972,10 +975,10 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
chunk.offset += add_undef_bits_lsb;
}
if (add_undef_bits_lsb)
log("Warning: Range select out of bounds on signal `%s' at %s:%d: Setting %d LSB bits to undef.\n",
log_warning("Range select out of bounds on signal `%s' at %s:%d: Setting %d LSB bits to undef.\n",
str.c_str(), filename.c_str(), linenum, add_undef_bits_lsb);
if (add_undef_bits_msb)
log("Warning: Range select out of bounds on signal `%s' at %s:%d: Setting %d MSB bits to undef.\n",
log_warning("Range select out of bounds on signal `%s' at %s:%d: Setting %d MSB bits to undef.\n",
str.c_str(), filename.c_str(), linenum, add_undef_bits_msb);
}
}
@ -1213,9 +1216,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
RTLIL::Wire *wire = current_module->addWire(cell->name.str() + "_DATA", current_module->memories[str]->width);
wire->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
int addr_bits = 1;
while ((1 << addr_bits) < current_module->memories[str]->size)
addr_bits++;
int mem_width, mem_size, addr_bits;
id2ast->meminfo(mem_width, mem_size, addr_bits);
cell->setPort("\\CLK", RTLIL::SigSpec(RTLIL::State::Sx, 1));
cell->setPort("\\ADDR", children[0]->genWidthRTLIL(addr_bits));
@ -1234,28 +1236,30 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
// generate $memwr cells for memory write ports
case AST_MEMWR:
case AST_MEMINIT:
{
std::stringstream sstr;
sstr << "$memwr$" << str << "$" << filename << ":" << linenum << "$" << (autoidx++);
sstr << (type == AST_MEMWR ? "$memwr$" : "$meminit$") << str << "$" << filename << ":" << linenum << "$" << (autoidx++);
RTLIL::Cell *cell = current_module->addCell(sstr.str(), "$memwr");
RTLIL::Cell *cell = current_module->addCell(sstr.str(), type == AST_MEMWR ? "$memwr" : "$meminit");
cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
int addr_bits = 1;
while ((1 << addr_bits) < current_module->memories[str]->size)
addr_bits++;
int mem_width, mem_size, addr_bits;
id2ast->meminfo(mem_width, mem_size, addr_bits);
cell->setPort("\\CLK", RTLIL::SigSpec(RTLIL::State::Sx, 1));
cell->setPort("\\ADDR", children[0]->genWidthRTLIL(addr_bits));
cell->setPort("\\DATA", children[1]->genWidthRTLIL(current_module->memories[str]->width));
cell->setPort("\\EN", children[2]->genRTLIL());
cell->parameters["\\MEMID"] = RTLIL::Const(str);
cell->parameters["\\ABITS"] = RTLIL::Const(addr_bits);
cell->parameters["\\WIDTH"] = RTLIL::Const(current_module->memories[str]->width);
cell->parameters["\\CLK_ENABLE"] = RTLIL::Const(0);
cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(0);
if (type == AST_MEMWR) {
cell->setPort("\\CLK", RTLIL::SigSpec(RTLIL::State::Sx, 1));
cell->setPort("\\EN", children[2]->genRTLIL());
cell->parameters["\\CLK_ENABLE"] = RTLIL::Const(0);
cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(0);
}
cell->parameters["\\PRIORITY"] = RTLIL::Const(autoidx-1);
}
@ -1263,19 +1267,22 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
// generate $assert cells
case AST_ASSERT:
case AST_ASSUME:
{
log_assert(children.size() == 2);
RTLIL::SigSpec check = children[0]->genRTLIL();
log_assert(check.size() == 1);
if (GetSize(check) != 1)
check = current_module->ReduceBool(NEW_ID, check);
RTLIL::SigSpec en = children[1]->genRTLIL();
log_assert(en.size() == 1);
if (GetSize(en) != 1)
en = current_module->ReduceBool(NEW_ID, en);
std::stringstream sstr;
sstr << "$assert$" << filename << ":" << linenum << "$" << (autoidx++);
sstr << (type == AST_ASSERT ? "$assert$" : "$assume$") << filename << ":" << linenum << "$" << (autoidx++);
RTLIL::Cell *cell = current_module->addCell(sstr.str(), "$assert");
RTLIL::Cell *cell = current_module->addCell(sstr.str(), type == AST_ASSERT ? "$assert" : "$assume");
cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
for (auto &attr : attributes) {
@ -1293,15 +1300,23 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
// add entries to current_module->connections for assignments (outside of always blocks)
case AST_ASSIGN:
{
if (children[0]->type == AST_IDENTIFIER && children[0]->id2ast && children[0]->id2ast->type == AST_AUTOWIRE) {
RTLIL::SigSpec right = children[1]->genRTLIL();
RTLIL::SigSpec left = children[0]->genWidthRTLIL(right.size());
current_module->connect(RTLIL::SigSig(left, right));
} else {
RTLIL::SigSpec left = children[0]->genRTLIL();
RTLIL::SigSpec right = children[1]->genWidthRTLIL(left.size());
current_module->connect(RTLIL::SigSig(left, right));
RTLIL::SigSpec left = children[0]->genRTLIL();
RTLIL::SigSpec right = children[1]->genWidthRTLIL(left.size());
if (left.has_const()) {
RTLIL::SigSpec new_left, new_right;
for (int i = 0; i < GetSize(left); i++)
if (left[i].wire) {
new_left.append(left[i]);
new_right.append(right[i]);
}
log_warning("Ignoring assignment to constant bits at %s:%d:\n"
" old assignment: %s = %s\n new assignment: %s = %s.\n",
filename.c_str(), linenum, log_signal(left), log_signal(right),
log_signal(new_left), log_signal(new_right));
left = new_left;
right = new_right;
}
current_module->connect(RTLIL::SigSig(left, right));
}
break;
@ -1326,16 +1341,19 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
continue;
}
if (child->type == AST_PARASET) {
if (child->children[0]->type != AST_CONSTANT)
log_error("Parameter `%s' with non-constant value at %s:%d!\n",
child->str.c_str(), filename.c_str(), linenum);
if (child->str.size() == 0) {
char buf[100];
snprintf(buf, 100, "$%d", ++para_counter);
cell->parameters[buf] = child->children[0]->asParaConst();
} else {
cell->parameters[child->str] = child->children[0]->asParaConst();
IdString paraname = child->str.empty() ? stringf("$%d", ++para_counter) : child->str;
if (child->children[0]->type == AST_REALVALUE) {
log_warning("Replacing floating point parameter %s.%s = %f with string at %s:%d.\n",
log_id(cell), log_id(paraname), child->children[0]->realvalue,
filename.c_str(), linenum);
auto strnode = AstNode::mkconst_str(stringf("%f", child->children[0]->realvalue));
strnode->cloneInto(child->children[0]);
delete strnode;
}
if (child->children[0]->type != AST_CONSTANT)
log_error("Parameter %s.%s with non-constant value at %s:%d!\n",
log_id(cell), log_id(paraname), filename.c_str(), linenum);
cell->parameters[paraname] = child->children[0]->asParaConst();
continue;
}
if (child->type == AST_ARGUMENT) {
@ -1391,9 +1409,9 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
// this is a wrapper for AstNode::genRTLIL() when a specific signal width is requested and/or
// signals must be substituted before beeing used as input values (used by ProcessGenerator)
// note that this is using some global variables to communicate this special settings to AstNode::genRTLIL().
RTLIL::SigSpec AstNode::genWidthRTLIL(int width, const std::map<RTLIL::SigBit, RTLIL::SigBit> *new_subst_ptr)
RTLIL::SigSpec AstNode::genWidthRTLIL(int width, const dict<RTLIL::SigBit, RTLIL::SigBit> *new_subst_ptr)
{
const std::map<RTLIL::SigBit, RTLIL::SigBit> *backup_subst_ptr = genRTLIL_subst_ptr;
const dict<RTLIL::SigBit, RTLIL::SigBit> *backup_subst_ptr = genRTLIL_subst_ptr;
if (new_subst_ptr)
genRTLIL_subst_ptr = new_subst_ptr;

View File

@ -28,10 +28,12 @@
#include "kernel/log.h"
#include "libs/sha1/sha1.h"
#include "frontends/verilog/verilog_frontend.h"
#include "ast.h"
#include <sstream>
#include <stdarg.h>
#include <stdlib.h>
#include <math.h>
YOSYS_NAMESPACE_BEGIN
@ -47,39 +49,55 @@ using namespace AST_INTERNAL;
// nodes that link to a different node using names and lexical scoping.
bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, int width_hint, bool sign_hint, bool in_param)
{
static int recursion_counter = 0;
static pair<string, int> last_blocking_assignment_warn;
static bool deep_recursion_warning = false;
if (recursion_counter++ == 1000 && deep_recursion_warning) {
log_warning("Deep recursion in AST simplifier.\nDoes this design contain insanely long expressions?\n");
deep_recursion_warning = false;
}
AstNode *newNode = NULL;
bool did_something = false;
#if 0
log("-------------\n");
log("AST simplify[%d] depth %d at %s:%d,\n", stage, recursion_counter, filename.c_str(), linenum);
log("const_fold=%d, at_zero=%d, in_lvalue=%d, stage=%d, width_hint=%d, sign_hint=%d, in_param=%d\n",
int(const_fold), int(at_zero), int(in_lvalue), int(stage), int(width_hint), int(sign_hint), int(in_param));
dumpAst(NULL, "> ");
// dumpAst(NULL, "> ");
#endif
if (stage == 0)
{
log_assert(type == AST_MODULE);
last_blocking_assignment_warn = pair<string, int>();
deep_recursion_warning = true;
while (simplify(const_fold, at_zero, in_lvalue, 1, width_hint, sign_hint, in_param)) { }
if (!flag_nomem2reg && !get_bool_attribute("\\nomem2reg"))
{
std::map<AstNode*, std::set<std::string>> mem2reg_places;
std::map<AstNode*, uint32_t> mem2reg_candidates, dummy_proc_flags;
dict<AstNode*, pool<std::string>> mem2reg_places;
dict<AstNode*, uint32_t> mem2reg_candidates, dummy_proc_flags;
uint32_t flags = flag_mem2reg ? AstNode::MEM2REG_FL_ALL : 0;
mem2reg_as_needed_pass1(mem2reg_places, mem2reg_candidates, dummy_proc_flags, flags);
std::set<AstNode*> mem2reg_set;
pool<AstNode*> mem2reg_set;
for (auto &it : mem2reg_candidates)
{
AstNode *mem = it.first;
uint32_t memflags = it.second;
bool this_nomeminit = flag_nomeminit;
log_assert((memflags & ~0x00ffff00) == 0);
if (mem->get_bool_attribute("\\nomem2reg"))
continue;
if (mem->get_bool_attribute("\\nomeminit") || get_bool_attribute("\\nomeminit"))
this_nomeminit = true;
if (memflags & AstNode::MEM2REG_FL_FORCED)
goto silent_activate;
@ -89,7 +107,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (memflags & AstNode::MEM2REG_FL_SET_ASYNC)
goto verbose_activate;
if ((memflags & AstNode::MEM2REG_FL_SET_INIT) && (memflags & AstNode::MEM2REG_FL_SET_ELSE))
if ((memflags & AstNode::MEM2REG_FL_SET_INIT) && (memflags & AstNode::MEM2REG_FL_SET_ELSE) && this_nomeminit)
goto verbose_activate;
if (memflags & AstNode::MEM2REG_FL_CMPLX_LHS)
@ -100,13 +118,13 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
verbose_activate:
if (mem2reg_set.count(mem) == 0) {
log("Warning: Replacing memory %s with list of registers.", mem->str.c_str());
std::string message = stringf("Replacing memory %s with list of registers.", mem->str.c_str());
bool first_element = true;
for (auto &place : mem2reg_places[it.first]) {
log("%s%s", first_element ? " See " : ", ", place.c_str());
message += stringf("%s%s", first_element ? " See " : ", ", place.c_str());
first_element = false;
}
log("\n");
log_warning("%s\n", message.c_str());
}
silent_activate:
@ -141,6 +159,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
}
while (simplify(const_fold, at_zero, in_lvalue, 2, width_hint, sign_hint, in_param)) { }
recursion_counter--;
return false;
}
@ -149,11 +168,15 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
// we do not look inside a task or function
// (but as soon as a task of function is instanciated we process the generated AST as usual)
if (type == AST_FUNCTION || type == AST_TASK)
if (type == AST_FUNCTION || type == AST_TASK) {
recursion_counter--;
return false;
}
// deactivate all calls to non-synthesis system taks
if ((type == AST_FCALL || type == AST_TCALL) && (str == "$display" || str == "$stop" || str == "$finish")) {
if ((type == AST_FCALL || type == AST_TCALL) && (str == "$display" || str == "$strobe" || str == "$monitor" || str == "$time" || str == "$stop" || str == "$finish" ||
str == "$dumpfile" || str == "$dumpvars" || str == "$dumpon" || str == "$dumpoff" || str == "$dumpall")) {
log_warning("Ignoring call to system %s %s at %s:%d.\n", type == AST_FCALL ? "function" : "task", str.c_str(), filename.c_str(), linenum);
delete_children();
str = std::string();
}
@ -182,6 +205,13 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
AstNode *first_node = this_wire_scope[node->str];
if (!node->is_input && !node->is_output && node->is_reg && node->children.size() == 0)
goto wires_are_compatible;
if (first_node->children.size() == 0 && node->children.size() == 1 && node->children[0]->type == AST_RANGE) {
AstNode *r = node->children[0];
if (r->range_valid && r->range_left == 0 && r->range_right == 0) {
delete r;
node->children.pop_back();
}
}
if (first_node->children.size() != node->children.size())
goto wires_are_incompatible;
for (size_t j = 0; j < node->children.size(); j++) {
@ -242,6 +272,10 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
auto backup_current_block = current_block;
auto backup_current_block_child = current_block_child;
auto backup_current_top_block = current_top_block;
auto backup_current_always = current_always;
if (type == AST_ALWAYS || type == AST_INITIAL)
current_always = this;
int backup_width_hint = width_hint;
bool backup_sign_hint = sign_hint;
@ -382,6 +416,41 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
}
}
if (const_fold && type == AST_CASE)
{
while (children[0]->simplify(const_fold, at_zero, in_lvalue, stage, width_hint, sign_hint, in_param)) { }
if (children[0]->type == AST_CONSTANT && children[0]->bits_only_01()) {
std::vector<AstNode*> new_children;
new_children.push_back(children[0]);
for (int i = 1; i < GetSize(children); i++) {
AstNode *child = children[i];
log_assert(child->type == AST_COND);
for (auto v : child->children) {
if (v->type == AST_DEFAULT)
goto keep_const_cond;
if (v->type == AST_BLOCK)
continue;
while (v->simplify(const_fold, at_zero, in_lvalue, stage, width_hint, sign_hint, in_param)) { }
if (v->type == AST_CONSTANT && v->bits_only_01()) {
if (v->bits == children[0]->bits) {
while (i+1 < GetSize(children))
delete children[++i];
goto keep_const_cond;
}
continue;
}
goto keep_const_cond;
}
if (0)
keep_const_cond:
new_children.push_back(child);
else
delete child;
}
new_children.swap(children);
}
}
// simplify all children first
// (iterate by index as e.g. auto wires can add new children in the process)
for (size_t i = 0; i < children.size(); i++) {
@ -446,6 +515,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
current_block = backup_current_block;
current_block_child = backup_current_block_child;
current_top_block = backup_current_top_block;
current_always = backup_current_always;
for (auto it = backup_scope.begin(); it != backup_scope.end(); it++) {
if (it->second == NULL)
@ -575,9 +645,9 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
{
AstNode *index_expr = nullptr;
for (int i = 0; 2*i < SIZE(id2ast->multirange_dimensions); i++)
for (int i = 0; 2*i < GetSize(id2ast->multirange_dimensions); i++)
{
if (SIZE(children[0]->children) < i)
if (GetSize(children[0]->children) < i)
log_error("Insufficient number of array indices for %s at %s:%d.\n", log_id(str), filename.c_str(), linenum);
AstNode *new_index_expr = children[0]->children[i]->children.at(0)->clone();
@ -591,7 +661,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
index_expr = new AstNode(AST_ADD, new AstNode(AST_MUL, index_expr, AstNode::mkconst_int(id2ast->multirange_dimensions[2*i-1], true)), new_index_expr);
}
for (int i = SIZE(id2ast->multirange_dimensions)/1; i < SIZE(children[0]->children); i++)
for (int i = GetSize(id2ast->multirange_dimensions)/1; i < GetSize(children[0]->children); i++)
children.push_back(children[0]->children[i]->clone());
delete children[0];
@ -611,7 +681,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
int width = children[1]->range_left - children[1]->range_right + 1;
if (children[0]->type == AST_REALVALUE) {
RTLIL::Const constvalue = children[0]->realAsConst(width);
log("Warning: converting real value %e to binary %s at %s:%d.\n",
log_warning("converting real value %e to binary %s at %s:%d.\n",
children[0]->realvalue, log_signal(constvalue), filename.c_str(), linenum);
delete children[0];
children[0] = mkconst_bits(constvalue.bits, sign_hint);
@ -653,7 +723,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
}
}
if (current_scope.count(str) == 0) {
// log("Warning: Creating auto-wire `%s' in module `%s'.\n", str.c_str(), current_ast_mod->str.c_str());
// log_warning("Creating auto-wire `%s' in module `%s'.\n", str.c_str(), current_ast_mod->str.c_str());
AstNode *auto_wire = new AstNode(AST_AUTOWIRE);
auto_wire->str = str;
current_ast_mod->children.push_back(auto_wire);
@ -1123,7 +1193,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT)
log_error("Unsupported expression on dynamic range select on signal `%s' at %s:%d!\n",
str.c_str(), filename.c_str(), linenum);
result_width = abs(left_at_zero_ast->integer - right_at_zero_ast->integer) + 1;
result_width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1;
}
did_something = true;
newNode = new AstNode(AST_CASE, shift_expr);
@ -1141,7 +1211,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
}
skip_dynamic_range_lvalue_expansion:;
if (stage > 1 && type == AST_ASSERT && current_block != NULL)
if (stage > 1 && (type == AST_ASSERT || type == AST_ASSUME) && current_block != NULL)
{
std::stringstream sstr;
sstr << "$assert$" << filename << ":" << linenum << "$" << (autoidx++);
@ -1185,7 +1255,7 @@ skip_dynamic_range_lvalue_expansion:;
newNode->children.push_back(assign_check);
newNode->children.push_back(assign_en);
AstNode *assertnode = new AstNode(AST_ASSERT);
AstNode *assertnode = new AstNode(type);
assertnode->children.push_back(new AstNode(AST_IDENTIFIER));
assertnode->children.push_back(new AstNode(AST_IDENTIFIER));
assertnode->children[0]->str = id_check;
@ -1196,9 +1266,8 @@ skip_dynamic_range_lvalue_expansion:;
goto apply_newNode;
}
if (stage > 1 && type == AST_ASSERT && children.size() == 1)
if (stage > 1 && (type == AST_ASSERT || type == AST_ASSUME) && children.size() == 1)
{
children[0] = new AstNode(AST_REDUCE_BOOL, children[0]->clone());
children.push_back(mkconst_int(1, false, 1));
did_something = true;
}
@ -1222,9 +1291,13 @@ skip_dynamic_range_lvalue_expansion:;
sstr << "$memwr$" << children[0]->str << "$" << filename << ":" << linenum << "$" << (autoidx++);
std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA", id_en = sstr.str() + "_EN";
if (type == AST_ASSIGN_EQ)
log("Warning: Blocking assignment to memory in line %s:%d is handled like a non-blocking assignment.\n",
filename.c_str(), linenum);
if (type == AST_ASSIGN_EQ) {
pair<string, int> this_blocking_assignment_warn(filename, linenum);
if (this_blocking_assignment_warn != last_blocking_assignment_warn)
log_warning("Blocking assignment to memory in line %s:%d is handled like a non-blocking assignment.\n",
filename.c_str(), linenum);
last_blocking_assignment_warn = this_blocking_assignment_warn;
}
int mem_width, mem_size, addr_bits;
children[0]->id2ast->meminfo(mem_width, mem_size, addr_bits);
@ -1241,11 +1314,14 @@ skip_dynamic_range_lvalue_expansion:;
current_scope[wire_data->str] = wire_data;
while (wire_data->simplify(true, false, false, 1, -1, false, false)) { }
AstNode *wire_en = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true)));
wire_en->str = id_en;
current_ast_mod->children.push_back(wire_en);
current_scope[wire_en->str] = wire_en;
while (wire_en->simplify(true, false, false, 1, -1, false, false)) { }
AstNode *wire_en = nullptr;
if (current_always->type != AST_INITIAL) {
wire_en = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true)));
wire_en->str = id_en;
current_ast_mod->children.push_back(wire_en);
current_scope[wire_en->str] = wire_en;
while (wire_en->simplify(true, false, false, 1, -1, false, false)) { }
}
std::vector<RTLIL::State> x_bits_addr, x_bits_data, set_bits_en;
for (int i = 0; i < addr_bits; i++)
@ -1261,13 +1337,17 @@ skip_dynamic_range_lvalue_expansion:;
AstNode *assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bits_data, false));
assign_data->children[0]->str = id_data;
AstNode *assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(0, false, mem_width));
assign_en->children[0]->str = id_en;
AstNode *assign_en = nullptr;
if (current_always->type != AST_INITIAL) {
assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(0, false, mem_width));
assign_en->children[0]->str = id_en;
}
AstNode *default_signals = new AstNode(AST_BLOCK);
default_signals->children.push_back(assign_addr);
default_signals->children.push_back(assign_data);
default_signals->children.push_back(assign_en);
if (current_always->type != AST_INITIAL)
default_signals->children.push_back(assign_en);
current_top_block->children.insert(current_top_block->children.begin(), default_signals);
assign_addr = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), children[0]->children[0]->children[0]->clone());
@ -1282,15 +1362,16 @@ skip_dynamic_range_lvalue_expansion:;
std::vector<RTLIL::State> padding_x(offset, RTLIL::State::Sx);
for (int i = 0; i < mem_width; i++)
set_bits_en[i] = offset <= i && i < offset+width ? RTLIL::State::S1 : RTLIL::State::S0;
assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER),
new AstNode(AST_CONCAT, mkconst_bits(padding_x, false), children[1]->clone()));
assign_data->children[0]->str = id_data;
assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(set_bits_en, false));
assign_en->children[0]->str = id_en;
if (current_always->type != AST_INITIAL) {
for (int i = 0; i < mem_width; i++)
set_bits_en[i] = offset <= i && i < offset+width ? RTLIL::State::S1 : RTLIL::State::S0;
assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(set_bits_en, false));
assign_en->children[0]->str = id_en;
}
}
else
{
@ -1305,16 +1386,17 @@ skip_dynamic_range_lvalue_expansion:;
log_error("Unsupported expression on dynamic range select on signal `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
int width = left_at_zero_ast->integer - right_at_zero_ast->integer + 1;
for (int i = 0; i < mem_width; i++)
set_bits_en[i] = i < width ? RTLIL::State::S1 : RTLIL::State::S0;
assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER),
new AstNode(AST_SHIFT_LEFT, children[1]->clone(), offset_ast->clone()));
assign_data->children[0]->str = id_data;
assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER),
new AstNode(AST_SHIFT_LEFT, mkconst_bits(set_bits_en, false), offset_ast->clone()));
assign_en->children[0]->str = id_en;
if (current_always->type != AST_INITIAL) {
for (int i = 0; i < mem_width; i++)
set_bits_en[i] = i < width ? RTLIL::State::S1 : RTLIL::State::S0;
assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER),
new AstNode(AST_SHIFT_LEFT, mkconst_bits(set_bits_en, false), offset_ast->clone()));
assign_en->children[0]->str = id_en;
}
delete left_at_zero_ast;
delete right_at_zero_ast;
@ -1326,23 +1408,29 @@ skip_dynamic_range_lvalue_expansion:;
assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), children[1]->clone());
assign_data->children[0]->str = id_data;
assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(set_bits_en, false));
assign_en->children[0]->str = id_en;
if (current_always->type != AST_INITIAL) {
assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(set_bits_en, false));
assign_en->children[0]->str = id_en;
}
}
newNode = new AstNode(AST_BLOCK);
newNode->children.push_back(assign_addr);
newNode->children.push_back(assign_data);
newNode->children.push_back(assign_en);
if (current_always->type != AST_INITIAL)
newNode->children.push_back(assign_en);
AstNode *wrnode = new AstNode(AST_MEMWR);
wrnode->children.push_back(new AstNode(AST_IDENTIFIER));
AstNode *wrnode = new AstNode(current_always->type == AST_INITIAL ? AST_MEMINIT : AST_MEMWR);
wrnode->children.push_back(new AstNode(AST_IDENTIFIER));
wrnode->children.push_back(new AstNode(AST_IDENTIFIER));
if (current_always->type != AST_INITIAL)
wrnode->children.push_back(new AstNode(AST_IDENTIFIER));
wrnode->str = children[0]->str;
wrnode->id2ast = children[0]->id2ast;
wrnode->children[0]->str = id_addr;
wrnode->children[1]->str = id_data;
wrnode->children[2]->str = id_en;
if (current_always->type != AST_INITIAL)
wrnode->children[2]->str = id_en;
current_ast_mod->children.push_back(wrnode);
goto apply_newNode;
@ -1366,7 +1454,7 @@ skip_dynamic_range_lvalue_expansion:;
RTLIL::Const arg_value = buf->bitsAsConst();
if (arg_value.as_bool())
arg_value = const_sub(arg_value, 1, false, false, SIZE(arg_value));
arg_value = const_sub(arg_value, 1, false, false, GetSize(arg_value));
delete buf;
uint32_t result = 0;
@ -1455,9 +1543,9 @@ skip_dynamic_range_lvalue_expansion:;
rtype = RTLIL::unescape_id(dpi_decl->children.at(0)->str);
fname = RTLIL::unescape_id(dpi_decl->children.at(1)->str);
for (int i = 2; i < SIZE(dpi_decl->children); i++)
for (int i = 2; i < GetSize(dpi_decl->children); i++)
{
if (i-2 >= SIZE(children))
if (i-2 >= GetSize(children))
log_error("Insufficient number of arguments in DPI function call at %s:%d.\n", filename.c_str(), linenum);
argtypes.push_back(RTLIL::unescape_id(dpi_decl->children.at(i)->str));
@ -1480,6 +1568,44 @@ skip_dynamic_range_lvalue_expansion:;
log_error("Can't resolve function name `%s' at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
}
if (type == AST_TCALL) {
if (str == "\\$readmemh" || str == "\\$readmemb")
{
if (GetSize(children) < 2 || GetSize(children) > 4)
log_error("System function %s got %d arguments, expected 2-4 at %s:%d.\n",
RTLIL::unescape_id(str).c_str(), int(children.size()), filename.c_str(), linenum);
AstNode *node_filename = children[0]->clone();
while (node_filename->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
if (node_filename->type != AST_CONSTANT)
log_error("Failed to evaluate system function `%s' with non-constant 1st argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
AstNode *node_memory = children[1]->clone();
while (node_memory->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
if (node_memory->type != AST_IDENTIFIER || node_memory->id2ast == nullptr || node_memory->id2ast->type != AST_MEMORY)
log_error("Failed to evaluate system function `%s' with non-memory 2nd argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
int start_addr = -1, finish_addr = -1;
if (GetSize(children) > 2) {
AstNode *node_addr = children[2]->clone();
while (node_addr->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
if (node_addr->type != AST_CONSTANT)
log_error("Failed to evaluate system function `%s' with non-constant 3rd argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
start_addr = node_addr->asInt(false);
}
if (GetSize(children) > 3) {
AstNode *node_addr = children[3]->clone();
while (node_addr->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
if (node_addr->type != AST_CONSTANT)
log_error("Failed to evaluate system function `%s' with non-constant 4th argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
finish_addr = node_addr->asInt(false);
}
newNode = readmem(str == "\\$readmemh", node_filename->bitsAsConst().decode_string(), node_memory->id2ast, start_addr, finish_addr);
goto apply_newNode;
}
if (current_scope.count(str) == 0 || current_scope[str]->type != AST_TASK)
log_error("Can't resolve task name `%s' at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
}
@ -1558,7 +1684,7 @@ skip_dynamic_range_lvalue_expansion:;
celltype = RTLIL::escape_id(celltype);
AstNode *cell = new AstNode(AST_CELL, new AstNode(AST_CELLTYPE));
cell->str = prefix.substr(0, SIZE(prefix)-1);
cell->str = prefix.substr(0, GetSize(prefix)-1);
cell->children[0]->str = celltype;
for (auto attr : decl->attributes)
@ -1681,7 +1807,7 @@ skip_dynamic_range_lvalue_expansion:;
bool param_upto = current_scope[str]->range_valid && current_scope[str]->range_swapped;
int param_offset = current_scope[str]->range_valid ? current_scope[str]->range_right : 0;
int param_width = current_scope[str]->range_valid ? current_scope[str]->range_left - current_scope[str]->range_right + 1 :
SIZE(current_scope[str]->children[0]->bits);
GetSize(current_scope[str]->children[0]->bits);
int tmp_range_left = children[0]->range_left, tmp_range_right = children[0]->range_right;
if (param_upto) {
tmp_range_left = (param_width + 2*param_offset) - children[0]->range_right - 1;
@ -1843,37 +1969,6 @@ skip_dynamic_range_lvalue_expansion:;
newNode->realvalue = -children[0]->asReal(sign_hint);
}
break;
case AST_CASE:
if (children[0]->type == AST_CONSTANT && children[0]->bits_only_01()) {
std::vector<AstNode*> new_children;
new_children.push_back(children[0]);
for (int i = 1; i < SIZE(children); i++) {
AstNode *child = children[i];
log_assert(child->type == AST_COND);
for (auto v : child->children) {
if (v->type == AST_DEFAULT)
goto keep_const_cond;
if (v->type == AST_BLOCK)
continue;
if (v->type == AST_CONSTANT && v->bits_only_01()) {
if (v->bits == children[0]->bits) {
while (i+1 < SIZE(children))
delete children[++i];
goto keep_const_cond;
}
continue;
}
goto keep_const_cond;
}
if (0)
keep_const_cond:
new_children.push_back(child);
else
delete child;
}
new_children.swap(children);
}
break;
case AST_TERNARY:
if (children[0]->isConst())
{
@ -1977,6 +2072,7 @@ apply_newNode:
if (!did_something)
basic_prep = true;
recursion_counter--;
return did_something;
}
@ -1988,6 +2084,83 @@ static void replace_result_wire_name_in_function(AstNode *node, std::string &fro
node->str = to;
}
// replace a readmem[bh] TCALL ast node with a block of memory assignments
AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *memory, int start_addr, int finish_addr)
{
AstNode *block = new AstNode(AST_BLOCK);
std::ifstream f;
f.open(mem_filename.c_str());
if (f.fail())
log_error("Can not open file `%s` for %s at %s:%d.\n", mem_filename.c_str(), str.c_str(), filename.c_str(), linenum);
log_assert(GetSize(memory->children) == 2 && memory->children[1]->type == AST_RANGE && memory->children[1]->range_valid);
int range_left = memory->children[1]->range_left, range_right = memory->children[1]->range_right;
int range_min = std::min(range_left, range_right), range_max = std::max(range_left, range_right);
if (start_addr < 0)
start_addr = range_min;
if (finish_addr < 0)
finish_addr = range_max;
bool in_comment = false;
int increment = start_addr <= finish_addr ? +1 : -1;
int cursor = start_addr;
while (!f.eof())
{
std::string line, token;
std::getline(f, line);
for (int i = 0; i < GetSize(line); i++) {
if (in_comment && line.substr(i, 2) == "*/") {
line[i] = ' ';
line[i+1] = ' ';
in_comment = false;
continue;
}
if (!in_comment && line.substr(i, 2) == "/*")
in_comment = true;
if (in_comment)
line[i] = ' ';
}
while (1)
{
token = next_token(line, " \t\r\n");
if (token.empty() || token.substr(0, 2) == "//")
break;
if (token[0] == '@') {
token = token.substr(1);
const char *nptr = token.c_str();
char *endptr;
cursor = strtol(nptr, &endptr, 16);
if (!*nptr || *endptr)
log_error("Can not parse address `%s` for %s at %s:%d.\n", nptr, str.c_str(), filename.c_str(), linenum);
continue;
}
AstNode *value = VERILOG_FRONTEND::const2ast((is_readmemh ? "'h" : "'b") + token);
block->children.push_back(new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER, new AstNode(AST_RANGE, AstNode::mkconst_int(cursor, false))), value));
block->children.back()->children[0]->str = memory->str;
block->children.back()->children[0]->id2ast = memory;
if ((cursor == finish_addr) || (increment > 0 && cursor >= range_max) || (increment < 0 && cursor <= range_min))
break;
cursor += increment;
}
if ((cursor == finish_addr) || (increment > 0 && cursor >= range_max) || (increment < 0 && cursor <= range_min))
break;
}
return block;
}
// annotate the names of all wires and other named objects in a generate block
void AstNode::expand_genblock(std::string index_var, std::string prefix, std::map<std::string, std::string> &name_map)
{
@ -2063,8 +2236,8 @@ void AstNode::replace_ids(const std::string &prefix, const std::map<std::string,
}
// helper function for mem2reg_as_needed_pass1
static void mark_memories_assign_lhs_complex(std::map<AstNode*, std::set<std::string>> &mem2reg_places,
std::map<AstNode*, uint32_t> &mem2reg_candidates, AstNode *that)
static void mark_memories_assign_lhs_complex(dict<AstNode*, pool<std::string>> &mem2reg_places,
dict<AstNode*, uint32_t> &mem2reg_candidates, AstNode *that)
{
for (auto &child : that->children)
mark_memories_assign_lhs_complex(mem2reg_places, mem2reg_candidates, child);
@ -2078,8 +2251,8 @@ static void mark_memories_assign_lhs_complex(std::map<AstNode*, std::set<std::st
}
// find memories that should be replaced by registers
void AstNode::mem2reg_as_needed_pass1(std::map<AstNode*, std::set<std::string>> &mem2reg_places,
std::map<AstNode*, uint32_t> &mem2reg_candidates, std::map<AstNode*, uint32_t> &proc_flags, uint32_t &flags)
void AstNode::mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg_places,
dict<AstNode*, uint32_t> &mem2reg_candidates, dict<AstNode*, uint32_t> &proc_flags, uint32_t &flags)
{
uint32_t children_flags = 0;
int ignore_children_counter = 0;
@ -2141,7 +2314,7 @@ void AstNode::mem2reg_as_needed_pass1(std::map<AstNode*, std::set<std::string>>
if (type == AST_MODULE && get_bool_attribute("\\mem2reg"))
children_flags |= AstNode::MEM2REG_FL_ALL;
std::map<AstNode*, uint32_t> *proc_flags_p = NULL;
dict<AstNode*, uint32_t> *proc_flags_p = NULL;
if (type == AST_ALWAYS) {
int count_edge_events = 0;
@ -2150,12 +2323,12 @@ void AstNode::mem2reg_as_needed_pass1(std::map<AstNode*, std::set<std::string>>
count_edge_events++;
if (count_edge_events != 1)
children_flags |= AstNode::MEM2REG_FL_ASYNC;
proc_flags_p = new std::map<AstNode*, uint32_t>;
proc_flags_p = new dict<AstNode*, uint32_t>;
}
if (type == AST_INITIAL) {
children_flags |= AstNode::MEM2REG_FL_INIT;
proc_flags_p = new std::map<AstNode*, uint32_t>;
proc_flags_p = new dict<AstNode*, uint32_t>;
}
uint32_t backup_flags = flags;
@ -2173,20 +2346,33 @@ void AstNode::mem2reg_as_needed_pass1(std::map<AstNode*, std::set<std::string>>
flags &= ~children_flags | backup_flags;
if (proc_flags_p) {
#ifndef NDEBUG
for (auto it : *proc_flags_p)
log_assert((it.second & ~0xff000000) == 0);
#endif
delete proc_flags_p;
}
}
bool AstNode::mem2reg_check(pool<AstNode*> &mem2reg_set)
{
if (type != AST_IDENTIFIER || !id2ast || !mem2reg_set.count(id2ast))
return false;
if (children.empty() || children[0]->type != AST_RANGE || GetSize(children[0]->children) != 1)
log_error("Invalid array access at %s:%d.\n", filename.c_str(), linenum);
return true;
}
// actually replace memories with registers
void AstNode::mem2reg_as_needed_pass2(std::set<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block)
void AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, AstNode *block)
{
if (type == AST_BLOCK)
block = this;
if ((type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ) && block != NULL && children[0]->id2ast &&
mem2reg_set.count(children[0]->id2ast) > 0 && children[0]->children[0]->children[0]->type != AST_CONSTANT)
if ((type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ) && block != NULL &&
children[0]->mem2reg_check(mem2reg_set) && children[0]->children[0]->children[0]->type != AST_CONSTANT)
{
std::stringstream sstr;
sstr << "$mem2reg_wr$" << children[0]->str << "$" << filename << ":" << linenum << "$" << (autoidx++);
@ -2242,7 +2428,7 @@ void AstNode::mem2reg_as_needed_pass2(std::set<AstNode*> &mem2reg_set, AstNode *
type = AST_ASSIGN_EQ;
}
if (type == AST_IDENTIFIER && id2ast && mem2reg_set.count(id2ast) > 0)
if (mem2reg_check(mem2reg_set))
{
AstNode *bit_part_sel = NULL;
if (children.size() == 2)
@ -2446,7 +2632,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
}
log_assert(block != NULL);
log_assert(variables.count(str));
log_assert(variables.count(str) != 0);
while (!block->children.empty())
{

View File

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

View File

@ -1,18 +1,18 @@
GENFILES += frontends/ilang/parser.tab.cc
GENFILES += frontends/ilang/parser.tab.h
GENFILES += frontends/ilang/parser.output
GENFILES += frontends/ilang/lexer.cc
GENFILES += frontends/ilang/ilang_parser.tab.cc
GENFILES += frontends/ilang/ilang_parser.tab.h
GENFILES += frontends/ilang/ilang_parser.output
GENFILES += frontends/ilang/ilang_lexer.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/ilang_parser.tab.cc: frontends/ilang/ilang_parser.y
$(P) $(BISON) -d -r all -b frontends/ilang/ilang_parser frontends/ilang/ilang_parser.y
$(Q) mv frontends/ilang/ilang_parser.tab.c frontends/ilang/ilang_parser.tab.cc
frontends/ilang/parser.tab.h: frontends/ilang/parser.tab.cc
frontends/ilang/ilang_parser.tab.h: frontends/ilang/ilang_parser.tab.cc
frontends/ilang/lexer.cc: frontends/ilang/lexer.l
$(P) flex -o frontends/ilang/lexer.cc frontends/ilang/lexer.l
frontends/ilang/ilang_lexer.cc: frontends/ilang/ilang_lexer.l
$(P) flex -o frontends/ilang/ilang_lexer.cc frontends/ilang/ilang_lexer.l
OBJS += frontends/ilang/parser.tab.o frontends/ilang/lexer.o
OBJS += frontends/ilang/ilang_parser.tab.o frontends/ilang/ilang_lexer.o
OBJS += frontends/ilang/ilang_frontend.o

View File

@ -26,13 +26,13 @@
#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);
YOSYS_NAMESPACE_PREFIX log_error("Parser error in line %d: %s\n", rtlil_frontend_ilang_yyget_lineno(), s);
}
YOSYS_NAMESPACE_BEGIN
struct IlangFrontend : public Frontend {
IlangFrontend() : Frontend("ilang", "read modules from ilang file") { }
virtual void help()

View File

@ -30,10 +30,12 @@
#endif
#include "ilang_frontend.h"
#include "parser.tab.h"
#include "ilang_parser.tab.h"
USING_YOSYS_NAMESPACE
#define YY_INPUT(buf,result,max_size) \
result = ILANG_FRONTEND::lexin->readsome(buf, max_size);
result = readsome(*ILANG_FRONTEND::lexin, buf, max_size)
%}

View File

@ -36,7 +36,7 @@ namespace ILANG_FRONTEND {
RTLIL::Process *current_process;
std::vector<std::vector<RTLIL::SwitchRule*>*> switch_stack;
std::vector<RTLIL::CaseRule*> case_stack;
std::map<RTLIL::IdString, RTLIL::Const> attrbuf;
dict<RTLIL::IdString, RTLIL::Const> attrbuf;
}
using namespace ILANG_FRONTEND;
YOSYS_NAMESPACE_END
@ -183,6 +183,9 @@ memory_options:
memory_options TOK_SIZE TOK_INT {
current_memory->size = $3;
} |
memory_options TOK_OFFSET TOK_INT {
current_memory->start_offset = $3;
} |
/* empty */;
cell_stmt:

View File

@ -22,7 +22,6 @@
#include "kernel/log.h"
YOSYS_NAMESPACE_BEGIN
using namespace PASS_DFFLIBMAP;
struct token_t {
char type;

View File

@ -10,6 +10,7 @@ CONFIG := clang
ENABLE_TCL := 0
ENABLE_QT4 := 0
ENABLE_ABC := 0
ENABLE_PLUGINS := 0
ENABLE_VERIFIC := 1
CXXFLAGS += -m32
LDFLAGS += -m32

View File

@ -20,11 +20,14 @@
#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>
#ifndef _WIN32
# include <unistd.h>
# include <dirent.h>
#endif
USING_YOSYS_NAMESPACE
@ -324,7 +327,7 @@ static bool import_netlist_instance_cells(RTLIL::Module *module, std::map<Net*,
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));
RTLIL::SigSpec tmp = module->addWire(NEW_ID, GetSize(out));
module->addAdd(NEW_ID, IN1, IN2, tmp, SIGNED);
module->addAdd(RTLIL::escape_id(inst->Name()), tmp, net_map.at(inst->GetCin()), out, false);
}
@ -687,8 +690,8 @@ static void import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*
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->parameters["\\ABITS"] = GetSize(addr);
cell->parameters["\\WIDTH"] = GetSize(data);
cell->setPort("\\CLK", RTLIL::State::S0);
cell->setPort("\\ADDR", addr);
cell->setPort("\\DATA", data);
@ -709,9 +712,9 @@ static void import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*
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->parameters["\\ABITS"] = GetSize(addr);
cell->parameters["\\WIDTH"] = GetSize(data);
cell->setPort("\\EN", RTLIL::SigSpec(net_map.at(inst->GetControl())).repeat(GetSize(data)));
cell->setPort("\\CLK", RTLIL::State::S0);
cell->setPort("\\ADDR", addr);
cell->setPort("\\DATA", data);
@ -727,7 +730,7 @@ static void import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*
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());
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;
@ -753,9 +756,9 @@ static void import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*
RTLIL::SigSpec conn;
if (cell->hasPort(RTLIL::escape_id(port_name)))
conn = cell->getPort(RTLIL::escape_id(port_name));
while (SIZE(conn) <= port_offset) {
while (GetSize(conn) <= port_offset) {
if (pr->GetPort()->GetDir() != DIR_IN)
conn.append(module->addWire(NEW_ID, port_offset - SIZE(conn)));
conn.append(module->addWire(NEW_ID, port_offset - GetSize(conn)));
conn.append(RTLIL::State::Sz);
}
conn.replace(port_offset, net_map.at(pr->GetNet()));

View File

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

View File

@ -1,20 +1,20 @@
GENFILES += frontends/verilog/parser.tab.cc
GENFILES += frontends/verilog/parser.tab.h
GENFILES += frontends/verilog/parser.output
GENFILES += frontends/verilog/lexer.cc
GENFILES += frontends/verilog/verilog_parser.tab.cc
GENFILES += frontends/verilog/verilog_parser.tab.h
GENFILES += frontends/verilog/verilog_parser.output
GENFILES += frontends/verilog/verilog_lexer.cc
frontends/verilog/parser.tab.cc: frontends/verilog/parser.y
$(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/verilog_parser.tab.cc: frontends/verilog/verilog_parser.y
$(P) $(BISON) -d -r all -b frontends/verilog/verilog_parser frontends/verilog/verilog_parser.y
$(Q) mv frontends/verilog/verilog_parser.tab.c frontends/verilog/verilog_parser.tab.cc
frontends/verilog/parser.tab.h: frontends/verilog/parser.tab.cc
frontends/verilog/verilog_parser.tab.h: frontends/verilog/verilog_parser.tab.cc
frontends/verilog/lexer.cc: frontends/verilog/lexer.l
$(P) flex -o frontends/verilog/lexer.cc frontends/verilog/lexer.l
frontends/verilog/verilog_lexer.cc: frontends/verilog/verilog_lexer.l
$(P) flex -o frontends/verilog/verilog_lexer.cc frontends/verilog/verilog_lexer.l
OBJS += frontends/verilog/parser.tab.o
OBJS += frontends/verilog/lexer.o
OBJS += frontends/verilog/verilog_parser.tab.o
OBJS += frontends/verilog/verilog_lexer.o
OBJS += frontends/verilog/preproc.o
OBJS += frontends/verilog/verilog_frontend.o
OBJS += frontends/verilog/const2ast.o

View File

@ -132,8 +132,16 @@ static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int le
}
// convert the verilog code for a constant to an AST node
AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type)
AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn_z)
{
if (warn_z) {
AstNode *ret = const2ast(code, case_type);
if (std::find(ret->bits.begin(), ret->bits.end(), RTLIL::State::Sz) != ret->bits.end())
log_warning("Yosys does not support tri-state logic at the moment. (%s:%d)\n",
current_filename.c_str(), frontend_verilog_yyget_lineno());
return ret;
}
const char *str = code.c_str();
// Strings
@ -174,7 +182,7 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type)
if (str == endptr)
len_in_bits = -1;
// The "<bits>'s?[bodh]<digits>" syntax
// The "<bits>'s?[bodhBODH]<digits>" syntax
if (*endptr == '\'')
{
std::vector<RTLIL::State> data;
@ -186,15 +194,19 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type)
switch (*(endptr+1))
{
case 'b':
case 'B':
my_strtobin(data, endptr+2, len_in_bits, 2, case_type);
break;
case 'o':
case 'O':
my_strtobin(data, endptr+2, len_in_bits, 8, case_type);
break;
case 'd':
case 'D':
my_strtobin(data, endptr+2, len_in_bits, 10, case_type);
break;
case 'h':
case 'H':
my_strtobin(data, endptr+2, len_in_bits, 16, case_type);
break;
default:

View File

@ -201,8 +201,8 @@ static void input_file(std::istream &f, std::string filename)
insert_input("");
auto it = input_buffer.begin();
input_buffer.insert(it, "`file_push " + filename + "\n");
while ((rc = f.readsome(buffer, sizeof(buffer)-1)) > 0) {
input_buffer.insert(it, "`file_push \"" + filename + "\"\n");
while ((rc = readsome(f, buffer, sizeof(buffer)-1)) > 0) {
buffer[rc] = 0;
input_buffer.insert(it, buffer);
}
@ -221,7 +221,8 @@ std::string frontend_verilog_preproc(std::istream &f, std::string filename, cons
input_buffer_charp = 0;
input_file(f, filename);
defines_map["__YOSYS__"] = "1";
defines_map["YOSYS"] = "1";
defines_map["SYNTHESIS"] = "1";
while (!input_buffer.empty())
{
@ -422,7 +423,7 @@ std::string frontend_verilog_preproc(std::istream &f, std::string filename, cons
if (tok == "(" || tok == "{" || tok == "[")
level++;
}
for (size_t i = 0; i < args.size(); i++)
for (int i = 0; i < GetSize(args); i++)
defines_map[stringf("macro_%s_arg%d", name.c_str(), i+1)] = args[i];
} else {
insert_input(tok);

View File

@ -54,6 +54,10 @@ struct VerilogFrontend : public Frontend {
log(" enable support for SystemVerilog features. (only a small subset\n");
log(" of SystemVerilog is supported)\n");
log("\n");
log(" -formal\n");
log(" enable support for assert() and assume() statements\n");
log(" (assert support is also enabled with -sv)\n");
log("\n");
log(" -dump_ast1\n");
log(" dump abstract syntax tree (before simplification)\n");
log("\n");
@ -83,11 +87,20 @@ struct VerilogFrontend : public Frontend {
log(" this can also be achieved by setting the 'nomem2reg'\n");
log(" attribute on the respective module or register.\n");
log("\n");
log(" This is potentially dangerous. Usually the front-end has good\n");
log(" reasons for converting an array to a list of registers.\n");
log(" Prohibiting this step will likely result in incorrect synthesis\n");
log(" results.\n");
log("\n");
log(" -mem2reg\n");
log(" always convert memories to registers. this can also be\n");
log(" achieved by setting the 'mem2reg' attribute on the respective\n");
log(" module or register.\n");
log("\n");
log(" -nomeminit\n");
log(" do not infer $meminit cells and instead convert initialized\n");
log(" memories to registers directly in the front-end.\n");
log("\n");
log(" -ppdump\n");
log(" dump verilog code after pre-processor\n");
log("\n");
@ -139,6 +152,7 @@ struct VerilogFrontend : public Frontend {
bool flag_dump_ast2 = false;
bool flag_dump_vlog = false;
bool flag_nolatches = false;
bool flag_nomeminit = false;
bool flag_nomem2reg = false;
bool flag_mem2reg = false;
bool flag_ppdump = false;
@ -154,6 +168,7 @@ struct VerilogFrontend : public Frontend {
frontend_verilog_yydebug = false;
sv_mode = false;
formal_mode = false;
log_header("Executing Verilog-2005 frontend.\n");
@ -166,6 +181,10 @@ struct VerilogFrontend : public Frontend {
sv_mode = true;
continue;
}
if (arg == "-formal") {
formal_mode = true;
continue;
}
if (arg == "-dump_ast1") {
flag_dump_ast1 = true;
continue;
@ -186,6 +205,10 @@ struct VerilogFrontend : public Frontend {
flag_nolatches = true;
continue;
}
if (arg == "-nomeminit") {
flag_nomeminit = true;
continue;
}
if (arg == "-nomem2reg") {
flag_nomem2reg = true;
continue;
@ -257,7 +280,8 @@ struct VerilogFrontend : public Frontend {
}
extra_args(f, filename, args, argidx);
log("Parsing Verilog input from `%s' to AST representation.\n", filename.c_str());
log("Parsing %s%s input from `%s' to AST representation.\n",
formal_mode ? "formal " : "", sv_mode ? "SystemVerilog" : "Verilog", filename.c_str());
AST::current_filename = filename;
AST::set_line_num = &frontend_verilog_yyset_lineno;
@ -288,7 +312,7 @@ struct VerilogFrontend : public Frontend {
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, flag_defer, default_nettype_wire);
AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, flag_nolatches, flag_nomeminit, flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_ignore_redef, flag_defer, default_nettype_wire);
if (!flag_nopp)
delete lexin;
@ -300,22 +324,6 @@ struct VerilogFrontend : public Frontend {
}
} VerilogFrontend;
// the yyerror function used by bison to report parser errors
void frontend_verilog_yyerror(char const *fmt, ...)
{
va_list ap;
char buffer[1024];
char *p = buffer;
p += snprintf(p, buffer + sizeof(buffer) - p, "Parser error in line %s:%d: ",
AST::current_filename.c_str(), frontend_verilog_yyget_lineno());
va_start(ap, fmt);
p += vsnprintf(p, buffer + sizeof(buffer) - p, fmt, ap);
va_end(ap);
p += snprintf(p, buffer + sizeof(buffer) - p, "\n");
log_error("%s", buffer);
exit(1);
}
struct VerilogDefaults : public Pass {
VerilogDefaults() : Pass("verilog_defaults", "set default options for read_verilog") { }
virtual void help()
@ -376,3 +384,19 @@ struct VerilogDefaults : public Pass {
YOSYS_NAMESPACE_END
// the yyerror function used by bison to report parser errors
void frontend_verilog_yyerror(char const *fmt, ...)
{
va_list ap;
char buffer[1024];
char *p = buffer;
p += snprintf(p, buffer + sizeof(buffer) - p, "Parser error in line %s:%d: ",
YOSYS_NAMESPACE_PREFIX AST::current_filename.c_str(), frontend_verilog_yyget_lineno());
va_start(ap, fmt);
p += vsnprintf(p, buffer + sizeof(buffer) - p, fmt, ap);
va_end(ap);
p += snprintf(p, buffer + sizeof(buffer) - p, "\n");
YOSYS_NAMESPACE_PREFIX log_error("%s", buffer);
exit(1);
}

View File

@ -43,7 +43,7 @@ namespace VERILOG_FRONTEND
extern struct AST::AstNode *current_ast;
// this function converts a Verilog constant to an AST_CONSTANT node
AST::AstNode *const2ast(std::string code, char case_type = 0);
AST::AstNode *const2ast(std::string code, char case_type = 0, bool warn_z = false);
// state of `default_nettype
extern bool default_nettype_wire;
@ -51,6 +51,9 @@ namespace VERILOG_FRONTEND
// running in SystemVerilog mode
extern bool sv_mode;
// running in -formal mode
extern bool formal_mode;
// lexer input stream
extern std::istream *lexin;
}

View File

@ -42,7 +42,7 @@
#include "kernel/log.h"
#include "verilog_frontend.h"
#include "frontends/ast/ast.h"
#include "parser.tab.h"
#include "verilog_parser.tab.h"
USING_YOSYS_NAMESPACE
using namespace AST;
@ -64,7 +64,7 @@ YOSYS_NAMESPACE_END
return TOK_ID;
#define YY_INPUT(buf,result,max_size) \
result = lexin->readsome(buf, max_size);
result = readsome(*VERILOG_FRONTEND::lexin, buf, max_size)
%}
@ -85,6 +85,10 @@ YOSYS_NAMESPACE_END
fn_stack.push_back(current_filename);
ln_stack.push_back(frontend_verilog_yyget_lineno());
current_filename = yytext+11;
if (!current_filename.empty() && current_filename.front() == '"')
current_filename = current_filename.substr(1);
if (!current_filename.empty() && current_filename.back() == '"')
current_filename = current_filename.substr(0, current_filename.size()-1);
frontend_verilog_yyset_lineno(0);
}
@ -112,6 +116,9 @@ YOSYS_NAMESPACE_END
"`timescale"[ \t]+[^ \t\r\n/]+[ \t]*"/"[ \t]*[^ \t\r\n]* /* ignore timescale directive */
"`celldefine"[^\n]* /* ignore `celldefine */
"`endcelldefine"[^\n]* /* ignore `endcelldefine */
"`default_nettype"[ \t]+[^ \t\r\n/]+ {
char *p = yytext;
while (*p != 0 && *p != ' ' && *p != '\t') p++;
@ -162,8 +169,9 @@ YOSYS_NAMESPACE_END
"always_ff" { SV_KEYWORD(TOK_ALWAYS); }
"always_latch" { SV_KEYWORD(TOK_ALWAYS); }
"assert" { SV_KEYWORD(TOK_ASSERT); }
"property" { SV_KEYWORD(TOK_PROPERTY); }
"assert" { if (formal_mode) return TOK_ASSERT; SV_KEYWORD(TOK_ASSERT); }
"assume" { if (formal_mode) return TOK_ASSUME; return TOK_ID; }
"property" { if (formal_mode) return TOK_PROPERTY; SV_KEYWORD(TOK_PROPERTY); }
"logic" { SV_KEYWORD(TOK_REG); }
"bit" { SV_KEYWORD(TOK_REG); }
@ -177,12 +185,12 @@ YOSYS_NAMESPACE_END
"genvar" { return TOK_GENVAR; }
"real" { return TOK_REAL; }
[0-9]+ {
[0-9][0-9_]* {
frontend_verilog_yylval.string = new std::string(yytext);
return TOK_CONST;
}
[0-9]*[ \t]*\'s?[bodh][ \t\r\n]*[0-9a-fA-FzxZX?_]+ {
[0-9]*[ \t]*\'s?[bodhBODH][ \t\r\n]*[0-9a-fA-FzxZX?_]+ {
frontend_verilog_yylval.string = new std::string(yytext);
return TOK_CONST;
}
@ -240,7 +248,7 @@ and|nand|or|nor|xor|xnor|not|buf|bufif0|bufif1|notif0|notif1 {
supply0 { return TOK_SUPPLY0; }
supply1 { return TOK_SUPPLY1; }
"$"(display|time|stop|finish) {
"$"(display|strobe|monitor|time|stop|finish|dumpfile|dumpvars|dumpon|dumpoff|dumpall) {
frontend_verilog_yylval.string = new std::string(yytext);
return TOK_ID;
}
@ -254,8 +262,12 @@ supply1 { return TOK_SUPPLY1; }
}
"/*"[ \t]*(synopsys|synthesis)[ \t]*translate_off[ \t]*"*/" {
log("Warning: Found one of those horrible `(synopsys|synthesis) translate_off' comments.\n");
log("It is strongly suggested to use `ifdef constructs instead!\n");
static bool printed_warning = false;
if (!printed_warning) {
log_warning("Found one of those horrible `(synopsys|synthesis) translate_off' comments.\n"
"Yosys does support them but it is recommended to use `ifdef constructs instead!\n");
printed_warning = true;
}
BEGIN(SYNOPSYS_TRANSLATE_OFF);
}
<SYNOPSYS_TRANSLATE_OFF>. /* ignore synopsys translate_off body */
@ -266,13 +278,21 @@ supply1 { return TOK_SUPPLY1; }
BEGIN(SYNOPSYS_FLAGS);
}
<SYNOPSYS_FLAGS>full_case {
log("Warning: Found one of those horrible `(synopsys|synthesis) full_case' comments.\n");
log("It is strongly suggested to use verilog x-values and default branches instead!\n");
static bool printed_warning = false;
if (!printed_warning) {
log_warning("Found one of those horrible `(synopsys|synthesis) full_case' comments.\n"
"Yosys does support them but it is recommended to use verilog `full_case' attributes instead!\n");
printed_warning = true;
}
return TOK_SYNOPSYS_FULL_CASE;
}
<SYNOPSYS_FLAGS>parallel_case {
log("Warning: Found one of those horrible `(synopsys|synthesis) parallel_case' comments.\n");
log("It is strongly suggested to use verilog `parallel_case' attributes instead!\n");
static bool printed_warning = false;
if (!printed_warning) {
log_warning("Found one of those horrible `(synopsys|synthesis) parallel_case' comments.\n"
"Yosys does support them but it is recommended to use verilog `parallel_case' attributes instead!\n");
printed_warning = true;
}
return TOK_SYNOPSYS_PARALLEL_CASE;
}
<SYNOPSYS_FLAGS>. /* ignore everything else */
@ -342,7 +362,10 @@ import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ {
[ \t\r\n] /* ignore whitespaces */
\\[\r\n] /* ignore continuation sequence */
"//"[^\r\n]* /* ignore one-line comments */
"#"[$a-zA-Z_0-9\.]+ /* ignore simulation timings */
"#"\ *[0-9][0-9_]* /* ignore simulation timings */
"#"\ *[0-9][0-9_]*\.[0-9][0-9_]* /* ignore simulation timings */
"#"\ *[$a-zA-Z_\.][$a-zA-Z_0-9\.]* /* ignore simulation timings */
. { return *yytext; }

View File

@ -57,7 +57,7 @@ namespace VERILOG_FRONTEND {
std::vector<char> case_type_stack;
bool do_not_require_port_stubs;
bool default_nettype_wire;
bool sv_mode;
bool sv_mode, formal_mode;
std::istream *lexin;
}
YOSYS_NAMESPACE_END
@ -111,7 +111,7 @@ static void free_attr(std::map<std::string, AstNode*> *al)
%token TOK_GENERATE TOK_ENDGENERATE TOK_GENVAR TOK_REAL
%token TOK_SYNOPSYS_FULL_CASE TOK_SYNOPSYS_PARALLEL_CASE
%token TOK_SUPPLY0 TOK_SUPPLY1 TOK_TO_SIGNED TOK_TO_UNSIGNED
%token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_ASSERT TOK_PROPERTY
%token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_ASSERT TOK_ASSUME TOK_PROPERTY
%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
@ -139,10 +139,11 @@ static void free_attr(std::map<std::string, AstNode*> *al)
%%
input: {
ast_stack.clear();
ast_stack.push_back(current_ast);
} design {
ast_stack.pop_back();
log_assert(SIZE(ast_stack) == 0);
log_assert(GetSize(ast_stack) == 0);
for (auto &it : default_attr_list)
delete it.second;
default_attr_list.clear();
@ -240,7 +241,7 @@ module:
};
module_para_opt:
'#' '(' module_para_list ')' | /* empty */;
'#' '(' { astbuf1 = nullptr; } module_para_list { if (astbuf1) delete astbuf1; } ')' | /* empty */;
module_para_list:
single_module_para |
@ -249,11 +250,10 @@ module_para_list:
single_module_para:
TOK_PARAMETER {
if (astbuf1) delete astbuf1;
astbuf1 = new AstNode(AST_PARAMETER);
astbuf1->children.push_back(AstNode::mkconst_int(0, true));
} param_signed param_integer param_range single_param_decl {
delete astbuf1;
};
} param_signed param_integer param_range single_param_decl | single_param_decl;
module_args_opt:
'(' ')' | /* empty */ | '(' module_args optional_comma ')';
@ -310,10 +310,17 @@ module_arg:
do_not_require_port_stubs = true;
};
non_opt_delay:
'#' '(' expr ')' { delete $3; } |
'#' '(' expr ':' expr ':' expr ')' { delete $3; delete $5; delete $7; };
delay:
non_opt_delay | /* empty */;
wire_type:
{
astbuf3 = new AstNode(AST_WIRE);
} wire_type_token_list {
} wire_type_token_list delay {
$$ = astbuf3;
};
@ -449,7 +456,7 @@ task_func_decl:
} opt_dpi_function_args ';' {
current_function_or_task = NULL;
} |
attr TOK_TASK TOK_ID ';' {
attr TOK_TASK TOK_ID {
current_function_or_task = new AstNode(AST_TASK);
current_function_or_task->str = *$3;
append_attr(current_function_or_task, $1);
@ -457,11 +464,11 @@ task_func_decl:
ast_stack.push_back(current_function_or_task);
current_function_or_task_port_id = 1;
delete $3;
} task_func_body TOK_ENDTASK {
} task_func_args_opt ';' task_func_body TOK_ENDTASK {
current_function_or_task = NULL;
ast_stack.pop_back();
} |
attr TOK_FUNCTION opt_signed range_or_signed_int 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 = *$5;
append_attr(current_function_or_task, $1);
@ -478,7 +485,7 @@ task_func_decl:
current_function_or_task->children.push_back(outreg);
current_function_or_task_port_id = 1;
delete $5;
} task_func_body TOK_ENDFUNCTION {
} task_func_args_opt ';' task_func_body TOK_ENDFUNCTION {
current_function_or_task = NULL;
ast_stack.pop_back();
};
@ -512,6 +519,45 @@ opt_signed:
$$ = false;
};
task_func_args_opt:
'(' ')' | /* empty */ | '(' {
albuf = nullptr;
astbuf1 = nullptr;
astbuf2 = nullptr;
} task_func_args optional_comma {
delete astbuf1;
if (astbuf2 != NULL)
delete astbuf2;
free_attr(albuf);
} ')';
task_func_args:
task_func_port | task_func_args ',' task_func_port;
task_func_port:
attr wire_type range {
if (albuf) {
delete astbuf1;
if (astbuf2 != NULL)
delete astbuf2;
free_attr(albuf);
}
albuf = $1;
astbuf1 = $2;
astbuf2 = $3;
if (astbuf1->range_left >= 0 && astbuf1->range_right >= 0) {
if (astbuf2) {
frontend_verilog_yyerror("Syntax error.");
} else {
astbuf2 = new AstNode(AST_RANGE);
astbuf2->children.push_back(AstNode::mkconst_int(astbuf1->range_left, true));
astbuf2->children.push_back(AstNode::mkconst_int(astbuf1->range_right, true));
}
}
if (astbuf2 && astbuf2->children.size() != 2)
frontend_verilog_yyerror("Syntax error.");
} wire_name | wire_name;
task_func_body:
task_func_body behavioral_stmt |
/* empty */;
@ -568,6 +614,8 @@ param_decl_list:
single_param_decl:
TOK_ID '=' expr {
if (astbuf1 == nullptr)
frontend_verilog_yyerror("syntax error");
AstNode *node = astbuf1->clone();
node->str = *$1;
delete node->children[0];
@ -609,27 +657,39 @@ wire_decl:
}
if (astbuf2 && astbuf2->children.size() != 2)
frontend_verilog_yyerror("Syntax error.");
} wire_name_list ';' {
} wire_name_list {
delete astbuf1;
if (astbuf2 != NULL)
delete astbuf2;
free_attr(albuf);
} |
attr TOK_SUPPLY0 TOK_ID ';' {
} ';' |
attr TOK_SUPPLY0 TOK_ID {
ast_stack.back()->children.push_back(new AstNode(AST_WIRE));
ast_stack.back()->children.back()->str = *$3;
append_attr(ast_stack.back()->children.back(), $1);
ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, new AstNode(AST_IDENTIFIER), AstNode::mkconst_int(0, false, 1)));
ast_stack.back()->children.back()->children[0]->str = *$3;
delete $3;
} |
attr TOK_SUPPLY1 TOK_ID ';' {
} opt_supply_wires ';' |
attr TOK_SUPPLY1 TOK_ID {
ast_stack.back()->children.push_back(new AstNode(AST_WIRE));
ast_stack.back()->children.back()->str = *$3;
append_attr(ast_stack.back()->children.back(), $1);
ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, new AstNode(AST_IDENTIFIER), AstNode::mkconst_int(1, false, 1)));
ast_stack.back()->children.back()->children[0]->str = *$3;
delete $3;
} opt_supply_wires ';';
opt_supply_wires:
/* empty */ |
opt_supply_wires ',' TOK_ID {
AstNode *wire_node = ast_stack.back()->children.at(GetSize(ast_stack.back()->children)-2)->clone();
AstNode *assign_node = ast_stack.back()->children.at(GetSize(ast_stack.back()->children)-1)->clone();
wire_node->str = *$3;
assign_node->children[0]->str = *$3;
ast_stack.back()->children.push_back(wire_node);
ast_stack.back()->children.push_back(assign_node);
delete $3;
};
wire_name_list:
@ -689,7 +749,7 @@ wire_name:
};
assign_stmt:
TOK_ASSIGN assign_expr_list ';';
TOK_ASSIGN delay assign_expr_list ';';
assign_expr_list:
assign_expr | assign_expr_list ',' assign_expr;
@ -709,7 +769,7 @@ cell_stmt:
} cell_parameter_list_opt cell_list ';' {
delete astbuf1;
} |
attr tok_prim_wrapper {
attr tok_prim_wrapper delay {
astbuf1 = new AstNode(AST_PRIMITIVE);
astbuf1->str = *$2;
append_attr(astbuf1, $1);
@ -874,27 +934,34 @@ opt_label:
assert:
TOK_ASSERT '(' expr ')' ';' {
ast_stack.back()->children.push_back(new AstNode(AST_ASSERT, $3));
} |
TOK_ASSUME '(' expr ')' ';' {
ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $3));
};
assert_property:
TOK_ASSERT TOK_PROPERTY '(' expr ')' ';' {
ast_stack.back()->children.push_back(new AstNode(AST_ASSERT, $4));
} |
TOK_ASSUME TOK_PROPERTY '(' expr ')' ';' {
ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $4));
};
simple_behavioral_stmt:
lvalue '=' expr {
AstNode *node = new AstNode(AST_ASSIGN_EQ, $1, $3);
lvalue '=' delay expr {
AstNode *node = new AstNode(AST_ASSIGN_EQ, $1, $4);
ast_stack.back()->children.push_back(node);
} |
lvalue OP_LE expr {
AstNode *node = new AstNode(AST_ASSIGN_LE, $1, $3);
lvalue OP_LE delay expr {
AstNode *node = new AstNode(AST_ASSIGN_LE, $1, $4);
ast_stack.back()->children.push_back(node);
};
// this production creates the obligatory if-else shift/reduce conflict
behavioral_stmt:
defattr | assert | wire_decl |
simple_behavioral_stmt ';' |
non_opt_delay behavioral_stmt |
simple_behavioral_stmt ';' | ';' |
hierarchical_id attr {
AstNode *node = new AstNode(AST_TCALL);
node->str = *$1;
@ -1008,10 +1075,6 @@ opt_synopsys_attr:
} |
/* empty */;
behavioral_stmt_opt:
behavioral_stmt |
';' ;
behavioral_stmt_list:
behavioral_stmt_list behavioral_stmt |
/* empty */;
@ -1040,7 +1103,7 @@ case_item:
ast_stack.back()->children.push_back(block);
ast_stack.push_back(block);
case_type_stack.push_back(0);
} behavioral_stmt_opt {
} behavioral_stmt {
case_type_stack.pop_back();
ast_stack.pop_back();
ast_stack.pop_back();
@ -1211,7 +1274,7 @@ basic_expr:
if ($4->substr(0, 1) != "'")
frontend_verilog_yyerror("Syntax error.");
AstNode *bits = $2;
AstNode *val = const2ast(*$4, case_type_stack.size() == 0 ? 0 : case_type_stack.back());
AstNode *val = const2ast(*$4, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), true);
if (val == NULL)
log_error("Value conversion failed: `%s'\n", $4->c_str());
$$ = new AstNode(AST_TO_BITS, bits, val);
@ -1222,7 +1285,7 @@ basic_expr:
frontend_verilog_yyerror("Syntax error.");
AstNode *bits = new AstNode(AST_IDENTIFIER);
bits->str = *$1;
AstNode *val = const2ast(*$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back());
AstNode *val = const2ast(*$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), true);
if (val == NULL)
log_error("Value conversion failed: `%s'\n", $2->c_str());
$$ = new AstNode(AST_TO_BITS, bits, val);
@ -1230,14 +1293,14 @@ basic_expr:
delete $2;
} |
TOK_CONST TOK_CONST {
$$ = const2ast(*$1 + *$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back());
$$ = const2ast(*$1 + *$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), true);
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());
$$ = const2ast(*$1, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), true);
if ($$ == NULL)
log_error("Value conversion failed: `%s'\n", $1->c_str());
delete $1;
@ -1278,10 +1341,15 @@ basic_expr:
'(' expr ')' {
$$ = $2;
} |
'(' expr ':' expr ':' expr ')' {
delete $2;
$$ = $4;
delete $6;
} |
'{' concat_list '}' {
$$ = $2;
} |
'{' expr '{' expr '}' '}' {
'{' expr '{' concat_list '}' '}' {
$$ = new AstNode(AST_REPLICATE, $2, $4);
} |
'~' attr basic_expr %prec UNARY_OPS {

View File

@ -20,14 +20,17 @@
#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>
#ifndef _WIN32
# include <unistd.h>
# include <dirent.h>
#endif
YOSYS_NAMESPACE_BEGIN
struct Vhdl2verilogPass : public Pass {
@ -120,11 +123,8 @@ struct Vhdl2verilogPass : public Pass {
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");
std::string tempdir_name = make_temp_dir("/tmp/yosys-vhdl2verilog-XXXXXX");
log("Using temp directory %s.\n", tempdir_name.c_str());
if (!out_file.empty() && out_file[0] != '/') {
char pwd[PATH_MAX];
@ -135,7 +135,7 @@ struct Vhdl2verilogPass : public Pass {
out_file = pwd + ("/" + out_file);
}
FILE *f = fopen(stringf("%s/files.list", tempdir_name).c_str(), "wt");
FILE *f = fopen(stringf("%s/files.list", tempdir_name.c_str()).c_str(), "wt");
while (argidx < args.size()) {
std::string file = args[argidx++];
if (file.empty())
@ -156,38 +156,25 @@ struct Vhdl2verilogPass : public Pass {
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,
command += stringf("cd '%s'; vhdl2verilog -out '%s' -filelist files.list -top '%s'%s", tempdir_name.c_str(),
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));
int ret = run_command(command, [](const std::string &line) { log("%s", line.c_str()); });
if (ret != 0)
log_error("Execution of command \"%s\" failed: return code %d.\n", command.c_str(), ret);
if (out_file.empty()) {
std::ifstream ff;
ff.open(stringf("%s/vhdl2verilog_output.v", tempdir_name).c_str());
ff.open(stringf("%s/vhdl2verilog_output.v", tempdir_name.c_str()).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");
Frontend::frontend_call(design, &ff, stringf("%s/vhdl2verilog_output.v", tempdir_name.c_str()), "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_header("Removing temp directory `%s':\n", tempdir_name.c_str());
remove_directory(tempdir_name);
log_pop();
}
} Vhdl2verilogPass;

View File

@ -23,24 +23,46 @@
#include "kernel/log.h"
#include "kernel/rtlil.h"
YOSYS_NAMESPACE_BEGIN
struct BitPatternPool
{
int width;
typedef std::vector<RTLIL::State> bits_t;
std::set<bits_t> pool;
struct bits_t {
std::vector<RTLIL::State> bitdata;
unsigned int cached_hash;
bits_t(int width = 0) : bitdata(width), cached_hash(0) { }
RTLIL::State &operator[](int index) {
return bitdata[index];
}
const RTLIL::State &operator[](int index) const {
return bitdata[index];
}
bool operator==(const bits_t &other) const {
if (hash() != other.hash())
return false;
return bitdata == other.bitdata;
}
unsigned int hash() const {
if (!cached_hash)
((bits_t*)this)->cached_hash = hash_ops<std::vector<RTLIL::State>>::hash(bitdata);
return cached_hash;
}
};
pool<bits_t> database;
BitPatternPool(RTLIL::SigSpec sig)
{
width = sig.size();
if (width > 0) {
std::vector<RTLIL::State> pattern(width);
bits_t pattern(width);
for (int i = 0; i < width; i++) {
if (sig[i].wire == NULL && sig[i].data <= RTLIL::State::S1)
pattern[i] = sig[i].data;
else
pattern[i] = RTLIL::State::Sa;
}
pool.insert(pattern);
database.insert(pattern);
}
}
@ -48,17 +70,18 @@ struct BitPatternPool
{
this->width = width;
if (width > 0) {
std::vector<RTLIL::State> pattern(width);
bits_t pattern(width);
for (int i = 0; i < width; i++)
pattern[i] = RTLIL::State::Sa;
pool.insert(pattern);
database.insert(pattern);
}
}
bits_t sig2bits(RTLIL::SigSpec sig)
{
bits_t bits = sig.as_const().bits;
for (auto &b : bits)
bits_t bits;
bits.bitdata = sig.as_const().bits;
for (auto &b : bits.bitdata)
if (b > RTLIL::State::S1)
b = RTLIL::State::Sa;
return bits;
@ -66,8 +89,8 @@ struct BitPatternPool
bool match(bits_t a, bits_t b)
{
log_assert(int(a.size()) == width);
log_assert(int(b.size()) == width);
log_assert(int(a.bitdata.size()) == width);
log_assert(int(b.bitdata.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;
@ -77,7 +100,7 @@ struct BitPatternPool
bool has_any(RTLIL::SigSpec sig)
{
bits_t bits = sig2bits(sig);
for (auto &it : pool)
for (auto &it : database)
if (match(it, bits))
return true;
return false;
@ -86,13 +109,13 @@ struct BitPatternPool
bool has_all(RTLIL::SigSpec sig)
{
bits_t bits = sig2bits(sig);
for (auto &it : pool)
for (auto &it : database)
if (match(it, bits)) {
for (int i = 0; i < width; i++)
if (bits[i] > RTLIL::State::S1 && it[i] <= RTLIL::State::S1)
goto next_pool_entry;
goto next_database_entry;
return true;
next_pool_entry:;
next_database_entry:;
}
return false;
}
@ -101,36 +124,38 @@ struct BitPatternPool
{
bool status = false;
bits_t bits = sig2bits(sig);
std::vector<bits_t> pattern_list;
for (auto &it : pool)
if (match(it, bits))
pattern_list.push_back(it);
for (auto pattern : pattern_list) {
pool.erase(pattern);
for (int i = 0; i < width; i++) {
if (pattern[i] != RTLIL::State::Sa || bits[i] == RTLIL::State::Sa)
continue;
bits_t new_pattern = pattern;
new_pattern[i] = bits[i] == RTLIL::State::S1 ? RTLIL::State::S0 : RTLIL::State::S1;
pool.insert(new_pattern);
}
status = true;
}
for (auto it = database.begin(); it != database.end();)
if (match(*it, bits)) {
for (int i = 0; i < width; i++) {
if ((*it)[i] != RTLIL::State::Sa || bits[i] == RTLIL::State::Sa)
continue;
bits_t new_pattern;
new_pattern.bitdata = it->bitdata;
new_pattern[i] = bits[i] == RTLIL::State::S1 ? RTLIL::State::S0 : RTLIL::State::S1;
database.insert(new_pattern);
}
it = database.erase(it);
status = true;
continue;
} else
++it;
return status;
}
bool take_all()
{
if (pool.empty())
if (database.empty())
return false;
pool.clear();
database.clear();
return true;
}
bool empty()
{
return pool.empty();
return database.empty();
}
};
YOSYS_NAMESPACE_END
#endif

View File

@ -303,7 +303,7 @@ RTLIL::Const RTLIL::const_shl(const RTLIL::Const &arg1, const RTLIL::Const &arg2
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_u0(arg1_ext, std::max(result_len, SIZE(arg1)), signed1);
extend_u0(arg1_ext, std::max(result_len, GetSize(arg1)), signed1);
return const_shift_worker(arg1_ext, arg2, false, +1, result_len);
}

View File

@ -27,13 +27,13 @@ YOSYS_NAMESPACE_BEGIN
struct CellType
{
RTLIL::IdString type;
std::set<RTLIL::IdString> inputs, outputs;
pool<RTLIL::IdString> inputs, outputs;
bool is_evaluable;
};
struct CellTypes
{
std::map<RTLIL::IdString, CellType> cell_types;
dict<RTLIL::IdString, CellType> cell_types;
CellTypes()
{
@ -55,7 +55,7 @@ struct CellTypes
setup_stdcells_mem();
}
void setup_type(RTLIL::IdString type, const std::set<RTLIL::IdString> &inputs, const std::set<RTLIL::IdString> &outputs, bool is_evaluable = false)
void setup_type(RTLIL::IdString type, const pool<RTLIL::IdString> &inputs, const pool<RTLIL::IdString> &outputs, bool is_evaluable = false)
{
CellType ct = {type, inputs, outputs, is_evaluable};
cell_types[ct.type] = ct;
@ -63,7 +63,7 @@ struct CellTypes
void setup_module(RTLIL::Module *module)
{
std::set<RTLIL::IdString> inputs, outputs;
pool<RTLIL::IdString> inputs, outputs;
for (RTLIL::IdString wire_name : module->ports) {
RTLIL::Wire *wire = module->wire(wire_name);
if (wire->port_input)
@ -96,82 +96,105 @@ struct CellTypes
"$logic_and", "$logic_or", "$concat", "$macc"
};
IdString A = "\\A", B = "\\B", S = "\\S", Y = "\\Y";
IdString P = "\\P", G = "\\G", C = "\\C", X = "\\X";
IdString BI = "\\BI", CI = "\\CI", CO = "\\CO", EN = "\\EN";
for (auto type : unary_ops)
setup_type(type, {"\\A"}, {"\\Y"}, true);
setup_type(type, {A}, {Y}, true);
for (auto type : binary_ops)
setup_type(type, {"\\A", "\\B"}, {"\\Y"}, true);
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(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("$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);
setup_type("$assert", {A, EN}, pool<RTLIL::IdString>(), true);
setup_type("$assume", {A, EN}, pool<RTLIL::IdString>(), true);
setup_type("$equiv", {A, B}, {Y}, true);
}
void setup_internals_mem()
{
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"});
IdString SET = "\\SET", CLR = "\\CLR", CLK = "\\CLK", ARST = "\\ARST", EN = "\\EN";
IdString Q = "\\Q", D = "\\D", ADDR = "\\ADDR", DATA = "\\DATA";
IdString RD_CLK = "\\RD_CLK", RD_ADDR = "\\RD_ADDR", WR_CLK = "\\WR_CLK", WR_EN = "\\WR_EN";
IdString WR_ADDR = "\\WR_ADDR", WR_DATA = "\\WR_DATA", RD_DATA = "\\RD_DATA";
IdString CTRL_IN = "\\CTRL_IN", CTRL_OUT = "\\CTRL_OUT";
setup_type("$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("$sr", {SET, CLR}, {Q});
setup_type("$dff", {CLK, D}, {Q});
setup_type("$dffe", {CLK, EN, D}, {Q});
setup_type("$dffsr", {CLK, SET, CLR, D}, {Q});
setup_type("$adff", {CLK, ARST, D}, {Q});
setup_type("$dlatch", {EN, D}, {Q});
setup_type("$dlatchsr", {EN, SET, CLR, D}, {Q});
setup_type("$fsm", {"\\CLK", "\\ARST", "\\CTRL_IN"}, {"\\CTRL_OUT"});
setup_type("$memrd", {CLK, ADDR}, {DATA});
setup_type("$memwr", {CLK, EN, ADDR, DATA}, pool<RTLIL::IdString>());
setup_type("$meminit", {ADDR, DATA}, pool<RTLIL::IdString>());
setup_type("$mem", {RD_CLK, RD_ADDR, WR_CLK, WR_EN, WR_ADDR, WR_DATA}, {RD_DATA});
setup_type("$fsm", {CLK, ARST, CTRL_IN}, {CTRL_OUT});
}
void setup_stdcells()
{
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);
IdString A = "\\A", B = "\\B", C = "\\C", D = "\\D", S = "\\S", Y = "\\Y";
setup_type("$_BUF_", {A}, {Y}, true);
setup_type("$_NOT_", {A}, {Y}, true);
setup_type("$_AND_", {A, B}, {Y}, true);
setup_type("$_NAND_", {A, B}, {Y}, true);
setup_type("$_OR_", {A, B}, {Y}, true);
setup_type("$_NOR_", {A, B}, {Y}, true);
setup_type("$_XOR_", {A, B}, {Y}, true);
setup_type("$_XNOR_", {A, B}, {Y}, true);
setup_type("$_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()
{
IdString S = "\\S", R = "\\R", C = "\\C";
IdString D = "\\D", Q = "\\Q", E = "\\E";
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"});
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"});
setup_type(stringf("$_DFF_%c_", c1), {C, D}, {Q});
for (auto c1 : list_np)
for (auto c2 : list_np)
setup_type(stringf("$_DFFE_%c%c_", c1, c2), {C, D, E}, {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"});
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"});
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"});
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"});
setup_type(stringf("$_DLATCHSR_%c%c%c_", c1, c2, c3), {E, S, R, D}, {Q});
}
void clear()
@ -261,6 +284,8 @@ struct CellTypes
HANDLE_CELL_TYPE(neg)
#undef HANDLE_CELL_TYPE
if (type == "$_BUF_")
return arg1;
if (type == "$_NOT_")
return eval_not(arg1);
if (type == "$_AND_")
@ -300,7 +325,7 @@ struct CellTypes
int width = cell->parameters.at("\\WIDTH").as_int();
std::vector<RTLIL::State> t = cell->parameters.at("\\LUT").bits;
while (SIZE(t) < (1 << width))
while (GetSize(t) < (1 << width))
t.push_back(RTLIL::S0);
t.resize(1 << width);
@ -308,16 +333,16 @@ struct CellTypes
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);
new_t = std::vector<RTLIL::State>(t.begin(), t.begin() + GetSize(t)/2);
else if (sel == RTLIL::S1)
new_t = std::vector<RTLIL::State>(t.begin() + SIZE(t)/2, t.end());
new_t = std::vector<RTLIL::State>(t.begin() + GetSize(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);
for (int j = 0; j < GetSize(t)/2; j++)
new_t.push_back(t[j] == t[j + GetSize(t)/2] ? t[j] : RTLIL::Sx);
t.swap(new_t);
}
log_assert(SIZE(t) == 1);
log_assert(GetSize(t) == 1);
return t;
}
@ -360,6 +385,9 @@ struct CellTypes
}
};
// initialized by yosys_setup()
extern CellTypes yosys_celltypes;
YOSYS_NAMESPACE_END
#endif

View File

@ -25,6 +25,8 @@
#include "kernel/celltypes.h"
#include "kernel/macc.h"
YOSYS_NAMESPACE_BEGIN
struct ConstEval
{
RTLIL::Module *module;
@ -72,7 +74,7 @@ struct ConstEval
assign_map.apply(sig);
#ifndef NDEBUG
RTLIL::SigSpec current_val = values_map(sig);
for (int i = 0; i < SIZE(current_val); i++)
for (int i = 0; i < GetSize(current_val); i++)
log_assert(current_val[i].wire != NULL || current_val[i] == value.bits[i]);
#endif
values_map.add(sig, RTLIL::SigSpec(value));
@ -107,10 +109,10 @@ struct ConstEval
if (sig_p.is_fully_def() && sig_g.is_fully_def() && sig_ci.is_fully_def())
{
RTLIL::Const coval(RTLIL::Sx, SIZE(sig_co));
RTLIL::Const coval(RTLIL::Sx, GetSize(sig_co));
bool carry = sig_ci.as_bool();
for (int i = 0; i < SIZE(coval); i++) {
for (int i = 0; i < GetSize(coval); i++) {
carry = (sig_g[i] == RTLIL::S1) || (sig_p[i] == RTLIL::S1 && carry);
coval.bits[i] = carry ? RTLIL::S1 : RTLIL::S0;
}
@ -118,7 +120,7 @@ struct ConstEval
set(sig_co, coval);
}
else
set(sig_co, RTLIL::Const(RTLIL::Sx, SIZE(sig_co)));
set(sig_co, RTLIL::Const(RTLIL::Sx, GetSize(sig_co)));
return true;
}
@ -196,7 +198,7 @@ struct ConstEval
{
RTLIL::SigSpec sig_c = cell->getPort("\\C");
RTLIL::SigSpec sig_x = cell->getPort("\\X");
int width = SIZE(sig_c);
int width = GetSize(sig_c);
if (!eval(sig_a, undef, cell))
return false;
@ -214,7 +216,7 @@ struct ConstEval
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++)
for (int i = 0; i < GetSize(val_y); i++)
if (val_y.bits[i] == RTLIL::Sx)
val_x.bits[i] = RTLIL::Sx;
@ -245,13 +247,13 @@ struct ConstEval
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);
sig_a.extend_u0(GetSize(sig_y), signed_a);
sig_b.extend_u0(GetSize(sig_y), signed_b);
bool carry = sig_ci[0] == RTLIL::S1;
bool b_inv = sig_bi[0] == RTLIL::S1;
for (int i = 0; i < SIZE(sig_y); i++)
for (int i = 0; i < GetSize(sig_y); i++)
{
RTLIL::SigSpec x_inputs = { sig_a[i], sig_b[i], sig_bi[0] };
@ -292,7 +294,7 @@ struct ConstEval
return false;
}
RTLIL::Const result(0, SIZE(cell->getPort("\\Y")));
RTLIL::Const result(0, GetSize(cell->getPort("\\Y")));
if (!macc.eval(result))
log_abort();
@ -376,4 +378,6 @@ struct ConstEval
}
};
YOSYS_NAMESPACE_END
#endif

84
kernel/cost.h Normal file
View File

@ -0,0 +1,84 @@
/*
* 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 COST_H
#define COST_H
#include <kernel/yosys.h>
YOSYS_NAMESPACE_BEGIN
int get_cell_cost(RTLIL::Cell *cell, dict<RTLIL::IdString, int> *mod_cost_cache = nullptr);
int get_cell_cost(RTLIL::IdString type, const dict<RTLIL::IdString, RTLIL::Const> &parameters = dict<RTLIL::IdString, RTLIL::Const>(),
RTLIL::Design *design = nullptr, dict<RTLIL::IdString, int> *mod_cost_cache = nullptr)
{
static dict<RTLIL::IdString, int> gate_cost = {
{ "$_BUF_", 1 },
{ "$_NOT_", 2 },
{ "$_AND_", 4 },
{ "$_NAND_", 4 },
{ "$_OR_", 4 },
{ "$_NOR_", 4 },
{ "$_XOR_", 8 },
{ "$_XNOR_", 8 },
{ "$_AOI3_", 6 },
{ "$_OAI3_", 6 },
{ "$_AOI4_", 8 },
{ "$_OAI4_", 8 },
{ "$_MUX_", 4 }
};
if (gate_cost.count(type))
return gate_cost.at(type);
if (parameters.empty() && design && design->module(type))
{
RTLIL::Module *mod = design->module(type);
if (mod->attributes.count("\\cost"))
return mod->attributes.at("\\cost").as_int();
dict<RTLIL::IdString, int> local_mod_cost_cache;
if (mod_cost_cache == nullptr)
mod_cost_cache = &local_mod_cost_cache;
if (mod_cost_cache->count(mod->name))
return mod_cost_cache->at(mod->name);
int module_cost = 1;
for (auto c : mod->cells())
module_cost += get_cell_cost(c, mod_cost_cache);
(*mod_cost_cache)[mod->name] = module_cost;
return module_cost;
}
log_warning("Can't determine cost of %s cell (%d parameters).\n", log_id(type), GetSize(parameters));
return 1;
}
int get_cell_cost(RTLIL::Cell *cell, dict<RTLIL::IdString, int> *mod_cost_cache)
{
return get_cell_cost(cell->type, cell->parameters, cell->module->design, mod_cost_cache);
}
YOSYS_NAMESPACE_END
#endif

View File

@ -27,13 +27,98 @@
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <libgen.h>
#include <limits.h>
#include <errno.h>
#ifdef __linux__
# include <sys/types.h>
# include <unistd.h>
#endif
#if !defined(_WIN32) || defined(__MINGW32__)
# include <unistd.h>
#else
char *optarg;
int optind = 1, optcur = 1;
int getopt(int argc, char **argv, const char *optstring)
{
if (optind >= argc || argv[optind][0] != '-')
return -1;
bool takes_arg = false;
int opt = argv[optind][optcur];
for (int i = 0; optstring[i]; i++)
if (opt == optstring[i] && optstring[i + 1] == ':')
takes_arg = true;
if (!takes_arg) {
if (argv[optind][++optcur] == 0)
optind++, optcur = 1;
return opt;
}
if (argv[optind][++optcur]) {
optarg = argv[optind++] + optcur;
optcur = 1;
return opt;
}
optarg = argv[++optind];
optind++, optcur = 1;
return opt;
}
#endif
USING_YOSYS_NAMESPACE
#ifdef EMSCRIPTEN
# include <sys/stat.h>
# include <sys/types.h>
extern "C" int main(int, char**);
extern "C" void run(const char*);
extern "C" const char *errmsg();
extern "C" const char *prompt();
int main(int, char**)
{
mkdir("/work", 0777);
chdir("/work");
log_files.push_back(stdout);
log_error_stderr = true;
yosys_banner();
yosys_setup();
}
void run(const char *command)
{
int selSize = GetSize(yosys_get_design()->selection_stack);
try {
log_last_error = "Internal error (see JavaScript console for details)";
run_pass(command);
log_last_error = "";
} catch (...) {
while (GetSize(yosys_get_design()->selection_stack) > selSize)
yosys_get_design()->selection_stack.pop_back();
throw;
}
}
const char *errmsg()
{
return log_last_error.c_str();
}
const char *prompt()
{
const char *p = create_prompt(yosys_get_design(), 0);
while (*p == '\n') p++;
return p;
}
#else /* EMSCRIPTEN */
int main(int argc, char **argv)
{
std::string frontend_command = "auto";
@ -47,6 +132,9 @@ int main(int argc, char **argv)
bool print_banner = true;
bool print_stats = true;
bool call_abort = false;
bool timing_details = false;
bool mode_v = false;
bool mode_q = false;
#ifdef YOSYS_ENABLE_READLINE
int history_offset = 0;
@ -58,11 +146,103 @@ int main(int argc, char **argv)
}
#endif
if (argc == 2 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "-help") || !strcmp(argv[1], "--help")))
{
printf("\n");
printf("Usage: %s [options] [<infile> [..]]\n", argv[0]);
printf("\n");
printf(" -Q\n");
printf(" suppress printing of banner (copyright, disclaimer, version)\n");
printf("\n");
printf(" -T\n");
printf(" suppress printing of footer (log hash, version, timing statistics)\n");
printf("\n");
printf(" -q\n");
printf(" quiet operation. only write warnings and error messages to console\n");
printf(" use this option twice to also quiet warning messages\n");
printf("\n");
printf(" -v <level>\n");
printf(" print log headers up to level <level> to the console. (this\n");
printf(" implies -q for everything except the 'End of script.' message.)\n");
printf("\n");
printf(" -t\n");
printf(" annotate all log messages with a time stamp\n");
printf("\n");
printf(" -d\n");
printf(" print more detailed timing stats at exit\n");
printf("\n");
printf(" -l logfile\n");
printf(" write log messages to the specified file\n");
printf("\n");
printf(" -L logfile\n");
printf(" like -l but open log file in line buffered mode\n");
printf("\n");
printf(" -o outfile\n");
printf(" write the design to the specified file on exit\n");
printf("\n");
printf(" -b backend\n");
printf(" use this backend for the output file specified on the command line\n");
printf("\n");
printf(" -f backend\n");
printf(" use the specified front for the input files on the command line\n");
printf("\n");
printf(" -H\n");
printf(" print the command list\n");
printf("\n");
printf(" -h command\n");
printf(" print the help message for the specified command\n");
printf("\n");
printf(" -s scriptfile\n");
printf(" execute the commands in the script file\n");
printf("\n");
printf(" -c tcl_scriptfile\n");
printf(" execute the commands in the tcl script file (see 'help tcl' for details)\n");
printf("\n");
printf(" -p command\n");
printf(" execute the commands\n");
printf("\n");
printf(" -m module_file\n");
printf(" load the specified module (aka plugin)\n");
printf("\n");
printf(" -X\n");
printf(" enable tracing of core data structure changes. for debugging\n");
printf("\n");
printf(" -M\n");
printf(" will slightly randomize allocated pointer addresses. for debugging\n");
printf("\n");
printf(" -A\n");
printf(" will call abort() at the end of the script. for debugging\n");
printf("\n");
printf(" -V\n");
printf(" print version information and exit\n");
printf("\n");
printf("The option -S is an shortcut for calling the \"synth\" command, a default\n");
printf("script for transforming the verilog input to a gate-level netlist. For example:\n");
printf("\n");
printf(" yosys -o output.blif -S input.v\n");
printf("\n");
printf("For more complex synthesis jobs it is recommended to use the read_* and write_*\n");
printf("commands in a script file instead of specifying input and output files on the\n");
printf("command line.\n");
printf("\n");
printf("When no commands, script files or input files are specified on the command\n");
printf("line, yosys automatically enters the interactive command mode. Use the 'help'\n");
printf("command to get information on the individual commands.\n");
printf("\n");
exit(0);
}
int opt;
while ((opt = getopt(argc, argv, "AQTVSm:f:Hh:b:o:p:l:qv:ts:c:")) != -1)
while ((opt = getopt(argc, argv, "MXAQTVSm:f:Hh:b:o:p:l:L:qv:tds:c:")) != -1)
{
switch (opt)
{
case 'M':
memhasher_on();
break;
case 'X':
yosys_xtrace++;
break;
case 'A':
call_abort = true;
break;
@ -101,22 +281,32 @@ int main(int argc, char **argv)
got_output_filename = true;
break;
case 'l':
case 'L':
log_files.push_back(fopen(optarg, "wt"));
if (log_files.back() == NULL) {
fprintf(stderr, "Can't open log file `%s' for writing!\n", optarg);
exit(1);
}
if (opt == 'L')
setvbuf(log_files.back(), NULL, _IOLBF, 0);
break;
case 'q':
mode_q = true;
if (log_errfile == stderr)
log_quiet_warnings = true;
log_errfile = stderr;
break;
case 'v':
mode_v = true;
log_errfile = stderr;
log_verbose_level = atoi(optarg);
break;
case 't':
log_time = true;
break;
case 'd':
timing_details = true;
break;
case 's':
scriptfile = optarg;
scriptfile_tcl = false;
@ -126,107 +316,19 @@ int main(int argc, char **argv)
scriptfile_tcl = true;
break;
default:
fprintf(stderr, "\n");
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");
fprintf(stderr, " -v <level>\n");
fprintf(stderr, " print log headers up to level <level> to the console. (implies -q)\n");
fprintf(stderr, "\n");
fprintf(stderr, " -t\n");
fprintf(stderr, " annotate all log messages with a time stamp\n");
fprintf(stderr, "\n");
fprintf(stderr, " -l logfile\n");
fprintf(stderr, " write log messages to the specified file\n");
fprintf(stderr, "\n");
fprintf(stderr, " -o outfile\n");
fprintf(stderr, " write the design to the specified file on exit\n");
fprintf(stderr, "\n");
fprintf(stderr, " -b backend\n");
fprintf(stderr, " use this backend for the output file specified on the command line\n");
fprintf(stderr, "\n");
fprintf(stderr, " -f backend\n");
fprintf(stderr, " use the specified front for the input files on the command line\n");
fprintf(stderr, "\n");
fprintf(stderr, " -H\n");
fprintf(stderr, " print the command list\n");
fprintf(stderr, "\n");
fprintf(stderr, " -h command\n");
fprintf(stderr, " print the help message for the specified command\n");
fprintf(stderr, "\n");
fprintf(stderr, " -s scriptfile\n");
fprintf(stderr, " execute the commands in the script file\n");
fprintf(stderr, "\n");
fprintf(stderr, " -c tcl_scriptfile\n");
fprintf(stderr, " execute the commands in the tcl script file (see 'help tcl' for details)\n");
fprintf(stderr, "\n");
fprintf(stderr, " -p command\n");
fprintf(stderr, " execute the commands\n");
fprintf(stderr, "\n");
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 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, " 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");
fprintf(stderr, "command line.\n");
fprintf(stderr, "\n");
fprintf(stderr, "When no commands, script files or input files are specified on the command\n");
fprintf(stderr, "line, yosys automatically enters the interactive command mode. Use the 'help'\n");
fprintf(stderr, "command to get information on the individual commands.\n");
fprintf(stderr, "\n");
fprintf(stderr, "Run '%s -h' for help.\n", argv[0]);
exit(1);
}
}
if (log_errfile == NULL)
log_files.push_back(stderr);
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");
if (log_errfile == NULL) {
log_files.push_back(stdout);
log_error_stderr = true;
}
if (print_banner)
yosys_banner();
if (print_stats)
log_hasher = new SHA1;
@ -242,7 +344,7 @@ int main(int argc, char **argv)
}
while (optind < argc)
run_frontend(argv[optind++], frontend_command, yosys_design, output_filename == "-" ? &backend_command : NULL, NULL);
run_frontend(argv[optind++], frontend_command, output_filename == "-" ? &backend_command : NULL);
if (!scriptfile.empty()) {
if (scriptfile_tcl) {
@ -253,14 +355,14 @@ 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, NULL);
run_frontend(scriptfile, "script", output_filename == "-" ? &backend_command : NULL);
}
for (auto it = passes_commands.begin(); it != passes_commands.end(); it++)
run_pass(*it, yosys_design);
run_pass(*it);
if (!backend_command.empty())
run_backend(output_filename, backend_command, yosys_design);
run_backend(output_filename, backend_command);
if (print_stats)
{
@ -268,12 +370,37 @@ int main(int argc, char **argv)
delete log_hasher;
log_hasher = nullptr;
log_time = false;
yosys_xtrace = 0;
log_spacer();
if (mode_v && !mode_q)
log_files.push_back(stderr);
#ifdef _WIN32
log("End of script. Logfile hash: %s\n", hash.c_str());
#else
std::string meminfo;
std::string stats_divider = ", ";
# ifdef __linux__
std::ifstream statm;
statm.open(stringf("/proc/%lld/statm", (long long)getpid()));
if (statm.is_open()) {
int sz_total, sz_resident;
statm >> sz_total >> sz_resident;
meminfo = stringf(", MEM: %.2f MB total, %.2f MB resident",
sz_total * (getpagesize() / 1024.0 / 1024.0),
sz_resident * (getpagesize() / 1024.0 / 1024.0));
stats_divider = "\n";
}
# endif
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("End of script. Logfile hash: %s%sCPU: user %.2fs system %.2fs%s\n", hash.c_str(),
stats_divider.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, meminfo.c_str());
#endif
log("%s\n", yosys_version_str);
int64_t total_ns = 0;
@ -285,37 +412,49 @@ int main(int argc, char **argv)
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;
if (timing_details)
{
log("Time spent:\n");
for (auto it = timedat.rbegin(); it != timedat.rend(); it++) {
log("%5d%% %5d calls %8.3f sec %s\n", int(100*std::get<0>(*it) / total_ns),
std::get<1>(*it), std::get<0>(*it) / 1000000000.0, std::get<2>(*it).c_str());
}
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");
else
{
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 defined(YOSYS_ENABLE_COVER) && defined(__linux__)
if (getenv("YOSYS_COVER_DIR") || getenv("YOSYS_COVER_FILE"))
{
char filename_buffer[4096];
string filename;
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");
filename = stringf("%s/yosys_cover_%d_XXXXXX.txt", getenv("YOSYS_COVER_DIR"), getpid());
filename = make_temp_file(filename);
} else {
snprintf(filename_buffer, 4096, "%s", getenv("YOSYS_COVER_FILE"));
f = fopen(filename_buffer, "a+");
filename = getenv("YOSYS_COVER_FILE");
}
if (f == NULL)
log_error("Can't create coverage file `%s'.\n", filename_buffer);
f = fopen(filename.c_str(), "a+");
log("<writing coverage file \"%s\">\n", filename_buffer);
if (f == NULL)
log_error("Can't create coverage file `%s'.\n", filename.c_str());
log("<writing coverage file \"%s\">\n", filename.c_str());
for (auto &it : get_coverage_data())
fprintf(f, "%-60s %10d %s\n", it.second.first.c_str(), it.second.second, it.first.c_str());
@ -324,6 +463,7 @@ int main(int argc, char **argv)
}
#endif
memhasher_off();
if (call_abort)
abort();
@ -347,3 +487,5 @@ int main(int argc, char **argv)
return 0;
}
#endif /* EMSCRIPTEN */

887
kernel/hashlib.h Normal file
View File

@ -0,0 +1,887 @@
// This is free and unencumbered software released into the public domain.
//
// Anyone is free to copy, modify, publish, use, compile, sell, or
// distribute this software, either in source code form or as a compiled
// binary, for any purpose, commercial or non-commercial, and by any
// means.
// -------------------------------------------------------
// Written by Clifford Wolf <clifford@clifford.at> in 2014
// -------------------------------------------------------
#ifndef HASHLIB_H
#include <stdexcept>
#include <algorithm>
#include <string>
#include <vector>
namespace hashlib {
const int hashtable_size_trigger = 2;
const int hashtable_size_factor = 3;
// The XOR version of DJB2
inline unsigned int mkhash(unsigned int a, unsigned int b) {
return ((a << 5) + a) ^ b;
}
// traditionally 5381 is used as starting value for the djb2 hash
const unsigned int mkhash_init = 5381;
// The ADD version of DJB2
// (usunsigned int mkhashe this version for cache locality in b)
inline unsigned int mkhash_add(unsigned int a, unsigned int b) {
return ((a << 5) + a) + b;
}
inline unsigned int mkhash_xorshift(unsigned int a) {
if (sizeof(a) == 4) {
a ^= a << 13;
a ^= a >> 17;
a ^= a << 5;
} else if (sizeof(a) == 8) {
a ^= a << 13;
a ^= a >> 7;
a ^= a << 17;
} else
throw std::runtime_error("mkhash_xorshift() only implemented for 32 bit and 64 bit ints");
return a;
}
template<typename T> struct hash_ops {
static inline bool cmp(const T &a, const T &b) {
return a == b;
}
static inline unsigned int hash(const T &a) {
return a.hash();
}
};
template<> struct hash_ops<int> {
template<typename T>
static inline bool cmp(T a, T b) {
return a == b;
}
template<typename T>
static inline unsigned int hash(T a) {
return a;
}
};
template<> struct hash_ops<std::string> {
static inline bool cmp(const std::string &a, const std::string &b) {
return a == b;
}
static inline unsigned int hash(const std::string &a) {
unsigned int v = 0;
for (auto c : a)
v = mkhash(v, c);
return v;
}
};
template<typename P, typename Q> struct hash_ops<std::pair<P, Q>> {
static inline bool cmp(std::pair<P, Q> a, std::pair<P, Q> b) {
return a == b;
}
static inline unsigned int hash(std::pair<P, Q> a) {
hash_ops<P> p_ops;
hash_ops<Q> q_ops;
return mkhash(p_ops.hash(a.first), q_ops.hash(a.second));
}
};
template<typename T> struct hash_ops<std::vector<T>> {
static inline bool cmp(std::vector<T> a, std::vector<T> b) {
return a == b;
}
static inline unsigned int hash(std::vector<T> a) {
hash_ops<T> t_ops;
unsigned int h = mkhash_init;
for (auto k : a)
h = mkhash(h, t_ops.hash(k));
return h;
}
};
struct hash_cstr_ops {
static inline bool cmp(const char *a, const char *b) {
for (int i = 0; a[i] || b[i]; i++)
if (a[i] != b[i])
return false;
return true;
}
static inline unsigned int hash(const char *a) {
unsigned int hash = mkhash_init;
while (*a)
hash = mkhash(hash, *(a++));
return hash;
}
};
struct hash_ptr_ops {
static inline bool cmp(const void *a, const void *b) {
return a == b;
}
static inline unsigned int hash(const void *a) {
return (unsigned long)a;
}
};
struct hash_obj_ops {
static inline bool cmp(const void *a, const void *b) {
return a == b;
}
template<typename T>
static inline unsigned int hash(const T *a) {
return a->hash();
}
};
inline int hashtable_size(int min_size)
{
static std::vector<int> zero_and_some_primes = {
0, 23, 29, 37, 47, 59, 79, 101, 127, 163, 211, 269, 337, 431, 541, 677,
853, 1069, 1361, 1709, 2137, 2677, 3347, 4201, 5261, 6577, 8231, 10289,
12889, 16127, 20161, 25219, 31531, 39419, 49277, 61603, 77017, 96281,
120371, 150473, 188107, 235159, 293957, 367453, 459317, 574157, 717697,
897133, 1121423, 1401791, 1752239, 2190299, 2737937, 3422429, 4278037,
5347553, 6684443, 8355563, 10444457, 13055587, 16319519, 20399411,
25499291, 31874149, 39842687, 49803361, 62254207, 77817767, 97272239,
121590311, 151987889, 189984863, 237481091, 296851369, 371064217
};
for (auto p : zero_and_some_primes)
if (p >= min_size) return p;
if (sizeof(int) == 4)
throw std::length_error("hash table exceeded maximum size. use a ILP64 abi for larger tables.");
for (auto p : zero_and_some_primes)
if (100129 * p > min_size) return 100129 * p;
throw std::length_error("hash table exceeded maximum size.");
}
template<typename K, typename T, typename OPS = hash_ops<K>> class dict;
template<typename K, int offset = 0, typename OPS = hash_ops<K>> class idict;
template<typename K, typename OPS = hash_ops<K>> class pool;
template<typename K, typename T, typename OPS>
class dict
{
struct entry_t
{
std::pair<K, T> udata;
int next;
entry_t() { }
entry_t(const std::pair<K, T> &udata, int next) : udata(udata), next(next) { }
entry_t(std::pair<K, T> &&udata, int next) : udata(std::move(udata)), next(next) { }
};
std::vector<int> hashtable;
std::vector<entry_t> entries;
OPS ops;
#ifdef NDEBUG
static inline void do_assert(bool) { }
#else
static inline void do_assert(bool cond) {
if (!cond) throw std::runtime_error("dict<> assert failed.");
}
#endif
int do_hash(const K &key) const
{
unsigned int hash = 0;
if (!hashtable.empty())
hash = ops.hash(key) % (unsigned int)(hashtable.size());
return hash;
}
void do_rehash()
{
hashtable.clear();
hashtable.resize(hashtable_size(entries.size() * hashtable_size_factor), -1);
for (int i = 0; i < int(entries.size()); i++) {
do_assert(-1 <= entries[i].next && entries[i].next < int(entries.size()));
int hash = do_hash(entries[i].udata.first);
entries[i].next = hashtable[hash];
hashtable[hash] = i;
}
}
int do_erase(int index, int hash)
{
do_assert(index < int(entries.size()));
if (hashtable.empty() || index < 0)
return 0;
int k = hashtable[hash];
do_assert(0 <= k && k < int(entries.size()));
if (k == index) {
hashtable[hash] = entries[index].next;
} else {
while (entries[k].next != index) {
k = entries[k].next;
do_assert(0 <= k && k < int(entries.size()));
}
entries[k].next = entries[index].next;
}
int back_idx = entries.size()-1;
if (index != back_idx)
{
int back_hash = do_hash(entries[back_idx].udata.first);
k = hashtable[back_hash];
do_assert(0 <= k && k < int(entries.size()));
if (k == back_idx) {
hashtable[back_hash] = index;
} else {
while (entries[k].next != back_idx) {
k = entries[k].next;
do_assert(0 <= k && k < int(entries.size()));
}
entries[k].next = index;
}
entries[index] = std::move(entries[back_idx]);
}
entries.pop_back();
if (entries.empty())
hashtable.clear();
return 1;
}
int do_lookup(const K &key, int &hash) const
{
if (hashtable.empty())
return -1;
if (entries.size() * hashtable_size_trigger > hashtable.size()) {
((dict*)this)->do_rehash();
hash = do_hash(key);
}
int index = hashtable[hash];
while (index >= 0 && !ops.cmp(entries[index].udata.first, key)) {
index = entries[index].next;
do_assert(-1 <= index && index < int(entries.size()));
}
return index;
}
int do_insert(const K &key, int &hash)
{
if (hashtable.empty()) {
entries.push_back(entry_t(std::pair<K, T>(key, T()), -1));
do_rehash();
hash = do_hash(key);
} else {
entries.push_back(entry_t(std::pair<K, T>(key, T()), hashtable[hash]));
hashtable[hash] = entries.size() - 1;
}
return entries.size() - 1;
}
int do_insert(const std::pair<K, T> &value, int &hash)
{
if (hashtable.empty()) {
entries.push_back(entry_t(value, -1));
do_rehash();
hash = do_hash(value.first);
} else {
entries.push_back(entry_t(value, hashtable[hash]));
hashtable[hash] = entries.size() - 1;
}
return entries.size() - 1;
}
public:
class const_iterator : public std::iterator<std::forward_iterator_tag, std::pair<K, T>>
{
friend class dict;
protected:
const dict *ptr;
int index;
const_iterator(const dict *ptr, int index) : ptr(ptr), index(index) { }
public:
const_iterator() { }
const_iterator operator++() { index--; return *this; }
bool operator<(const const_iterator &other) const { return index > other.index; }
bool operator==(const const_iterator &other) const { return index == other.index; }
bool operator!=(const const_iterator &other) const { return index != other.index; }
const std::pair<K, T> &operator*() const { return ptr->entries[index].udata; }
const std::pair<K, T> *operator->() const { return &ptr->entries[index].udata; }
};
class iterator : public std::iterator<std::forward_iterator_tag, std::pair<K, T>>
{
friend class dict;
protected:
dict *ptr;
int index;
iterator(dict *ptr, int index) : ptr(ptr), index(index) { }
public:
iterator() { }
iterator operator++() { index--; return *this; }
bool operator<(const iterator &other) const { return index > other.index; }
bool operator==(const iterator &other) const { return index == other.index; }
bool operator!=(const iterator &other) const { return index != other.index; }
std::pair<K, T> &operator*() { return ptr->entries[index].udata; }
std::pair<K, T> *operator->() { return &ptr->entries[index].udata; }
const std::pair<K, T> &operator*() const { return ptr->entries[index].udata; }
const std::pair<K, T> *operator->() const { return &ptr->entries[index].udata; }
operator const_iterator() const { return const_iterator(ptr, index); }
};
dict()
{
}
dict(const dict &other)
{
entries = other.entries;
do_rehash();
}
dict(dict &&other)
{
swap(other);
}
dict &operator=(const dict &other) {
entries = other.entries;
do_rehash();
return *this;
}
dict &operator=(dict &&other) {
clear();
swap(other);
return *this;
}
dict(const std::initializer_list<std::pair<K, T>> &list)
{
for (auto &it : list)
insert(it);
}
template<class InputIterator>
dict(InputIterator first, InputIterator last)
{
insert(first, last);
}
template<class InputIterator>
void insert(InputIterator first, InputIterator last)
{
for (; first != last; ++first)
insert(*first);
}
std::pair<iterator, bool> insert(const K &key)
{
int hash = do_hash(key);
int i = do_lookup(key, hash);
if (i >= 0)
return std::pair<iterator, bool>(iterator(this, i), false);
i = do_insert(key, hash);
return std::pair<iterator, bool>(iterator(this, i), true);
}
std::pair<iterator, bool> insert(const std::pair<K, T> &value)
{
int hash = do_hash(value.first);
int i = do_lookup(value.first, hash);
if (i >= 0)
return std::pair<iterator, bool>(iterator(this, i), false);
i = do_insert(value, hash);
return std::pair<iterator, bool>(iterator(this, i), true);
}
int erase(const K &key)
{
int hash = do_hash(key);
int index = do_lookup(key, hash);
return do_erase(index, hash);
}
iterator erase(iterator it)
{
int hash = do_hash(it->first);
do_erase(it.index, hash);
return ++it;
}
int count(const K &key) const
{
int hash = do_hash(key);
int i = do_lookup(key, hash);
return i < 0 ? 0 : 1;
}
int count(const K &key, const_iterator it) const
{
int hash = do_hash(key);
int i = do_lookup(key, hash);
return i < 0 || i > it.index ? 0 : 1;
}
iterator find(const K &key)
{
int hash = do_hash(key);
int i = do_lookup(key, hash);
if (i < 0)
return end();
return iterator(this, i);
}
const_iterator find(const K &key) const
{
int hash = do_hash(key);
int i = do_lookup(key, hash);
if (i < 0)
return end();
return const_iterator(this, i);
}
T& at(const K &key)
{
int hash = do_hash(key);
int i = do_lookup(key, hash);
if (i < 0)
throw std::out_of_range("dict::at()");
return entries[i].udata.second;
}
const T& at(const K &key) const
{
int hash = do_hash(key);
int i = do_lookup(key, hash);
if (i < 0)
throw std::out_of_range("dict::at()");
return entries[i].udata.second;
}
T& operator[](const K &key)
{
int hash = do_hash(key);
int i = do_lookup(key, hash);
if (i < 0)
i = do_insert(std::pair<K, T>(key, T()), hash);
return entries[i].udata.second;
}
template<typename Compare = std::less<K>>
void sort(Compare comp = Compare())
{
std::sort(entries.begin(), entries.end(), [comp](const entry_t &a, const entry_t &b){ return comp(b.udata.first, a.udata.first); });
do_rehash();
}
void swap(dict &other)
{
hashtable.swap(other.hashtable);
entries.swap(other.entries);
}
bool operator==(const dict &other) const {
if (size() != other.size())
return false;
for (auto &it : entries) {
auto oit = other.find(it.udata.first);
if (oit == other.end() || !(oit->second == it.udata.second))
return false;
}
return true;
}
bool operator!=(const dict &other) const {
return !operator==(other);
}
size_t size() const { return entries.size(); }
bool empty() const { return entries.empty(); }
void clear() { hashtable.clear(); entries.clear(); }
iterator begin() { return iterator(this, int(entries.size())-1); }
iterator end() { return iterator(nullptr, -1); }
const_iterator begin() const { return const_iterator(this, int(entries.size())-1); }
const_iterator end() const { return const_iterator(nullptr, -1); }
};
template<typename K, typename OPS>
class pool
{
template<typename, int, typename> friend class idict;
protected:
struct entry_t
{
K udata;
int next;
entry_t() { }
entry_t(const K &udata, int next) : udata(udata), next(next) { }
};
std::vector<int> hashtable;
std::vector<entry_t> entries;
OPS ops;
#ifdef NDEBUG
static inline void do_assert(bool) { }
#else
static inline void do_assert(bool cond) {
if (!cond) throw std::runtime_error("pool<> assert failed.");
}
#endif
int do_hash(const K &key) const
{
unsigned int hash = 0;
if (!hashtable.empty())
hash = ops.hash(key) % (unsigned int)(hashtable.size());
return hash;
}
void do_rehash()
{
hashtable.clear();
hashtable.resize(hashtable_size(entries.size() * hashtable_size_factor), -1);
for (int i = 0; i < int(entries.size()); i++) {
do_assert(-1 <= entries[i].next && entries[i].next < int(entries.size()));
int hash = do_hash(entries[i].udata);
entries[i].next = hashtable[hash];
hashtable[hash] = i;
}
}
int do_erase(int index, int hash)
{
do_assert(index < int(entries.size()));
if (hashtable.empty() || index < 0)
return 0;
int k = hashtable[hash];
if (k == index) {
hashtable[hash] = entries[index].next;
} else {
while (entries[k].next != index) {
k = entries[k].next;
do_assert(0 <= k && k < int(entries.size()));
}
entries[k].next = entries[index].next;
}
int back_idx = entries.size()-1;
if (index != back_idx)
{
int back_hash = do_hash(entries[back_idx].udata);
k = hashtable[back_hash];
if (k == back_idx) {
hashtable[back_hash] = index;
} else {
while (entries[k].next != back_idx) {
k = entries[k].next;
do_assert(0 <= k && k < int(entries.size()));
}
entries[k].next = index;
}
entries[index] = std::move(entries[back_idx]);
}
entries.pop_back();
if (entries.empty())
hashtable.clear();
return 1;
}
int do_lookup(const K &key, int &hash) const
{
if (hashtable.empty())
return -1;
if (entries.size() * hashtable_size_trigger > hashtable.size()) {
((pool*)this)->do_rehash();
hash = do_hash(key);
}
int index = hashtable[hash];
while (index >= 0 && !ops.cmp(entries[index].udata, key)) {
index = entries[index].next;
do_assert(-1 <= index && index < int(entries.size()));
}
return index;
}
int do_insert(const K &value, int &hash)
{
if (hashtable.empty()) {
entries.push_back(entry_t(value, -1));
do_rehash();
hash = do_hash(value);
} else {
entries.push_back(entry_t(value, hashtable[hash]));
hashtable[hash] = entries.size() - 1;
}
return entries.size() - 1;
}
public:
class const_iterator : public std::iterator<std::forward_iterator_tag, K>
{
friend class pool;
protected:
const pool *ptr;
int index;
const_iterator(const pool *ptr, int index) : ptr(ptr), index(index) { }
public:
const_iterator() { }
const_iterator operator++() { index--; return *this; }
bool operator==(const const_iterator &other) const { return index == other.index; }
bool operator!=(const const_iterator &other) const { return index != other.index; }
const K &operator*() const { return ptr->entries[index].udata; }
const K *operator->() const { return &ptr->entries[index].udata; }
};
class iterator : public std::iterator<std::forward_iterator_tag, K>
{
friend class pool;
protected:
pool *ptr;
int index;
iterator(pool *ptr, int index) : ptr(ptr), index(index) { }
public:
iterator() { }
iterator operator++() { index--; return *this; }
bool operator==(const iterator &other) const { return index == other.index; }
bool operator!=(const iterator &other) const { return index != other.index; }
K &operator*() { return ptr->entries[index].udata; }
K *operator->() { return &ptr->entries[index].udata; }
const K &operator*() const { return ptr->entries[index].udata; }
const K *operator->() const { return &ptr->entries[index].udata; }
operator const_iterator() const { return const_iterator(ptr, index); }
};
pool()
{
}
pool(const pool &other)
{
entries = other.entries;
do_rehash();
}
pool(pool &&other)
{
swap(other);
}
pool &operator=(const pool &other) {
entries = other.entries;
do_rehash();
return *this;
}
pool &operator=(pool &&other) {
clear();
swap(other);
return *this;
}
pool(const std::initializer_list<K> &list)
{
for (auto &it : list)
insert(it);
}
template<class InputIterator>
pool(InputIterator first, InputIterator last)
{
insert(first, last);
}
template<class InputIterator>
void insert(InputIterator first, InputIterator last)
{
for (; first != last; ++first)
insert(*first);
}
std::pair<iterator, bool> insert(const K &value)
{
int hash = do_hash(value);
int i = do_lookup(value, hash);
if (i >= 0)
return std::pair<iterator, bool>(iterator(this, i), false);
i = do_insert(value, hash);
return std::pair<iterator, bool>(iterator(this, i), true);
}
int erase(const K &key)
{
int hash = do_hash(key);
int index = do_lookup(key, hash);
return do_erase(index, hash);
}
iterator erase(iterator it)
{
int hash = do_hash(*it);
do_erase(it.index, hash);
return ++it;
}
int count(const K &key) const
{
int hash = do_hash(key);
int i = do_lookup(key, hash);
return i < 0 ? 0 : 1;
}
int count(const K &key, const_iterator it) const
{
int hash = do_hash(key);
int i = do_lookup(key, hash);
return i < 0 || i > it.index ? 0 : 1;
}
iterator find(const K &key)
{
int hash = do_hash(key);
int i = do_lookup(key, hash);
if (i < 0)
return end();
return iterator(this, i);
}
const_iterator find(const K &key) const
{
int hash = do_hash(key);
int i = do_lookup(key, hash);
if (i < 0)
return end();
return const_iterator(this, i);
}
bool operator[](const K &key)
{
int hash = do_hash(key);
int i = do_lookup(key, hash);
return i >= 0;
}
template<typename Compare = std::less<K>>
void sort(Compare comp = Compare())
{
std::sort(entries.begin(), entries.end(), [comp](const entry_t &a, const entry_t &b){ return comp(b.udata, a.udata); });
do_rehash();
}
void swap(pool &other)
{
hashtable.swap(other.hashtable);
entries.swap(other.entries);
}
bool operator==(const pool &other) const {
if (size() != other.size())
return false;
for (auto &it : entries)
if (!other.count(it.udata))
return false;
return true;
}
bool operator!=(const pool &other) const {
return !operator==(other);
}
size_t size() const { return entries.size(); }
bool empty() const { return entries.empty(); }
void clear() { hashtable.clear(); entries.clear(); }
iterator begin() { return iterator(this, int(entries.size())-1); }
iterator end() { return iterator(nullptr, -1); }
const_iterator begin() const { return const_iterator(this, int(entries.size())-1); }
const_iterator end() const { return const_iterator(nullptr, -1); }
};
template<typename K, int offset, typename OPS>
class idict
{
pool<K, OPS> database;
public:
typedef typename pool<K, OPS>::const_iterator const_iterator;
int operator()(const K &key)
{
int hash = database.do_hash(key);
int i = database.do_lookup(key, hash);
if (i < 0)
i = database.do_insert(key, hash);
return i + offset;
}
int at(const K &key) const
{
int hash = database.do_hash(key);
int i = database.do_lookup(key, hash);
if (i < 0)
throw std::out_of_range("idict::at()");
return i + offset;
}
int count(const K &key) const
{
int hash = database.do_hash(key);
int i = database.do_lookup(key, hash);
return i < 0 ? 0 : 1;
}
void expect(const K &key, int i)
{
int j = (*this)(key);
if (i != j)
throw std::out_of_range("idict::expect()");
}
const K &operator[](int index) const
{
return database.entries.at(index - offset).udata;
}
const_iterator begin() const { return database.begin(); }
const_iterator end() const { return database.end(); }
};
} /* namespace hashlib */
#endif

View File

@ -21,7 +21,14 @@
#include "libs/sha1/sha1.h"
#include "backends/ilang/ilang_backend.h"
#include <sys/time.h>
#if !defined(_WIN32) || defined(__MINGW32__)
# include <sys/time.h>
#endif
#ifdef __linux__
# include <dlfcn.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
@ -37,17 +44,41 @@ FILE *log_errfile = NULL;
SHA1 *log_hasher = NULL;
bool log_time = false;
bool log_error_stderr = false;
bool log_cmd_error_throw = false;
bool log_quiet_warnings = false;
int log_verbose_level;
string log_last_error;
std::vector<int> header_count;
std::list<std::string> string_buf;
int string_buf_size = 0;
vector<int> header_count;
pool<RTLIL::IdString> log_id_cache;
vector<string> string_buf;
int string_buf_index = -1;
static struct timeval initial_tv = { 0, 0 };
static bool next_print_log = false;
static int log_newline_count = 0;
#if defined(_WIN32) && !defined(__MINGW32__)
// this will get time information and return it in timeval, simulating gettimeofday()
int gettimeofday(struct timeval *tv, struct timezone *tz)
{
LARGE_INTEGER counter;
LARGE_INTEGER freq;
QueryPerformanceFrequency(&freq);
QueryPerformanceCounter(&counter);
counter.QuadPart *= 1000000;
counter.QuadPart /= freq.QuadPart;
tv->tv_sec = long(counter.QuadPart / 1000000);
tv->tv_usec = counter.QuadPart % 1000000;
return 0;
}
#endif
void logv(const char *format, va_list ap)
{
while (format[0] == '\n' && format[1] != 0) {
@ -62,9 +93,9 @@ void logv(const char *format, va_list ap)
size_t nnl_pos = str.find_last_not_of('\n');
if (nnl_pos == std::string::npos)
log_newline_count += SIZE(str);
log_newline_count += GetSize(str);
else
log_newline_count = SIZE(str) - nnl_pos - 1;
log_newline_count = GetSize(str) - nnl_pos - 1;
if (log_hasher)
log_hasher->update(str);
@ -128,15 +159,43 @@ void logv_header(const char *format, va_list ap)
log_files.pop_back();
}
void logv_warning(const char *format, va_list ap)
{
if (log_errfile != NULL && !log_quiet_warnings)
log_files.push_back(log_errfile);
log("Warning: ");
logv(format, ap);
log_flush();
if (log_errfile != NULL && !log_quiet_warnings)
log_files.pop_back();
}
void logv_error(const char *format, va_list ap)
{
#ifdef EMSCRIPTEN
auto backup_log_files = log_files;
#endif
if (log_errfile != NULL)
log_files.push_back(log_errfile);
log("ERROR: ");
logv(format, ap);
if (log_error_stderr)
for (auto &f : log_files)
if (f == stdout)
f = stderr;
log_last_error = vstringf(format, ap);
log("ERROR: %s", log_last_error.c_str());
log_flush();
#ifdef EMSCRIPTEN
log_files = backup_log_files;
throw 0;
#else
exit(1);
#endif
}
void log(const char *format, ...)
@ -155,6 +214,14 @@ void log_header(const char *format, ...)
va_end(ap);
}
void log_warning(const char *format, ...)
{
va_list ap;
va_start(ap, format);
logv_warning(format, ap);
va_end(ap);
}
void log_error(const char *format, ...)
{
va_list ap;
@ -168,10 +235,10 @@ void log_cmd_error(const char *format, ...)
va_start(ap, format);
if (log_cmd_error_throw) {
log("ERROR: ");
logv(format, ap);
log_last_error = vstringf(format, ap);
log("ERROR: %s", log_last_error.c_str());
log_flush();
throw log_cmd_error_expection();
throw log_cmd_error_exception();
}
logv_error(format, ap);
@ -191,17 +258,112 @@ void log_push()
void log_pop()
{
header_count.pop_back();
log_id_cache.clear();
string_buf.clear();
string_buf_size = 0;
string_buf_index = -1;
log_flush();
}
#ifdef __linux__
void log_backtrace(const char *prefix, int levels)
{
if (levels <= 0) return;
Dl_info dli;
void *p;
if ((p = __builtin_extract_return_addr(__builtin_return_address(0))) && dladdr(p, &dli)) {
log("%sframe #1: %p %s(%p) %s(%p)\n", prefix, p, dli.dli_fname, dli.dli_fbase, dli.dli_sname, dli.dli_saddr);
} else {
log("%sframe #1: ---\n", prefix);
return;
}
if (levels <= 1) return;
if ((p = __builtin_extract_return_addr(__builtin_return_address(1))) && dladdr(p, &dli)) {
log("%sframe #2: %p %s(%p) %s(%p)\n", prefix, p, dli.dli_fname, dli.dli_fbase, dli.dli_sname, dli.dli_saddr);
} else {
log("%sframe #2: ---\n", prefix);
return;
}
if (levels <= 2) return;
if ((p = __builtin_extract_return_addr(__builtin_return_address(2))) && dladdr(p, &dli)) {
log("%sframe #3: %p %s(%p) %s(%p)\n", prefix, p, dli.dli_fname, dli.dli_fbase, dli.dli_sname, dli.dli_saddr);
} else {
log("%sframe #3: ---\n", prefix);
return;
}
if (levels <= 3) return;
if ((p = __builtin_extract_return_addr(__builtin_return_address(3))) && dladdr(p, &dli)) {
log("%sframe #4: %p %s(%p) %s(%p)\n", prefix, p, dli.dli_fname, dli.dli_fbase, dli.dli_sname, dli.dli_saddr);
} else {
log("%sframe #4: ---\n", prefix);
return;
}
if (levels <= 4) return;
if ((p = __builtin_extract_return_addr(__builtin_return_address(4))) && dladdr(p, &dli)) {
log("%sframe #5: %p %s(%p) %s(%p)\n", prefix, p, dli.dli_fname, dli.dli_fbase, dli.dli_sname, dli.dli_saddr);
} else {
log("%sframe #5: ---\n", prefix);
return;
}
if (levels <= 5) return;
if ((p = __builtin_extract_return_addr(__builtin_return_address(5))) && dladdr(p, &dli)) {
log("%sframe #6: %p %s(%p) %s(%p)\n", prefix, p, dli.dli_fname, dli.dli_fbase, dli.dli_sname, dli.dli_saddr);
} else {
log("%sframe #6: ---\n", prefix);
return;
}
if (levels <= 6) return;
if ((p = __builtin_extract_return_addr(__builtin_return_address(6))) && dladdr(p, &dli)) {
log("%sframe #7: %p %s(%p) %s(%p)\n", prefix, p, dli.dli_fname, dli.dli_fbase, dli.dli_sname, dli.dli_saddr);
} else {
log("%sframe #7: ---\n", prefix);
return;
}
if (levels <= 7) return;
if ((p = __builtin_extract_return_addr(__builtin_return_address(7))) && dladdr(p, &dli)) {
log("%sframe #8: %p %s(%p) %s(%p)\n", prefix, p, dli.dli_fname, dli.dli_fbase, dli.dli_sname, dli.dli_saddr);
} else {
log("%sframe #8: ---\n", prefix);
return;
}
if (levels <= 8) return;
if ((p = __builtin_extract_return_addr(__builtin_return_address(8))) && dladdr(p, &dli)) {
log("%sframe #9: %p %s(%p) %s(%p)\n", prefix, p, dli.dli_fname, dli.dli_fbase, dli.dli_sname, dli.dli_saddr);
} else {
log("%sframe #9: ---\n", prefix);
return;
}
if (levels <= 9) return;
}
#else
void log_backtrace(const char*, int) { }
#endif
void log_reset_stack()
{
while (header_count.size() > 1)
header_count.pop_back();
log_id_cache.clear();
string_buf.clear();
string_buf_size = 0;
string_buf_index = -1;
log_flush();
}
@ -223,22 +385,28 @@ const char *log_signal(const RTLIL::SigSpec &sig, bool autoint)
std::stringstream buf;
ILANG_BACKEND::dump_sigspec(buf, sig, autoint);
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();
if (string_buf.size() < 100) {
string_buf.push_back(buf.str());
return string_buf.back().c_str();
} else {
if (++string_buf_index == 100)
string_buf_index = 0;
string_buf[string_buf_index] = buf.str();
return string_buf[string_buf_index].c_str();
}
}
const char *log_id(RTLIL::IdString str)
{
log_id_cache.insert(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;
if (p[0] != '\\')
return p;
if (p[1] == '$' || p[1] == '\\' || p[1] == 0)
return p;
if (p[1] >= '0' && p[1] <= '9')
return p;
return p+1;
}
void log_cell(RTLIL::Cell *cell, std::string indent)
@ -251,9 +419,9 @@ void log_cell(RTLIL::Cell *cell, std::string indent)
// ---------------------------------------------------
// This is the magic behind the code coverage counters
// ---------------------------------------------------
#ifdef COVER_ACTIVE
#if defined(YOSYS_ENABLE_COVER) && defined(__linux__)
std::map<std::string, std::pair<std::string, int>> extra_coverage_data;
dict<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) {
@ -266,9 +434,9 @@ void cover_extra(std::string parent, std::string id, bool increment) {
extra_coverage_data[id].second++;
}
std::map<std::string, std::pair<std::string, int>> get_coverage_data()
dict<std::string, std::pair<std::string, int>> get_coverage_data()
{
std::map<std::string, std::pair<std::string, int>> coverage_data;
dict<std::string, std::pair<std::string, int>> coverage_data;
for (auto &it : pass_register) {
std::string key = stringf("passes.%s", it.first.c_str());
@ -278,14 +446,14 @@ std::map<std::string, std::pair<std::string, int>> get_coverage_data()
for (auto &it : extra_coverage_data) {
if (coverage_data.count(it.first))
log("WARNING: found duplicate coverage id \"%s\".\n", it.first.c_str());
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);
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;
}

View File

@ -23,8 +23,14 @@
#define LOG_H
#include <time.h>
#include <sys/time.h>
#include <sys/resource.h>
#ifndef _WIN32
# include <sys/time.h>
# include <sys/resource.h>
#endif
// from libs/sha1/sha1.h
class SHA1;
YOSYS_NAMESPACE_BEGIN
@ -32,30 +38,36 @@ YOSYS_NAMESPACE_BEGIN
#define S__LINE__sub1(x) S__LINE__sub2(x)
#define S__LINE__ S__LINE__sub1(__LINE__)
struct log_cmd_error_expection { };
struct log_cmd_error_exception { };
extern std::vector<FILE*> log_files;
extern std::vector<std::ostream*> log_streams;
extern FILE *log_errfile;
extern class SHA1 *log_hasher;
extern SHA1 *log_hasher;
extern bool log_time;
extern bool log_error_stderr;
extern bool log_cmd_error_throw;
extern bool log_quiet_warnings;
extern int log_verbose_level;
extern string log_last_error;
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));
void logv_warning(const char *format, va_list ap);
YS_NORETURN void logv_error(const char *format, va_list ap) YS_ATTRIBUTE(noreturn);
void log(const char *format, ...) __attribute__ ((format (printf, 1, 2)));
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(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2));
void log_header(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2));
void log_warning(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2));
YS_NORETURN void log_error(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2), noreturn);
YS_NORETURN void log_cmd_error(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2), noreturn);
void log_spacer();
void log_push();
void log_pop();
void log_backtrace(const char *prefix, int levels);
void log_reset_stack();
void log_flush();
@ -68,36 +80,43 @@ template<typename T> static inline const char *log_id(T *obj) {
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__)
#ifndef NDEBUG
static inline void log_assert_worker(bool cond, const char *expr, const char *file, int line) {
if (!cond) log_error("Assert `%s' failed in %s:%d.\n", expr, file, line);
}
# define log_assert(_assert_expr_) YOSYS_NAMESPACE_PREFIX log_assert_worker(_assert_expr_, #_assert_expr_, __FILE__, __LINE__)
#else
# define log_assert(_assert_expr_)
#endif
#define log_abort() YOSYS_NAMESPACE_PREFIX log_error("Abort in %s:%d.\n", __FILE__, __LINE__)
#define log_ping() YOSYS_NAMESPACE_PREFIX 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
#if defined(YOSYS_ENABLE_COVER) && defined(__linux__)
#define cover(_id) do { \
static CoverData __d __attribute__((section("yosys_cover_list"), aligned(1))) = { __FILE__, __FUNCTION__, _id, __LINE__, 0 }; \
static CoverData __d __attribute__((section("yosys_cover_list"), aligned(1), used)) = { __FILE__, __FUNCTION__, _id, __LINE__, 0 }; \
__d.counter++; \
} while (0)
struct CoverData {
const char *file, *func, *id;
int line, counter;
} __attribute__ ((packed));
} YS_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;
extern dict<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();
dict<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__); \
@ -151,6 +170,8 @@ struct PerformanceTimer
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;
#elif _WIN32
return 0;
#else
#error Dont know how to measure per-process CPU time. Need alternative method (times()/clocks()/gettimeofday()?).
#endif
@ -169,7 +190,7 @@ struct PerformanceTimer
}
float sec() const {
return total_ns * 1e-9;
return total_ns * 1e-9f;
}
#else
static int64_t query() { return 0; }
@ -188,8 +209,10 @@ static inline void log_dump_val_worker(int v) { log("%d", v); }
static inline void log_dump_val_worker(unsigned int v) { log("%u", v); }
static inline void log_dump_val_worker(long int v) { log("%ld", v); }
static inline void log_dump_val_worker(unsigned long int v) { log("%lu", v); }
#ifndef _WIN32
static inline void log_dump_val_worker(long long int v) { log("%lld", v); }
static inline void log_dump_val_worker(unsigned long long int v) { log("%lld", v); }
#endif
static inline void log_dump_val_worker(char c) { log(c >= 32 && c < 127 ? "'%c'" : "'\\x%02x'", 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"); }
@ -198,7 +221,7 @@ 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(PerformanceTimer p) { log("%f seconds", p.sec()); }
static inline void log_dump_args_worker(const char *p) { log_assert(*p == 0); }
static inline void log_dump_args_worker(const char *p YS_ATTRIBUTE(unused)) { log_assert(*p == 0); }
void log_dump_val_worker(RTLIL::SigSpec v);
template<typename T>

View File

@ -42,17 +42,20 @@ struct Macc
for (auto &port : ports)
{
if (SIZE(port.in_a) == 0 && SIZE(port.in_b) == 0)
if (GetSize(port.in_a) == 0 && GetSize(port.in_b) == 0)
continue;
if (SIZE(port.in_a) == 1 && SIZE(port.in_b) == 0 && !port.is_signed && !port.do_subtract) {
if (GetSize(port.in_a) < GetSize(port.in_b))
std::swap(port.in_a, port.in_b);
if (GetSize(port.in_a) == 1 && GetSize(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))
if (GetSize(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);
@ -62,15 +65,15 @@ struct Macc
}
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);
while (GetSize(port.in_a) > 1 && port.in_a[GetSize(port.in_a)-1] == port.in_a[GetSize(port.in_a)-2])
port.in_a.remove(GetSize(port.in_a)-1);
while (GetSize(port.in_b) > 1 && port.in_b[GetSize(port.in_b)-1] == port.in_b[GetSize(port.in_b)-2])
port.in_b.remove(GetSize(port.in_b)-1);
} else {
while (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);
while (GetSize(port.in_a) > 1 && port.in_a[GetSize(port.in_a)-1] == RTLIL::S0)
port.in_a.remove(GetSize(port.in_a)-1);
while (GetSize(port.in_b) > 1 && port.in_b[GetSize(port.in_b)-1] == RTLIL::S0)
port.in_b.remove(GetSize(port.in_b)-1);
}
new_ports.push_back(port);
@ -102,10 +105,12 @@ struct Macc
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);
#ifndef NDEBUG
int config_width = cell->getParam("\\CONFIG_WIDTH").as_int();
log_assert(GetSize(config_bits) >= config_width);
#endif
int num_bits = 0;
if (config_bits[config_cursor++] == RTLIL::S1) num_bits |= 1;
@ -114,7 +119,7 @@ struct Macc
if (config_bits[config_cursor++] == RTLIL::S1) num_bits |= 8;
int port_a_cursor = 0;
while (port_a_cursor < SIZE(port_a))
while (port_a_cursor < GetSize(port_a))
{
log_assert(config_cursor + 2 + 2*num_bits <= config_width);
@ -143,7 +148,7 @@ struct Macc
}
log_assert(config_cursor == config_width);
log_assert(port_a_cursor == SIZE(port_a));
log_assert(port_a_cursor == GetSize(port_a));
}
void to_cell(RTLIL::Cell *cell) const
@ -153,8 +158,8 @@ struct Macc
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));
max_size = std::max(max_size, GetSize(port.in_a));
max_size = std::max(max_size, GetSize(port.in_b));
}
while (max_size)
@ -168,17 +173,17 @@ struct Macc
for (auto &port : ports)
{
if (SIZE(port.in_a) == 0)
if (GetSize(port.in_a) == 0)
continue;
config_bits.push_back(port.is_signed ? RTLIL::S1 : RTLIL::S0);
config_bits.push_back(port.do_subtract ? RTLIL::S1 : RTLIL::S0);
int size_a = SIZE(port.in_a);
int size_a = GetSize(port.in_a);
for (int i = 0; i < num_bits; i++)
config_bits.push_back(size_a & (1 << i) ? RTLIL::S1 : RTLIL::S0);
int size_b = SIZE(port.in_b);
int size_b = GetSize(port.in_b);
for (int i = 0; i < num_bits; i++)
config_bits.push_back(size_b & (1 << i) ? RTLIL::S1 : RTLIL::S0);
@ -189,9 +194,9 @@ struct Macc
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));
cell->setParam("\\CONFIG_WIDTH", GetSize(config_bits));
cell->setParam("\\A_WIDTH", GetSize(port_a));
cell->setParam("\\B_WIDTH", GetSize(bit_ports));
}
bool eval(RTLIL::Const &result) const
@ -205,25 +210,31 @@ struct Macc
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));
if (GetSize(port.in_b) == 0)
summand = const_pos(port.in_a.as_const(), port.in_b.as_const(), port.is_signed, port.is_signed, GetSize(result));
else
summand = const_mul(port.in_a.as_const(), port.in_b.as_const(), port.is_signed, port.is_signed, SIZE(result));
summand = const_mul(port.in_a.as_const(), port.in_b.as_const(), port.is_signed, port.is_signed, GetSize(result));
if (port.do_subtract)
result = const_sub(result, summand, port.is_signed, port.is_signed, SIZE(result));
result = const_sub(result, summand, port.is_signed, port.is_signed, GetSize(result));
else
result = const_add(result, summand, port.is_signed, port.is_signed, SIZE(result));
result = const_add(result, summand, port.is_signed, port.is_signed, GetSize(result));
}
for (auto bit : bit_ports) {
if (bit.wire)
return false;
result = const_add(result, bit.data, false, false, SIZE(result));
result = const_add(result, bit.data, false, false, GetSize(result));
}
return true;
}
Macc(RTLIL::Cell *cell = nullptr)
{
if (cell != nullptr)
from_cell(cell);
}
};
YOSYS_NAMESPACE_END

View File

@ -33,6 +33,7 @@ struct ModIndex : public RTLIL::Monitor
RTLIL::IdString port;
int offset;
PortInfo() : cell(), port(), offset() { }
PortInfo(RTLIL::Cell* _c, RTLIL::IdString _p, int _o) : cell(_c), port(_p), offset(_o) { }
bool operator<(const PortInfo &other) const {
@ -42,24 +43,44 @@ struct ModIndex : public RTLIL::Monitor
return offset < other.offset;
return port < other.port;
}
bool operator==(const PortInfo &other) const {
return cell == other.cell && port == other.port && offset == other.offset;
}
unsigned int hash() const {
return mkhash_add(mkhash(cell->name.hash(), port.hash()), offset);
}
};
struct SigBitInfo
{
bool is_input, is_output;
std::set<PortInfo> ports;
pool<PortInfo> ports;
SigBitInfo() : is_input(false), is_output(false) { }
bool operator==(const SigBitInfo &other) const {
return is_input == other.is_input && is_output == other.is_output && ports == other.ports;
}
void merge(const SigBitInfo &other)
{
is_input = is_input || other.is_input;
is_output = is_output || other.is_output;
ports.insert(other.ports.begin(), other.ports.end());
}
};
SigMap sigmap;
RTLIL::Module *module;
std::map<RTLIL::SigBit, SigBitInfo> database;
int auto_reload_counter;
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++) {
for (int i = 0; i < GetSize(sig); i++) {
RTLIL::SigBit bit = sigmap(sig[i]);
if (bit.wire)
database[bit].ports.insert(PortInfo(cell, port, i));
@ -68,7 +89,7 @@ struct ModIndex : public RTLIL::Monitor
void port_del(RTLIL::Cell *cell, RTLIL::IdString port, const RTLIL::SigSpec &sig)
{
for (int i = 0; i < SIZE(sig); i++) {
for (int i = 0; i < GetSize(sig); i++) {
RTLIL::SigBit bit = sigmap(sig[i]);
if (bit.wire)
database[bit].ports.erase(PortInfo(cell, port, i));
@ -80,15 +101,17 @@ struct ModIndex : public RTLIL::Monitor
return database[sigmap(bit)];
}
void reload_module()
void reload_module(bool reset_sigmap = true)
{
sigmap.clear();
sigmap.set(module);
if (reset_sigmap) {
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++) {
for (int i = 0; i < GetSize(wire); i++) {
RTLIL::SigBit bit = sigmap(RTLIL::SigBit(wire, i));
if (bit.wire && wire->port_input)
database[bit].is_input = true;
@ -99,31 +122,105 @@ struct ModIndex : public RTLIL::Monitor
for (auto &conn : cell->connections())
port_add(cell, conn.first, conn.second);
auto_reload_module = false;
if (auto_reload_module) {
if (++auto_reload_counter > 2)
log_warning("Auto-reload in ModIndex -- possible performance bug!\n");
auto_reload_module = false;
}
}
virtual void notify_connect(RTLIL::Cell *cell, const RTLIL::IdString &port, const RTLIL::SigSpec &old_sig, RTLIL::SigSpec &sig) OVERRIDE
void check()
{
#ifndef NDEBUG
if (auto_reload_module)
reload_module();
return;
for (auto it : database)
log_assert(it.first == sigmap(it.first));
auto database_bak = std::move(database);
reload_module(false);
if (!(database == database_bak))
{
for (auto &it : database_bak)
if (!database.count(it.first))
log("ModuleIndex::check(): Only in database_bak, not database: %s\n", log_signal(it.first));
for (auto &it : database)
if (!database_bak.count(it.first))
log("ModuleIndex::check(): Only in database, not database_bak: %s\n", log_signal(it.first));
else if (!(it.second == database_bak.at(it.first)))
log("ModuleIndex::check(): Different content for database[%s].\n", log_signal(it.first));
log_assert(database == database_bak);
}
#endif
}
virtual void notify_connect(RTLIL::Cell *cell, const RTLIL::IdString &port, const RTLIL::SigSpec &old_sig, RTLIL::SigSpec &sig) YS_OVERRIDE
{
log_assert(module == cell->module);
if (auto_reload_module)
return;
port_del(cell, port, old_sig);
port_add(cell, port, sig);
}
virtual void notify_connect(RTLIL::Module *mod, const RTLIL::SigSig&)
virtual void notify_connect(RTLIL::Module *mod YS_ATTRIBUTE(unused), const RTLIL::SigSig &sigsig) YS_OVERRIDE
{
log_assert(module == mod);
if (auto_reload_module)
return;
for (int i = 0; i < GetSize(sigsig.first); i++)
{
RTLIL::SigBit lhs = sigmap(sigsig.first[i]);
RTLIL::SigBit rhs = sigmap(sigsig.second[i]);
bool has_lhs = database.count(lhs);
bool has_rhs = database.count(rhs);
if (!has_lhs && !has_rhs) {
sigmap.add(lhs, rhs);
} else
if (!has_rhs) {
SigBitInfo new_info = database.at(lhs);
database.erase(lhs);
sigmap.add(lhs, rhs);
lhs = sigmap(lhs);
if (lhs.wire)
database[lhs] = new_info;
} else
if (!has_lhs) {
SigBitInfo new_info = database.at(rhs);
database.erase(rhs);
sigmap.add(lhs, rhs);
rhs = sigmap(rhs);
if (rhs.wire)
database[rhs] = new_info;
} else {
SigBitInfo new_info = database.at(lhs);
new_info.merge(database.at(rhs));
database.erase(lhs);
database.erase(rhs);
sigmap.add(lhs, rhs);
rhs = sigmap(rhs);
if (rhs.wire)
database[rhs] = new_info;
}
}
}
virtual void notify_connect(RTLIL::Module *mod YS_ATTRIBUTE(unused), const std::vector<RTLIL::SigSig>&) YS_OVERRIDE
{
log_assert(module == mod);
auto_reload_module = true;
}
virtual void notify_connect(RTLIL::Module *mod, const std::vector<RTLIL::SigSig>&)
{
log_assert(module == mod);
auto_reload_module = true;
}
virtual void notify_blackout(RTLIL::Module *mod)
virtual void notify_blackout(RTLIL::Module *mod YS_ATTRIBUTE(unused)) YS_OVERRIDE
{
log_assert(module == mod);
auto_reload_module = true;
@ -131,6 +228,7 @@ struct ModIndex : public RTLIL::Monitor
ModIndex(RTLIL::Module *_m) : module(_m)
{
auto_reload_counter = 0;
auto_reload_module = true;
module->monitors.insert(this);
}
@ -168,9 +266,9 @@ struct ModIndex : public RTLIL::Monitor
return info->is_output;
}
std::set<PortInfo> &query_ports(RTLIL::SigBit bit)
pool<PortInfo> &query_ports(RTLIL::SigBit bit)
{
static std::set<PortInfo> empty_result_set;
static pool<PortInfo> empty_result_set;
SigBitInfo *info = query(bit);
if (info == nullptr)
return empty_result_set;
@ -193,6 +291,14 @@ struct ModWalker
return port < other.port;
return offset < other.offset;
}
bool operator==(const PortBit &other) const {
return cell == other.cell && port == other.port && offset == other.offset;
}
unsigned int hash() const {
return mkhash_add(mkhash(cell->name.hash(), port.hash()), offset);
}
};
RTLIL::Design *design;
@ -201,11 +307,11 @@ struct ModWalker
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;
dict<RTLIL::SigBit, pool<PortBit>> signal_drivers;
dict<RTLIL::SigBit, pool<PortBit>> signal_consumers;
pool<RTLIL::SigBit> signal_inputs, signal_outputs;
std::map<RTLIL::Cell*, std::set<RTLIL::SigBit>> cell_outputs, cell_inputs;
dict<RTLIL::Cell*, pool<RTLIL::SigBit>> cell_outputs, cell_inputs;
void add_wire(RTLIL::Wire *wire)
{
@ -286,11 +392,11 @@ struct ModWalker
// get_* methods -- single RTLIL::SigBit
template<typename T>
inline bool get_drivers(std::set<PortBit> &result, RTLIL::SigBit bit) const
inline bool get_drivers(pool<PortBit> &result, RTLIL::SigBit bit) const
{
bool found = false;
if (signal_drivers.count(bit)) {
const std::set<PortBit> &r = signal_drivers.at(bit);
const pool<PortBit> &r = signal_drivers.at(bit);
result.insert(r.begin(), r.end());
found = true;
}
@ -298,11 +404,11 @@ struct ModWalker
}
template<typename T>
inline bool get_consumers(std::set<PortBit> &result, RTLIL::SigBit bit) const
inline bool get_consumers(pool<PortBit> &result, RTLIL::SigBit bit) const
{
bool found = false;
if (signal_consumers.count(bit)) {
const std::set<PortBit> &r = signal_consumers.at(bit);
const pool<PortBit> &r = signal_consumers.at(bit);
result.insert(r.begin(), r.end());
found = true;
}
@ -310,7 +416,7 @@ struct ModWalker
}
template<typename T>
inline bool get_inputs(std::set<RTLIL::SigBit> &result, RTLIL::SigBit bit) const
inline bool get_inputs(pool<RTLIL::SigBit> &result, RTLIL::SigBit bit) const
{
bool found = false;
if (signal_inputs.count(bit))
@ -319,7 +425,7 @@ struct ModWalker
}
template<typename T>
inline bool get_outputs(std::set<RTLIL::SigBit> &result, RTLIL::SigBit bit) const
inline bool get_outputs(pool<RTLIL::SigBit> &result, RTLIL::SigBit bit) const
{
bool found = false;
if (signal_outputs.count(bit))
@ -330,12 +436,12 @@ struct ModWalker
// 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
inline bool get_drivers(pool<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);
const pool<PortBit> &r = signal_drivers.at(bit);
result.insert(r.begin(), r.end());
found = true;
}
@ -343,12 +449,12 @@ struct ModWalker
}
template<typename T>
inline bool get_consumers(std::set<PortBit> &result, const T &bits) const
inline bool get_consumers(pool<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);
const pool<PortBit> &r = signal_consumers.at(bit);
result.insert(r.begin(), r.end());
found = true;
}
@ -356,7 +462,7 @@ struct ModWalker
}
template<typename T>
inline bool get_inputs(std::set<RTLIL::SigBit> &result, const T &bits) const
inline bool get_inputs(pool<RTLIL::SigBit> &result, const T &bits) const
{
bool found = false;
for (RTLIL::SigBit bit : bits)
@ -366,7 +472,7 @@ struct ModWalker
}
template<typename T>
inline bool get_outputs(std::set<RTLIL::SigBit> &result, const T &bits) const
inline bool get_outputs(pool<RTLIL::SigBit> &result, const T &bits) const
{
bool found = false;
for (RTLIL::SigBit bit : bits)
@ -377,25 +483,25 @@ struct ModWalker
// get_* methods -- call by RTLIL::SigSpec (always by value)
bool get_drivers(std::set<PortBit> &result, RTLIL::SigSpec signal) const
bool get_drivers(pool<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
bool get_consumers(pool<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
bool get_inputs(pool<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
bool get_outputs(pool<RTLIL::SigBit> &result, RTLIL::SigSpec signal) const
{
std::vector<RTLIL::SigBit> bits = sigmap(signal);
return get_outputs(result, bits);
@ -405,47 +511,47 @@ struct ModWalker
template<typename T>
inline bool has_drivers(const T &sig) const {
std::set<PortBit> result;
pool<PortBit> result;
return get_drivers(result, sig);
}
template<typename T>
inline bool has_consumers(const T &sig) const {
std::set<PortBit> result;
pool<PortBit> result;
return get_consumers(result, sig);
}
template<typename T>
inline bool has_inputs(const T &sig) const {
std::set<RTLIL::SigBit> result;
pool<RTLIL::SigBit> result;
return get_inputs(result, sig);
}
template<typename T>
inline bool has_outputs(const T &sig) const {
std::set<RTLIL::SigBit> result;
pool<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;
pool<PortBit> result;
return get_drivers(result, sig);
}
inline bool has_consumers(RTLIL::SigSpec sig) const {
std::set<PortBit> result;
pool<PortBit> result;
return get_consumers(result, sig);
}
inline bool has_inputs(RTLIL::SigSpec sig) const {
std::set<RTLIL::SigBit> result;
pool<RTLIL::SigBit> result;
return get_inputs(result, sig);
}
inline bool has_outputs(RTLIL::SigSpec sig) const {
std::set<RTLIL::SigBit> result;
pool<RTLIL::SigBit> result;
return get_outputs(result, sig);
}
};

View File

@ -18,6 +18,8 @@
*/
#include "kernel/yosys.h"
#include "kernel/satgen.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
@ -146,35 +148,39 @@ void Pass::extra_args(std::vector<std::string> args, size_t argidx, RTLIL::Desig
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 == '#') {
free(sstart);
std::string cmd_buf = command;
std::string tok = next_token(cmd_buf, " \t\r\n");
if (tok.empty())
return;
}
if (*s == '!') {
for (s++; *s == ' ' || *s == '\t'; s++) { }
char *p = s + strlen(s) - 1;
while (p >= s && (*p == '\r' || *p == '\n'))
*(p--) = 0;
log_header("Shell command: %s\n", s);
int retCode = system(s);
if (tok[0] == '!') {
cmd_buf = command.substr(command.find('!') + 1);
while (!cmd_buf.empty() && (cmd_buf.back() == ' ' || cmd_buf.back() == '\t' ||
cmd_buf.back() == '\r' || cmd_buf.back() == '\n'))
cmd_buf.resize(cmd_buf.size()-1);
log_header("Shell command: %s\n", cmd_buf.c_str());
int retCode = run_command(cmd_buf);
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)) {
std::string str = p;
int strsz = str.size();
if (str == "#")
break;
if (strsz > 0 && str[strsz-1] == ';') {
while (!tok.empty()) {
if (tok == "#") {
int stop;
for (stop = 0; stop < GetSize(cmd_buf); stop++)
if (cmd_buf[stop] == '\r' || cmd_buf[stop] == '\n')
break;
cmd_buf = cmd_buf.substr(stop);
} else
if (tok.back() == ';') {
int num_semikolon = 0;
while (strsz > 0 && str[strsz-1] == ';')
strsz--, num_semikolon++;
if (strsz > 0)
args.push_back(str.substr(0, strsz));
while (!tok.empty() && tok.back() == ';')
tok.resize(tok.size()-1), num_semikolon++;
if (!tok.empty())
args.push_back(tok);
call(design, args);
args.clear();
if (num_semikolon == 2)
@ -182,9 +188,22 @@ void Pass::call(RTLIL::Design *design, std::string command)
if (num_semikolon == 3)
call(design, "clean -purge");
} else
args.push_back(str);
args.push_back(tok);
bool found_nl = false;
for (auto c : cmd_buf) {
if (c == ' ' || c == '\t')
continue;
if (c == '\r' || c == '\n')
found_nl = true;
break;
}
if (found_nl) {
call(design, args);
args.clear();
}
tok = next_token(cmd_buf, " \t\r\n");
}
free(sstart);
call(design, args);
}
@ -333,8 +352,8 @@ void Frontend::extra_args(std::istream *&f, std::string &filename, std::vector<s
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)
size_t indent = buffer.find_first_not_of(" \t\r\n");
if (indent != std::string::npos && buffer.substr(indent, eot_marker.size()) == eot_marker)
break;
last_here_document += buffer;
}
@ -528,11 +547,10 @@ struct HelpPass : public Pass {
}
void escape_tex(std::string &tex)
{
size_t pos = 0;
while ((pos = tex.find('_', pos)) != std::string::npos) {
for (size_t pos = 0; (pos = tex.find('_', pos)) != std::string::npos; pos += 2)
tex.replace(pos, 1, "\\_");
pos += 2;
}
for (size_t pos = 0; (pos = tex.find('$', pos)) != std::string::npos; pos += 2)
tex.replace(pos, 1, "\\$");
}
void write_tex(FILE *f, std::string cmd, std::string title, std::string text)
{
@ -676,5 +694,17 @@ struct EchoPass : public Pass {
}
} EchoPass;
SatSolver *yosys_satsolver_list;
SatSolver *yosys_satsolver;
struct MinisatSatSolver : public SatSolver {
MinisatSatSolver() : SatSolver("minisat") {
yosys_satsolver = this;
}
virtual ezSAT *create() YS_OVERRIDE {
return new ezMiniSAT();
}
} MinisatSatSolver;
YOSYS_NAMESPACE_END

View File

@ -71,9 +71,9 @@ struct Frontend : Pass
std::string frontend_name;
Frontend(std::string name, std::string short_help = "** document me **");
virtual void run_register();
virtual void run_register() YS_OVERRIDE;
virtual ~Frontend();
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) OVERRIDE FINAL;
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE YS_FINAL;
virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) = 0;
static std::vector<std::string> next_args;
@ -87,9 +87,9 @@ struct Backend : Pass
{
std::string backend_name;
Backend(std::string name, std::string short_help = "** document me **");
virtual void run_register();
virtual void run_register() YS_OVERRIDE;
virtual ~Backend();
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) OVERRIDE FINAL;
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE YS_FINAL;
virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) = 0;
void extra_args(std::ostream *&f, std::string &filename, std::vector<std::string> args, size_t argidx);
@ -100,6 +100,8 @@ struct Backend : Pass
// 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);
extern RTLIL::Selection eval_select_args(const vector<string> &args, RTLIL::Design *design);
extern void eval_select_op(vector<RTLIL::Selection> &work, const string &op, RTLIL::Design *design);
extern std::map<std::string, Pass*> pass_register;
extern std::map<std::string, Frontend*> frontend_register;

File diff suppressed because it is too large Load Diff

View File

@ -76,18 +76,15 @@ namespace RTLIL
{
// the global id string cache
struct char_ptr_cmp {
bool operator()(const char *a, const char *b) const {
for (int i = 0; a[i] || b[i]; i++)
if (a[i] != b[i])
return a[i] < b[i];
return false;
}
};
static struct destruct_guard_t {
bool ok; // POD, will be initialized to zero
destruct_guard_t() { ok = true; }
~destruct_guard_t() { ok = false; }
} destruct_guard;
static std::vector<int> global_refcount_storage_;
static std::vector<char*> global_id_storage_;
static std::map<char*, int, char_ptr_cmp> global_id_index_;
static dict<char*, int, hash_cstr_ops> global_id_index_;
static std::vector<int> global_free_idx_list_;
static inline int get_reference(int idx)
@ -98,6 +95,8 @@ namespace RTLIL
static inline int get_reference(const char *p)
{
log_assert(destruct_guard.ok);
if (p[0]) {
log_assert(p[1] != 0);
log_assert(p[0] == '$' || p[0] == '\\');
@ -121,16 +120,38 @@ namespace RTLIL
global_id_storage_.at(idx) = strdup(p);
global_id_index_[global_id_storage_.at(idx)] = idx;
global_refcount_storage_.at(idx)++;
// Avoid Create->Delete->Create pattern
static IdString last_created_id;
put_reference(last_created_id.index_);
last_created_id.index_ = idx;
get_reference(last_created_id.index_);
if (yosys_xtrace) {
log("#X# New IdString '%s' with index %d.\n", p, idx);
log_backtrace("-X- ", yosys_xtrace-1);
}
return idx;
}
static inline void put_reference(int idx)
{
// put_reference() may be called from destructors after the destructor of
// global_refcount_storage_ has been run. in this case we simply do nothing.
if (!destruct_guard.ok)
return;
log_assert(global_refcount_storage_.at(idx) > 0);
if (--global_refcount_storage_.at(idx) != 0)
return;
if (yosys_xtrace) {
log("#X# Removed IdString '%s' with index %d.\n", global_id_storage_.at(idx), idx);
log_backtrace("-X- ", yosys_xtrace-1);
}
global_id_index_.erase(global_id_storage_.at(idx));
free(global_id_storage_.at(idx));
global_id_storage_.at(idx) = nullptr;
@ -211,12 +232,16 @@ namespace RTLIL
*this = IdString();
}
unsigned int hash() const {
return index_;
}
// The following is a helper key_compare class. Instead of for example std::set<Cell*>
// use std::set<Cell*, IdString::compare_ptr_by_name<Cell>> if the order of cells in the
// set has an influence on the algorithm.
template<typename T> struct compare_ptr_by_name {
bool operator()(const T *a, const T *b) {
bool operator()(const T *a, const T *b) const {
return (a == nullptr || b == nullptr) ? (a < b) : (a->name < b->name);
}
};
@ -225,14 +250,14 @@ namespace RTLIL
// of cell types). the following functions helps with that.
template<typename T, typename... Args>
bool in(T first, Args... rest) {
bool in(T first, Args... rest) const {
return in(first) || in(rest...);
}
bool in(IdString rhs) { return *this == rhs; }
bool in(const char *rhs) { return *this == rhs; }
bool in(const std::string &rhs) { return *this == rhs; }
bool in(const std::set<IdString> &rhs) { return rhs.count(*this) != 0; }
bool in(IdString rhs) const { return *this == rhs; }
bool in(const char *rhs) const { return *this == rhs; }
bool in(const std::string &rhs) const { return *this == rhs; }
bool in(const pool<IdString> &rhs) const { return rhs.count(*this) != 0; }
};
static inline std::string escape_id(std::string str) {
@ -242,9 +267,15 @@ namespace RTLIL
}
static inline std::string unescape_id(std::string str) {
if (str.size() > 1 && str[0] == '\\' && str[1] != '$')
return str.substr(1);
return str;
if (str.size() < 2)
return str;
if (str[0] != '\\')
return str;
if (str[1] == '$' || str[1] == '\\')
return str;
if (str[1] >= '0' && str[1] <= '9')
return str;
return str.substr(1);
}
static inline std::string unescape_id(RTLIL::IdString str) {
@ -323,8 +354,8 @@ namespace RTLIL
template<typename T>
struct ObjIterator
{
typename std::map<RTLIL::IdString, T>::iterator it;
std::map<RTLIL::IdString, T> *list_p;
typename dict<RTLIL::IdString, T>::iterator it;
dict<RTLIL::IdString, T> *list_p;
int *refcount_p;
ObjIterator() : list_p(nullptr), refcount_p(nullptr) {
@ -388,7 +419,7 @@ namespace RTLIL
template<typename T>
struct ObjRange
{
std::map<RTLIL::IdString, T> *list_p;
dict<RTLIL::IdString, T> *list_p;
int *refcount_p;
ObjRange(decltype(list_p) list_p, int *refcount_p) : list_p(list_p), refcount_p(refcount_p) { }
@ -399,8 +430,8 @@ namespace RTLIL
return list_p->size();
}
operator std::set<T>() const {
std::set<T> result;
operator pool<T>() const {
pool<T> result;
for (auto &it : *list_p)
result.insert(it.second);
return result;
@ -414,7 +445,7 @@ namespace RTLIL
return result;
}
std::set<T> to_set() const { return *this; }
pool<T> to_pool() const { return *this; }
std::vector<T> to_vector() const { return *this; }
};
};
@ -438,17 +469,249 @@ struct RTLIL::Const
bool as_bool() const;
int as_int(bool is_signed = false) const;
std::string as_string() const;
static Const from_string(std::string str);
std::string decode_string() const;
inline int size() const { return bits.size(); }
inline unsigned int hash() const {
unsigned int h = mkhash_init;
for (auto b : bits)
mkhash(h, b);
return h;
}
};
struct RTLIL::SigChunk
{
RTLIL::Wire *wire;
std::vector<RTLIL::State> data; // only used if wire == NULL, LSB at index 0
int width, offset;
SigChunk();
SigChunk(const RTLIL::Const &value);
SigChunk(RTLIL::Wire *wire);
SigChunk(RTLIL::Wire *wire, int offset, int width = 1);
SigChunk(const std::string &str);
SigChunk(int val, int width = 32);
SigChunk(RTLIL::State bit, int width = 1);
SigChunk(RTLIL::SigBit bit);
RTLIL::SigChunk extract(int offset, int length) const;
bool operator <(const RTLIL::SigChunk &other) const;
bool operator ==(const RTLIL::SigChunk &other) const;
bool operator !=(const RTLIL::SigChunk &other) const;
};
struct RTLIL::SigBit
{
RTLIL::Wire *wire;
union {
RTLIL::State data; // used if wire == NULL
int offset; // used if wire != NULL
};
SigBit();
SigBit(RTLIL::State bit);
SigBit(bool bit);
SigBit(RTLIL::Wire *wire);
SigBit(RTLIL::Wire *wire, int offset);
SigBit(const RTLIL::SigChunk &chunk);
SigBit(const RTLIL::SigChunk &chunk, int index);
SigBit(const RTLIL::SigSpec &sig);
bool operator <(const RTLIL::SigBit &other) const;
bool operator ==(const RTLIL::SigBit &other) const;
bool operator !=(const RTLIL::SigBit &other) const;
unsigned int hash() const;
};
struct RTLIL::SigSpecIterator : public std::iterator<std::input_iterator_tag, RTLIL::SigSpec>
{
RTLIL::SigSpec *sig_p;
int index;
inline RTLIL::SigBit &operator*() const;
inline bool operator!=(const RTLIL::SigSpecIterator &other) const { return index != other.index; }
inline bool operator==(const RTLIL::SigSpecIterator &other) const { return index == other.index; }
inline void operator++() { index++; }
};
struct RTLIL::SigSpecConstIterator : public std::iterator<std::input_iterator_tag, RTLIL::SigSpec>
{
const RTLIL::SigSpec *sig_p;
int index;
inline const RTLIL::SigBit &operator*() const;
inline bool operator!=(const RTLIL::SigSpecConstIterator &other) const { return index != other.index; }
inline bool operator==(const RTLIL::SigSpecIterator &other) const { return index == other.index; }
inline void operator++() { index++; }
};
struct RTLIL::SigSpec
{
private:
int width_;
unsigned long hash_;
std::vector<RTLIL::SigChunk> chunks_; // LSB at index 0
std::vector<RTLIL::SigBit> bits_; // LSB at index 0
void pack() const;
void unpack() const;
void updhash() const;
inline bool packed() const {
return bits_.empty();
}
inline void inline_unpack() const {
if (!chunks_.empty())
unpack();
}
public:
SigSpec();
SigSpec(const RTLIL::SigSpec &other);
SigSpec(std::initializer_list<RTLIL::SigSpec> parts);
const RTLIL::SigSpec &operator=(const RTLIL::SigSpec &other);
SigSpec(const RTLIL::Const &value);
SigSpec(const RTLIL::SigChunk &chunk);
SigSpec(RTLIL::Wire *wire);
SigSpec(RTLIL::Wire *wire, int offset, int width = 1);
SigSpec(const std::string &str);
SigSpec(int val, int width = 32);
SigSpec(RTLIL::State bit, int width = 1);
SigSpec(RTLIL::SigBit bit, int width = 1);
SigSpec(std::vector<RTLIL::SigChunk> chunks);
SigSpec(std::vector<RTLIL::SigBit> bits);
SigSpec(pool<RTLIL::SigBit> bits);
SigSpec(std::set<RTLIL::SigBit> bits);
SigSpec(bool bit);
SigSpec(RTLIL::SigSpec &&other) {
width_ = other.width_;
hash_ = other.hash_;
chunks_ = std::move(other.chunks_);
bits_ = std::move(other.bits_);
}
const RTLIL::SigSpec &operator=(RTLIL::SigSpec &&other) {
width_ = other.width_;
hash_ = other.hash_;
chunks_ = std::move(other.chunks_);
bits_ = std::move(other.bits_);
return *this;
}
size_t get_hash() const {
if (!hash_) hash();
return hash_;
}
inline const std::vector<RTLIL::SigChunk> &chunks() const { pack(); return chunks_; }
inline const std::vector<RTLIL::SigBit> &bits() const { inline_unpack(); return bits_; }
inline int size() const { return width_; }
inline bool empty() const { return width_ == 0; }
inline RTLIL::SigBit &operator[](int index) { inline_unpack(); return bits_.at(index); }
inline const RTLIL::SigBit &operator[](int index) const { inline_unpack(); return bits_.at(index); }
inline RTLIL::SigSpecIterator begin() { RTLIL::SigSpecIterator it; it.sig_p = this; it.index = 0; return it; }
inline RTLIL::SigSpecIterator end() { RTLIL::SigSpecIterator it; it.sig_p = this; it.index = width_; return it; }
inline RTLIL::SigSpecConstIterator begin() const { RTLIL::SigSpecConstIterator it; it.sig_p = this; it.index = 0; return it; }
inline RTLIL::SigSpecConstIterator end() const { RTLIL::SigSpecConstIterator it; it.sig_p = this; it.index = width_; return it; }
void sort();
void sort_and_unify();
void replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with);
void replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with, RTLIL::SigSpec *other) const;
void replace(const dict<RTLIL::SigBit, RTLIL::SigBit> &rules);
void replace(const dict<RTLIL::SigBit, RTLIL::SigBit> &rules, RTLIL::SigSpec *other) const;
void replace(const std::map<RTLIL::SigBit, RTLIL::SigBit> &rules);
void replace(const std::map<RTLIL::SigBit, RTLIL::SigBit> &rules, RTLIL::SigSpec *other) const;
void replace(int offset, const RTLIL::SigSpec &with);
void remove(const RTLIL::SigSpec &pattern);
void remove(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *other) const;
void remove2(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *other);
void remove(const pool<RTLIL::SigBit> &pattern);
void remove(const pool<RTLIL::SigBit> &pattern, RTLIL::SigSpec *other) const;
void remove2(const pool<RTLIL::SigBit> &pattern, RTLIL::SigSpec *other);
void remove(int offset, int length = 1);
void remove_const();
RTLIL::SigSpec extract(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec *other = NULL) const;
RTLIL::SigSpec extract(const pool<RTLIL::SigBit> &pattern, const RTLIL::SigSpec *other = NULL) const;
RTLIL::SigSpec extract(int offset, int length = 1) const;
void append(const RTLIL::SigSpec &signal);
void append_bit(const RTLIL::SigBit &bit);
void extend_u0(int width, bool is_signed = false);
RTLIL::SigSpec repeat(int num) const;
bool operator <(const RTLIL::SigSpec &other) const;
bool operator ==(const RTLIL::SigSpec &other) const;
inline bool operator !=(const RTLIL::SigSpec &other) const { return !(*this == other); }
bool is_wire() const;
bool is_chunk() const;
bool is_fully_const() const;
bool is_fully_def() const;
bool is_fully_undef() const;
bool has_const() const;
bool has_marked_bits() const;
bool as_bool() const;
int as_int(bool is_signed = false) const;
std::string as_string() const;
RTLIL::Const as_const() const;
RTLIL::Wire *as_wire() const;
RTLIL::SigChunk as_chunk() const;
bool match(std::string pattern) const;
std::set<RTLIL::SigBit> to_sigbit_set() const;
pool<RTLIL::SigBit> to_sigbit_pool() const;
std::vector<RTLIL::SigBit> to_sigbit_vector() const;
std::map<RTLIL::SigBit, RTLIL::SigBit> to_sigbit_map(const RTLIL::SigSpec &other) const;
dict<RTLIL::SigBit, RTLIL::SigBit> to_sigbit_dict(const RTLIL::SigSpec &other) const;
RTLIL::SigBit to_single_sigbit() const;
static bool parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::string str);
static bool parse_sel(RTLIL::SigSpec &sig, RTLIL::Design *design, RTLIL::Module *module, std::string str);
static bool parse_rhs(const RTLIL::SigSpec &lhs, RTLIL::SigSpec &sig, RTLIL::Module *module, std::string str);
operator std::vector<RTLIL::SigChunk>() const { return chunks(); }
operator std::vector<RTLIL::SigBit>() const { return bits(); }
unsigned int hash() const { if (!hash_) updhash(); return hash_; };
#ifndef NDEBUG
void check() const;
#else
void check() const { }
#endif
};
struct RTLIL::Selection
{
bool full_selection;
std::set<RTLIL::IdString> selected_modules;
std::map<RTLIL::IdString, std::set<RTLIL::IdString>> selected_members;
pool<RTLIL::IdString> selected_modules;
dict<RTLIL::IdString, pool<RTLIL::IdString>> selected_members;
Selection(bool full = true) : full_selection(full) { }
@ -476,6 +739,15 @@ struct RTLIL::Selection
struct RTLIL::Monitor
{
unsigned int hashidx_;
unsigned int hash() const { return hashidx_; }
Monitor() {
static unsigned int hashidx_count = 123456789;
hashidx_count = mkhash_xorshift(hashidx_count);
hashidx_ = hashidx_count;
}
virtual ~Monitor() { }
virtual void notify_module_add(RTLIL::Module*) { }
virtual void notify_module_del(RTLIL::Module*) { }
@ -487,14 +759,17 @@ struct RTLIL::Monitor
struct RTLIL::Design
{
std::set<RTLIL::Monitor*> monitors;
std::map<std::string, std::string> scratchpad;
unsigned int hashidx_;
unsigned int hash() const { return hashidx_; }
pool<RTLIL::Monitor*> monitors;
dict<std::string, std::string> scratchpad;
int refcount_modules_;
std::map<RTLIL::IdString, RTLIL::Module*> modules_;
dict<RTLIL::IdString, RTLIL::Module*> modules_;
std::vector<RTLIL::Selection> selection_stack;
std::map<RTLIL::IdString, RTLIL::Selection> selection_vars;
dict<RTLIL::IdString, RTLIL::Selection> selection_vars;
std::string selected_active_module;
Design();
@ -521,6 +796,7 @@ struct RTLIL::Design
bool scratchpad_get_bool(std::string varname, bool default_value = false) const;
std::string scratchpad_get_string(std::string varname, std::string default_value = std::string()) const;
void sort();
void check();
void optimize();
@ -531,6 +807,14 @@ struct RTLIL::Design
bool selected_module(RTLIL::Module *mod) const;
bool selected_whole_module(RTLIL::Module *mod) const;
RTLIL::Selection &selection() {
return selection_stack.back();
}
const RTLIL::Selection &selection() const {
return selection_stack.back();
}
bool full_selection() const {
return selection_stack.back().full_selection;
}
@ -556,7 +840,7 @@ struct RTLIL::Design
};
#define RTLIL_ATTRIBUTE_MEMBERS \
std::map<RTLIL::IdString, RTLIL::Const> attributes; \
dict<RTLIL::IdString, RTLIL::Const> attributes; \
void set_bool_attribute(RTLIL::IdString id) { \
attributes[id] = RTLIL::Const(1); \
} \
@ -568,31 +852,36 @@ struct RTLIL::Design
struct RTLIL::Module
{
unsigned int hashidx_;
unsigned int hash() const { return hashidx_; }
protected:
void add(RTLIL::Wire *wire);
void add(RTLIL::Cell *cell);
public:
RTLIL::Design *design;
std::set<RTLIL::Monitor*> monitors;
pool<RTLIL::Monitor*> monitors;
int refcount_wires_;
int refcount_cells_;
std::map<RTLIL::IdString, RTLIL::Wire*> wires_;
std::map<RTLIL::IdString, RTLIL::Cell*> cells_;
dict<RTLIL::IdString, RTLIL::Wire*> wires_;
dict<RTLIL::IdString, RTLIL::Cell*> cells_;
std::vector<RTLIL::SigSig> connections_;
RTLIL::IdString name;
std::set<RTLIL::IdString> avail_parameters;
std::map<RTLIL::IdString, RTLIL::Memory*> memories;
std::map<RTLIL::IdString, RTLIL::Process*> processes;
pool<RTLIL::IdString> avail_parameters;
dict<RTLIL::IdString, RTLIL::Memory*> memories;
dict<RTLIL::IdString, RTLIL::Process*> processes;
RTLIL_ATTRIBUTE_MEMBERS
Module();
virtual ~Module();
virtual RTLIL::IdString derive(RTLIL::Design *design, std::map<RTLIL::IdString, RTLIL::Const> parameters);
virtual RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters);
virtual size_t count_id(RTLIL::IdString id);
virtual void sort();
virtual void check();
virtual void optimize();
@ -628,7 +917,7 @@ public:
RTLIL::ObjRange<RTLIL::Cell*> cells() { return RTLIL::ObjRange<RTLIL::Cell*>(&cells_, &refcount_cells_); }
// Removing wires is expensive. If you have to remove wires, remove them all at once.
void remove(const std::set<RTLIL::Wire*> &wires);
void remove(const pool<RTLIL::Wire*> &wires);
void remove(RTLIL::Cell *cell);
void rename(RTLIL::Wire *wire, RTLIL::IdString new_name);
@ -698,9 +987,11 @@ public:
RTLIL::Cell* addConcat (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y);
RTLIL::Cell* addLut (RTLIL::IdString name, RTLIL::SigSpec sig_i, RTLIL::SigSpec sig_o, RTLIL::Const lut);
RTLIL::Cell* addAssert (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_en);
RTLIL::Cell* addEquiv (RTLIL::IdString name, RTLIL::SigSpec sig_a, RTLIL::SigSpec sig_b, RTLIL::SigSpec sig_y);
RTLIL::Cell* addSr (RTLIL::IdString name, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr, RTLIL::SigSpec sig_q, bool set_polarity = true, bool clr_polarity = true);
RTLIL::Cell* addDff (RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity = true);
RTLIL::Cell* addDffe (RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity = true, bool en_polarity = true);
RTLIL::Cell* addDffsr (RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr,
RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity = true, bool set_polarity = true, bool clr_polarity = true);
RTLIL::Cell* addAdff (RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_arst, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q,
@ -723,6 +1014,7 @@ public:
RTLIL::Cell* addOai4Gate (RTLIL::IdString name, RTLIL::SigBit sig_a, RTLIL::SigBit sig_b, RTLIL::SigBit sig_c, RTLIL::SigBit sig_d, RTLIL::SigBit sig_y);
RTLIL::Cell* addDffGate (RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity = true);
RTLIL::Cell* addDffeGate (RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_en, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity = true, bool en_polarity = true);
RTLIL::Cell* addDffsrGate (RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr,
RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q, bool clk_polarity = true, bool set_polarity = true, bool clr_polarity = true);
RTLIL::Cell* addAdffGate (RTLIL::IdString name, RTLIL::SigSpec sig_clk, RTLIL::SigSpec sig_arst, RTLIL::SigSpec sig_d, RTLIL::SigSpec sig_q,
@ -795,6 +1087,9 @@ public:
struct RTLIL::Wire
{
unsigned int hashidx_;
unsigned int hash() const { return hashidx_; }
protected:
// use module->addWire() and module->remove() to create or destroy wires
friend struct RTLIL::Module;
@ -815,6 +1110,9 @@ public:
struct RTLIL::Memory
{
unsigned int hashidx_;
unsigned int hash() const { return hashidx_; }
Memory();
RTLIL::IdString name;
@ -824,6 +1122,9 @@ struct RTLIL::Memory
struct RTLIL::Cell
{
unsigned int hashidx_;
unsigned int hash() const { return hashidx_; }
protected:
// use module->addCell() and module->remove() to create or destroy cells
friend struct RTLIL::Module;
@ -837,8 +1138,8 @@ public:
RTLIL::Module *module;
RTLIL::IdString name;
RTLIL::IdString type;
std::map<RTLIL::IdString, RTLIL::SigSpec> connections_;
std::map<RTLIL::IdString, RTLIL::Const> parameters;
dict<RTLIL::IdString, RTLIL::SigSpec> connections_;
dict<RTLIL::IdString, RTLIL::Const> parameters;
RTLIL_ATTRIBUTE_MEMBERS
// access cell ports
@ -846,7 +1147,12 @@ public:
void unsetPort(RTLIL::IdString portname);
void setPort(RTLIL::IdString portname, RTLIL::SigSpec signal);
const RTLIL::SigSpec &getPort(RTLIL::IdString portname) const;
const std::map<RTLIL::IdString, RTLIL::SigSpec> &connections() const;
const dict<RTLIL::IdString, RTLIL::SigSpec> &connections() const;
// information about cell ports
bool known() const;
bool input(RTLIL::IdString portname) const;
bool output(RTLIL::IdString portname) const;
// access cell parameters
bool hasParam(RTLIL::IdString paramname) const;
@ -854,242 +1160,18 @@ public:
void setParam(RTLIL::IdString paramname, RTLIL::Const value);
const RTLIL::Const &getParam(RTLIL::IdString paramname) const;
void sort();
void check();
void fixup_parameters(bool set_a_signed = false, bool set_b_signed = false);
bool has_keep_attr() const {
return get_bool_attribute("\\keep") || (module && module->design && module->design->module(type) &&
module->design->module(type)->get_bool_attribute("\\keep"));
}
template<typename T> void rewrite_sigspecs(T functor);
};
struct RTLIL::SigChunk
{
RTLIL::Wire *wire;
std::vector<RTLIL::State> data; // only used if wire == NULL, LSB at index 0
int width, offset;
SigChunk();
SigChunk(const RTLIL::Const &value);
SigChunk(RTLIL::Wire *wire);
SigChunk(RTLIL::Wire *wire, int offset, int width = 1);
SigChunk(const std::string &str);
SigChunk(int val, int width = 32);
SigChunk(RTLIL::State bit, int width = 1);
SigChunk(RTLIL::SigBit bit);
RTLIL::SigChunk extract(int offset, int length) const;
bool operator <(const RTLIL::SigChunk &other) const;
bool operator ==(const RTLIL::SigChunk &other) const;
bool operator !=(const RTLIL::SigChunk &other) const;
};
struct RTLIL::SigBit
{
RTLIL::Wire *wire;
union {
RTLIL::State data; // used if wire == NULL
int offset; // used if wire != NULL
};
SigBit() : wire(NULL), data(RTLIL::State::S0) { }
SigBit(RTLIL::State bit) : wire(NULL), data(bit) { }
SigBit(RTLIL::Wire *wire) : wire(wire), offset(0) { log_assert(wire && wire->width == 1); }
SigBit(RTLIL::Wire *wire, int offset) : wire(wire), offset(offset) { log_assert(wire); }
SigBit(const RTLIL::SigChunk &chunk) : wire(chunk.wire) { log_assert(chunk.width == 1); if (wire) offset = chunk.offset; else data = chunk.data[0]; }
SigBit(const RTLIL::SigChunk &chunk, int index) : wire(chunk.wire) { if (wire) offset = chunk.offset + index; else data = chunk.data[index]; }
SigBit(const RTLIL::SigSpec &sig);
bool operator <(const RTLIL::SigBit &other) const {
if (wire == other.wire)
return wire ? (offset < other.offset) : (data < other.data);
if (wire != nullptr && other.wire != nullptr)
return wire->name < other.wire->name;
return wire < other.wire;
}
bool operator ==(const RTLIL::SigBit &other) const {
return (wire == other.wire) && (wire ? (offset == other.offset) : (data == other.data));
}
bool operator !=(const RTLIL::SigBit &other) const {
return (wire != other.wire) || (wire ? (offset != other.offset) : (data != other.data));
}
};
struct RTLIL::SigSpecIterator
{
RTLIL::SigSpec *sig_p;
int index;
inline RTLIL::SigBit &operator*() const;
inline bool operator!=(const RTLIL::SigSpecIterator &other) const { return index != other.index; }
inline void operator++() { index++; }
};
struct RTLIL::SigSpecConstIterator
{
const RTLIL::SigSpec *sig_p;
int index;
inline const RTLIL::SigBit &operator*() const;
inline bool operator!=(const RTLIL::SigSpecConstIterator &other) const { return index != other.index; }
inline void operator++() { index++; }
};
struct RTLIL::SigSpec
{
private:
int width_;
unsigned long hash_;
std::vector<RTLIL::SigChunk> chunks_; // LSB at index 0
std::vector<RTLIL::SigBit> bits_; // LSB at index 0
void pack() const;
void unpack() const;
void hash() const;
inline bool packed() const {
return bits_.empty();
}
inline void inline_unpack() const {
if (!chunks_.empty())
unpack();
}
public:
SigSpec();
SigSpec(const RTLIL::SigSpec &other);
SigSpec(std::initializer_list<RTLIL::SigSpec> parts);
const RTLIL::SigSpec &operator=(const RTLIL::SigSpec &other);
SigSpec(const RTLIL::Const &value);
SigSpec(const RTLIL::SigChunk &chunk);
SigSpec(RTLIL::Wire *wire);
SigSpec(RTLIL::Wire *wire, int offset, int width = 1);
SigSpec(const std::string &str);
SigSpec(int val, int width = 32);
SigSpec(RTLIL::State bit, int width = 1);
SigSpec(RTLIL::SigBit bit, int width = 1);
SigSpec(std::vector<RTLIL::SigChunk> chunks);
SigSpec(std::vector<RTLIL::SigBit> bits);
SigSpec(std::set<RTLIL::SigBit> bits);
SigSpec(RTLIL::SigSpec &&other) {
width_ = other.width_;
hash_ = other.hash_;
chunks_ = std::move(other.chunks_);
bits_ = std::move(other.bits_);
}
const RTLIL::SigSpec &operator=(RTLIL::SigSpec &&other) {
width_ = other.width_;
hash_ = other.hash_;
chunks_ = std::move(other.chunks_);
bits_ = std::move(other.bits_);
return *this;
}
inline const std::vector<RTLIL::SigChunk> &chunks() const { pack(); return chunks_; }
inline const std::vector<RTLIL::SigBit> &bits() const { inline_unpack(); return bits_; }
inline int size() const { return width_; }
inline RTLIL::SigBit &operator[](int index) { inline_unpack(); return bits_.at(index); }
inline const RTLIL::SigBit &operator[](int index) const { inline_unpack(); return bits_.at(index); }
inline RTLIL::SigSpecIterator begin() { RTLIL::SigSpecIterator it; it.sig_p = this; it.index = 0; return it; }
inline RTLIL::SigSpecIterator end() { RTLIL::SigSpecIterator it; it.sig_p = this; it.index = width_; return it; }
inline RTLIL::SigSpecConstIterator begin() const { RTLIL::SigSpecConstIterator it; it.sig_p = this; it.index = 0; return it; }
inline RTLIL::SigSpecConstIterator end() const { RTLIL::SigSpecConstIterator it; it.sig_p = this; it.index = width_; return it; }
void sort();
void sort_and_unify();
void replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with);
void replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with, RTLIL::SigSpec *other) const;
void replace(const std::map<RTLIL::SigBit, RTLIL::SigBit> &rules);
void replace(const std::map<RTLIL::SigBit, RTLIL::SigBit> &rules, RTLIL::SigSpec *other) const;
void replace(int offset, const RTLIL::SigSpec &with);
void remove(const RTLIL::SigSpec &pattern);
void remove(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *other) const;
void remove2(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *other);
void remove(const std::set<RTLIL::SigBit> &pattern);
void remove(const std::set<RTLIL::SigBit> &pattern, RTLIL::SigSpec *other) const;
void remove2(const std::set<RTLIL::SigBit> &pattern, RTLIL::SigSpec *other);
void remove(int offset, int length = 1);
void remove_const();
RTLIL::SigSpec extract(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec *other = NULL) const;
RTLIL::SigSpec extract(const std::set<RTLIL::SigBit> &pattern, const RTLIL::SigSpec *other = NULL) const;
RTLIL::SigSpec extract(int offset, int length = 1) const;
void append(const RTLIL::SigSpec &signal);
void append_bit(const RTLIL::SigBit &bit);
void extend(int width, bool is_signed = false);
void extend_u0(int width, bool is_signed = false);
RTLIL::SigSpec repeat(int num) const;
bool operator <(const RTLIL::SigSpec &other) const;
bool operator ==(const RTLIL::SigSpec &other) const;
inline bool operator !=(const RTLIL::SigSpec &other) const { return !(*this == other); }
bool is_wire() const;
bool is_chunk() const;
bool is_fully_const() const;
bool is_fully_def() const;
bool is_fully_undef() const;
bool has_marked_bits() const;
bool as_bool() const;
int as_int(bool is_signed = false) const;
std::string as_string() const;
RTLIL::Const as_const() const;
RTLIL::Wire *as_wire() const;
RTLIL::SigChunk as_chunk() const;
bool match(std::string pattern) const;
std::set<RTLIL::SigBit> to_sigbit_set() const;
std::vector<RTLIL::SigBit> to_sigbit_vector() const;
std::map<RTLIL::SigBit, RTLIL::SigBit> to_sigbit_map(const RTLIL::SigSpec &other) const;
RTLIL::SigBit to_single_sigbit() const;
static bool parse(RTLIL::SigSpec &sig, RTLIL::Module *module, std::string str);
static bool parse_sel(RTLIL::SigSpec &sig, RTLIL::Design *design, RTLIL::Module *module, std::string str);
static bool parse_rhs(const RTLIL::SigSpec &lhs, RTLIL::SigSpec &sig, RTLIL::Module *module, std::string str);
operator std::vector<RTLIL::SigChunk>() const { return chunks(); }
operator std::vector<RTLIL::SigBit>() const { return bits(); }
#ifndef NDEBUG
void check() const;
#else
inline void check() const { }
#endif
};
inline RTLIL::SigBit &RTLIL::SigSpecIterator::operator*() const {
return (*sig_p)[index];
}
inline const RTLIL::SigBit &RTLIL::SigSpecConstIterator::operator*() const {
return (*sig_p)[index];
}
inline RTLIL::SigBit::SigBit(const RTLIL::SigSpec &sig) {
log_assert(sig.size() == 1 && sig.chunks().size() == 1);
*this = SigBit(sig.chunks().front());
}
struct RTLIL::CaseRule
{
std::vector<RTLIL::SigSpec> compare;
@ -1138,6 +1220,50 @@ struct RTLIL::Process
RTLIL::Process *clone() const;
};
inline RTLIL::SigBit::SigBit() : wire(NULL), data(RTLIL::State::S0) { }
inline RTLIL::SigBit::SigBit(RTLIL::State bit) : wire(NULL), data(bit) { }
inline RTLIL::SigBit::SigBit(bool bit) : wire(NULL), data(bit ? RTLIL::S1 : RTLIL::S0) { }
inline RTLIL::SigBit::SigBit(RTLIL::Wire *wire) : wire(wire), offset(0) { log_assert(wire && wire->width == 1); }
inline RTLIL::SigBit::SigBit(RTLIL::Wire *wire, int offset) : wire(wire), offset(offset) { log_assert(wire != nullptr); }
inline RTLIL::SigBit::SigBit(const RTLIL::SigChunk &chunk) : wire(chunk.wire) { log_assert(chunk.width == 1); if (wire) offset = chunk.offset; else data = chunk.data[0]; }
inline RTLIL::SigBit::SigBit(const RTLIL::SigChunk &chunk, int index) : wire(chunk.wire) { if (wire) offset = chunk.offset + index; else data = chunk.data[index]; }
inline bool RTLIL::SigBit::operator<(const RTLIL::SigBit &other) const {
if (wire == other.wire)
return wire ? (offset < other.offset) : (data < other.data);
if (wire != nullptr && other.wire != nullptr)
return wire->name < other.wire->name;
return wire < other.wire;
}
inline bool RTLIL::SigBit::operator==(const RTLIL::SigBit &other) const {
return (wire == other.wire) && (wire ? (offset == other.offset) : (data == other.data));
}
inline bool RTLIL::SigBit::operator!=(const RTLIL::SigBit &other) const {
return (wire != other.wire) || (wire ? (offset != other.offset) : (data != other.data));
}
inline unsigned int RTLIL::SigBit::hash() const {
if (wire)
return mkhash_add(wire->name.hash(), offset);
return data;
}
inline RTLIL::SigBit &RTLIL::SigSpecIterator::operator*() const {
return (*sig_p)[index];
}
inline const RTLIL::SigBit &RTLIL::SigSpecConstIterator::operator*() const {
return (*sig_p)[index];
}
inline RTLIL::SigBit::SigBit(const RTLIL::SigSpec &sig) {
log_assert(sig.size() == 1 && sig.chunks().size() == 1);
*this = SigBit(sig.chunks().front());
}
template<typename T>
void RTLIL::Module::rewrite_sigspecs(T functor)
{

View File

@ -26,7 +26,40 @@
#include "kernel/macc.h"
#include "libs/ezsat/ezminisat.h"
typedef ezMiniSAT ezDefaultSAT;
YOSYS_NAMESPACE_BEGIN
// defined in kernel/register.cc
extern struct SatSolver *yosys_satsolver_list;
extern struct SatSolver *yosys_satsolver;
struct SatSolver
{
string name;
SatSolver *next;
virtual ezSAT *create() = 0;
SatSolver(string name) : name(name) {
next = yosys_satsolver_list;
yosys_satsolver_list = this;
}
virtual ~SatSolver() {
auto p = &yosys_satsolver_list;
while (*p) {
if (*p == this)
*p = next;
else
p = &(*p)->next;
}
if (yosys_satsolver == this)
yosys_satsolver = yosys_satsolver_list;
}
};
struct ezSatPtr : public std::unique_ptr<ezSAT> {
ezSatPtr() : unique_ptr<ezSAT>(yosys_satsolver->create()) { }
};
struct SatGen
{
@ -35,6 +68,8 @@ struct SatGen
std::string prefix;
SigPool initial_state;
std::map<std::string, RTLIL::SigSpec> asserts_a, asserts_en;
std::map<std::string, RTLIL::SigSpec> assumes_a, assumes_en;
std::map<std::string, std::map<RTLIL::SigBit, int>> imported_signals;
bool ignore_div_by_zero;
bool model_undef;
@ -49,23 +84,24 @@ struct SatGen
this->prefix = prefix;
}
std::vector<int> importSigSpecWorker(RTLIL::SigSpec &sig, std::string &pf, bool undef_mode, bool dup_undef)
std::vector<int> importSigSpecWorker(RTLIL::SigSpec sig, std::string &pf, bool undef_mode, bool dup_undef)
{
log_assert(!undef_mode || model_undef);
sigmap->apply(sig);
std::vector<int> vec;
vec.reserve(SIZE(sig));
vec.reserve(GetSize(sig));
for (auto &bit : sig)
if (bit.wire == NULL) {
if (model_undef && dup_undef && bit == RTLIL::State::Sx)
vec.push_back(ez->frozen_literal());
else
vec.push_back(bit == (undef_mode ? RTLIL::State::Sx : RTLIL::State::S1) ? ez->TRUE : ez->FALSE);
vec.push_back(bit == (undef_mode ? RTLIL::State::Sx : RTLIL::State::S1) ? ez->CONST_TRUE : ez->CONST_FALSE);
} else {
std::string name = pf + stringf(bit.wire->width == 1 ? "%s" : "%s [%d]", RTLIL::id2cstr(bit.wire->name), bit.offset);
std::string name = pf + (bit.wire->width == 1 ? stringf("%s", log_id(bit.wire)) : stringf("%s [%d]", log_id(bit.wire->name), bit.offset));
vec.push_back(ez->frozen_literal(name));
imported_signals[pf][bit] = vec.back();
}
return vec;
}
@ -91,6 +127,34 @@ struct SatGen
return importSigSpecWorker(sig, pf, true, false);
}
int importSigBit(RTLIL::SigBit bit, int timestep = -1)
{
log_assert(timestep != 0);
std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep));
return importSigSpecWorker(bit, pf, false, false).front();
}
int importDefSigBit(RTLIL::SigBit bit, int timestep = -1)
{
log_assert(timestep != 0);
std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep));
return importSigSpecWorker(bit, pf, false, true).front();
}
int importUndefSigBit(RTLIL::SigBit bit, int timestep = -1)
{
log_assert(timestep != 0);
std::string pf = "undef:" + prefix + (timestep == -1 ? "" : stringf("@%d:", timestep));
return importSigSpecWorker(bit, pf, true, false).front();
}
bool importedSigBit(RTLIL::SigBit bit, int timestep = -1)
{
log_assert(timestep != 0);
std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep));
return imported_signals[pf].count(bit) != 0;
}
void getAsserts(RTLIL::SigSpec &sig_a, RTLIL::SigSpec &sig_en, int timestep = -1)
{
std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep));
@ -98,6 +162,13 @@ struct SatGen
sig_en = asserts_en[pf];
}
void getAssumes(RTLIL::SigSpec &sig_a, RTLIL::SigSpec &sig_en, int timestep = -1)
{
std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep));
sig_a = assumes_a[pf];
sig_en = assumes_en[pf];
}
int importAsserts(int timestep = -1)
{
std::vector<int> check_bits, enable_bits;
@ -112,6 +183,20 @@ struct SatGen
return ez->vec_reduce_and(ez->vec_or(check_bits, ez->vec_not(enable_bits)));
}
int importAssumes(int timestep = -1)
{
std::vector<int> check_bits, enable_bits;
std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep));
if (model_undef) {
check_bits = ez->vec_and(ez->vec_not(importUndefSigSpec(assumes_a[pf], timestep)), importDefSigSpec(assumes_a[pf], timestep));
enable_bits = ez->vec_and(ez->vec_not(importUndefSigSpec(assumes_en[pf], timestep)), importDefSigSpec(assumes_en[pf], timestep));
} else {
check_bits = importDefSigSpec(assumes_a[pf], timestep);
enable_bits = importDefSigSpec(assumes_en[pf], timestep);
}
return ez->vec_reduce_and(ez->vec_or(check_bits, ez->vec_not(enable_bits)));
}
int signals_eq(RTLIL::SigSpec lhs, RTLIL::SigSpec rhs, int timestep_lhs = -1, int timestep_rhs = -1)
{
if (timestep_rhs < 0)
@ -141,9 +226,9 @@ struct SatGen
if (!forced_signed && cell->parameters.count("\\A_SIGNED") > 0 && cell->parameters.count("\\B_SIGNED") > 0)
is_signed = cell->parameters["\\A_SIGNED"].as_bool() && cell->parameters["\\B_SIGNED"].as_bool();
while (vec_a.size() < vec_b.size() || vec_a.size() < y_width)
vec_a.push_back(is_signed && vec_a.size() > 0 ? vec_a.back() : ez->FALSE);
vec_a.push_back(is_signed && vec_a.size() > 0 ? vec_a.back() : ez->CONST_FALSE);
while (vec_b.size() < vec_a.size() || vec_b.size() < y_width)
vec_b.push_back(is_signed && vec_b.size() > 0 ? vec_b.back() : ez->FALSE);
vec_b.push_back(is_signed && vec_b.size() > 0 ? vec_b.back() : ez->CONST_FALSE);
}
void extendSignalWidth(std::vector<int> &vec_a, std::vector<int> &vec_b, std::vector<int> &vec_y, RTLIL::Cell *cell, bool forced_signed = false)
@ -157,7 +242,7 @@ struct SatGen
{
bool is_signed = forced_signed || (cell->parameters.count("\\A_SIGNED") > 0 && cell->parameters["\\A_SIGNED"].as_bool());
while (vec_a.size() < vec_y.size())
vec_a.push_back(is_signed && vec_a.size() > 0 ? vec_a.back() : ez->FALSE);
vec_a.push_back(is_signed && vec_a.size() > 0 ? vec_a.back() : ez->CONST_FALSE);
while (vec_y.size() < vec_a.size())
vec_y.push_back(ez->literal());
}
@ -207,7 +292,7 @@ struct SatGen
if (is_arith_compare) {
for (size_t i = 1; i < undef_y.size(); i++)
ez->SET(ez->FALSE, undef_y.at(i));
ez->SET(ez->CONST_FALSE, undef_y.at(i));
ez->SET(undef_y_bit, undef_y.at(0));
} else {
std::vector<int> undef_y_bits(undef_y.size(), undef_y_bit);
@ -288,7 +373,7 @@ struct SatGen
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 d = three_mode ? (aoi_mode ? ez->CONST_TRUE : ez->CONST_FALSE) : importDefSigSpec(cell->getPort("\\D"), timestep).at(0);
int y = importDefSigSpec(cell->getPort("\\Y"), timestep).at(0);
int yy = model_undef ? ez->literal() : y;
@ -302,7 +387,7 @@ struct SatGen
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_d = three_mode ? ez->CONST_FALSE : importUndefSigSpec(cell->getPort("\\D"), timestep).at(0);
int undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep).at(0);
if (aoi_mode)
@ -414,14 +499,14 @@ struct SatGen
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;
int maybe_one_hot = ez->CONST_FALSE;
int maybe_many_hot = ez->CONST_FALSE;
int sure_one_hot = ez->FALSE;
int sure_many_hot = ez->FALSE;
int sure_one_hot = ez->CONST_FALSE;
int sure_many_hot = ez->CONST_FALSE;
std::vector<int> bits_set = std::vector<int>(undef_y.size(), ez->FALSE);
std::vector<int> bits_clr = std::vector<int>(undef_y.size(), ez->FALSE);
std::vector<int> bits_set = std::vector<int>(undef_y.size(), ez->CONST_FALSE);
std::vector<int> bits_clr = std::vector<int>(undef_y.size(), ez->CONST_FALSE);
for (size_t i = 0; i < s.size(); i++)
{
@ -463,7 +548,7 @@ struct SatGen
if (cell->type == "$pos") {
ez->assume(ez->vec_eq(a, yy));
} else {
std::vector<int> zero(a.size(), ez->FALSE);
std::vector<int> zero(a.size(), ez->CONST_FALSE);
ez->assume(ez->vec_eq(ez->vec_sub(zero, a), yy));
}
@ -505,7 +590,7 @@ struct SatGen
if (cell->type == "$logic_not")
ez->SET(ez->NOT(ez->expression(ez->OpOr, a)), yy.at(0));
for (size_t i = 1; i < y.size(); i++)
ez->SET(ez->FALSE, yy.at(i));
ez->SET(ez->CONST_FALSE, yy.at(i));
if (model_undef)
{
@ -527,7 +612,7 @@ struct SatGen
log_abort();
for (size_t i = 1; i < undef_y.size(); i++)
ez->SET(ez->FALSE, undef_y.at(i));
ez->SET(ez->CONST_FALSE, undef_y.at(i));
undefGating(y, yy, undef_y);
}
@ -550,7 +635,7 @@ struct SatGen
else
ez->SET(ez->expression(ez->OpOr, a, b), yy.at(0));
for (size_t i = 1; i < y.size(); i++)
ez->SET(ez->FALSE, yy.at(i));
ez->SET(ez->CONST_FALSE, yy.at(i));
if (model_undef)
{
@ -573,7 +658,7 @@ struct SatGen
log_abort();
for (size_t i = 1; i < undef_y.size(); i++)
ez->SET(ez->FALSE, undef_y.at(i));
ez->SET(ez->CONST_FALSE, undef_y.at(i));
undefGating(y, yy, undef_y);
}
@ -611,7 +696,7 @@ struct SatGen
if (cell->type == "$gt")
ez->SET(is_signed ? ez->vec_gt_signed(a, b) : ez->vec_gt_unsigned(a, b), yy.at(0));
for (size_t i = 1; i < y.size(); i++)
ez->SET(ez->FALSE, yy.at(i));
ez->SET(ez->CONST_FALSE, yy.at(i));
if (model_undef && (cell->type == "$eqx" || cell->type == "$nex"))
{
@ -626,7 +711,7 @@ struct SatGen
yy.at(0) = ez->OR(yy.at(0), ez->vec_ne(undef_a, undef_b));
for (size_t i = 0; i < y.size(); i++)
ez->SET(ez->FALSE, undef_y.at(i));
ez->SET(ez->CONST_FALSE, undef_y.at(i));
ez->assume(ez->vec_eq(y, yy));
}
@ -648,7 +733,7 @@ struct SatGen
int undef_y_bit = ez->AND(undef_any, ez->NOT(masked_ne));
for (size_t i = 1; i < undef_y.size(); i++)
ez->SET(ez->FALSE, undef_y.at(i));
ez->SET(ez->CONST_FALSE, undef_y.at(i));
ez->SET(undef_y_bit, undef_y.at(0));
undefGating(y, yy, undef_y);
@ -670,7 +755,7 @@ struct SatGen
std::vector<int> b = importDefSigSpec(cell->getPort("\\B"), timestep);
std::vector<int> y = importDefSigSpec(cell->getPort("\\Y"), timestep);
int extend_bit = ez->FALSE;
int extend_bit = ez->CONST_FALSE;
if (!cell->type.in("$shift", "$shiftx") && cell->parameters["\\A_SIGNED"].as_bool())
extend_bit = a.back();
@ -684,16 +769,16 @@ struct SatGen
std::vector<int> shifted_a;
if (cell->type == "$shl" || cell->type == "$sshl")
shifted_a = ez->vec_shift_left(a, b, false, ez->FALSE, ez->FALSE);
shifted_a = ez->vec_shift_left(a, b, false, ez->CONST_FALSE, ez->CONST_FALSE);
if (cell->type == "$shr")
shifted_a = ez->vec_shift_right(a, b, false, ez->FALSE, ez->FALSE);
shifted_a = ez->vec_shift_right(a, b, false, ez->CONST_FALSE, ez->CONST_FALSE);
if (cell->type == "$sshr")
shifted_a = ez->vec_shift_right(a, b, false, cell->parameters["\\A_SIGNED"].as_bool() ? a.back() : ez->FALSE, ez->FALSE);
shifted_a = ez->vec_shift_right(a, b, false, cell->parameters["\\A_SIGNED"].as_bool() ? a.back() : ez->CONST_FALSE, ez->CONST_FALSE);
if (cell->type == "$shift" || cell->type == "$shiftx")
shifted_a = ez->vec_shift_right(a, b, cell->parameters["\\B_SIGNED"].as_bool(), ez->FALSE, ez->FALSE);
shifted_a = ez->vec_shift_right(a, b, cell->parameters["\\B_SIGNED"].as_bool(), ez->CONST_FALSE, ez->CONST_FALSE);
ez->assume(ez->vec_eq(shifted_a, yy));
@ -704,7 +789,7 @@ struct SatGen
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;
extend_bit = cell->type == "$shiftx" ? ez->CONST_TRUE : ez->CONST_FALSE;
if (!cell->type.in("$shift", "$shiftx") && cell->parameters["\\A_SIGNED"].as_bool())
extend_bit = undef_a.back();
@ -714,19 +799,19 @@ struct SatGen
undef_a.push_back(extend_bit);
if (cell->type == "$shl" || cell->type == "$sshl")
undef_a_shifted = ez->vec_shift_left(undef_a, b, false, ez->FALSE, ez->FALSE);
undef_a_shifted = ez->vec_shift_left(undef_a, b, false, ez->CONST_FALSE, ez->CONST_FALSE);
if (cell->type == "$shr")
undef_a_shifted = ez->vec_shift_right(undef_a, b, false, ez->FALSE, ez->FALSE);
undef_a_shifted = ez->vec_shift_right(undef_a, b, false, ez->CONST_FALSE, ez->CONST_FALSE);
if (cell->type == "$sshr")
undef_a_shifted = ez->vec_shift_right(undef_a, b, false, cell->parameters["\\A_SIGNED"].as_bool() ? undef_a.back() : ez->FALSE, ez->FALSE);
undef_a_shifted = ez->vec_shift_right(undef_a, b, false, cell->parameters["\\A_SIGNED"].as_bool() ? undef_a.back() : ez->CONST_FALSE, ez->CONST_FALSE);
if (cell->type == "$shift")
undef_a_shifted = ez->vec_shift_right(undef_a, b, cell->parameters["\\B_SIGNED"].as_bool(), ez->FALSE, ez->FALSE);
undef_a_shifted = ez->vec_shift_right(undef_a, b, cell->parameters["\\B_SIGNED"].as_bool(), ez->CONST_FALSE, ez->CONST_FALSE);
if (cell->type == "$shiftx")
undef_a_shifted = ez->vec_shift_right(undef_a, b, cell->parameters["\\B_SIGNED"].as_bool(), ez->TRUE, ez->TRUE);
undef_a_shifted = ez->vec_shift_right(undef_a, b, cell->parameters["\\B_SIGNED"].as_bool(), ez->CONST_TRUE, ez->CONST_TRUE);
int undef_any_b = ez->expression(ezSAT::OpOr, undef_b);
std::vector<int> undef_all_y_bits(undef_y.size(), undef_any_b);
@ -745,10 +830,10 @@ struct SatGen
std::vector<int> yy = model_undef ? ez->vec_var(y.size()) : y;
std::vector<int> tmp(a.size(), ez->FALSE);
std::vector<int> tmp(a.size(), ez->CONST_FALSE);
for (int i = 0; i < int(a.size()); i++)
{
std::vector<int> shifted_a(a.size(), ez->FALSE);
std::vector<int> shifted_a(a.size(), ez->CONST_FALSE);
for (int j = i; j < int(a.size()); j++)
shifted_a.at(j) = a.at(j-i);
tmp = ez->vec_ite(b.at(i), ez->vec_add(tmp, shifted_a), tmp);
@ -772,25 +857,25 @@ struct SatGen
Macc macc;
macc.from_cell(cell);
std::vector<int> tmp(SIZE(y), ez->FALSE);
std::vector<int> tmp(GetSize(y), ez->CONST_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));
while (GetSize(in_a) < GetSize(y))
in_a.push_back(port.is_signed && !in_a.empty() ? in_a.back() : ez->CONST_FALSE);
in_a.resize(GetSize(y));
if (SIZE(in_b))
if (GetSize(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));
while (GetSize(in_b) < GetSize(y))
in_b.push_back(port.is_signed && !in_b.empty() ? in_b.back() : ez->CONST_FALSE);
in_b.resize(GetSize(y));
for (int i = 0; i < SIZE(in_b); i++) {
std::vector<int> shifted_a(in_a.size(), ez->FALSE);
for (int i = 0; i < GetSize(in_b); i++) {
std::vector<int> shifted_a(in_a.size(), ez->CONST_FALSE);
for (int j = i; j < int(in_a.size()); j++)
shifted_a.at(j) = in_a.at(j-i);
if (port.do_subtract)
@ -808,8 +893,8 @@ struct SatGen
}
}
for (int i = 0; i < SIZE(b); i++) {
std::vector<int> val(SIZE(y), ez->FALSE);
for (int i = 0; i < GetSize(b); i++) {
std::vector<int> val(GetSize(y), ez->CONST_FALSE);
val.at(0) = b.at(i);
tmp = ez->vec_add(tmp, val);
}
@ -823,7 +908,7 @@ struct SatGen
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))));
ez->assume(ez->vec_eq(undef_y, std::vector<int>(GetSize(y), ez->OR(undef_any_a, undef_any_b))));
undefGating(y, tmp, undef_y);
}
@ -852,14 +937,14 @@ struct SatGen
}
std::vector<int> chain_buf = a_u;
std::vector<int> y_u(a_u.size(), ez->FALSE);
std::vector<int> y_u(a_u.size(), ez->CONST_FALSE);
for (int i = int(a.size())-1; i >= 0; i--)
{
chain_buf.insert(chain_buf.end(), chain_buf.size(), ez->FALSE);
chain_buf.insert(chain_buf.end(), chain_buf.size(), ez->CONST_FALSE);
std::vector<int> b_shl(i, ez->FALSE);
std::vector<int> b_shl(i, ez->CONST_FALSE);
b_shl.insert(b_shl.end(), b_u.begin(), b_u.end());
b_shl.insert(b_shl.end(), chain_buf.size()-b_shl.size(), ez->FALSE);
b_shl.insert(b_shl.end(), chain_buf.size()-b_shl.size(), ez->CONST_FALSE);
y_u.at(i) = ez->vec_ge_unsigned(chain_buf, b_shl);
chain_buf = ez->vec_ite(y_u.at(i), ez->vec_sub(chain_buf, b_shl), chain_buf);
@ -886,13 +971,13 @@ struct SatGen
std::vector<int> div_zero_result;
if (cell->type == "$div") {
if (cell->parameters["\\A_SIGNED"].as_bool() && cell->parameters["\\B_SIGNED"].as_bool()) {
std::vector<int> all_ones(y.size(), ez->TRUE);
std::vector<int> only_first_one(y.size(), ez->FALSE);
only_first_one.at(0) = ez->TRUE;
std::vector<int> all_ones(y.size(), ez->CONST_TRUE);
std::vector<int> only_first_one(y.size(), ez->CONST_FALSE);
only_first_one.at(0) = ez->CONST_TRUE;
div_zero_result = ez->vec_ite(a.back(), only_first_one, all_ones);
} else {
div_zero_result.insert(div_zero_result.end(), cell->getPort("\\A").size(), ez->TRUE);
div_zero_result.insert(div_zero_result.end(), y.size() - div_zero_result.size(), ez->FALSE);
div_zero_result.insert(div_zero_result.end(), cell->getPort("\\A").size(), ez->CONST_TRUE);
div_zero_result.insert(div_zero_result.end(), y.size() - div_zero_result.size(), ez->CONST_FALSE);
}
} else {
int copy_a_bits = std::min(cell->getPort("\\A").size(), cell->getPort("\\B").size());
@ -900,7 +985,7 @@ struct SatGen
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());
else
div_zero_result.insert(div_zero_result.end(), y.size() - div_zero_result.size(), ez->FALSE);
div_zero_result.insert(div_zero_result.end(), y.size() - div_zero_result.size(), ez->CONST_FALSE);
}
ez->assume(ez->vec_eq(yy, ez->vec_ite(ez->expression(ezSAT::OpOr, b), y_tmp, div_zero_result)));
}
@ -920,44 +1005,44 @@ struct SatGen
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));
lut.push_back(bit == RTLIL::S1 ? ez->CONST_TRUE : ez->CONST_FALSE);
while (GetSize(lut) < (1 << GetSize(a)))
lut.push_back(ez->CONST_FALSE);
lut.resize(1 << GetSize(a));
if (model_undef)
{
std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
std::vector<int> t(lut), u(SIZE(t), ez->FALSE);
std::vector<int> t(lut), u(GetSize(t), ez->CONST_FALSE);
for (int i = SIZE(a)-1; i >= 0; i--)
for (int i = GetSize(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> t0(t.begin(), t.begin() + GetSize(t)/2);
std::vector<int> t1(t.begin() + GetSize(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());
std::vector<int> u0(u.begin(), u.begin() + GetSize(u)/2);
std::vector<int> u1(u.begin() + GetSize(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);
log_assert(GetSize(t) == 1);
log_assert(GetSize(u) == 1);
undefGating(y, t, u);
ez->assume(ez->vec_eq(importUndefSigSpec(cell->getPort("\\Y"), timestep), u));
}
else
{
std::vector<int> t = lut;
for (int i = SIZE(a)-1; i >= 0; i--)
for (int i = GetSize(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> t0(t.begin(), t.begin() + GetSize(t)/2);
std::vector<int> t1(t.begin() + GetSize(t)/2, t.end());
t = ez->vec_ite(a[i], t1, t0);
}
log_assert(SIZE(t) == 1);
log_assert(GetSize(t) == 1);
ez->assume(ez->vec_eq(y, t));
}
return true;
@ -1008,7 +1093,7 @@ struct SatGen
std::vector<int> yy = model_undef ? ez->vec_var(co.size()) : co;
for (int i = 0; i < SIZE(co); i++)
for (int i = 0; i < GetSize(co); i++)
ez->SET(yy[i], ez->OR(g[i], ez->AND(p[i], i ? yy[i-1] : ci[0])));
if (model_undef)
@ -1049,12 +1134,12 @@ struct SatGen
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);
log_assert(GetSize(y) == GetSize(x));
log_assert(GetSize(y) == GetSize(co));
log_assert(GetSize(ci) == 1);
log_assert(GetSize(bi) == 1);
for (int i = 0; i < SIZE(y); i++)
for (int i = 0; i < GetSize(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));
@ -1084,7 +1169,7 @@ struct SatGen
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++) {
for (int i = 0; i < GetSize(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);
@ -1144,6 +1229,25 @@ struct SatGen
return true;
}
if (cell->type == "$_BUF_" || cell->type == "$equiv")
{
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(a, yy));
if (model_undef) {
std::vector<int> undef_a = importUndefSigSpec(cell->getPort("\\A"), timestep);
std::vector<int> undef_y = importUndefSigSpec(cell->getPort("\\Y"), timestep);
extendSignalWidthUnary(undef_a, undef_y, cell, false);
ez->assume(ez->vec_eq(undef_a, undef_y));
undefGating(y, yy, undef_y);
}
return true;
}
if (cell->type == "$assert")
{
std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep));
@ -1152,10 +1256,20 @@ struct SatGen
return true;
}
if (cell->type == "$assume")
{
std::string pf = prefix + (timestep == -1 ? "" : stringf("@%d:", timestep));
assumes_a[pf].append((*sigmap)(cell->getPort("\\A")));
assumes_en[pf].append((*sigmap)(cell->getPort("\\EN")));
return true;
}
// Unsupported internal cell types: $pow $lut
// .. and all sequential cells except $dff and $_DFF_[NP]_
return false;
}
};
YOSYS_NAMESPACE_END
#endif

View File

@ -29,9 +29,10 @@ struct SigPool
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) { }
unsigned int hash() const { return first->name.hash() + second; }
};
std::set<bitDef_t> bits;
pool<bitDef_t> bits;
void clear()
{
@ -66,8 +67,8 @@ struct SigPool
void expand(RTLIL::SigSpec from, RTLIL::SigSpec to)
{
log_assert(SIZE(from) == SIZE(to));
for (int i = 0; i < SIZE(from); i++) {
log_assert(GetSize(from) == GetSize(to));
for (int i = 0; i < GetSize(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);
@ -122,13 +123,13 @@ struct SigPool
RTLIL::SigSpec export_all()
{
std::set<RTLIL::SigBit> sig;
pool<RTLIL::SigBit> sig;
for (auto &bit : bits)
sig.insert(RTLIL::SigBit(bit.first, bit.second));
return sig;
}
size_t size()
size_t size() const
{
return bits.size();
}
@ -140,9 +141,10 @@ struct SigSet
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) { }
unsigned int hash() const { return first->name.hash() + second; }
};
std::map<bitDef_t, std::set<T, Compare>> bits;
dict<bitDef_t, std::set<T, Compare>> bits;
void clear()
{
@ -193,6 +195,15 @@ struct SigSet
}
}
void find(RTLIL::SigSpec sig, pool<T> &result)
{
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)
{
std::set<T> result;
@ -214,6 +225,7 @@ struct SigMap
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) { }
unsigned int hash() const { return first->name.hash() + second; }
};
struct shared_bit_data_t {
@ -221,7 +233,7 @@ struct SigMap
std::set<bitDef_t> bits;
};
std::map<bitDef_t, shared_bit_data_t*> bits;
dict<bitDef_t, shared_bit_data_t*> bits;
SigMap(RTLIL::Module *module = NULL)
{
@ -346,9 +358,9 @@ struct SigMap
void add(RTLIL::SigSpec from, RTLIL::SigSpec to)
{
log_assert(SIZE(from) == SIZE(to));
log_assert(GetSize(from) == GetSize(to));
for (int i = 0; i < SIZE(from); i++)
for (int i = 0; i < GetSize(from); i++)
{
RTLIL::SigBit &bf = from[i];
RTLIL::SigBit &bt = to[i];

View File

@ -25,21 +25,23 @@
#ifndef UTILS_H
#define UTILS_H
YOSYS_NAMESPACE_BEGIN
// ------------------------------------------------
// A map-like container, but you can save and restore the state
// ------------------------------------------------
template<typename Key, typename T, typename Compare = std::less<Key>>
template<typename Key, typename T, typename OPS = hash_ops<Key>>
struct stackmap
{
private:
std::vector<std::map<Key, T*, Compare>> backup_state;
std::map<Key, T, Compare> current_state;
std::vector<dict<Key, T*, OPS>> backup_state;
dict<Key, T, OPS> current_state;
static T empty_tuple;
public:
stackmap() { }
stackmap(const std::map<Key, T, Compare> &other) : current_state(other) { }
stackmap(const dict<Key, T, OPS> &other) : current_state(other) { }
template<typename Other>
void operator=(const Other &other)
@ -81,7 +83,7 @@ public:
void reset(const Key &k)
{
for (int i = SIZE(backup_state)-1; i >= 0; i--)
for (int i = GetSize(backup_state)-1; i >= 0; i--)
if (backup_state[i].count(k) != 0) {
if (backup_state[i].at(k) == nullptr)
current_state.erase(k);
@ -92,7 +94,7 @@ public:
current_state.erase(k);
}
const std::map<Key, T, Compare> &stdmap()
const dict<Key, T, OPS> &stdmap()
{
return current_state;
}
@ -126,12 +128,12 @@ public:
// A simple class for topological sorting
// ------------------------------------------------
template<typename T>
template<typename T, typename C = std::less<T>>
struct TopoSort
{
bool analyze_loops, found_loops;
std::map<T, std::set<T>> database;
std::set<std::set<T>> loops;
std::map<T, std::set<T, C>, C> database;
std::set<std::set<T, C>> loops;
std::vector<T> sorted;
TopoSort()
@ -143,7 +145,7 @@ struct TopoSort
void node(T n)
{
if (database.count(n) == 0)
database[n] = std::set<T>();
database[n] = std::set<T, C>();
}
void edge(T left, T right)
@ -152,13 +154,13 @@ struct TopoSort
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)
void sort_worker(const T &n, std::set<T, C> &marked_cells, std::set<T, C> &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--) {
std::set<T, C> loop;
for (int i = GetSize(active_stack)-1; i >= 0; i--) {
loop.insert(active_stack[i]);
if (active_stack[i] == n)
break;
@ -195,16 +197,18 @@ struct TopoSort
sorted.clear();
found_loops = false;
std::set<T> marked_cells;
std::set<T> active_cells;
std::set<T, C> marked_cells;
std::set<T, C> 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));
log_assert(GetSize(sorted) == GetSize(database));
return !found_loops;
}
};
YOSYS_NAMESPACE_END
#endif

View File

@ -18,26 +18,112 @@
*/
#include "kernel/yosys.h"
#include "kernel/celltypes.h"
#ifdef YOSYS_ENABLE_READLINE
# include <readline/readline.h>
# include <readline/history.h>
#endif
#include <dlfcn.h>
#include <unistd.h>
#ifdef YOSYS_ENABLE_PLUGINS
# include <dlfcn.h>
#endif
#ifdef _WIN32
# include <windows.h>
# include <io.h>
#elif defined(__APPLE__)
# include <mach-o/dyld.h>
# include <unistd.h>
# include <dirent.h>
# include <sys/stat.h>
#else
# include <unistd.h>
# include <dirent.h>
# include <sys/types.h>
# include <sys/stat.h>
#endif
#include <limits.h>
#include <errno.h>
YOSYS_NAMESPACE_BEGIN
int autoidx = 1;
int yosys_xtrace = 0;
RTLIL::Design *yosys_design = NULL;
CellTypes yosys_celltypes;
#ifdef YOSYS_ENABLE_TCL
Tcl_Interp *yosys_tcl_interp = NULL;
#endif
bool memhasher_active = false;
uint32_t memhasher_rng = 123456;
std::vector<void*> memhasher_store;
void memhasher_on()
{
#ifdef __linux__
memhasher_rng += time(NULL) << 16 ^ getpid();
#endif
memhasher_store.resize(0x10000);
memhasher_active = true;
}
void memhasher_off()
{
for (auto p : memhasher_store)
if (p) free(p);
memhasher_store.clear();
memhasher_active = false;
}
void memhasher_do()
{
memhasher_rng ^= memhasher_rng << 13;
memhasher_rng ^= memhasher_rng >> 17;
memhasher_rng ^= memhasher_rng << 5;
int size, index = (memhasher_rng >> 4) & 0xffff;
switch (memhasher_rng & 7) {
case 0: size = 16; break;
case 1: size = 256; break;
case 2: size = 1024; break;
case 3: size = 4096; break;
default: size = 0;
}
if (index < 16) size *= 16;
memhasher_store[index] = realloc(memhasher_store[index], size);
}
void yosys_banner()
{
log("\n");
log(" /----------------------------------------------------------------------------\\\n");
log(" | |\n");
log(" | yosys -- Yosys Open SYnthesis Suite |\n");
log(" | |\n");
log(" | Copyright (C) 2012 - 2015 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");
}
std::string stringf(const char *fmt, ...)
{
std::string string;
@ -55,8 +141,22 @@ std::string vstringf(const char *fmt, va_list ap)
std::string string;
char *str = NULL;
#ifdef _WIN32
int sz = 64, rc;
while (1) {
va_list apc;
va_copy(apc, ap);
str = (char*)realloc(str, sz);
rc = vsnprintf(str, sz, fmt, apc);
va_end(apc);
if (rc >= 0 && rc < sz)
break;
sz *= 2;
}
#else
if (vasprintf(&str, fmt, ap) < 0)
str = NULL;
#endif
if (str != NULL) {
string = str;
@ -66,15 +166,264 @@ std::string vstringf(const char *fmt, va_list ap)
return string;
}
int SIZE(RTLIL::Wire *wire)
int readsome(std::istream &f, char *s, int n)
{
int rc = f.readsome(s, n);
// f.readsome() sometimes returns 0 on a non-empty stream..
if (rc == 0) {
int c = f.get();
if (c != EOF) {
*s = c;
rc = 1;
}
}
return rc;
}
std::string next_token(std::string &text, const char *sep)
{
size_t pos_begin = text.find_first_not_of(sep);
if (pos_begin == std::string::npos)
pos_begin = text.size();
size_t pos_end = text.find_first_of(sep, pos_begin);
if (pos_end == std::string::npos)
pos_end = text.size();
std::string token = text.substr(pos_begin, pos_end-pos_begin);
text = text.substr(pos_end);
return token;
}
// this is very similar to fnmatch(). the exact rules used by this
// function are:
//
// ? matches any character except
// * matches any sequence of characters
// [...] matches any of the characters in the list
// [!..] matches any of the characters not in the list
//
// a backslash may be used to escape the next characters in the
// pattern. each special character can also simply match itself.
//
bool patmatch(const char *pattern, const char *string)
{
if (*pattern == 0)
return *string == 0;
if (*pattern == '\\') {
if (pattern[1] == string[0] && patmatch(pattern+2, string+1))
return true;
}
if (*pattern == '?') {
if (*string == 0)
return false;
return patmatch(pattern+1, string+1);
}
if (*pattern == '*') {
while (*string) {
if (patmatch(pattern+1, string++))
return true;
}
return pattern[1] == 0;
}
if (*pattern == '[') {
bool found_match = false;
bool inverted_list = pattern[1] == '!';
const char *p = pattern + (inverted_list ? 1 : 0);
while (*++p) {
if (*p == ']') {
if (found_match != inverted_list && patmatch(p+1, string+1))
return true;
break;
}
if (*p == '\\') {
if (*++p == *string)
found_match = true;
} else
if (*p == *string)
found_match = true;
}
}
if (*pattern == *string)
return patmatch(pattern+1, string+1);
return false;
}
int run_command(const std::string &command, std::function<void(const std::string&)> process_line)
{
if (!process_line)
return system(command.c_str());
FILE *f = popen(command.c_str(), "r");
if (f == nullptr)
return -1;
std::string line;
char logbuf[128];
while (fgets(logbuf, 128, f) != NULL) {
line += logbuf;
if (!line.empty() && line.back() == '\n')
process_line(line), line.clear();
}
if (!line.empty())
process_line(line);
int ret = pclose(f);
if (ret < 0)
return -1;
#ifdef _WIN32
return ret;
#else
return WEXITSTATUS(ret);
#endif
}
std::string make_temp_file(std::string template_str)
{
#ifdef _WIN32
if (template_str.rfind("/tmp/", 0) == 0) {
# ifdef __MINGW32__
char longpath[MAX_PATH + 1];
char shortpath[MAX_PATH + 1];
# else
WCHAR longpath[MAX_PATH + 1];
TCHAR shortpath[MAX_PATH + 1];
# endif
if (!GetTempPath(MAX_PATH+1, longpath))
log_error("GetTempPath() failed.\n");
if (!GetShortPathName(longpath, shortpath, MAX_PATH + 1))
log_error("GetShortPathName() failed.\n");
std::string path;
for (int i = 0; shortpath[i]; i++)
path += char(shortpath[i]);
template_str = stringf("%s\\%s", path.c_str(), template_str.c_str() + 5);
}
size_t pos = template_str.rfind("XXXXXX");
log_assert(pos != std::string::npos);
while (1) {
for (int i = 0; i < 6; i++) {
static std::string y = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
static uint32_t x = 314159265 ^ uint32_t(time(NULL));
x ^= x << 13, x ^= x >> 17, x ^= x << 5;
template_str[pos+i] = y[x % y.size()];
}
if (_access(template_str.c_str(), 0) != 0)
break;
}
#else
size_t pos = template_str.rfind("XXXXXX");
log_assert(pos != std::string::npos);
int suffixlen = GetSize(template_str) - pos - 6;
char *p = strdup(template_str.c_str());
close(mkstemps(p, suffixlen));
template_str = p;
free(p);
#endif
return template_str;
}
std::string make_temp_dir(std::string template_str)
{
#ifdef _WIN32
template_str = make_temp_file(template_str);
mkdir(template_str.c_str());
return template_str;
#else
# ifndef NDEBUG
size_t pos = template_str.rfind("XXXXXX");
log_assert(pos != std::string::npos);
int suffixlen = GetSize(template_str) - pos - 6;
log_assert(suffixlen == 0);
# endif
char *p = strdup(template_str.c_str());
p = mkdtemp(p);
log_assert(p != NULL);
template_str = p;
free(p);
return template_str;
#endif
}
#ifdef _WIN32
bool check_file_exists(std::string filename, bool)
{
return _access(filename.c_str(), 0) == 0;
}
#else
bool check_file_exists(std::string filename, bool is_exec)
{
return access(filename.c_str(), is_exec ? X_OK : F_OK) == 0;
}
#endif
bool is_absolute_path(std::string filename)
{
#ifdef _WIN32
return filename[0] == '/' || filename[0] == '\\' || (filename[0] != 0 && filename[1] == ':');
#else
return filename[0] == '/';
#endif
}
void remove_directory(std::string dirname)
{
#ifdef _WIN32
run_command(stringf("rmdir /s /q \"%s\"", dirname.c_str()));
#else
struct stat stbuf;
struct dirent **namelist;
int n = scandir(dirname.c_str(), &namelist, nullptr, alphasort);
log_assert(n >= 0);
for (int i = 0; i < n; i++) {
if (strcmp(namelist[i]->d_name, ".") && strcmp(namelist[i]->d_name, "..")) {
std::string buffer = stringf("%s/%s", dirname.c_str(), namelist[i]->d_name);
if (!stat(buffer.c_str(), &stbuf) && S_ISREG(stbuf.st_mode)) {
remove(buffer.c_str());
} else
remove_directory(buffer);
}
free(namelist[i]);
}
free(namelist);
rmdir(dirname.c_str());
#endif
}
int GetSize(RTLIL::Wire *wire)
{
return wire->width;
}
void yosys_setup()
{
// if there are already IdString objects then we have a global initialization order bug
IdString empty_id;
log_assert(empty_id.index_ == 0);
IdString::get_reference(empty_id.index_);
Pass::init_register();
yosys_design = new RTLIL::Design;
yosys_celltypes.setup();
log_push();
}
@ -92,6 +441,7 @@ void yosys_shutdown()
log_files.clear();
Pass::done_register();
yosys_celltypes.clear();
#ifdef YOSYS_ENABLE_TCL
if (yosys_tcl_interp != NULL) {
@ -101,20 +451,33 @@ void yosys_shutdown()
}
#endif
#ifdef YOSYS_ENABLE_PLUGINS
for (auto &it : loaded_plugins)
dlclose(it.second);
loaded_plugins.clear();
loaded_plugin_aliases.clear();
#endif
IdString empty_id;
IdString::put_reference(empty_id.index_);
}
RTLIL::IdString new_id(std::string file, int line, std::string func)
{
std::string str = "$auto$";
#ifdef _WIN32
size_t pos = file.find_last_of("/\\");
#else
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;
#endif
if (pos != std::string::npos)
file = file.substr(pos+1);
pos = func.find_last_of(':');
if (pos != std::string::npos)
func = func.substr(pos+1);
return stringf("$auto$%s:%d:%s$%d", file.c_str(), line, func.c_str(), autoidx++);
}
RTLIL::Design *yosys_get_design()
@ -210,9 +573,9 @@ struct TclPass : public Pass {
#endif
#if defined(__linux__)
std::string proc_self_dirname ()
std::string proc_self_dirname()
{
char path [PATH_MAX];
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));
@ -222,10 +585,9 @@ std::string proc_self_dirname ()
return std::string(path, buflen);
}
#elif defined(__APPLE__)
#include <mach-o/dyld.h>
std::string proc_self_dirname ()
std::string proc_self_dirname()
{
char * path = NULL;
char *path = NULL;
uint32_t buflen = 0;
while (_NSGetExecutablePath(path, &buflen) != 0)
path = (char *) realloc((void *) path, buflen);
@ -233,8 +595,32 @@ std::string proc_self_dirname ()
buflen--;
return std::string(path, buflen);
}
#elif defined(_WIN32)
std::string proc_self_dirname()
{
int i = 0;
# ifdef __MINGW32__
char longpath[MAX_PATH + 1];
char shortpath[MAX_PATH + 1];
# else
WCHAR longpath[MAX_PATH + 1];
TCHAR shortpath[MAX_PATH + 1];
# endif
if (!GetModuleFileName(0, longpath, MAX_PATH+1))
log_error("GetModuleFileName() failed.\n");
if (!GetShortPathName(longpath, shortpath, MAX_PATH+1))
log_error("GetShortPathName() failed.\n");
while (shortpath[i] != 0)
i++;
while (i > 0 && shortpath[i-1] != '/' && shortpath[i-1] != '\\')
shortpath[--i] = 0;
std::string path;
for (i = 0; shortpath[i]; i++)
path += char(shortpath[i]);
return path;
}
#elif defined(EMSCRIPTEN)
std::string proc_self_dirname ()
std::string proc_self_dirname()
{
return "/";
}
@ -242,17 +628,33 @@ std::string proc_self_dirname ()
#error Dont know how to determine process executable base path!
#endif
std::string proc_share_dirname ()
#ifdef EMSCRIPTEN
std::string proc_share_dirname()
{
return "/share";
}
#else
std::string proc_share_dirname()
{
std::string proc_self_path = proc_self_dirname();
# ifdef _WIN32
std::string proc_share_path = proc_self_path + "share\\";
if (check_file_exists(proc_share_path, true))
return proc_share_path;
proc_share_path = proc_self_path + "..\\share\\";
if (check_file_exists(proc_share_path, true))
return proc_share_path;
# else
std::string proc_share_path = proc_self_path + "share/";
if (access(proc_share_path.c_str(), X_OK) == 0)
if (check_file_exists(proc_share_path, true))
return proc_share_path;
proc_share_path = proc_self_path + "../share/yosys/";
if (access(proc_share_path.c_str(), X_OK) == 0)
if (check_file_exists(proc_share_path, true))
return proc_share_path;
# endif
log_error("proc_share_dirname: unable to determine share/ directory!\n");
}
#endif
bool fgetline(FILE *f, std::string &buffer)
{
@ -275,15 +677,15 @@ static void handle_label(std::string &command, bool &from_to_active, const std::
int pos = 0;
std::string label;
while (pos < SIZE(command) && (command[pos] == ' ' || command[pos] == '\t'))
while (pos < GetSize(command) && (command[pos] == ' ' || command[pos] == '\t'))
pos++;
while (pos < SIZE(command) && command[pos] != ' ' && command[pos] != '\t' && command[pos] != '\r' && command[pos] != '\n')
while (pos < GetSize(command) && command[pos] != ' ' && command[pos] != '\t' && command[pos] != '\r' && command[pos] != '\n')
label += command[pos++];
if (label.back() == ':' && SIZE(label) > 1)
if (label.back() == ':' && GetSize(label) > 1)
{
label = label.substr(0, SIZE(label)-1);
label = label.substr(0, GetSize(label)-1);
command = command.substr(pos);
if (label == run_from)
@ -293,8 +695,11 @@ static void handle_label(std::string &command, bool &from_to_active, const std::
}
}
void run_frontend(std::string filename, std::string command, RTLIL::Design *design, std::string *backend_command, std::string *from_to_label)
void run_frontend(std::string filename, std::string command, std::string *backend_command, std::string *from_to_label, RTLIL::Design *design)
{
if (design == nullptr)
design = yosys_design;
if (command == "auto") {
if (filename.size() > 2 && filename.substr(filename.size()-2) == ".v")
command = "verilog";
@ -361,9 +766,9 @@ void run_frontend(std::string filename, std::string command, RTLIL::Design *desi
Pass::call(design, command);
}
}
catch (log_cmd_error_expection) {
catch (...) {
Frontend::current_script_file = backup_script_file;
throw log_cmd_error_expection();
throw;
}
Frontend::current_script_file = backup_script_file;
@ -386,15 +791,26 @@ void run_frontend(std::string filename, std::string command, RTLIL::Design *desi
Frontend::frontend_call(design, NULL, filename, command);
}
void run_frontend(std::string filename, std::string command, RTLIL::Design *design)
{
run_frontend(filename, command, nullptr, nullptr, design);
}
void run_pass(std::string command, RTLIL::Design *design)
{
log("\n-- Running pass `%s' --\n", command.c_str());
if (design == nullptr)
design = yosys_design;
log("\n-- Running command `%s' --\n", command.c_str());
Pass::call(design, command);
}
void run_backend(std::string filename, std::string command, RTLIL::Design *design)
{
if (design == nullptr)
design = yosys_design;
if (command == "auto") {
if (filename.size() > 2 && filename.substr(filename.size()-2) == ".v")
command = "verilog";
@ -518,11 +934,16 @@ void shell(RTLIL::Design *design)
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
while (1)
{
fputs(create_prompt(design, recursion_counter), stdout);
fflush(stdout);
if ((command = fgets(command_buffer, 4096, stdin)) == NULL)
break;
#endif
if (command[strspn(command, " \t\r\n")] == 0)
continue;
#ifdef YOSYS_ENABLE_READLINE
@ -540,7 +961,7 @@ void shell(RTLIL::Design *design)
try {
log_assert(design->selection_stack.size() == 1);
Pass::call(design, command);
} catch (log_cmd_error_expection) {
} catch (log_cmd_error_exception) {
while (design->selection_stack.size() > 1)
design->selection_stack.pop_back();
log_reset_stack();
@ -634,9 +1055,9 @@ struct ScriptPass : public Pass {
if (args.size() < 2)
log_cmd_error("Missing script file.\n");
else if (args.size() == 2)
run_frontend(args[1], "script", design, NULL, NULL);
run_frontend(args[1], "script", design);
else if (args.size() == 3)
run_frontend(args[1], "script", design, NULL, &args[2]);
run_frontend(args[1], "script", NULL, &args[2], design);
else
extra_args(args, 2, design, false);
}

View File

@ -45,7 +45,11 @@
#include <string>
#include <algorithm>
#include <functional>
#include <unordered_map>
#include <unordered_set>
#include <initializer_list>
#include <stdexcept>
#include <memory>
#include <sstream>
#include <fstream>
@ -56,44 +60,164 @@
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdio.h>
#ifndef _YOSYS_
# error It looks like you are trying to build Yosys without the config defines set. \
When building Yosys with a custom make system, make sure you set all the \
defines the Yosys Makefile would set for your build configuration.
#endif
#ifdef YOSYS_ENABLE_TCL
# include <tcl.h>
#endif
#ifdef _WIN32
# undef NOMINMAX
# define NOMINMAX 1
# undef YY_NO_UNISTD_H
# define YY_NO_UNISTD_H 1
# include <windows.h>
# include <io.h>
# include <direct.h>
# define strtok_r strtok_s
# define strdup _strdup
# define snprintf _snprintf
# define getcwd _getcwd
# define mkdir _mkdir
# define popen _popen
# define pclose _pclose
# define PATH_MAX MAX_PATH
# ifndef __MINGW32__
# define isatty _isatty
# define fileno _fileno
# endif
#endif
#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
#define YOSYS_NAMESPACE_BEGIN namespace Yosys {
#define YOSYS_NAMESPACE_END }
#define YOSYS_NAMESPACE_PREFIX Yosys::
#define USING_YOSYS_NAMESPACE using namespace Yosys;
#if __cplusplus >= 201103L
# define OVERRIDE override
# define FINAL final
# define YS_OVERRIDE override
# define YS_FINAL final
#else
# define OVERRIDE
# define FINAL
# define YS_OVERRIDE
# define YS_FINAL
#endif
#if defined(__GNUC__) || defined(__clang__)
# define YS_ATTRIBUTE(...) __attribute__((__VA_ARGS__))
# define YS_NORETURN
#elif defined(_MSC_VER)
# define YS_ATTRIBUTE(...)
# define YS_NORETURN __declspec(noreturn)
#else
# define YS_ATTRIBUTE(...)
# define YS_NORETURN
#endif
YOSYS_NAMESPACE_BEGIN
// Note: All headers included in hashlib.h must be included
// outside of YOSYS_NAMESPACE before this or bad things will happen.
#ifdef HASHLIB_H
# undef HASHLIB_H
# include "kernel/hashlib.h"
#else
# include "kernel/hashlib.h"
# undef HASHLIB_H
#endif
using std::vector;
using std::string;
using std::pair;
using hashlib::mkhash;
using hashlib::mkhash_init;
using hashlib::mkhash_add;
using hashlib::mkhash_xorshift;
using hashlib::hash_ops;
using hashlib::hash_cstr_ops;
using hashlib::hash_ptr_ops;
using hashlib::hash_obj_ops;
using hashlib::dict;
using hashlib::idict;
using hashlib::pool;
namespace RTLIL {
struct IdString;
struct Const;
struct SigBit;
struct SigSpec;
struct Wire;
struct Cell;
struct Module;
struct Design;
struct Monitor;
}
std::string stringf(const char *fmt, ...);
namespace AST {
struct AstNode;
}
using RTLIL::IdString;
using RTLIL::Const;
using RTLIL::SigBit;
using RTLIL::SigSpec;
using RTLIL::Wire;
using RTLIL::Cell;
using RTLIL::Module;
using RTLIL::Design;
namespace hashlib {
template<> struct hash_ops<RTLIL::Wire*> : hash_obj_ops {};
template<> struct hash_ops<RTLIL::Cell*> : hash_obj_ops {};
template<> struct hash_ops<RTLIL::Module*> : hash_obj_ops {};
template<> struct hash_ops<RTLIL::Design*> : hash_obj_ops {};
template<> struct hash_ops<RTLIL::Monitor*> : hash_obj_ops {};
template<> struct hash_ops<AST::AstNode*> : hash_obj_ops {};
template<> struct hash_ops<const RTLIL::Wire*> : hash_obj_ops {};
template<> struct hash_ops<const RTLIL::Cell*> : hash_obj_ops {};
template<> struct hash_ops<const RTLIL::Module*> : hash_obj_ops {};
template<> struct hash_ops<const RTLIL::Design*> : hash_obj_ops {};
template<> struct hash_ops<const RTLIL::Monitor*> : hash_obj_ops {};
template<> struct hash_ops<const AST::AstNode*> : hash_obj_ops {};
}
void memhasher_on();
void memhasher_off();
void memhasher_do();
extern bool memhasher_active;
inline void memhasher() { if (memhasher_active) memhasher_do(); }
void yosys_banner();
std::string stringf(const char *fmt, ...) YS_ATTRIBUTE(format(printf, 1, 2));
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);
int readsome(std::istream &f, char *s, int n);
std::string next_token(std::string &text, const char *sep = " \t\r\n");
bool patmatch(const char *pattern, const char *string);
int run_command(const std::string &command, std::function<void(const std::string&)> process_line = std::function<void(const std::string&)>());
std::string make_temp_file(std::string template_str = "/tmp/yosys_XXXXXX");
std::string make_temp_dir(std::string template_str = "/tmp/yosys_XXXXXX");
bool check_file_exists(std::string filename, bool is_exec = false);
bool is_absolute_path(std::string filename);
void remove_directory(std::string dirname);
template<typename T> int GetSize(const T &obj) { return obj.size(); }
int GetSize(RTLIL::Wire *wire);
extern int autoidx;
extern int yosys_xtrace;
YOSYS_NAMESPACE_END
@ -103,15 +227,19 @@ YOSYS_NAMESPACE_END
YOSYS_NAMESPACE_BEGIN
using RTLIL::State;
namespace hashlib {
template<> struct hash_ops<RTLIL::State> : hash_ops<int> {};
}
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);
@ -127,9 +255,10 @@ 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 run_pass(std::string command, RTLIL::Design *design = nullptr);
void run_frontend(std::string filename, std::string command, std::string *backend_command, std::string *from_to_label = nullptr, RTLIL::Design *design = nullptr);
void run_frontend(std::string filename, std::string command, RTLIL::Design *design = nullptr);
void run_backend(std::string filename, std::string command, RTLIL::Design *design = nullptr);
void shell(RTLIL::Design *design);
// from kernel/version_*.o (cc source generated from Makefile)

View File

@ -27,7 +27,10 @@
#include <stdint.h>
#include <csignal>
#include <cinttypes>
#include <unistd.h>
#ifndef _WIN32
# include <unistd.h>
#endif
#include "../minisat/Solver.h"
#include "../minisat/SimpSolver.h"
@ -37,8 +40,8 @@ ezMiniSAT::ezMiniSAT() : minisatSolver(NULL)
minisatSolver = NULL;
foundContradiction = false;
freeze(TRUE);
freeze(FALSE);
freeze(CONST_TRUE);
freeze(CONST_FALSE);
}
ezMiniSAT::~ezMiniSAT()
@ -77,6 +80,7 @@ bool ezMiniSAT::eliminated(int idx)
}
#endif
#ifndef _WIN32
ezMiniSAT *ezMiniSAT::alarmHandlerThis = NULL;
clock_t ezMiniSAT::alarmHandlerTimeout = 0;
@ -88,6 +92,7 @@ void ezMiniSAT::alarmHandler(int)
} else
alarm(1);
}
#endif
bool ezMiniSAT::solver(const std::vector<int> &modelExpressions, std::vector<bool> &modelValues, const std::vector<int> &assumptions)
{
@ -174,6 +179,7 @@ contradiction:
#endif
}
#ifndef _WIN32
struct sigaction sig_action;
struct sigaction old_sig_action;
int old_alarm_timeout = 0;
@ -188,9 +194,11 @@ contradiction:
sigaction(SIGALRM, &sig_action, &old_sig_action);
alarm(1);
}
#endif
bool foundSolution = minisatSolver->solve(assumps);
#ifndef _WIN32
if (solverTimeout > 0) {
if (alarmHandlerTimeout == 0)
solverTimoutStatus = true;
@ -198,6 +206,7 @@ contradiction:
sigaction(SIGALRM, &old_sig_action, NULL);
alarm(old_alarm_timeout);
}
#endif
if (!foundSolution) {
#if !EZMINISAT_INCREMENTAL

View File

@ -51,9 +51,11 @@ private:
std::set<int> cnfFrozenVars;
#endif
#ifndef _WIN32
static ezMiniSAT *alarmHandlerThis;
static clock_t alarmHandlerTimeout;
static void alarmHandler(int);
#endif
public:
ezMiniSAT();

View File

@ -22,14 +22,28 @@
#include <cmath>
#include <algorithm>
#include <cassert>
#include <string>
#include <stdlib.h>
const int ezSAT::TRUE = 1;
const int ezSAT::FALSE = 2;
const int ezSAT::CONST_TRUE = 1;
const int ezSAT::CONST_FALSE = 2;
static std::string my_int_to_string(int i)
{
#ifdef __MINGW32__
char buffer[64];
snprintf(buffer, 64, "%d", i);
return buffer;
#else
return std::to_string(i);
#endif
}
ezSAT::ezSAT()
{
statehash = 5381;
flag_keep_cnf = false;
flag_non_incremental = false;
@ -42,20 +56,25 @@ ezSAT::ezSAT()
solverTimeout = 0;
solverTimoutStatus = false;
literal("TRUE");
literal("FALSE");
literal("CONST_TRUE");
literal("CONST_FALSE");
assert(literal("TRUE") == TRUE);
assert(literal("FALSE") == FALSE);
assert(literal("CONST_TRUE") == CONST_TRUE);
assert(literal("CONST_FALSE") == CONST_FALSE);
}
ezSAT::~ezSAT()
{
}
void ezSAT::addhash(unsigned int h)
{
statehash = ((statehash << 5) + statehash) ^ h;
}
int ezSAT::value(bool val)
{
return val ? TRUE : FALSE;
return val ? CONST_TRUE : CONST_FALSE;
}
int ezSAT::literal()
@ -101,15 +120,21 @@ int ezSAT::expression(OpId op, const std::vector<int> &args)
myArgs.reserve(args.size());
bool xorRemovedOddTrues = false;
addhash(__LINE__);
addhash(op);
for (auto arg : args)
{
addhash(__LINE__);
addhash(arg);
if (arg == 0)
continue;
if (op == OpAnd && arg == TRUE)
if (op == OpAnd && arg == CONST_TRUE)
continue;
if ((op == OpOr || op == OpXor) && arg == FALSE)
if ((op == OpOr || op == OpXor) && arg == CONST_FALSE)
continue;
if (op == OpXor && arg == TRUE) {
if (op == OpXor && arg == CONST_TRUE) {
xorRemovedOddTrues = !xorRemovedOddTrues;
continue;
}
@ -131,29 +156,29 @@ int ezSAT::expression(OpId op, const std::vector<int> &args)
{
case OpNot:
assert(myArgs.size() == 1);
if (myArgs[0] == TRUE)
return FALSE;
if (myArgs[0] == FALSE)
return TRUE;
if (myArgs[0] == CONST_TRUE)
return CONST_FALSE;
if (myArgs[0] == CONST_FALSE)
return CONST_TRUE;
break;
case OpAnd:
if (myArgs.size() == 0)
return TRUE;
return CONST_TRUE;
if (myArgs.size() == 1)
return myArgs[0];
break;
case OpOr:
if (myArgs.size() == 0)
return FALSE;
return CONST_FALSE;
if (myArgs.size() == 1)
return myArgs[0];
break;
case OpXor:
if (myArgs.size() == 0)
return xorRemovedOddTrues ? TRUE : FALSE;
return xorRemovedOddTrues ? CONST_TRUE : CONST_FALSE;
if (myArgs.size() == 1)
return xorRemovedOddTrues ? NOT(myArgs[0]) : myArgs[0];
break;
@ -161,15 +186,15 @@ int ezSAT::expression(OpId op, const std::vector<int> &args)
case OpIFF:
assert(myArgs.size() >= 1);
if (myArgs.size() == 1)
return TRUE;
return CONST_TRUE;
// FIXME: Add proper const folding
break;
case OpITE:
assert(myArgs.size() == 3);
if (myArgs[0] == TRUE)
if (myArgs[0] == CONST_TRUE)
return myArgs[1];
if (myArgs[0] == FALSE)
if (myArgs[0] == CONST_FALSE)
return myArgs[2];
break;
@ -183,12 +208,18 @@ int ezSAT::expression(OpId op, const std::vector<int> &args)
if (expressionsCache.count(myExpr) > 0) {
id = expressionsCache.at(myExpr);
} else {
id = -(expressions.size() + 1);
id = -(int(expressions.size()) + 1);
expressionsCache[myExpr] = id;
expressions.push_back(myExpr);
}
return xorRemovedOddTrues ? NOT(id) : id;
if (xorRemovedOddTrues)
id = NOT(id);
addhash(__LINE__);
addhash(id);
return id;
}
void ezSAT::lookup_literal(int id, std::string &name) const
@ -281,7 +312,7 @@ std::string ezSAT::to_string(int id) const
int ezSAT::eval(int id, const std::vector<int> &values) const
{
if (id > 0) {
if (id <= int(values.size()) && (values[id-1] == TRUE || values[id-1] == FALSE || values[id-1] == 0))
if (id <= int(values.size()) && (values[id-1] == CONST_TRUE || values[id-1] == CONST_FALSE || values[id-1] == 0))
return values[id-1];
return 0;
}
@ -295,39 +326,39 @@ int ezSAT::eval(int id, const std::vector<int> &values) const
case OpNot:
assert(args.size() == 1);
a = eval(args[0], values);
if (a == TRUE)
return FALSE;
if (a == FALSE)
return TRUE;
if (a == CONST_TRUE)
return CONST_FALSE;
if (a == CONST_FALSE)
return CONST_TRUE;
return 0;
case OpAnd:
a = TRUE;
a = CONST_TRUE;
for (auto arg : args) {
b = eval(arg, values);
if (b != TRUE && b != FALSE)
if (b != CONST_TRUE && b != CONST_FALSE)
a = 0;
if (b == FALSE)
return FALSE;
if (b == CONST_FALSE)
return CONST_FALSE;
}
return a;
case OpOr:
a = FALSE;
a = CONST_FALSE;
for (auto arg : args) {
b = eval(arg, values);
if (b != TRUE && b != FALSE)
if (b != CONST_TRUE && b != CONST_FALSE)
a = 0;
if (b == TRUE)
return TRUE;
if (b == CONST_TRUE)
return CONST_TRUE;
}
return a;
case OpXor:
a = FALSE;
a = CONST_FALSE;
for (auto arg : args) {
b = eval(arg, values);
if (b != TRUE && b != FALSE)
if (b != CONST_TRUE && b != CONST_FALSE)
return 0;
if (b == TRUE)
a = a == TRUE ? FALSE : TRUE;
if (b == CONST_TRUE)
a = a == CONST_TRUE ? CONST_FALSE : CONST_TRUE;
}
return a;
case OpIFF:
@ -335,18 +366,18 @@ int ezSAT::eval(int id, const std::vector<int> &values) const
a = eval(args[0], values);
for (auto arg : args) {
b = eval(arg, values);
if (b != TRUE && b != FALSE)
if (b != CONST_TRUE && b != CONST_FALSE)
return 0;
if (b != a)
return FALSE;
return CONST_FALSE;
}
return TRUE;
return CONST_TRUE;
case OpITE:
assert(args.size() == 3);
a = eval(args[0], values);
if (a == TRUE)
if (a == CONST_TRUE)
return eval(args[1], values);
if (a == FALSE)
if (a == CONST_FALSE)
return eval(args[2], values);
return 0;
default:
@ -375,6 +406,9 @@ bool ezSAT::eliminated(int)
void ezSAT::assume(int id)
{
addhash(__LINE__);
addhash(id);
if (id < 0)
{
assert(0 < -id && -id <= int(expressions.size()));
@ -417,6 +451,10 @@ void ezSAT::assume(int id)
void ezSAT::add_clause(const std::vector<int> &args)
{
addhash(__LINE__);
for (auto arg : args)
addhash(arg);
cnfClauses.push_back(args);
cnfClausesCount++;
}
@ -490,13 +528,13 @@ int ezSAT::bound(int id) const
std::string ezSAT::cnfLiteralInfo(int idx) const
{
for (size_t i = 0; i < cnfLiteralVariables.size(); i++) {
for (int i = 0; i < int(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++) {
for (int i = 0; i < int(cnfExpressionVariables.size()); i++) {
if (cnfExpressionVariables[i] == idx)
return to_string(-i-1);
if (cnfExpressionVariables[i] == -idx)
@ -507,6 +545,10 @@ std::string ezSAT::cnfLiteralInfo(int idx) const
int ezSAT::bind(int id, bool auto_freeze)
{
addhash(__LINE__);
addhash(id);
addhash(auto_freeze);
if (id >= 0) {
assert(0 < id && id <= int(literals.size()));
cnfLiteralVariables.resize(literals.size());
@ -516,9 +558,9 @@ int ezSAT::bind(int id, bool auto_freeze)
}
if (cnfLiteralVariables[id-1] == 0) {
cnfLiteralVariables[id-1] = ++cnfVariableCount;
if (id == TRUE)
if (id == CONST_TRUE)
add_clause(+cnfLiteralVariables[id-1]);
if (id == FALSE)
if (id == CONST_FALSE)
add_clause(-cnfLiteralVariables[id-1]);
}
return cnfLiteralVariables[id-1];
@ -549,10 +591,13 @@ int ezSAT::bind(int id, bool auto_freeze)
while (args.size() > 1) {
std::vector<int> newArgs;
for (int i = 0; i < int(args.size()); i += 2)
if (i+1 == int(args.size()))
if (i+1 == int(args.size())) {
newArgs.push_back(args[i]);
else
newArgs.push_back(OR(AND(args[i], NOT(args[i+1])), AND(NOT(args[i]), args[i+1])));
} else {
int sub1 = AND(args[i], NOT(args[i+1]));
int sub2 = AND(NOT(args[i]), args[i+1]);
newArgs.push_back(OR(sub1, sub2));
}
args.swap(newArgs);
}
idx = bind(args.at(0), false);
@ -563,12 +608,16 @@ int ezSAT::bind(int id, bool auto_freeze)
std::vector<int> invArgs;
for (auto arg : args)
invArgs.push_back(NOT(arg));
idx = bind(OR(expression(OpAnd, args), expression(OpAnd, invArgs)), false);
int sub1 = expression(OpAnd, args);
int sub2 = expression(OpAnd, invArgs);
idx = bind(OR(sub1, sub2), false);
goto assign_idx;
}
if (op == OpITE) {
idx = bind(OR(AND(args[0], args[1]), AND(NOT(args[0]), args[2])), false);
int sub1 = AND(args[0], args[1]);
int sub2 = AND(NOT(args[0]), args[2]);
idx = bind(OR(sub1, sub2), false);
goto assign_idx;
}
@ -638,7 +687,7 @@ std::vector<int> ezSAT::vec_const(const std::vector<bool> &bits)
{
std::vector<int> vec;
for (auto bit : bits)
vec.push_back(bit ? TRUE : FALSE);
vec.push_back(bit ? CONST_TRUE : CONST_FALSE);
return vec;
}
@ -646,7 +695,7 @@ std::vector<int> ezSAT::vec_const_signed(int64_t value, int numBits)
{
std::vector<int> vec;
for (int i = 0; i < numBits; i++)
vec.push_back(((value >> i) & 1) != 0 ? TRUE : FALSE);
vec.push_back(((value >> i) & 1) != 0 ? CONST_TRUE : CONST_FALSE);
return vec;
}
@ -654,7 +703,7 @@ std::vector<int> ezSAT::vec_const_unsigned(uint64_t value, int numBits)
{
std::vector<int> vec;
for (int i = 0; i < numBits; i++)
vec.push_back(((value >> i) & 1) != 0 ? TRUE : FALSE);
vec.push_back(((value >> i) & 1) != 0 ? CONST_TRUE : CONST_FALSE);
return vec;
}
@ -669,8 +718,9 @@ std::vector<int> ezSAT::vec_var(int numBits)
std::vector<int> ezSAT::vec_var(std::string name, int numBits)
{
std::vector<int> vec;
for (int i = 0; i < numBits; i++)
vec.push_back(VAR(name + "[" + std::to_string(i) + "]"));
for (int i = 0; i < numBits; i++) {
vec.push_back(VAR(name + my_int_to_string(i)));
}
return vec;
}
@ -679,7 +729,7 @@ std::vector<int> ezSAT::vec_cast(const std::vector<int> &vec1, int toBits, bool
std::vector<int> vec;
for (int i = 0; i < toBits; i++)
if (i >= int(vec1.size()))
vec.push_back(signExtend ? vec1.back() : FALSE);
vec.push_back(signExtend ? vec1.back() : CONST_FALSE);
else
vec.push_back(vec1[i]);
return vec;
@ -807,7 +857,7 @@ std::vector<int> ezSAT::vec_add(const std::vector<int> &vec1, const std::vector<
{
assert(vec1.size() == vec2.size());
std::vector<int> vec(vec1.size());
int carry = FALSE;
int carry = CONST_FALSE;
for (int i = 0; i < int(vec1.size()); i++)
fulladder(this, vec1[i], vec2[i], carry, carry, vec[i]);
@ -831,7 +881,7 @@ std::vector<int> ezSAT::vec_sub(const std::vector<int> &vec1, const std::vector<
{
assert(vec1.size() == vec2.size());
std::vector<int> vec(vec1.size());
int carry = TRUE;
int carry = CONST_TRUE;
for (int i = 0; i < int(vec1.size()); i++)
fulladder(this, vec1[i], NOT(vec2[i]), carry, carry, vec[i]);
@ -853,15 +903,15 @@ std::vector<int> ezSAT::vec_sub(const std::vector<int> &vec1, const std::vector<
std::vector<int> ezSAT::vec_neg(const std::vector<int> &vec)
{
std::vector<int> zero(vec.size(), FALSE);
std::vector<int> zero(vec.size(), CONST_FALSE);
return vec_sub(zero, vec);
}
void ezSAT::vec_cmp(const std::vector<int> &vec1, const std::vector<int> &vec2, int &carry, int &overflow, int &sign, int &zero)
{
assert(vec1.size() == vec2.size());
carry = TRUE;
zero = FALSE;
carry = CONST_TRUE;
zero = CONST_FALSE;
for (int i = 0; i < int(vec1.size()); i++) {
overflow = carry;
fulladder(this, vec1[i], NOT(vec2[i]), carry, carry, sign);
@ -954,11 +1004,11 @@ std::vector<int> ezSAT::vec_shl(const std::vector<int> &vec1, int shift, bool si
for (int i = 0; i < int(vec1.size()); i++) {
int j = i-shift;
if (int(vec1.size()) <= j)
vec.push_back(signExtend ? vec1.back() : FALSE);
vec.push_back(signExtend ? vec1.back() : CONST_FALSE);
else if (0 <= j)
vec.push_back(vec1[j]);
else
vec.push_back(FALSE);
vec.push_back(CONST_FALSE);
}
return vec;
}
@ -1005,10 +1055,10 @@ std::vector<int> ezSAT::vec_shift_right(const std::vector<int> &vec1, const std:
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;
int overflow_left = CONST_FALSE, overflow_right = CONST_FALSE;
if (vec2_signed) {
int overflow = FALSE;
int overflow = CONST_FALSE;
for (auto bit : overflow_bits)
overflow = OR(overflow, XOR(bit, vec2[vec2_bits-1]));
overflow_left = AND(overflow, NOT(vec2.back()));
@ -1046,7 +1096,7 @@ std::vector<int> ezSAT::vec_shift_right(const std::vector<int> &vec1, const std:
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);
if (vec2_signed) assert(vec2_signed == false);
int vec2_bits = std::min(my_clog2(vec1.size()), int(vec2.size()));
@ -1105,7 +1155,7 @@ int64_t ezSAT::vec_model_get_signed(const std::vector<int> &modelExpressions, co
for (int i = 0; i < 64; i++) {
int j = i < int(vec1.size()) ? i : vec1.size()-1;
if (modelMap.at(vec1[j]))
value |= 1 << i;
value |= int64_t(1) << i;
}
return value;
}
@ -1119,7 +1169,7 @@ uint64_t ezSAT::vec_model_get_unsigned(const std::vector<int> &modelExpressions,
modelMap[modelExpressions[i]] = modelValues[i];
for (int i = 0; i < int(vec1.size()); i++)
if (modelMap.at(vec1[i]))
value |= 1 << i;
value |= uint64_t(1) << i;
return value;
}
@ -1195,7 +1245,7 @@ void ezSAT::printDIMACS(FILE *f, bool verbose) const
fprintf(f, "c mapping of variables to expressions:\n");
for (int i = 0; i < int(cnfExpressionVariables.size()); i++)
if (cnfExpressionVariables[i] != 0)
fprintf(f, "c %*d: %s\n", digits, cnfExpressionVariables[i], to_string(-i-1).c_str());
fprintf(f, "c %*d: %d\n", digits, cnfExpressionVariables[i], -i-1);
if (mode_keep_cnf()) {
fprintf(f, "c\n");
@ -1243,7 +1293,7 @@ static std::string expression2str(const std::pair<ezSAT::OpId, std::vector<int>>
}
text += ":";
for (auto it : data.second)
text += " " + std::to_string(it);
text += " " + my_int_to_string(it);
return text;
}
@ -1330,7 +1380,7 @@ int ezSAT::manyhot(const std::vector<int> &vec, int min_hot, int max_hot)
for (int i = -1; i < N; i++)
for (int j = -1; j < M; j++)
x[std::pair<int,int>(i,j)] = j < 0 ? TRUE : i < 0 ? FALSE : literal();
x[std::pair<int,int>(i,j)] = j < 0 ? CONST_TRUE : i < 0 ? CONST_FALSE : literal();
for (int i = 0; i < N; i++)
for (int j = 0; j < M; j++) {
@ -1358,7 +1408,7 @@ int ezSAT::manyhot(const std::vector<int> &vec, int min_hot, int max_hot)
int ezSAT::ordered(const std::vector<int> &vec1, const std::vector<int> &vec2, bool allow_equal)
{
std::vector<int> formula;
int last_x = FALSE;
int last_x = CONST_FALSE;
assert(vec1.size() == vec2.size());
for (size_t i = 0; i < vec1.size(); i++)
@ -1366,7 +1416,7 @@ int ezSAT::ordered(const std::vector<int> &vec1, const std::vector<int> &vec2, b
int a = vec1[i], b = vec2[i];
formula.push_back(OR(NOT(a), b, last_x));
int next_x = i+1 < vec1.size() ? literal() : allow_equal ? FALSE : TRUE;
int next_x = i+1 < vec1.size() ? literal() : allow_equal ? CONST_FALSE : CONST_TRUE;
formula.push_back(OR(a, b, last_x, NOT(next_x)));
formula.push_back(OR(NOT(a), NOT(b), last_x, NOT(next_x)));
last_x = next_x;

View File

@ -25,6 +25,7 @@
#include <vector>
#include <string>
#include <stdio.h>
#include <stdint.h>
class ezSAT
{
@ -34,7 +35,7 @@ class ezSAT
// the number zero is not used as valid token number and is used to encode
// unused parameters for the functions.
//
// positive numbers are literals, with 1 = TRUE and 2 = FALSE;
// positive numbers are literals, with 1 = CONST_TRUE and 2 = CONST_FALSE;
//
// negative numbers are non-literal expressions. each expression is represented
// by an operator id and a list of expressions (literals or non-literals).
@ -44,8 +45,8 @@ public:
OpNot, OpAnd, OpOr, OpXor, OpIFF, OpITE
};
static const int TRUE;
static const int FALSE;
static const int CONST_TRUE;
static const int CONST_FALSE;
private:
bool flag_keep_cnf;
@ -82,6 +83,9 @@ public:
ezSAT();
virtual ~ezSAT();
unsigned int statehash;
void addhash(unsigned int);
void keep_cnf() { flag_keep_cnf = true; }
void non_incremental() { flag_non_incremental = true; }
@ -159,6 +163,7 @@ public:
virtual void freeze(int id);
virtual bool eliminated(int idx);
void assume(int id);
void assume(int id, int context_id) { assume(OR(id, NOT(context_id))); }
int bind(int id, bool auto_freeze = true);
int bound(int id) const;

View File

@ -13,6 +13,8 @@
-- Bruce Guenter <bruce@untroubled.org>
Translation to simpler C++ Code
-- Volker Grabsch <vog@notjusthosting.com>
Fixing bugs and improving style
-- Eugene Hopkinson <slowriot at voxelstorm dot com>
*/
#include "sha1.h"
@ -52,7 +54,7 @@ void SHA1::update(std::istream &is)
while (is)
{
uint32 block[BLOCK_INTS];
uint32_t block[BLOCK_INTS];
buffer_to_block(buffer, block);
transform(block);
read(is, buffer, BLOCK_BYTES);
@ -67,7 +69,7 @@ void SHA1::update(std::istream &is)
std::string SHA1::final()
{
/* Total number of hashed bits */
uint64 total_bits = (transforms*BLOCK_BYTES + buffer.size()) * 8;
uint64_t total_bits = (transforms*BLOCK_BYTES + buffer.size()) * 8;
/* Padding */
buffer += 0x80;
@ -77,7 +79,7 @@ std::string SHA1::final()
buffer += (char)0x00;
}
uint32 block[BLOCK_INTS];
uint32_t block[BLOCK_INTS];
buffer_to_block(buffer, block);
if (orig_size > BLOCK_BYTES - 8)
@ -89,7 +91,7 @@ std::string SHA1::final()
}
}
/* Append total_bits, split this uint64 into two uint32 */
/* Append total_bits, split this uint64_t into two uint32_t */
block[BLOCK_INTS - 1] = total_bits;
block[BLOCK_INTS - 2] = (total_bits >> 32);
transform(block);
@ -137,14 +139,14 @@ void SHA1::reset()
* Hash a single 512-bit block. This is the core of the algorithm.
*/
void SHA1::transform(uint32 block[BLOCK_BYTES])
void SHA1::transform(uint32_t 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];
uint32_t a = digest[0];
uint32_t b = digest[1];
uint32_t c = digest[2];
uint32_t d = digest[3];
uint32_t e = digest[4];
/* 4 rounds of 20 operations each. Loop unrolled. */
@ -241,9 +243,9 @@ void SHA1::transform(uint32 block[BLOCK_BYTES])
}
void SHA1::buffer_to_block(const std::string &buffer, uint32 block[BLOCK_BYTES])
void SHA1::buffer_to_block(const std::string &buffer, uint32_t block[BLOCK_INTS])
{
/* Convert the std::string (byte buffer) to a uint32 array (MSB) */
/* Convert the std::string (byte buffer) to a uint32_t array (MSB) */
for (unsigned int i = 0; i < BLOCK_INTS; i++)
{
block[i] = (buffer[4*i+3] & 0xff)
@ -254,11 +256,14 @@ void SHA1::buffer_to_block(const std::string &buffer, uint32 block[BLOCK_BYTES])
}
void SHA1::read(std::istream &is, std::string &s, int max)
void SHA1::read(std::istream &is, std::string &s, size_t max)
{
char sbuf[max];
char* sbuf = new char[max];
is.read(sbuf, max);
s.assign(sbuf, is.gcount());
delete[] sbuf;
}

View File

@ -13,6 +13,8 @@
-- Bruce Guenter <bruce@untroubled.org>
Translation to simpler C++ Code
-- Volker Grabsch <vog@notjusthosting.com>
Fixing bugs and improving style
-- Eugene Hopkinson <slowriot at voxelstorm dot com>
*/
#ifndef SHA1_HPP
@ -21,6 +23,7 @@
#include <iostream>
#include <string>
#include <stdint.h>
class SHA1
{
@ -32,22 +35,19 @@ public:
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];
uint32_t digest[DIGEST_INTS];
std::string buffer;
uint64 transforms;
uint64_t transforms;
void reset();
void transform(uint32 block[BLOCK_BYTES]);
void transform(uint32_t 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);
static void read(std::istream &is, std::string &s, size_t max);
static void buffer_to_block(const std::string &buffer, uint32_t block[BLOCK_INTS]);
};
std::string sha1(const std::string &string);

View File

@ -34,6 +34,7 @@
using namespace SubCircuit;
#ifndef _YOSYS_
static std::string my_stringf(const char *fmt, ...)
{
std::string string;
@ -52,6 +53,9 @@ static std::string my_stringf(const char *fmt, ...)
return string;
}
#else
# define my_stringf YOSYS_NAMESPACE_PREFIX stringf
#endif
SubCircuit::Graph::Graph(const Graph &other, const std::vector<std::string> &otherNodes)
{

View File

@ -61,7 +61,7 @@ to easily create complex designs from small HDL code. It is the preferred
method of design entry for many designers\footnote{The other half prefers VHDL,
a very different but -- of course -- equally powerful language.}.
The Berkeley Logic Interchange Format (BLIF) is a simple file format for
The Berkeley Logic Interchange Format (BLIF) \cite{blif} is a simple file format for
exchanging sequential logic between programs. It is easy to generate and
easy to parse and is therefore the preferred method of design entry for
many authors of logic synthesis tools.
@ -456,6 +456,10 @@ Conor Santifort. Amber ARM-compatible core. \\
Berkeley Logic Synthesis and Verification Group. ABC: A System for Sequential Synthesis and Verification. \\
\url{http://www.eecs.berkeley.edu/~alanmi/abc/}
\bibitem{blif}
Berkeley Logic Interchange Format (BLIF) \\
\url{http://vlsi.colorado.edu/~vis/blif.ps}
\end{thebibliography}

View File

@ -31,4 +31,4 @@ n5:e -> c11:p7:w [color="black", label=""];
n6:e -> x0:s0:w [color="black", label=""];
n6:e -> x1:s0:w [color="black", label=""];
n6:e -> x2:s0:w [color="black", label=""];
};
}

View File

@ -20,4 +20,4 @@ n5:e -> c12:p8:w [color="black", label=""];
c15:p10:e -> n6:w [color="black", label=""];
c14:p10:e -> n7:w [color="black", label=""];
n7:e -> c15:p9:w [color="black", label=""];
};
}

View File

@ -20,4 +20,4 @@ n7:e -> p1:w [color="black", label=""];
p1:e -> n8:w [color="black", style="setlinewidth(3)", label=""];
n8:e -> p1:w [color="black", style="setlinewidth(3)", label=""];
v0:e -> c14:p9:w [color="black", style="setlinewidth(3)", label=""];
};
}

View File

@ -30,4 +30,4 @@ n8:e -> c21:p19:w [color="black", label=""];
n8:e -> x1:w:w [color="black", label=""];
n9:e -> c18:p15:w [color="black", label=""];
v0:e -> c21:p11:w [color="black", style="setlinewidth(3)", label=""];
};
}

View File

@ -17,4 +17,4 @@ n5:e -> c17:p16:w [color="black", label=""];
n6:e -> c15:p12:w [color="black", label=""];
c15:p14:e -> n7:w [color="black", style="setlinewidth(3)", label=""];
n7:e -> c17:p8:w [color="black", style="setlinewidth(3)", label=""];
};
}

View File

@ -8,4 +8,4 @@ c4 [ shape=record, label="{{<p1> A|<p2> B}|$2\n$add|{<p3> Y}}" ];
v0:e -> c4:p1:w [color="black", label=""];
v1:e -> c4:p2:w [color="black", label=""];
c4:p3:e -> v2:w [color="black", style="setlinewidth(3)", label=""];
};
}

View File

@ -135,4 +135,4 @@ v6:e -> c47:p34:w [color="black", label=""];
v7:e -> c48:p33:w [color="black", style="setlinewidth(3)", label=""];
v8:e -> c49:p33:w [color="black", style="setlinewidth(3)", label=""];
v9:e -> c50:p33:w [color="black", style="setlinewidth(3)", label=""];
};
}

View File

@ -26,4 +26,4 @@ v0:e -> c13:p11:w [color="black", label=""];
v1:e -> c14:p11:w [color="black", label=""];
v2:e -> c15:p11:w [color="black", label=""];
v3:e -> c19:p16:w [color="black", label=""];
};
}

View File

@ -36,4 +36,4 @@ x1:s0:e -> n8:w [color="black", style="setlinewidth(3)", label=""];
x3:s0:e -> n8:w [color="black", style="setlinewidth(3)", label=""];
x3:s1:e -> n8:w [color="black", style="setlinewidth(3)", label=""];
x6:s0:e -> n8:w [color="black", style="setlinewidth(3)", label=""];
};
}

View File

@ -42,4 +42,4 @@ c21:p8:e -> n8:w [color="black", style="setlinewidth(3)", label=""];
n8:e -> c20:p8:w [color="black", style="setlinewidth(3)", label=""];
c21:p9:e -> n9:w [color="black", style="setlinewidth(3)", label=""];
n9:e -> c20:p9:w [color="black", style="setlinewidth(3)", label=""];
};
}

View File

@ -84,4 +84,4 @@ v4:e -> c35:p24:w [color="black", style="setlinewidth(3)", label=""];
v5:e -> c36:p24:w [color="black", style="setlinewidth(3)", label=""];
v6:e -> c37:p24:w [color="black", style="setlinewidth(3)", label=""];
v7:e -> c38:p24:w [color="black", style="setlinewidth(3)", label=""];
};
}

View File

@ -30,4 +30,4 @@ n8:e -> c17:p12:w [color="black", style="setlinewidth(3)", label=""];
n9:e -> x0:s0:w [color="black", label=""];
n9:e -> x1:s0:w [color="black", label=""];
n9:e -> x2:s0:w [color="black", label=""];
};
}

View File

@ -23,4 +23,4 @@ x1:s1:e -> n5:w [color="black", style="setlinewidth(3)", label=""];
n6:e -> x2:s1:w [color="black", style="setlinewidth(3)", label=""];
n7:e -> x2:s0:w [color="black", style="setlinewidth(3)", label=""];
v0:e -> c13:p8:w [color="black", style="setlinewidth(3)", label=""];
};
}

View File

@ -15,4 +15,4 @@ c4:p3:e -> v2:w [color="black", style="setlinewidth(3)", label=""];
v3:e -> c5:p1:w [color="black", style="setlinewidth(3)", label=""];
v4:e -> c5:p2:w [color="black", style="setlinewidth(3)", label=""];
c5:p3:e -> v5:w [color="black", style="setlinewidth(3)", label=""];
};
}

View File

@ -12,4 +12,4 @@ n2:e -> c9:p6:w [color="black", style="setlinewidth(3)", label=""];
n3:e -> c9:p7:w [color="black", style="setlinewidth(3)", label=""];
n4:e -> c10:p7:w [color="black", style="setlinewidth(3)", label=""];
c10:p8:e -> n5:w [color="black", style="setlinewidth(3)", label=""];
};
}

View File

@ -2,4 +2,4 @@ digraph "sumprod" {
rankdir="LR";
remincross=true;
n1 [ shape=octagon, label="prod", color="black", fontcolor="black" ];
};
}

View File

@ -8,4 +8,4 @@ c5 [ shape=record, label="{{<p2> A|<p3> B}|$4\n$mul|{<p4> Y}}" ];
c5:p4:e -> n1:w [color="black", style="setlinewidth(3)", label=""];
v0:e -> c5:p2:w [color="black", style="setlinewidth(3)", label=""];
v1:e -> c5:p3:w [color="black", style="setlinewidth(3)", label=""];
};
}

View File

@ -8,4 +8,4 @@ n1 [ shape=diamond, label="$3_Y" ];
n1:e -> c7:p4:w [color="black", style="setlinewidth(3)", label=""];
n2:e -> c7:p5:w [color="black", style="setlinewidth(3)", label=""];
c7:p6:e -> n3:w [color="black", style="setlinewidth(3)", label=""];
};
}

View File

@ -12,4 +12,4 @@ n2:e -> c8:p5:w [color="black", style="setlinewidth(3)", label=""];
c8:p6:e -> n3:w [color="black", style="setlinewidth(3)", label=""];
v0:e -> c7:p4:w [color="black", style="setlinewidth(3)", label=""];
v1:e -> c7:p5:w [color="black", style="setlinewidth(3)", label=""];
};
}

View File

@ -2,11 +2,24 @@
\chapter{Application Notes}
\label{chapter:appnotes}
\begin{fixme}
This appendix will cover some typical use-cases of Yosys in the form of application notes.
\end{fixme}
% \begin{fixme}
% This appendix will cover some typical use-cases of Yosys in the form of application notes.
% \end{fixme}
%
% \section{Synthesizing using a Cell Library in Liberty Format}
% \section{Reverse Engeneering the MOS6502 from an NMOS Transistor Netlist}
% \section{Reconfigurable Coarse-Grain Synthesis using Intersynth}
\section{Synthesizing using a Cell Library in Liberty Format}
\section{Reverse Engeneering the MOS6502 from an NMOS Transistor Netlist}
\section{Reconfigurable Coarse-Grain Synthesis using Intersynth}
This appendix contains copies of the Yosys application notes.
\begin{itemize}
\item Yosys AppNote 010: Converting Verilog to BLIF \dotfill Page \pageref{app:010} \hskip2cm\null
\item Yosys AppNote 011: Interactive Design Investigation \dotfill Page \pageref{app:011} \hskip2cm\null
\end{itemize}
\eject\label{app:010}
\includepdf[pages=-,pagecommand=\thispagestyle{plain}]{APPNOTE_010_Verilog_to_BLIF.pdf}
\eject\label{app:011}
\includepdf[pages=-,pagecommand=\thispagestyle{plain}]{APPNOTE_011_Design_Investigation.pdf}

View File

@ -17,3 +17,9 @@ The {\tt yosys-filterlib} tool is a small utility that can be used to strip
or extract information from a Liberty file. See Sec.~\ref{sec:techmap_extern}
for details.
\section{yosys-abc}
This is a unmodified copy of ABC \citeweblink{ABC}. Not all versions of Yosys
work with all versions of ABC. So Yosys comes with its own yosys-abc to avoid
compatibility issues between the two.

View File

@ -357,7 +357,7 @@ Add a brief description of the {\tt \$fsm} cell type.
For gate level logic networks, fixed function single bit cells are used that do
not provide any parameters.
Simulation models for these cells can be found in the file {\tt techlibs/common/stdcells\_sim.v} in the Yosys
Simulation models for these cells can be found in the file {\tt techlibs/common/simcells.v} in the Yosys
source tree.
\begin{table}[t]
@ -417,7 +417,7 @@ pass. The combinatorial logic cells can be mapped to physical cells from a Liber
using the {\tt abc} pass.
\begin{fixme}
Add information about {\tt \$assert} cells.
Add information about {\tt \$assert}, {\tt \$assume}, and {\tt \$equiv} cells.
\end{fixme}
\begin{fixme}
@ -428,6 +428,14 @@ Add information about {\tt \$slice} and {\tt \$concat} cells.
Add information about {\tt \$alu}, {\tt \$macc}, {\tt \$fa}, and {\tt \$lcu} cells.
\end{fixme}
\begin{fixme}
Add information about {\tt \$dffe}, {\tt \$dffsr}, {\tt \$dlatch}, and {\tt \$dlatchsr} cells.
\end{fixme}
\begin{fixme}
Add information about {\tt \$\_DFFE\_??\_}, {\tt \$\_DFFSR\_???\_}, {\tt \$\_DLATCH\_?\_}, and {\tt \$\_DLATCHSR\_???\_} cells.
\end{fixme}
\begin{fixme}
Add information about {\tt \$\_NAND\_}, {\tt \$\_NOR\_}, {\tt \$\_XNOR\_}, {\tt \$\_AOI3\_}, {\tt \$\_OAI3\_}, {\tt \$\_AOI4\_}, and {\tt \$\_OAI4\_} cells.
\end{fixme}

View File

@ -2,16 +2,21 @@
\chapter{Programming Yosys Extensions}
\label{chapter:prog}
\begin{fixme}
This chapter will contain a guided tour to the Yosys APIs and conclude
with an example module.
\end{fixme}
This chapter contains some bits and pieces of information about programming
yosys extensions. Also consult the section on programming in the ``Yosys
Presentation'' (can be downloaded from the Yosys website as PDF) and don't
be afraid to ask questions on the Yosys Subreddit.
\section{Programming with RTLIL}
\section{Internal Utility Libraries}
\section{Loadable Modules}
\section{The ``CodingReadme'' File}
The following is an excerpt of the {\tt CodingReadme} file from the Yosys source tree.
\lstinputlisting[title=CodingReadme,rangeprefix=--,rangesuffix=--,includerangemarker=false,linerange=snip-snap,numbers=left,frame=single]{../CodingReadme}
\section{The ``stubsnets'' Example Module}
The following is the complete code of the ``stubsnets'' example module. It is included in the Yosys source distribution as {\tt manual/CHAPTER\_Prog/stubnets.cc}.
\section{Example Module}
\lstinputlisting[title=stubnets.cc,numbers=left,frame=single,language=C++]{CHAPTER_Prog/stubnets.cc}

3
manual/CHAPTER_Prog/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
stubnets.so
stubnets.d
*.log

View File

@ -5,15 +5,16 @@
// binary, for any purpose, commercial or non-commercial, and by any
// means.
#include "kernel/rtlil.h"
#include "kernel/register.h"
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
#include "kernel/log.h"
#include <string>
#include <map>
#include <set>
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
// this function is called for each module in the design
static void find_stub_nets(RTLIL::Design *design, RTLIL::Module *module, bool report_bits)
{
@ -62,7 +63,7 @@ static void find_stub_nets(RTLIL::Design *design, RTLIL::Module *module, bool re
// for each bit (unless it is a constant):
// check if it is used at least two times and add to stub_bits otherwise
for (int i = 0; i < SIZE(sig); i++)
for (int i = 0; i < GetSize(sig); i++)
if (sig[i].wire != NULL && (bit_usage_count[sig[i]] + usage_offset) < 2)
stub_bits.insert(i);
@ -72,7 +73,7 @@ static void find_stub_nets(RTLIL::Design *design, RTLIL::Module *module, bool re
// report stub bits and/or stub wires, don't report single bits
// if called with report_bits set to false.
if (SIZE(stub_bits) == SIZE(sig)) {
if (GetSize(stub_bits) == GetSize(sig)) {
log(" found stub wire: %s\n", RTLIL::id2cstr(wire->name));
} else {
if (!report_bits)
@ -126,3 +127,4 @@ struct StubnetsPass : public Pass {
}
} StubnetsPass;
PRIVATE_NAMESPACE_END

View File

@ -790,7 +790,7 @@ Unwrap in {\tt test2}:
\hfil\begin{tikzpicture}
\node at (0,0) {\includegraphics[width=11cm,trim=1.5cm 1.5cm 1.5cm 1.5cm]{PRESENTATION_ExAdv/macc_xilinx_test2d.pdf}};
\node at (0,-4) {\includegraphics[width=11cm,trim=1.5cm 1.5cm 1.5cm 1.5cm]{PRESENTATION_ExAdv/macc_xilinx_test2e.pdf}};
\node at (0,-4) {\includegraphics[width=8cm,trim=1.5cm 1.5cm 1.5cm 1.5cm]{PRESENTATION_ExAdv/macc_xilinx_test2e.pdf}};
\node at (1,-1.7) {\begin{lstlisting}[linewidth=5.5cm, frame=single, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys]
techmap -map macc_xilinx_unwrap_map.v ;;
\end{lstlisting}};

View File

@ -13,7 +13,7 @@ module axis_master(aclk, aresetn, tvalid, tready, tdata);
if (tvalid && tready)
tvalid <= 0;
if (!tvalid || !tready) begin
// ^- should be not inverted!
// ^- should not be inverted!
state = state ^ state << 13;
state = state ^ state >> 7;
state = state ^ state << 17;

View File

@ -268,7 +268,7 @@ memory -nomap; techmap -map my_memory_map.v; memory_map
\end{frame}
\begin{frame}[t, fragile]{\subsecname{} -- Example 1/2}
\vbox to 0cm{\includegraphics[width=\linewidth,trim=0cm 0cm 0cm -10cm]{PRESENTATION_ExSyn/memory_01.pdf}\vss}
\vbox to 0cm{\includegraphics[width=0.7\linewidth,trim=0cm 0cm 0cm -10cm]{PRESENTATION_ExSyn/memory_01.pdf}\vss}
\vskip-1cm
\begin{columns}
\column[t]{5cm}
@ -455,7 +455,7 @@ read_verilog -D WITH_MULT cpu_alu.v
hierarchy -check -top cpu_top
# high-level synthesis
proc; opt; memory -nomap;; fsm; opt
proc; opt; fsm;; memory -nomap; opt
# substitute block rams
techmap -map map_rams.v
@ -497,7 +497,7 @@ the next part (Section 3, ``Advanced Synthesis'') of this presentation.}
\item Yosys provides commands for each phase of the synthesis.
\item Each command solves a (more or less) simple problem.
\item Complex commands are often only front-ends to simple commands.
\item {\tt proc; opt; memory; opt; fsm; opt; techmap; opt; abc;;}
\item {\tt proc; opt; fsm; opt; memory; opt; techmap; opt; abc;;}
\end{itemize}
\bigskip

View File

@ -277,7 +277,7 @@ Direct link to the files: \\ \footnotesize
\medskip
{\color{YosysGreen}\# the high-level stuff}\\
\boxalert<3>{proc}; \boxalert<4>{opt}; \boxalert<5>{memory}; \boxalert<6>{opt}; \boxalert<7>{fsm}; \boxalert<8>{opt}
\boxalert<3>{proc}; \boxalert<4>{opt}; \boxalert<5>{fsm}; \boxalert<6>{opt}; \boxalert<7>{memory}; \boxalert<8>{opt}
\medskip
{\color{YosysGreen}\# mapping to internal cell library}\\
@ -308,9 +308,9 @@ Direct link to the files: \\ \footnotesize
\only<2>{hierarchy -check -top counter}%
\only<3>{proc}%
\only<4>{opt}%
\only<5>{memory}%
\only<5>{fsm}%
\only<6>{opt}%
\only<7>{fsm}%
\only<7>{memory}%
\only<8>{opt}%
\only<9>{techmap}%
\only<10>{opt}%
@ -333,13 +333,13 @@ Direct link to the files: \\ \footnotesize
Perform some basic optimizations and cleanups.
}%
\only<5>{
Analyze memories and create circuits to implement them.
Analyze and optimize finite state machines.
}%
\only<6>{
Perform some basic optimizations and cleanups.
}%
\only<7>{
Analyze and optimize finite state machines.
Analyze memories and create circuits to implement them.
}%
\only<8>{
Perform some basic optimizations and cleanups.
@ -398,7 +398,7 @@ hierarchy -check -top counter
\begin{frame}[t, fragile]{\subsecname{} -- Step 2/4}
\begin{verbatim}
proc; opt; memory; opt; fsm; opt
proc; opt; fsm; opt; memory; opt
\end{verbatim}
\vfill
@ -411,7 +411,7 @@ techmap; opt
\end{verbatim}
\vfill
\includegraphics[width=\linewidth,trim=0 0cm 0 0cm]{PRESENTATION_Intro/counter_02.pdf}
\includegraphics[width=\linewidth,trim=0 0cm 0 2cm]{PRESENTATION_Intro/counter_02.pdf}
\end{frame}
\begin{frame}[t, fragile]{\subsecname{} -- Step 4/4}
@ -427,6 +427,48 @@ clean
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{The synth command}
\begin{frame}[fragile]{\subsecname{}}
Yosys contains a default (recommended example) synthesis script in form of the
{\tt synth} command. The following commands are executed by this synthesis command:
\begin{columns}
\column[t]{5cm}
\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys]
begin:
hierarchy -check [-top <top>]
coarse:
proc
opt
wreduce
alumacc
share
opt
fsm
opt -fast
memory -nomap
opt_clean
\end{lstlisting}
\column[t]{5cm}
\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys]
fine:
opt -fast -full
memory_map
opt -full
techmap
opt -fast
abc:
abc -fast
opt -fast
\end{lstlisting}
\end{columns}
\end{frame}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\subsection{Yosys Commands}
\begin{frame}[fragile]{\subsecname{} 1/3 \hspace{0pt plus 1 filll} (excerpt)}
@ -500,6 +542,7 @@ Commands for writing the results:
\bigskip
Script-Commands for standard synthesis tasks:
\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=ys]
synth # generic synthesis script
synth_xilinx # synthesis for Xilinx FPGAs
\end{lstlisting}
@ -603,12 +646,8 @@ endmodule
\begin{frame}{\subsecname}
\begin{itemize}
\item Multi-dimensional arrays (memories)
\item Writing to arrays using bit- and part-selects (todo for 0.4.0)
\item The wor/wand wire types (maybe for 0.4.0)
\item Tri-state logic
\bigskip
\item The wor/wand wire types (maybe for 0.5)
\item Latched logic (is synthesized as logic with feedback loops)
\item Some non-synthesizable features that should be ignored in synthesis are not supported by the parser and cause a parser error (file a bug report if you encounter this problem)
\end{itemize}
@ -813,10 +852,12 @@ control logic because it is simpler than setting up a commercial flow.
\item When building on other Linux distributions:
\begin{itemize}
\item Needs compiler with some C++11 support
\item See README file for build instructions
\item Post to the subreddit if you get stuck
\end{itemize}
\item Ported to OS X (Darwin) and OpenBSD
\item No win32 support (yet)
\item Native win32 build with VisualStudio
\item Cross win32 build with MXE
\end{itemize}
\end{frame}

View File

@ -89,12 +89,13 @@ left with a much simpler version of RTLIL:
\bigskip
Many commands simply choose to only work on this simpler version:
\begin{lstlisting}[xleftmargin=0.5cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont]
if (module->processes.size() != 0 || module->memories.size() != 0)
log_error("This command does not operate on modules with processes "
"and/or memories! Run 'proc' and 'memory' first.\n");
for (RTLIL::Module *module : design->selected_modules() {
if (module->has_memories_warn() || module->has_processes_warn())
continue;
....
}
\end{lstlisting}
\bigskip
For simplicity we only discuss this version of RTLIL in this presentation.
\end{frame}
@ -122,8 +123,9 @@ has been executed.
\subsection{The RTLIL Data Structures}
\begin{frame}{\subsecname}
The RTLIL data structures are simple structs utilizing C++ {\tt std::}
containers.
The RTLIL data structures are simple structs utilizing {\tt pool<>} and
{\tt dict<>} containers (drop-in replacementments for {\tt
std::unordered\_set<>} and {\tt std::unordered\_map<>}).
\bigskip
\begin{itemize}
@ -145,7 +147,9 @@ See {\tt yosys/kernel/rtlil.h} for details.
\subsubsection{RTLIL::IdString}
\begin{frame}{\subsubsecname}{}
{\tt RTLIL::IdString} is a simple wrapper for {\tt std::string}. It is used for names of RTLIL objects.
{\tt RTLIL::IdString} in many ways behave like a {\tt std::string}. It is used
for names of RTLIL objects. Internally a RTLIL::IdString object is only a
single integer.
\medskip
The first character of a {\tt RTLIL::IdString} specifies if the name is {\it public\/} or {\it private\/}:
@ -168,25 +172,25 @@ Use the {\tt NEW\_ID} macro to create a new unique private name.
\begin{frame}[t, fragile]{\subsubsecname}
The {\tt RTLIL::Design} and {\tt RTLIL::Module} structs are the top-level RTLIL
data structures.
Yosys always operates on one active design, but can hold many designs in memory.
data structures. Yosys always operates on one active design, but can hold many designs in memory.
\bigskip
\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
struct RTLIL::Design {
std::map<RTLIL::IdString, RTLIL::Module*> modules;
dict<RTLIL::IdString, RTLIL::Module*> modules_;
...
};
struct RTLIL::Module {
RTLIL::IdString name;
std::map<RTLIL::IdString, RTLIL::Wire*> wires;
std::map<RTLIL::IdString, RTLIL::Cell*> cells;
std::vector<RTLIL::SigSig> connections;
dict<RTLIL::IdString, RTLIL::Wire*> wires_;
dict<RTLIL::IdString, RTLIL::Cell*> cells_;
std::vector<RTLIL::SigSig> connections_;
...
};
\end{lstlisting}
(Use the various accessor functions instead of directly working with the {\tt *\_} members.)
\end{frame}
\subsubsection{The RTLIL::Wire Structure}
@ -251,21 +255,22 @@ constants are part of the RTLIL representation itself.
\begin{frame}[t, fragile]{\subsubsecname}
The {\tt RTLIL::SigSpec} struct represents a signal vector. Each bit can either be a bit from a wire
or a constant value. Consecutive bits from a wire or consecutive constant bits are consolidated into
a {\tt RTLIL::SigChunk}:
or a constant value.
\bigskip
\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
struct RTLIL::SigChunk {
struct RTLIL::SigBit
{
RTLIL::Wire *wire;
RTLIL::Const data; // only used if wire == NULL
int width, offset;
union {
RTLIL::State data; // used if wire == NULL
int offset; // used if wire != NULL
};
...
};
struct RTLIL::SigSpec {
std::vector<RTLIL::SigChunk> chunks; // LSB at index 0
int width;
std::vector<RTLIL::SigBit> bits_; // LSB at index 0
...
};
\end{lstlisting}
@ -289,8 +294,8 @@ instances:
\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
struct RTLIL::Cell {
RTLIL::IdString name, type;
std::map<RTLIL::IdString, RTLIL::SigSpec> connections;
std::map<RTLIL::IdString, RTLIL::Const> parameters;
dict<RTLIL::IdString, RTLIL::SigSpec> connections_;
dict<RTLIL::IdString, RTLIL::Const> parameters;
...
};
\end{lstlisting}
@ -345,7 +350,7 @@ typedef std::pair<RTLIL::SigSpec, RTLIL::SigSpec> RTLIL::SigSig;
struct RTLIL::Module {
...
std::vector<RTLIL::SigSig> connections;
std::vector<RTLIL::SigSig> connections_;
...
};
\end{lstlisting}
@ -354,8 +359,8 @@ struct RTLIL::Module {
{\tt RTLIL::SigSig::first} is the driven signal and {\tt RTLIL::SigSig::second} is the driving signal.
Example usage (setting wire {\tt foo} to value {\tt 42}):
\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
module->connections.push_back(RTLIL::SigSig(module->wires.at("\\foo"),
RTLIL::SigSpec(42, module->wires.at("\\foo")->width)));
module->connect(module->wire("\\foo"),
RTLIL::SigSpec(42, module->wire("\\foo")->width));
\end{lstlisting}
\end{frame}
@ -378,17 +383,19 @@ endmodule
RTLIL::Module *module = new RTLIL::Module;
module->name = "\\absval";
RTLIL::Wire *a = module->new_wire(4, "\\a");
RTLIL::Wire *a = module->addWire("\\a", 4);
a->port_input = true;
a->port_id = 1;
RTLIL::Wire *y = module->new_wire(4, "\\y");
RTLIL::Wire *y = module->addWire("\\y", 4);
y->port_output = true;
y->port_id = 2;
RTLIL::Wire *a_inv = module->new_wire(4, NEW_ID);
RTLIL::Wire *a_inv = module->addWire(NEW_ID, 4);
module->addNeg(NEW_ID, a, a_inv, true);
module->addMux(NEW_ID, a, a_inv, RTLIL::SigSpec(a, 1, 3), y);
module->fixup_ports();
\end{lstlisting}
\end{frame}
@ -431,8 +438,8 @@ In this case {\tt a}, {\tt x}, and {\tt y} are all different names for the same
\smallskip
\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
RTLIL::SigSpec a(module->wires.at("\\a")), x(module->wires.at("\\x")),
y(module->wires.at("\\y"));
RTLIL::SigSpec a(module->wire("\\a")), x(module->wire("\\x")),
y(module->wire("\\y"));
log("%d %d %d\n", a == x, x == y, y == a); // will print "0 0 0"
\end{lstlisting}
@ -462,9 +469,9 @@ log("Mapped signal x: %s\n", log_signal(sigmap(x)));
\end{lstlisting}
\medskip
Use {\tt RTLIL::id2cstr()} to create a C-string for an {\tt RTLIL::IdString}:
Use {\tt log\_id()} to create a C-string for an {\tt RTLIL::IdString}:
\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
log("Name of this module: %s\n", RTLIL::id2cstr(module->name));
log("Name of this module: %s\n", log_id(module->name));
\end{lstlisting}
\medskip
@ -513,9 +520,8 @@ a new yosys command:
\bigskip
\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont, language=C++]
#include "kernel/rtlil.h"
#include "kernel/register.h"
#include "kernel/log.h"
#include "kernel/yosys.h"
USING_YOSYS_NAMESPACE
struct MyPass : public Pass {
MyPass() : Pass("my_cmd", "just a simple test") { }
@ -526,9 +532,9 @@ struct MyPass : public Pass {
log(" %s\n", arg.c_str());
log("Modules in current design:\n");
for (auto &mod : design->modules)
log(" %s (%zd wires, %zd cells)\n", RTLIL::id2cstr(mod.first),
mod.second->wires.size(), mod.second->cells.size());
for (auto mod : design->modules())
log(" %s (%d wires, %d cells)\n", log_id(mod),
GetSize(mod->wires), GetSize(mod->cells));
}
} MyPass;
\end{lstlisting}
@ -549,6 +555,12 @@ yosys-config --exec --cxx --cxxflags --ldflags \
-o my_cmd.so -shared my_cmd.cc --ldlibs
\end{lstlisting}
\bigskip
Or shorter:
\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont]
yosys-config --build my_cmd.so my_cmd.cc
\end{lstlisting}
\bigskip
Load the plugin using the yosys {\tt -m} option:
\begin{lstlisting}[xleftmargin=1cm, basicstyle=\ttfamily\fontsize{8pt}{10pt}\selectfont]
@ -566,7 +578,7 @@ yosys -m ./my_cmd.so -p 'my_cmd foo bar'
\item \dots and even simpler if you don't need RTLIL::Memory or RTLIL::Process objects.
\bigskip
\item Writing synthesis software? Consider learning the Yosys API and make your stuff
\item Writing synthesis software? Consider learning the Yosys API and make your work
part of the Yosys framework.
\end{itemize}

View File

@ -1 +1,2 @@
my_cmd.so
my_cmd.d

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