aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/issue_template.md16
-rw-r--r--Makefile91
-rw-r--r--README.md22
-rw-r--r--backends/blif/blif.cc68
-rw-r--r--backends/json/json.cc4
-rw-r--r--backends/protobuf/.gitignore2
-rw-r--r--backends/protobuf/Makefile.inc8
-rw-r--r--backends/protobuf/protobuf.cc370
-rw-r--r--backends/smt2/Makefile.inc2
-rw-r--r--backends/smt2/smt2.cc20
-rw-r--r--backends/smt2/smtio.py50
-rw-r--r--backends/verilog/verilog_backend.cc38
-rw-r--r--examples/cmos/counter.ys10
-rw-r--r--frontends/ast/ast.cc29
-rw-r--r--frontends/ast/ast.h2
-rw-r--r--frontends/ast/genrtlil.cc189
-rw-r--r--frontends/ast/simplify.cc228
-rw-r--r--frontends/blif/blifparse.cc40
-rw-r--r--frontends/liberty/liberty.cc36
-rw-r--r--frontends/verific/verific.cc490
-rw-r--r--frontends/verific/verific.h12
-rw-r--r--frontends/verific/verificsva.cc360
-rw-r--r--frontends/verilog/const2ast.cc8
-rw-r--r--frontends/verilog/preproc.cc7
-rw-r--r--frontends/verilog/verilog_frontend.cc31
-rw-r--r--frontends/verilog/verilog_lexer.l13
-rw-r--r--frontends/verilog/verilog_parser.y254
-rw-r--r--kernel/driver.cc70
-rw-r--r--kernel/log.cc92
-rw-r--r--kernel/log.h9
-rw-r--r--kernel/yosys.cc39
-rw-r--r--misc/yosys.proto175
-rw-r--r--passes/cmds/cover.cc2
-rw-r--r--passes/cmds/setundef.cc83
-rw-r--r--passes/cmds/stat.cc8
-rw-r--r--passes/hierarchy/hierarchy.cc74
-rw-r--r--passes/memory/memory_dff.cc20
-rw-r--r--passes/memory/memory_nordff.cc62
-rw-r--r--passes/opt/opt_expr.cc17
-rw-r--r--passes/sat/Makefile.inc1
-rw-r--r--passes/sat/async2sync.cc147
-rw-r--r--passes/sat/expose.cc51
-rw-r--r--passes/sat/sat.cc1
-rw-r--r--passes/techmap/Makefile.inc2
-rw-r--r--passes/techmap/abc.cc40
-rw-r--r--passes/techmap/deminout.cc32
-rw-r--r--passes/techmap/dff2dffe.cc14
-rw-r--r--passes/techmap/dff2dffs.cc142
-rw-r--r--passes/techmap/dfflibmap.cc4
-rw-r--r--passes/techmap/extract_reduce.cc1
-rw-r--r--passes/techmap/iopadmap.cc57
-rw-r--r--passes/techmap/techmap.cc4
-rwxr-xr-xtechlibs/achronix/Makefile.inc2
-rwxr-xr-xtechlibs/achronix/speedster22i/cells_map.v66
-rwxr-xr-xtechlibs/achronix/speedster22i/cells_sim.v85
-rwxr-xr-xtechlibs/achronix/synth_achronix.cc (renamed from techlibs/achronix/synth_speedster.cc)20
-rw-r--r--techlibs/common/prep.cc22
-rw-r--r--techlibs/coolrunner2/Makefile.inc1
-rw-r--r--techlibs/coolrunner2/coolrunner2_sop.cc58
-rw-r--r--techlibs/coolrunner2/synth_coolrunner2.cc13
-rw-r--r--techlibs/coolrunner2/tff_extract.v41
-rw-r--r--techlibs/ecp5/Makefile.inc8
-rw-r--r--techlibs/ecp5/arith_map.v79
-rw-r--r--techlibs/ecp5/cells_map.v135
-rw-r--r--techlibs/ecp5/cells_sim.v448
-rw-r--r--techlibs/ecp5/dram.txt16
-rw-r--r--techlibs/ecp5/drams_map.v28
-rw-r--r--techlibs/ecp5/synth_ecp5.cc331
-rw-r--r--techlibs/ice40/cells_map.v2
-rw-r--r--techlibs/ice40/cells_sim.v72
-rw-r--r--techlibs/ice40/ice40_opt.cc34
-rw-r--r--techlibs/ice40/synth_ice40.cc48
-rw-r--r--techlibs/intel/cyclone10/cells_map.v20
-rw-r--r--techlibs/intel/cycloneiv/cells_map.v20
-rw-r--r--techlibs/intel/cycloneive/arith_map.v51
-rw-r--r--techlibs/intel/cycloneive/cells_map.v21
-rw-r--r--techlibs/intel/cyclonev/cells_map.v75
-rw-r--r--techlibs/intel/max10/cells_map.v24
-rw-r--r--techlibs/intel/synth_intel.cc40
-rw-r--r--techlibs/xilinx/cells_map.v2
-rw-r--r--techlibs/xilinx/synth_xilinx.cc37
-rw-r--r--tests/simple/specify.v31
-rwxr-xr-xtests/tools/autotest.sh4
83 files changed, 4495 insertions, 886 deletions
diff --git a/.github/issue_template.md b/.github/issue_template.md
new file mode 100644
index 000000000..24e91a4e7
--- /dev/null
+++ b/.github/issue_template.md
@@ -0,0 +1,16 @@
+## Steps to reproduce the issue
+
+*Provide instructions for reproducing the issue. Make sure to include
+all neccessary source files. (You can simply drag&drop a .zip file into
+the issue editor.)*
+
+## Expected behavior
+
+*Please describe the behavior you would have expected from the tool.*
+
+## Actual behavior
+
+*Please describe how the behavior you see differs from the expected behavior.*
+
+**Important Note:** Nobody will be able to help you and/or fix the issue if you
+do not provide sufficient information for reproducing the problem.
diff --git a/Makefile b/Makefile
index af29ff414..be266b628 100644
--- a/Makefile
+++ b/Makefile
@@ -15,6 +15,7 @@ ENABLE_EDITLINE := 0
ENABLE_VERIFIC := 0
ENABLE_COVER := 1
ENABLE_LIBYOSYS := 0
+ENABLE_PROTOBUF := 0
# other configuration flags
ENABLE_GPROF := 0
@@ -22,6 +23,9 @@ ENABLE_DEBUG := 0
ENABLE_NDEBUG := 0
LINK_CURSES := 0
LINK_TERMCAP := 0
+LINK_ABC := 0
+# Needed for environments that don't have proper thread support (i.e. emscripten)
+DISABLE_ABC_THREADS := 0
# clang sanitizers
SANITIZER =
@@ -31,6 +35,7 @@ SANITIZER =
# SANITIZER = cfi
+OS := $(shell uname -s)
PREFIX ?= /usr/local
INSTALL_SUDO :=
@@ -66,7 +71,7 @@ SED ?= sed
BISON ?= bison
STRIP ?= strip
-ifeq (Darwin,$(findstring Darwin,$(shell uname)))
+ifeq ($(OS), Darwin)
PLUGIN_LDFLAGS += -undefined dynamic_lookup
# homebrew search paths
@@ -102,9 +107,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 = 6e3c24b3308a
+ABCREV = ae6716b
ABCPULL = 1
-ABCURL ?= https://bitbucket.org/alanmi/abc
+ABCURL ?= https://github.com/berkeley-abc/abc
ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1
# set ABCEXTERNAL = <abc-command> to use an external ABC instance
@@ -125,6 +130,7 @@ ifeq ($(CONFIG),clang)
CXX = clang
LD = clang++
CXXFLAGS += -std=c++11 -Os
+ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H"
ifneq ($(SANITIZER),)
$(info [Clang Sanitizer] $(SANITIZER))
@@ -147,16 +153,19 @@ else ifeq ($(CONFIG),gcc)
CXX = gcc
LD = gcc
CXXFLAGS += -std=c++11 -Os
+ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H"
else ifeq ($(CONFIG),gcc-4.8)
CXX = gcc-4.8
LD = gcc-4.8
CXXFLAGS += -std=c++11 -Os
+ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H"
else ifeq ($(CONFIG),emcc)
CXX = emcc
LD = emcc
CXXFLAGS := -std=c++11 $(filter-out -fPIC -ggdb,$(CXXFLAGS))
+ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H -DABC_MEMALIGN=8"
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']"
@@ -170,6 +179,11 @@ EXE = .js
TARGETS := $(filter-out yosys-config,$(TARGETS))
EXTRA_TARGETS += yosysjs-$(YOSYS_VER).zip
+ifeq ($(ENABLE_ABC),1)
+LINK_ABC := 1
+DISABLE_ABC_THREADS := 1
+endif
+
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
@@ -191,8 +205,8 @@ CXXFLAGS += -std=c++11 -Os -D_POSIX_SOURCE -DYOSYS_MXE_HACKS -Wno-attributes
CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS))
LDFLAGS := $(filter-out -rdynamic,$(LDFLAGS)) -s
LDLIBS := $(filter-out -lrt,$(LDLIBS))
-ABCMKARGS += ARCHFLAGS="-DSIZEOF_VOID_P=4 -DSIZEOF_LONG=4 -DSIZEOF_INT=4 -DWIN32_NO_DLL -DHAVE_STRUCT_TIMESPEC -fpermissive -w"
-ABCMKARGS += LIBS="lib/x86/pthreadVC2.lib -s" ABC_USE_NO_READLINE=1 CC="$(CXX)" CXX="$(CXX)"
+ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H -DWIN32_NO_DLL -DHAVE_STRUCT_TIMESPEC -fpermissive -w"
+ABCMKARGS += LIBS="lib/x86/pthreadVC2.lib -s" ABC_USE_NO_READLINE=1
EXE = .exe
else ifeq ($(CONFIG),msys2)
@@ -202,8 +216,8 @@ CXXFLAGS += -std=c++11 -Os -D_POSIX_SOURCE -DYOSYS_WIN32_UNIX_DIR
CXXFLAGS := $(filter-out -fPIC,$(CXXFLAGS))
LDFLAGS := $(filter-out -rdynamic,$(LDFLAGS)) -s
LDLIBS := $(filter-out -lrt,$(LDLIBS))
-ABCMKARGS += ARCHFLAGS="-DSIZEOF_VOID_P=4 -DSIZEOF_LONG=4 -DSIZEOF_INT=4 -DWIN32_NO_DLL -DHAVE_STRUCT_TIMESPEC -fpermissive -w"
-ABCMKARGS += LIBS="lib/x86/pthreadVC2.lib -s" ABC_USE_NO_READLINE=0 CC="i686-w64-mingw32-gcc" CXX="$(CXX)"
+ABCMKARGS += ARCHFLAGS="-DABC_USE_STDINT_H -DWIN32_NO_DLL -DHAVE_STRUCT_TIMESPEC -fpermissive -w"
+ABCMKARGS += LIBS="lib/x86/pthreadVC2.lib -s" ABC_USE_NO_READLINE=0
EXE = .exe
else ifneq ($(CONFIG),none)
@@ -216,6 +230,9 @@ endif
ifeq ($(ENABLE_READLINE),1)
CXXFLAGS += -DYOSYS_ENABLE_READLINE
+ifeq ($(OS), FreeBSD)
+CXXFLAGS += -I/usr/local/include
+endif
LDLIBS += -lreadline
ifeq ($(LINK_CURSES),1)
LDLIBS += -lcurses
@@ -232,26 +249,44 @@ else
ifeq ($(ENABLE_EDITLINE),1)
CXXFLAGS += -DYOSYS_ENABLE_EDITLINE
LDLIBS += -ledit -ltinfo -lbsd
+else
+ABCMKARGS += "ABC_USE_NO_READLINE=1"
endif
endif
+ifeq ($(DISABLE_ABC_THREADS),1)
+ABCMKARGS += "ABC_USE_NO_PTHREADS=1"
+endif
+
ifeq ($(ENABLE_PLUGINS),1)
CXXFLAGS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --cflags libffi) -DYOSYS_ENABLE_PLUGINS
-LDLIBS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --libs libffi || echo -lffi) -ldl
+LDLIBS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --libs libffi || echo -lffi)
+ifneq ($(OS), FreeBSD)
+LDLIBS += -ldl
+endif
endif
ifeq ($(ENABLE_TCL),1)
TCL_VERSION ?= tcl$(shell bash -c "tclsh <(echo 'puts [info tclversion]')")
+ifeq ($(OS), FreeBSD)
+TCL_INCLUDE ?= /usr/local/include/$(TCL_VERSION)
+else
TCL_INCLUDE ?= /usr/include/$(TCL_VERSION)
+endif
ifeq ($(CONFIG),mxe)
CXXFLAGS += -DYOSYS_ENABLE_TCL
-LDLIBS += -ltcl86 -lwsock32 -lws2_32 -lnetapi32
+LDLIBS += -ltcl86 -lwsock32 -lws2_32 -lnetapi32 -lz
else
CXXFLAGS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --cflags tcl || echo -I$(TCL_INCLUDE)) -DYOSYS_ENABLE_TCL
+ifeq ($(OS), FreeBSD)
+# FreeBSD uses tcl8.6, but lib is named "libtcl86"
+LDLIBS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --libs tcl || echo -l$(TCL_VERSION) | tr -d '.')
+else
LDLIBS += $(shell PKG_CONFIG_PATH=$(PKG_CONFIG_PATH) $(PKG_CONFIG) --silence-errors --libs tcl || echo -l$(TCL_VERSION))
endif
endif
+endif
ifeq ($(ENABLE_GPROF),1)
CXXFLAGS += -pg
@@ -272,10 +307,17 @@ endif
ifeq ($(ENABLE_ABC),1)
CXXFLAGS += -DYOSYS_ENABLE_ABC
+ifeq ($(LINK_ABC),1)
+CXXFLAGS += -DYOSYS_LINK_ABC
+ifeq ($(DISABLE_ABC_THREADS),0)
+LDLIBS += -lpthread
+endif
+else
ifeq ($(ABCEXTERNAL),)
TARGETS += yosys-abc$(EXE)
endif
endif
+endif
ifeq ($(ENABLE_VERIFIC),1)
VERIFIC_DIR ?= /usr/local/src/verific_lib_eval
@@ -284,6 +326,10 @@ CXXFLAGS += $(patsubst %,-I$(VERIFIC_DIR)/%,$(VERIFIC_COMPONENTS)) -DYOSYS_ENABL
LDLIBS += $(patsubst %,$(VERIFIC_DIR)/%/*-linux.a,$(VERIFIC_COMPONENTS)) -lz
endif
+ifeq ($(ENABLE_PROTOBUF),1)
+LDLIBS += $(shell pkg-config --cflags --libs protobuf)
+endif
+
ifeq ($(ENABLE_COVER),1)
CXXFLAGS += -DYOSYS_ENABLE_COVER
endif
@@ -395,6 +441,10 @@ include techlibs/common/Makefile.inc
endif
+ifeq ($(LINK_ABC),1)
+OBJS += yosys-libabc.a
+endif
+
top-all: $(TARGETS) $(EXTRA_TARGETS)
@echo ""
@echo " Build successful."
@@ -439,29 +489,36 @@ yosys-config: misc/yosys-config.in
-e 's#@BINDIR@#$(strip $(BINDIR))#;' -e 's#@DATDIR@#$(strip $(DATDIR))#;' < $< > yosys-config
$(Q) chmod +x yosys-config
-abc/abc-$(ABCREV)$(EXE):
+abc/abc-$(ABCREV)$(EXE) abc/libabc-$(ABCREV).a:
$(P)
ifneq ($(ABCREV),default)
- $(Q) if ( cd abc 2> /dev/null && hg identify; ) | grep -q +; then \
+ $(Q) if test -d abc/.hg; then \
+ echo 'REEBE: NOP qverpgbel vf n ut jbexvat pbcl! Erzbir nop/ naq er-eha "znxr".' | tr 'A-Za-z' 'N-ZA-Mn-za-m'; false; \
+ fi
+ $(Q) if ( cd abc 2> /dev/null && ! git diff-index --quiet HEAD; ); then \
echo 'REEBE: NOP pbagnvaf ybpny zbqvsvpngvbaf! Frg NOPERI=qrsnhyg va Lbflf Znxrsvyr!' | tr 'A-Za-z' 'N-ZA-Mn-za-m'; false; \
fi
- $(Q) if test "`cd abc 2> /dev/null && hg identify | cut -f1 -d' '`" != "$(ABCREV)"; then \
+ $(Q) if test "`cd abc 2> /dev/null && git rev-parse --short HEAD`" != "$(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 $(ABCURL):"; set -x; \
- test -d abc || hg clone --insecure $(ABCURL) abc; \
- cd abc && $(MAKE) DEP= clean && hg pull --insecure && hg update -r $(ABCREV); \
+ test -d abc || git clone $(ABCURL) abc; \
+ cd abc && $(MAKE) DEP= clean && git fetch origin master && git checkout $(ABCREV); \
fi
endif
$(Q) rm -f abc/abc-[0-9a-f]*
- $(Q) cd abc && $(MAKE) $(S) $(ABCMKARGS) PROG="abc-$(ABCREV)$(EXE)" MSG_PREFIX="$(eval P_OFFSET = 5)$(call P_SHOW)$(eval P_OFFSET = 10) ABC: "
+ $(Q) cd abc && $(MAKE) $(S) $(ABCMKARGS) $(if $(filter %.a,$@),PROG="abc-$(ABCREV)",PROG="abc-$(ABCREV)$(EXE)") MSG_PREFIX="$(eval P_OFFSET = 5)$(call P_SHOW)$(eval P_OFFSET = 10) ABC: " $(if $(filter %.a,$@),libabc-$(ABCREV).a)
ifeq ($(ABCREV),default)
.PHONY: abc/abc-$(ABCREV)$(EXE)
+.PHONY: abc/libabc-$(ABCREV).a
endif
yosys-abc$(EXE): abc/abc-$(ABCREV)$(EXE)
$(P) cp abc/abc-$(ABCREV)$(EXE) yosys-abc$(EXE)
+yosys-libabc.a: abc/libabc-$(ABCREV).a
+ $(P) cp abc/libabc-$(ABCREV).a yosys-libabc.a
+
ifneq ($(SEED),)
SEEDOPT="-S $(SEED)"
else
@@ -545,7 +602,7 @@ clean:
rm -rf share
if test -d manual; then cd manual && sh clean.sh; fi
rm -f $(OBJS) $(GENFILES) $(TARGETS) $(EXTRA_TARGETS) $(EXTRA_OBJS)
- rm -f kernel/version_*.o kernel/version_*.cc abc/abc-[0-9a-f]*
+ rm -f kernel/version_*.o kernel/version_*.cc abc/abc-[0-9a-f]* abc/libabc-[0-9a-f]*.a
rm -f libs/*/*.d frontends/*/*.d passes/*/*.d backends/*/*.d kernel/*.d techlibs/*/*.d
rm -rf tests/asicworld/*.out tests/asicworld/*.log
rm -rf tests/hana/*.out tests/hana/*.log
@@ -558,7 +615,7 @@ clean:
clean-abc:
$(MAKE) -C abc DEP= clean
- rm -f yosys-abc$(EXE) abc/abc-[0-9a-f]*
+ rm -f yosys-abc$(EXE) yosys-libabc.a abc/abc-[0-9a-f]* abc/libabc-[0-9a-f]*.a
mrproper: clean
git clean -xdf
diff --git a/README.md b/README.md
index 514d8e2f7..424d9bbf2 100644
--- a/README.md
+++ b/README.md
@@ -52,14 +52,22 @@ For example on Ubuntu Linux 16.04 LTS the following commands will install all
prerequisites for building yosys:
$ sudo apt-get install build-essential clang bison flex \
- libreadline-dev gawk tcl-dev libffi-dev git mercurial \
+ libreadline-dev gawk tcl-dev libffi-dev git \
graphviz xdot pkg-config python3
Similarily, on Mac OS X MacPorts or Homebrew can be used to install dependencies:
$ brew tap Homebrew/bundle && brew bundle
$ sudo port install bison flex readline gawk libffi \
- git mercurial graphviz pkgconfig python36
+ git graphviz pkgconfig python36
+
+On FreeBSD use the following command to install all prerequisites:
+
+ # pkg install bison flex readline gawk libffi\
+ git graphviz pkgconfig python3 python36 tcl-wrapper
+
+On FreeBSD system use gmake instead of make. To run tests use:
+ % MAKE=gmake CC=cc gmake test
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
@@ -381,7 +389,7 @@ Verilog Attributes and non-standard features
Non-standard or SystemVerilog features for formal verification
==============================================================
-- Support for ``assert``, ``assume``, ``restrict``, and ``cover'' is enabled
+- Support for ``assert``, ``assume``, ``restrict``, and ``cover`` is enabled
when ``read_verilog`` is called with ``-formal``.
- The system task ``$initstate`` evaluates to 1 in the initial state and
@@ -402,11 +410,17 @@ Non-standard or SystemVerilog features for formal verification
statements it is sufficient if just one ``$allconst/$allseq`` value triggers
the property (similar to ``$anyconst/$anyseq``).
+- Wires/registers decalred using the ``anyconst/anyseq/allconst/allseq`` attribute
+ (for example ``(* anyconst *) reg [7:0] foobar;``) will behave as if driven
+ by a ``$anyconst/$anyseq/$allconst/$allseq`` function.
+
- The SystemVerilog tasks ``$past``, ``$stable``, ``$rose`` and ``$fell`` are
supported in any clocked block.
- The syntax ``@($global_clock)`` can be used to create FFs that have no
- explicit clock input ($ff cells).
+ explicit clock input ($ff cells). The same can be achieved by using
+ ``@(posedge <netname>)`` or ``@(negedge <netname>)`` when ``<netname>``
+ is marked with the ``(* gclk *)`` Verilog attribute.
Supported features from SystemVerilog
diff --git a/backends/blif/blif.cc b/backends/blif/blif.cc
index f9230a1e6..e4509e0d0 100644
--- a/backends/blif/blif.cc
+++ b/backends/blif/blif.cc
@@ -38,8 +38,10 @@ struct BlifDumperConfig
bool impltf_mode;
bool gates_mode;
bool cname_mode;
+ bool iname_mode;
bool param_mode;
bool attr_mode;
+ bool iattr_mode;
bool blackbox_mode;
bool noalias_mode;
@@ -48,7 +50,8 @@ struct BlifDumperConfig
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),
- cname_mode(false), param_mode(false), attr_mode(false), blackbox_mode(false), noalias_mode(false) { }
+ cname_mode(false), iname_mode(false), param_mode(false), attr_mode(false), iattr_mode(false),
+ blackbox_mode(false), noalias_mode(false) { }
};
struct BlifDumper
@@ -240,118 +243,118 @@ struct BlifDumper
if (!config->icells_mode && cell->type == "$_NOT_") {
f << stringf(".names %s %s\n0 1\n",
cstr(cell->getPort("\\A")), cstr(cell->getPort("\\Y")));
- continue;
+ goto internal_cell;
}
if (!config->icells_mode && cell->type == "$_AND_") {
f << stringf(".names %s %s %s\n11 1\n",
cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), cstr(cell->getPort("\\Y")));
- continue;
+ goto internal_cell;
}
if (!config->icells_mode && cell->type == "$_OR_") {
f << stringf(".names %s %s %s\n1- 1\n-1 1\n",
cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), cstr(cell->getPort("\\Y")));
- continue;
+ goto internal_cell;
}
if (!config->icells_mode && cell->type == "$_XOR_") {
f << stringf(".names %s %s %s\n10 1\n01 1\n",
cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), cstr(cell->getPort("\\Y")));
- continue;
+ goto internal_cell;
}
if (!config->icells_mode && cell->type == "$_NAND_") {
f << stringf(".names %s %s %s\n0- 1\n-0 1\n",
cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), cstr(cell->getPort("\\Y")));
- continue;
+ goto internal_cell;
}
if (!config->icells_mode && cell->type == "$_NOR_") {
f << stringf(".names %s %s %s\n00 1\n",
cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), cstr(cell->getPort("\\Y")));
- continue;
+ goto internal_cell;
}
if (!config->icells_mode && cell->type == "$_XNOR_") {
f << stringf(".names %s %s %s\n11 1\n00 1\n",
cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), cstr(cell->getPort("\\Y")));
- continue;
+ goto internal_cell;
}
if (!config->icells_mode && cell->type == "$_ANDNOT_") {
f << stringf(".names %s %s %s\n10 1\n",
cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), cstr(cell->getPort("\\Y")));
- continue;
+ goto internal_cell;
}
if (!config->icells_mode && cell->type == "$_ORNOT_") {
f << stringf(".names %s %s %s\n1- 1\n-0 1\n",
cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), cstr(cell->getPort("\\Y")));
- continue;
+ goto internal_cell;
}
if (!config->icells_mode && cell->type == "$_AOI3_") {
f << stringf(".names %s %s %s %s\n-00 1\n0-0 1\n",
cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), cstr(cell->getPort("\\C")), cstr(cell->getPort("\\Y")));
- continue;
+ goto internal_cell;
}
if (!config->icells_mode && cell->type == "$_OAI3_") {
f << stringf(".names %s %s %s %s\n00- 1\n--0 1\n",
cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")), cstr(cell->getPort("\\C")), cstr(cell->getPort("\\Y")));
- continue;
+ goto internal_cell;
}
if (!config->icells_mode && cell->type == "$_AOI4_") {
f << stringf(".names %s %s %s %s %s\n-0-0 1\n-00- 1\n0--0 1\n0-0- 1\n",
cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")),
cstr(cell->getPort("\\C")), cstr(cell->getPort("\\D")), cstr(cell->getPort("\\Y")));
- continue;
+ goto internal_cell;
}
if (!config->icells_mode && cell->type == "$_OAI4_") {
f << stringf(".names %s %s %s %s %s\n00-- 1\n--00 1\n",
cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")),
cstr(cell->getPort("\\C")), cstr(cell->getPort("\\D")), cstr(cell->getPort("\\Y")));
- continue;
+ goto internal_cell;
}
if (!config->icells_mode && cell->type == "$_MUX_") {
f << stringf(".names %s %s %s %s\n1-0 1\n-11 1\n",
cstr(cell->getPort("\\A")), cstr(cell->getPort("\\B")),
cstr(cell->getPort("\\S")), cstr(cell->getPort("\\Y")));
- continue;
+ goto internal_cell;
}
if (!config->icells_mode && cell->type == "$_FF_") {
f << stringf(".latch %s %s%s\n", cstr(cell->getPort("\\D")), cstr(cell->getPort("\\Q")),
cstr_init(cell->getPort("\\Q")));
- continue;
+ goto internal_cell;
}
if (!config->icells_mode && cell->type == "$_DFF_N_") {
f << stringf(".latch %s %s fe %s%s\n", cstr(cell->getPort("\\D")), cstr(cell->getPort("\\Q")),
cstr(cell->getPort("\\C")), cstr_init(cell->getPort("\\Q")));
- continue;
+ goto internal_cell;
}
if (!config->icells_mode && cell->type == "$_DFF_P_") {
f << stringf(".latch %s %s re %s%s\n", cstr(cell->getPort("\\D")), cstr(cell->getPort("\\Q")),
cstr(cell->getPort("\\C")), cstr_init(cell->getPort("\\Q")));
- continue;
+ goto internal_cell;
}
if (!config->icells_mode && cell->type == "$_DLATCH_N_") {
f << stringf(".latch %s %s al %s%s\n", cstr(cell->getPort("\\D")), cstr(cell->getPort("\\Q")),
cstr(cell->getPort("\\E")), cstr_init(cell->getPort("\\Q")));
- continue;
+ goto internal_cell;
}
if (!config->icells_mode && cell->type == "$_DLATCH_P_") {
f << stringf(".latch %s %s ah %s%s\n", cstr(cell->getPort("\\D")), cstr(cell->getPort("\\Q")),
cstr(cell->getPort("\\E")), cstr_init(cell->getPort("\\Q")));
- continue;
+ goto internal_cell;
}
if (!config->icells_mode && cell->type == "$lut") {
@@ -373,7 +376,7 @@ struct BlifDumper
}
f << " 1\n";
}
- continue;
+ goto internal_cell;
}
if (!config->icells_mode && cell->type == "$sop") {
@@ -401,7 +404,7 @@ struct BlifDumper
}
f << " 1\n";
}
- continue;
+ goto internal_cell;
}
f << stringf(".%s %s", subckt_or_gate(cell->type.str()), cstr(cell->type));
@@ -421,6 +424,14 @@ struct BlifDumper
dump_params(".attr", cell->attributes);
if (config->param_mode)
dump_params(".param", cell->parameters);
+
+ if (0) {
+ internal_cell:
+ if (config->iname_mode)
+ f << stringf(".cname %s\n", cstr(cell->name));
+ if (config->iattr_mode)
+ dump_params(".attr", cell->attributes);
+ }
}
for (auto &conn : module->connections())
@@ -511,6 +522,11 @@ struct BlifBackend : public Backend {
log(" -cname\n");
log(" use the non-standard .cname statement to write cell names\n");
log("\n");
+ log(" -iname, -iattr\n");
+ log(" enable -cname and -attr functionality for .names statements\n");
+ log(" (the .cname and .attr statements will be included in the BLIF\n");
+ log(" output after the truth table for the .names statement)\n");
+ log("\n");
log(" -blackbox\n");
log(" write blackbox cells with .blackbox statement.\n");
log("\n");
@@ -587,6 +603,14 @@ struct BlifBackend : public Backend {
config.attr_mode = true;
continue;
}
+ if (args[argidx] == "-iname") {
+ config.iname_mode = true;
+ continue;
+ }
+ if (args[argidx] == "-iattr") {
+ config.iattr_mode = true;
+ continue;
+ }
if (args[argidx] == "-blackbox") {
config.blackbox_mode = true;
continue;
diff --git a/backends/json/json.cc b/backends/json/json.cc
index d3b7077a2..1a3ca64a3 100644
--- a/backends/json/json.cc
+++ b/backends/json/json.cc
@@ -93,8 +93,10 @@ struct JsonWriter
f << get_string(param.second.decode_string());
else if (GetSize(param.second.bits) > 32)
f << get_string(param.second.as_string());
- else
+ else if ((param.second.flags & RTLIL::ConstFlags::CONST_FLAG_SIGNED) != 0)
f << stringf("%d", param.second.as_int());
+ else
+ f << stringf("%u", param.second.as_int());
first = false;
}
}
diff --git a/backends/protobuf/.gitignore b/backends/protobuf/.gitignore
new file mode 100644
index 000000000..849b38d45
--- /dev/null
+++ b/backends/protobuf/.gitignore
@@ -0,0 +1,2 @@
+yosys.pb.cc
+yosys.pb.h
diff --git a/backends/protobuf/Makefile.inc b/backends/protobuf/Makefile.inc
new file mode 100644
index 000000000..834cad42c
--- /dev/null
+++ b/backends/protobuf/Makefile.inc
@@ -0,0 +1,8 @@
+ifeq ($(ENABLE_PROTOBUF),1)
+
+backends/protobuf/yosys.pb.cc backends/protobuf/yosys.pb.h: misc/yosys.proto
+ $(Q) cd misc && protoc --cpp_out "../backends/protobuf" yosys.proto
+
+OBJS += backends/protobuf/protobuf.o backends/protobuf/yosys.pb.o
+
+endif
diff --git a/backends/protobuf/protobuf.cc b/backends/protobuf/protobuf.cc
new file mode 100644
index 000000000..9a6fedee7
--- /dev/null
+++ b/backends/protobuf/protobuf.cc
@@ -0,0 +1,370 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2018 Serge Bazanski <q3k@symbioticeda.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include <google/protobuf/text_format.h>
+
+#include "kernel/rtlil.h"
+#include "kernel/register.h"
+#include "kernel/sigtools.h"
+#include "kernel/celltypes.h"
+#include "kernel/cellaigs.h"
+#include "kernel/log.h"
+#include "yosys.pb.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct ProtobufDesignSerializer
+{
+ bool aig_mode_;
+ bool use_selection_;
+ yosys::pb::Design *pb_;
+
+ Design *design_;
+ Module *module_;
+
+ SigMap sigmap_;
+ int sigidcounter_;
+ dict<SigBit, uint64_t> sigids_;
+ pool<Aig> aig_models_;
+
+
+ ProtobufDesignSerializer(bool use_selection, bool aig_mode) :
+ aig_mode_(aig_mode), use_selection_(use_selection) { }
+
+ string get_name(IdString name)
+ {
+ return RTLIL::unescape_id(name);
+ }
+
+
+ void serialize_parameters(google::protobuf::Map<std::string, yosys::pb::Parameter> *out,
+ const dict<IdString, Const> &parameters)
+ {
+ for (auto &param : parameters) {
+ std::string key = get_name(param.first);
+
+
+ yosys::pb::Parameter pb_param;
+
+ if ((param.second.flags & RTLIL::ConstFlags::CONST_FLAG_STRING) != 0) {
+ pb_param.set_str(param.second.decode_string());
+ } else if (GetSize(param.second.bits) > 64) {
+ pb_param.set_str(param.second.as_string());
+ } else {
+ pb_param.set_int_(param.second.as_int());
+ }
+
+ (*out)[key] = pb_param;
+ }
+ }
+
+ void get_bits(yosys::pb::BitVector *out, SigSpec sig)
+ {
+ for (auto bit : sigmap_(sig)) {
+ auto sig = out->add_signal();
+
+ // Constant driver.
+ if (bit.wire == nullptr) {
+ if (bit == State::S0) sig->set_constant(sig->CONSTANT_DRIVER_LOW);
+ else if (bit == State::S1) sig->set_constant(sig->CONSTANT_DRIVER_HIGH);
+ else if (bit == State::Sz) sig->set_constant(sig->CONSTANT_DRIVER_Z);
+ else sig->set_constant(sig->CONSTANT_DRIVER_X);
+ continue;
+ }
+
+ // Signal - give it a unique identifier.
+ if (sigids_.count(bit) == 0) {
+ sigids_[bit] = sigidcounter_++;
+ }
+ sig->set_id(sigids_[bit]);
+ }
+ }
+
+ void serialize_module(yosys::pb::Module* out, Module *module)
+ {
+ module_ = module;
+ log_assert(module_->design == design_);
+ sigmap_.set(module_);
+ sigids_.clear();
+ sigidcounter_ = 0;
+
+ serialize_parameters(out->mutable_attribute(), module_->attributes);
+
+ for (auto n : module_->ports) {
+ Wire *w = module->wire(n);
+ if (use_selection_ && !module_->selected(w))
+ continue;
+
+ yosys::pb::Module::Port pb_port;
+ pb_port.set_direction(w->port_input ? w->port_output ?
+ yosys::pb::DIRECTION_INOUT : yosys::pb::DIRECTION_INPUT : yosys::pb::DIRECTION_OUTPUT);
+ get_bits(pb_port.mutable_bits(), w);
+ (*out->mutable_port())[get_name(n)] = pb_port;
+ }
+
+ for (auto c : module_->cells()) {
+ if (use_selection_ && !module_->selected(c))
+ continue;
+
+ yosys::pb::Module::Cell pb_cell;
+ pb_cell.set_hide_name(c->name[0] == '$');
+ pb_cell.set_type(get_name(c->type));
+
+ if (aig_mode_) {
+ Aig aig(c);
+ if (aig.name.empty())
+ continue;
+ pb_cell.set_model(aig.name);
+ aig_models_.insert(aig);
+ }
+ serialize_parameters(pb_cell.mutable_parameter(), c->parameters);
+ serialize_parameters(pb_cell.mutable_attribute(), c->attributes);
+
+ if (c->known()) {
+ for (auto &conn : c->connections()) {
+ yosys::pb::Direction direction = yosys::pb::DIRECTION_OUTPUT;
+ if (c->input(conn.first))
+ direction = c->output(conn.first) ? yosys::pb::DIRECTION_INOUT : yosys::pb::DIRECTION_INPUT;
+ (*pb_cell.mutable_port_direction())[get_name(conn.first)] = direction;
+ }
+ }
+ for (auto &conn : c->connections()) {
+ yosys::pb::BitVector vec;
+ get_bits(&vec, conn.second);
+ (*pb_cell.mutable_connection())[get_name(conn.first)] = vec;
+ }
+
+ (*out->mutable_cell())[get_name(c->name)] = pb_cell;
+ }
+
+ for (auto w : module_->wires()) {
+ if (use_selection_ && !module_->selected(w))
+ continue;
+
+ auto netname = out->add_netname();
+ netname->set_hide_name(w->name[0] == '$');
+ get_bits(netname->mutable_bits(), w);
+ serialize_parameters(netname->mutable_attributes(), w->attributes);
+ }
+ }
+
+
+ void serialize_models(google::protobuf::Map<string, yosys::pb::Model> *models)
+ {
+ for (auto &aig : aig_models_) {
+ yosys::pb::Model pb_model;
+ for (auto &node : aig.nodes) {
+ auto pb_node = pb_model.add_node();
+ if (node.portbit >= 0) {
+ if (node.inverter) {
+ pb_node->set_type(pb_node->TYPE_NPORT);
+ } else {
+ pb_node->set_type(pb_node->TYPE_PORT);
+ }
+ auto port = pb_node->mutable_port();
+ port->set_portname(log_id(node.portname));
+ port->set_bitindex(node.portbit);
+ } else if (node.left_parent < 0 && node.right_parent < 0) {
+ if (node.inverter) {
+ pb_node->set_type(pb_node->TYPE_TRUE);
+ } else {
+ pb_node->set_type(pb_node->TYPE_FALSE);
+ }
+ } else {
+ if (node.inverter) {
+ pb_node->set_type(pb_node->TYPE_NAND);
+ } else {
+ pb_node->set_type(pb_node->TYPE_AND);
+ }
+ auto gate = pb_node->mutable_gate();
+ gate->set_left(node.left_parent);
+ gate->set_right(node.right_parent);
+ }
+ for (auto &op : node.outports) {
+ auto pb_op = pb_node->add_out_port();
+ pb_op->set_name(log_id(op.first));
+ pb_op->set_bit_index(op.second);
+ }
+ }
+ (*models)[aig.name] = pb_model;
+ }
+ }
+
+ void serialize_design(yosys::pb::Design *pb, Design *design)
+ {
+ GOOGLE_PROTOBUF_VERIFY_VERSION;
+ pb_ = pb;
+ pb_->Clear();
+ pb_->set_creator(yosys_version_str);
+
+ design_ = design;
+ design_->sort();
+
+ auto modules = use_selection_ ? design_->selected_modules() : design_->modules();
+ for (auto mod : modules) {
+ yosys::pb::Module pb_mod;
+ serialize_module(&pb_mod, mod);
+ (*pb->mutable_modules())[mod->name.str()] = pb_mod;
+ }
+
+ serialize_models(pb_->mutable_models());
+ }
+};
+
+struct ProtobufBackend : public Backend {
+ ProtobufBackend(): Backend("protobuf", "write design to a Protocol Buffer file") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" write_protobuf [options] [filename]\n");
+ log("\n");
+ log("Write a JSON netlist of the current design.\n");
+ log("\n");
+ log(" -aig\n");
+ log(" include AIG models for the different gate types\n");
+ log("\n");
+ log(" -text\n");
+ log(" output protobuf in Text/ASCII representation\n");
+ log("\n");
+ log("The schema of the output Protocol Buffer is defined in misc/yosys.pb in the\n");
+ log("Yosys source code distribution.\n");
+ log("\n");
+ }
+ virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
+ {
+ bool aig_mode = false;
+ bool text_mode = false;
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++) {
+ if (args[argidx] == "-aig") {
+ aig_mode = true;
+ continue;
+ }
+ if (args[argidx] == "-text") {
+ text_mode = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(f, filename, args, argidx);
+
+ log_header(design, "Executing Protobuf backend.\n");
+
+ yosys::pb::Design pb;
+ ProtobufDesignSerializer serializer(false, aig_mode);
+ serializer.serialize_design(&pb, design);
+
+ if (text_mode) {
+ string out;
+ google::protobuf::TextFormat::PrintToString(pb, &out);
+ *f << out;
+ } else {
+ pb.SerializeToOstream(f);
+ }
+ }
+} ProtobufBackend;
+
+struct ProtobufPass : public Pass {
+ ProtobufPass() : Pass("protobuf", "write design in Protobuf format") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" protobuf [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(" -aig\n");
+ log(" include AIG models for the different gate types\n");
+ log("\n");
+ log(" -text\n");
+ log(" output protobuf in Text/ASCII representation\n");
+ log("\n");
+ log("The schema of the output Protocol Buffer is defined in misc/yosys.pb in the\n");
+ log("Yosys source code distribution.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ std::string filename;
+ bool aig_mode = false;
+ bool text_mode = false;
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-o" && argidx+1 < args.size()) {
+ filename = args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-aig") {
+ aig_mode = true;
+ continue;
+ }
+ if (args[argidx] == "-text") {
+ text_mode = true;
+ 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;
+ }
+
+ yosys::pb::Design pb;
+ ProtobufDesignSerializer serializer(true, aig_mode);
+ serializer.serialize_design(&pb, design);
+
+ if (text_mode) {
+ string out;
+ google::protobuf::TextFormat::PrintToString(pb, &out);
+ *f << out;
+ } else {
+ pb.SerializeToOstream(f);
+ }
+
+ if (!filename.empty()) {
+ delete f;
+ } else {
+ log("%s", buf.str().c_str());
+ }
+ }
+} ProtobufPass;
+
+PRIVATE_NAMESPACE_END;
diff --git a/backends/smt2/Makefile.inc b/backends/smt2/Makefile.inc
index eacda2734..dce82f01a 100644
--- a/backends/smt2/Makefile.inc
+++ b/backends/smt2/Makefile.inc
@@ -6,7 +6,7 @@ ifneq ($(CONFIG),emcc)
TARGETS += yosys-smtbmc
yosys-smtbmc: backends/smt2/smtbmc.py
- $(P) sed 's|##yosys-sys-path##|sys.path += [os.path.dirname(__file__) + p for p in ["/share/python3", "/../share/yosys/python3"]]|;' < $< > $@.new
+ $(P) sed 's|##yosys-sys-path##|sys.path += [os.path.dirname(os.path.realpath(__file__)) + p for p in ["/share/python3", "/../share/yosys/python3"]]|;' < $< > $@.new
$(Q) chmod +x $@.new
$(Q) mv $@.new $@
diff --git a/backends/smt2/smt2.cc b/backends/smt2/smt2.cc
index 47c993d05..ca1ceacc7 100644
--- a/backends/smt2/smt2.cc
+++ b/backends/smt2/smt2.cc
@@ -135,6 +135,24 @@ struct Smt2Worker
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));
+ if (cell->type.in("$mem") && conn.first.in("\\RD_CLK", "\\WR_CLK"))
+ {
+ SigSpec clk = sigmap(conn.second);
+ for (int i = 0; i < GetSize(clk); i++)
+ {
+ if (clk[i].wire == nullptr)
+ continue;
+
+ if (cell->getParam(conn.first == "\\RD_CLK" ? "\\RD_CLK_ENABLE" : "\\WR_CLK_ENABLE")[i] != State::S1)
+ continue;
+
+ if (cell->getParam(conn.first == "\\RD_CLK" ? "\\RD_CLK_POLARITY" : "\\WR_CLK_POLARITY")[i] == State::S1)
+ clock_posedge.insert(clk[i]);
+ else
+ clock_negedge.insert(clk[i]);
+ }
+ }
+ else
if (cell->type.in("$dff", "$_DFF_P_", "$_DFF_N_") && conn.first.in("\\CLK", "\\C"))
{
bool posedge = (cell->type == "$_DFF_N_") || (cell->type == "$dff" && cell->getParam("\\CLK_POLARITY").as_bool());
@@ -748,7 +766,7 @@ struct Smt2Worker
if (statebv)
makebits(stringf("%s_h %s", get_id(module), get_id(cell->name)), mod_stbv_width.at(cell->type));
- if (statedt)
+ else if (statedt)
dtmembers.push_back(stringf(" (|%s_h %s| |%s_s|)\n",
get_id(module), get_id(cell->name), get_id(cell->type)));
else
diff --git a/backends/smt2/smtio.py b/backends/smt2/smtio.py
index 1d5c89d8e..1a8d2484c 100644
--- a/backends/smt2/smtio.py
+++ b/backends/smt2/smtio.py
@@ -218,7 +218,7 @@ class SmtIo:
def timestamp(self):
secs = int(time() - self.start_time)
- return "## %6d %3d:%02d:%02d " % (secs, secs // (60*60), (secs // 60) % 60, secs % 60)
+ return "## %3d:%02d:%02d " % (secs // (60*60), (secs // 60) % 60, secs % 60)
def replace_in_stmt(self, stmt, pat, repl):
if stmt == pat:
@@ -294,20 +294,21 @@ class SmtIo:
def p_read(self):
assert self.p is not None
- assert self.p_running
if self.p_next is not None:
data = self.p_next
self.p_next = None
return data
+ if not self.p_running:
+ return ""
return self.p_queue.get()
- def p_poll(self):
+ def p_poll(self, timeout=0.1):
assert self.p is not None
assert self.p_running
if self.p_next is not None:
return False
try:
- self.p_next = self.p_queue.get(True, 0.1)
+ self.p_next = self.p_queue.get(True, timeout)
return False
except Empty:
return True
@@ -580,12 +581,12 @@ class SmtIo:
if count_brackets == 0:
break
if self.solver != "dummy" and self.p.poll():
- print("SMT Solver terminated unexpectedly: %s" % "".join(stmt), flush=True)
+ print("%s Solver terminated unexpectedly: %s" % (self.timestamp(), "".join(stmt)), flush=True)
sys.exit(1)
stmt = "".join(stmt)
if stmt.startswith("(error"):
- print("SMT Solver Error: %s" % stmt, file=sys.stderr, flush=True)
+ print("%s Solver Error: %s" % (self.timestamp(), stmt), flush=True)
if self.solver != "dummy":
self.p_close()
sys.exit(1)
@@ -645,13 +646,43 @@ class SmtIo:
print("\b \b" * num_bs, end="", file=sys.stderr)
sys.stderr.flush()
+ else:
+ count = 0
+ while self.p_poll(60):
+ count += 1
+ msg = None
+
+ if count == 1:
+ msg = "1 minute"
+
+ elif count in [5, 10, 15, 30]:
+ msg = "%d minutes" % count
+
+ elif count == 60:
+ msg = "1 hour"
+
+ elif count % 60 == 0:
+ msg = "%d hours" % (count // 60)
+
+ if msg is not None:
+ print("%s waiting for solver (%s)" % (self.timestamp(), msg), flush=True)
+
result = self.read()
- assert result in ["sat", "unsat"]
if self.debug_file:
print("(set-info :status %s)" % result, file=self.debug_file)
print("(check-sat)", file=self.debug_file)
self.debug_file.flush()
+
+ if result not in ["sat", "unsat"]:
+ if result == "":
+ print("%s Unexpected EOF response from solver." % (self.timestamp()), flush=True)
+ else:
+ print("%s Unexpected response from solver: %s" % (self.timestamp(), result), flush=True)
+ if self.solver != "dummy":
+ self.p_close()
+ sys.exit(1)
+
return result
def parse(self, stmt):
@@ -706,6 +737,9 @@ class SmtIo:
return h
def bv2bin(self, v):
+ if type(v) is list and len(v) == 3 and v[0] == "_" and v[1].startswith("bv"):
+ x, n = int(v[1][2:]), int(v[2])
+ return "".join("1" if (x & (1 << i)) else "0" for i in range(n-1, -1, -1))
if v == "true": return "1"
if v == "false": return "0"
if v.startswith("#b"):
@@ -981,7 +1015,7 @@ class MkVcd:
for i in range(len(uipath)):
uipath[i] = re.sub(r"\[([^\]]*)\]", r"<\1>", uipath[i])
- while uipath[:len(scope)] != scope[:-1]:
+ while uipath[:len(scope)] != scope:
print("$upscope $end", file=self.f)
scope = scope[:-1]
diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc
index bdf705056..b50dc12af 100644
--- a/backends/verilog/verilog_backend.cc
+++ b/backends/verilog/verilog_backend.cc
@@ -897,6 +897,42 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
return true;
}
+ if (cell->type == "$dlatch")
+ {
+ RTLIL::SigSpec sig_en;
+ bool pol_en = false;
+
+ 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);
+
+ if (!out_is_reg_wire) {
+ f << stringf("%s" "reg [%d:0] %s", indent.c_str(), cell->parameters["\\WIDTH"].as_int()-1, reg_name.c_str());
+ dump_reg_init(f, cell->getPort("\\Q"));
+ f << ";\n";
+ }
+
+ f << stringf("%s" "always @*\n", indent.c_str());
+
+ 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");
+
+ if (!out_is_reg_wire) {
+ f << stringf("%s" "assign ", indent.c_str());
+ dump_sigspec(f, cell->getPort("\\Q"));
+ f << stringf(" = %s;\n", reg_name.c_str());
+ }
+
+ return true;
+ }
+
if (cell->type == "$mem")
{
RTLIL::IdString memid = cell->parameters["\\MEMID"].decode_string();
@@ -1537,6 +1573,8 @@ struct VerilogBackend : public Backend {
reg_ct.insert("$dff");
reg_ct.insert("$adff");
+ reg_ct.insert("$dffe");
+ reg_ct.insert("$dlatch");
reg_ct.insert("$_DFF_N_");
reg_ct.insert("$_DFF_P_");
diff --git a/examples/cmos/counter.ys b/examples/cmos/counter.ys
index a784f3465..d0b093667 100644
--- a/examples/cmos/counter.ys
+++ b/examples/cmos/counter.ys
@@ -1,11 +1,12 @@
-
read_verilog counter.v
read_verilog -lib cmos_cells.v
-proc;; memory;; techmap;;
-
+synth
dfflibmap -liberty cmos_cells.lib
-abc -liberty cmos_cells.lib;;
+abc -liberty cmos_cells.lib
+opt_clean
+
+stat -liberty cmos_cells.lib
# http://vlsiarch.ecen.okstate.edu/flows/MOSIS_SCMOS/latest/cadence/lib/tsmc025/signalstorm/osu025_stdcells.lib
# dfflibmap -liberty osu025_stdcells.lib
@@ -13,4 +14,3 @@ abc -liberty cmos_cells.lib;;
write_verilog synth.v
write_spice synth.sp
-
diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc
index b8f25e53e..7c72a50d9 100644
--- a/frontends/ast/ast.cc
+++ b/frontends/ast/ast.cc
@@ -171,8 +171,8 @@ bool AstNode::get_bool_attribute(RTLIL::IdString id)
AstNode *attr = attributes.at(id);
if (attr->type != AST_CONSTANT)
- log_error("Attribute `%s' with non-constant value at %s:%d!\n",
- id.c_str(), attr->filename.c_str(), attr->linenum);
+ log_file_error(attr->filename, attr->linenum, "Attribute `%s' with non-constant value!\n",
+ id.c_str());
return attr->integer != 0;
}
@@ -961,8 +961,8 @@ static AstModule* process_module(AstNode *ast, bool defer)
for (auto &attr : ast->attributes) {
if (attr.second->type != AST_CONSTANT)
- log_error("Attribute `%s' with non-constant value at %s:%d!\n",
- attr.first.c_str(), ast->filename.c_str(), ast->linenum);
+ log_file_error(ast->filename, ast->linenum, "Attribute `%s' with non-constant value!\n",
+ attr.first.c_str());
current_module->attributes[attr.first] = attr.second->asAttrConst();
}
for (size_t i = 0; i < ast->children.size(); i++) {
@@ -1009,7 +1009,7 @@ static AstModule* process_module(AstNode *ast, bool defer)
// create AstModule instances for all modules in the AST tree and add them to 'design'
void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool dump_vlog, bool dump_rtlil,
- bool nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool ignore_redef, bool defer, bool autowire)
+ bool nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool nooverwrite, bool overwrite, bool defer, bool autowire)
{
current_ast = ast;
flag_dump_ast1 = dump_ast1;
@@ -1048,12 +1048,20 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump
(*it)->str = "$abstract" + (*it)->str;
if (design->has((*it)->str)) {
- if (!ignore_redef)
- log_error("Re-definition of module `%s' at %s:%d!\n",
+ RTLIL::Module *existing_mod = design->module((*it)->str);
+ if (!nooverwrite && !overwrite && !existing_mod->get_bool_attribute("\\blackbox")) {
+ log_file_error((*it)->filename, (*it)->linenum, "Re-definition of module `%s'!\n",
+ (*it)->str.c_str());
+ } else if (nooverwrite) {
+ log("Ignoring re-definition of module `%s' at %s:%d.\n",
(*it)->str.c_str(), (*it)->filename.c_str(), (*it)->linenum);
- log("Ignoring re-definition of module `%s' at %s:%d!\n",
- (*it)->str.c_str(), (*it)->filename.c_str(), (*it)->linenum);
- continue;
+ continue;
+ } else {
+ log("Replacing existing%s module `%s' at %s:%d.\n",
+ existing_mod->get_bool_attribute("\\blackbox") ? " blackbox" : "",
+ (*it)->str.c_str(), (*it)->filename.c_str(), (*it)->linenum);
+ design->remove(existing_mod);
+ }
}
design->add(process_module(*it, defer));
@@ -1195,4 +1203,3 @@ void AST::use_internal_line_num()
}
YOSYS_NAMESPACE_END
-
diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h
index 8a640b1cc..2f9967c37 100644
--- a/frontends/ast/ast.h
+++ b/frontends/ast/ast.h
@@ -275,7 +275,7 @@ namespace AST
// process an AST tree (ast must point to an AST_DESIGN node) and generate RTLIL code
void process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool dump_vlog, bool dump_rtlil, bool nolatches, bool nomeminit,
- bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool ignore_redef, bool defer, bool autowire);
+ bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool nooverwrite, bool overwrite, bool defer, bool autowire);
// parametric modules are supported directly by the AST library
// therefore we need our own derivate of RTLIL::Module with overloaded virtual functions
diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc
index 57ba9668d..0f7e910f3 100644
--- a/frontends/ast/genrtlil.cc
+++ b/frontends/ast/genrtlil.cc
@@ -55,8 +55,8 @@ static RTLIL::SigSpec uniop2rtlil(AstNode *that, std::string type, int result_wi
if (gen_attributes)
for (auto &attr : that->attributes) {
if (attr.second->type != AST_CONSTANT)
- log_error("Attribute `%s' with non-constant value at %s:%d!\n",
- attr.first.c_str(), that->filename.c_str(), that->linenum);
+ log_file_error(that->filename, that->linenum, "Attribute `%s' with non-constant value!\n",
+ attr.first.c_str());
cell->attributes[attr.first] = attr.second->asAttrConst();
}
@@ -89,8 +89,8 @@ static void widthExtend(AstNode *that, RTLIL::SigSpec &sig, int width, bool is_s
if (that != NULL)
for (auto &attr : that->attributes) {
if (attr.second->type != AST_CONSTANT)
- log_error("Attribute `%s' with non-constant value at %s:%d!\n",
- attr.first.c_str(), that->filename.c_str(), that->linenum);
+ log_file_error(that->filename, that->linenum, "Attribute `%s' with non-constant value!\n",
+ attr.first.c_str());
cell->attributes[attr.first] = attr.second->asAttrConst();
}
@@ -117,8 +117,8 @@ static RTLIL::SigSpec binop2rtlil(AstNode *that, std::string type, int result_wi
for (auto &attr : that->attributes) {
if (attr.second->type != AST_CONSTANT)
- log_error("Attribute `%s' with non-constant value at %s:%d!\n",
- attr.first.c_str(), that->filename.c_str(), that->linenum);
+ log_file_error(that->filename, that->linenum, "Attribute `%s' with non-constant value!\n",
+ attr.first.c_str());
cell->attributes[attr.first] = attr.second->asAttrConst();
}
@@ -152,8 +152,8 @@ static RTLIL::SigSpec mux2rtlil(AstNode *that, const RTLIL::SigSpec &cond, const
for (auto &attr : that->attributes) {
if (attr.second->type != AST_CONSTANT)
- log_error("Attribute `%s' with non-constant value at %s:%d!\n",
- attr.first.c_str(), that->filename.c_str(), that->linenum);
+ log_file_error(that->filename, that->linenum, "Attribute `%s' with non-constant value!\n",
+ attr.first.c_str());
cell->attributes[attr.first] = attr.second->asAttrConst();
}
@@ -207,8 +207,8 @@ struct AST_INTERNAL::ProcessGenerator
proc->name = stringf("$proc$%s:%d$%d", always->filename.c_str(), always->linenum, autoidx++);
for (auto &attr : always->attributes) {
if (attr.second->type != AST_CONSTANT)
- log_error("Attribute `%s' with non-constant value at %s:%d!\n",
- attr.first.c_str(), always->filename.c_str(), always->linenum);
+ log_file_error(always->filename, always->linenum, "Attribute `%s' with non-constant value!\n",
+ attr.first.c_str());
proc->attributes[attr.first] = attr.second->asAttrConst();
}
current_module->processes[proc->name] = proc;
@@ -223,16 +223,22 @@ struct AST_INTERNAL::ProcessGenerator
bool found_global_syncs = false;
bool found_anyedge_syncs = false;
for (auto child : always->children)
+ {
+ if ((child->type == AST_POSEDGE || child->type == AST_NEGEDGE) && GetSize(child->children) == 1 && child->children.at(0)->type == AST_IDENTIFIER &&
+ child->children.at(0)->id2ast && child->children.at(0)->id2ast->type == AST_WIRE && child->children.at(0)->id2ast->get_bool_attribute("\\gclk")) {
+ found_global_syncs = true;
+ }
if (child->type == AST_EDGE) {
if (GetSize(child->children) == 1 && child->children.at(0)->type == AST_IDENTIFIER && child->children.at(0)->str == "\\$global_clock")
found_global_syncs = true;
else
found_anyedge_syncs = true;
}
+ }
if (found_anyedge_syncs) {
if (found_global_syncs)
- log_error("Found non-synthesizable event list at %s:%d!\n", always->filename.c_str(), always->linenum);
+ log_file_error(always->filename, always->linenum, "Found non-synthesizable event list!\n");
log("Note: Assuming pure combinatorial block at %s:%d in\n", always->filename.c_str(), always->linenum);
log("compliance with IEC 62142(E):2005 / IEEE Std. 1364.1(E):2002. Recommending\n");
log("use of @* instead of @(...) for better match of synthesis and simulation.\n");
@@ -242,14 +248,17 @@ struct AST_INTERNAL::ProcessGenerator
bool found_clocked_sync = false;
for (auto child : always->children)
if (child->type == AST_POSEDGE || child->type == AST_NEGEDGE) {
+ if (GetSize(child->children) == 1 && child->children.at(0)->type == AST_IDENTIFIER && child->children.at(0)->id2ast &&
+ child->children.at(0)->id2ast->type == AST_WIRE && child->children.at(0)->id2ast->get_bool_attribute("\\gclk"))
+ continue;
found_clocked_sync = true;
if (found_global_syncs || found_anyedge_syncs)
- log_error("Found non-synthesizable event list at %s:%d!\n", always->filename.c_str(), always->linenum);
+ log_file_error(always->filename, always->linenum, "Found non-synthesizable event list!\n");
RTLIL::SyncRule *syncrule = new RTLIL::SyncRule;
syncrule->type = child->type == AST_POSEDGE ? RTLIL::STp : RTLIL::STn;
syncrule->signal = child->children[0]->genRTLIL();
if (GetSize(syncrule->signal) != 1)
- log_error("Found posedge/negedge event on a signal that is not 1 bit wide at %s:%d!\n", always->filename.c_str(), always->linenum);
+ log_file_error(always->filename, always->linenum, "Found posedge/negedge event on a signal that is not 1 bit wide!\n");
addChunkActions(syncrule->actions, subst_lvalue_from, subst_lvalue_to, true);
proc->syncs.push_back(syncrule);
}
@@ -471,8 +480,8 @@ struct AST_INTERNAL::ProcessGenerator
for (auto &attr : ast->attributes) {
if (attr.second->type != AST_CONSTANT)
- log_error("Attribute `%s' with non-constant value at %s:%d!\n",
- attr.first.c_str(), ast->filename.c_str(), ast->linenum);
+ log_file_error(ast->filename, ast->linenum, "Attribute `%s' with non-constant value!\n",
+ attr.first.c_str());
sw->attributes[attr.first] = attr.second->asAttrConst();
}
@@ -540,12 +549,12 @@ struct AST_INTERNAL::ProcessGenerator
break;
case AST_WIRE:
- log_error("Found wire declaration in block without label at at %s:%d!\n", ast->filename.c_str(), ast->linenum);
+ log_file_error(ast->filename, ast->linenum, "Found wire declaration in block without label!\n");
break;
case AST_PARAMETER:
case AST_LOCALPARAM:
- log_error("Found parameter declaration in block without label at at %s:%d!\n", ast->filename.c_str(), ast->linenum);
+ log_file_error(ast->filename, ast->linenum, "Found parameter declaration in block without label!\n");
break;
case AST_NONE:
@@ -593,7 +602,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
if (id_ast == NULL && current_scope.count(str))
id_ast = current_scope.at(str);
if (!id_ast)
- log_error("Failed to resolve identifier %s for width detection at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Failed to resolve identifier %s for width detection!\n", str.c_str());
if (id_ast->type == AST_PARAMETER || id_ast->type == AST_LOCALPARAM) {
if (id_ast->children.size() > 1 && id_ast->children[1]->range_valid) {
this_width = id_ast->children[1]->range_left - id_ast->children[1]->range_right + 1;
@@ -603,7 +612,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
if (id_ast->children[0]->type == AST_CONSTANT)
this_width = id_ast->children[0]->bits.size();
else
- log_error("Failed to detect width for parameter %s at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Failed to detect width for parameter %s!\n", str.c_str());
if (children.size() != 0)
range = children[0];
} else if (id_ast->type == AST_WIRE || id_ast->type == AST_AUTOWIRE) {
@@ -615,7 +624,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
// log("---\n");
// id_ast->dumpAst(NULL, "decl> ");
// dumpAst(NULL, "ref> ");
- log_error("Failed to detect width of signal access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Failed to detect width of signal access `%s'!\n", str.c_str());
}
} else {
this_width = id_ast->range_left - id_ast->range_right + 1;
@@ -626,10 +635,10 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
this_width = 32;
} else if (id_ast->type == AST_MEMORY) {
if (!id_ast->children[0]->range_valid)
- log_error("Failed to detect width of memory access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Failed to detect width of memory access `%s'!\n", str.c_str());
this_width = id_ast->children[0]->range_left - id_ast->children[0]->range_right + 1;
} else
- log_error("Failed to detect width for identifier %s at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Failed to detect width for identifier %s!\n", str.c_str());
if (range) {
if (range->children.size() == 1)
this_width = 1;
@@ -639,8 +648,8 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
while (left_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { }
while (right_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { }
if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT)
- log_error("Unsupported expression on dynamic range select on signal `%s' at %s:%d!\n",
- str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Unsupported expression on dynamic range select on signal `%s'!\n",
+ str.c_str());
this_width = left_at_zero_ast->integer - right_at_zero_ast->integer + 1;
delete left_at_zero_ast;
delete right_at_zero_ast;
@@ -656,7 +665,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
case AST_TO_BITS:
while (children[0]->simplify(true, false, false, 1, -1, false, false) == true) { }
if (children[0]->type != AST_CONSTANT)
- log_error("Left operand of tobits expression is not constant at %s:%d!\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Left operand of tobits expression is not constant!\n");
children[1]->detectSignWidthWorker(sub_width_hint, sign_hint);
width_hint = max(width_hint, children[0]->bitsAsConst().as_int());
break;
@@ -684,7 +693,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
case AST_REPLICATE:
while (children[0]->simplify(true, false, false, 1, -1, false, true) == true) { }
if (children[0]->type != AST_CONSTANT)
- log_error("Left operand of replicate expression is not constant at %s:%d!\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Left operand of replicate expression is not constant!\n");
children[1]->detectSignWidthWorker(sub_width_hint, sub_sign_hint);
width_hint = max(width_hint, children[0]->bitsAsConst().as_int() * sub_width_hint);
sign_hint = false;
@@ -758,7 +767,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
if (!id2ast->is_signed)
sign_hint = false;
if (!id2ast->children[0]->range_valid)
- log_error("Failed to detect width of memory access `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Failed to detect width of memory access `%s'!\n", str.c_str());
this_width = id2ast->children[0]->range_left - id2ast->children[0]->range_right + 1;
width_hint = max(width_hint, this_width);
break;
@@ -768,8 +777,8 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
if (GetSize(children) == 1) {
while (children[0]->simplify(true, false, false, 1, -1, false, true) == true) { }
if (children[0]->type != AST_CONSTANT)
- log_error("System function %s called with non-const argument at %s:%d!\n",
- RTLIL::unescape_id(str).c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "System function %s called with non-const argument!\n",
+ RTLIL::unescape_id(str).c_str());
width_hint = max(width_hint, int(children[0]->asInt(true)));
}
break;
@@ -790,8 +799,8 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
default:
for (auto f : log_files)
current_ast->dumpAst(f, "verilog-ast> ");
- log_error("Don't know how to detect sign and width for %s node at %s:%d!\n",
- type2str(type).c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Don't know how to detect sign and width for %s node!\n",
+ type2str(type).c_str());
}
if (*found_real)
@@ -854,11 +863,11 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
// create an RTLIL::Wire for an AST_WIRE node
case AST_WIRE: {
if (current_module->wires_.count(str) != 0)
- log_error("Re-definition of signal `%s' at %s:%d!\n",
- str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Re-definition of signal `%s'!\n",
+ str.c_str());
if (!range_valid)
- log_error("Signal `%s' with non-constant width at %s:%d!\n",
- str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Signal `%s' with non-constant width!\n",
+ str.c_str());
log_assert(range_left >= range_right || (range_left == -1 && range_right == 0));
@@ -872,8 +881,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
for (auto &attr : attributes) {
if (attr.second->type != AST_CONSTANT)
- log_error("Attribute `%s' with non-constant value at %s:%d!\n",
- attr.first.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n",
+ attr.first.c_str());
wire->attributes[attr.first] = attr.second->asAttrConst();
}
}
@@ -882,16 +891,16 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
// create an RTLIL::Memory for an AST_MEMORY node
case AST_MEMORY: {
if (current_module->memories.count(str) != 0)
- log_error("Re-definition of memory `%s' at %s:%d!\n",
- str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Re-definition of memory `%s'!\n",
+ str.c_str());
log_assert(children.size() >= 2);
log_assert(children[0]->type == AST_RANGE);
log_assert(children[1]->type == AST_RANGE);
if (!children[0]->range_valid || !children[1]->range_valid)
- log_error("Memory `%s' with non-constant width or size at %s:%d!\n",
- str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Memory `%s' with non-constant width or size!\n",
+ str.c_str());
RTLIL::Memory *memory = new RTLIL::Memory;
memory->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
@@ -908,8 +917,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
for (auto &attr : attributes) {
if (attr.second->type != AST_CONSTANT)
- log_error("Attribute `%s' with non-constant value at %s:%d!\n",
- attr.first.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n",
+ attr.first.c_str());
memory->attributes[attr.first] = attr.second->asAttrConst();
}
}
@@ -928,8 +937,8 @@ 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",
- realvalue, log_signal(sig), filename.c_str(), linenum);
+ log_file_warning(filename, linenum, "converting real value %e to binary %s.\n",
+ realvalue, log_signal(sig));
return sig;
}
@@ -949,25 +958,25 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
wire->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
wire->name = str;
if (flag_autowire)
- log_warning("Identifier `%s' is implicitly declared at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
+ log_file_warning(filename, linenum, "Identifier `%s' is implicitly declared.\n", str.c_str());
else
- log_error("Identifier `%s' is implicitly declared at %s:%d and `default_nettype is set to none.\n", str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Identifier `%s' is implicitly declared and `default_nettype is set to none.\n", str.c_str());
}
else if (id2ast->type == AST_PARAMETER || id2ast->type == AST_LOCALPARAM) {
if (id2ast->children[0]->type != AST_CONSTANT)
- log_error("Parameter %s does not evaluate to constant value at %s:%d!\n",
- str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Parameter %s does not evaluate to constant value!\n",
+ str.c_str());
chunk = RTLIL::Const(id2ast->children[0]->bits);
goto use_const_chunk;
}
else if (!id2ast || (id2ast->type != AST_WIRE && id2ast->type != AST_AUTOWIRE &&
id2ast->type != AST_MEMORY) || current_module->wires_.count(str) == 0)
- log_error("Identifier `%s' doesn't map to any signal at %s:%d!\n",
- str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Identifier `%s' doesn't map to any signal!\n",
+ str.c_str());
if (id2ast->type == AST_MEMORY)
- log_error("Identifier `%s' does map to an unexpanded memory at %s:%d!\n",
- str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Identifier `%s' does map to an unexpanded memory!\n",
+ str.c_str());
wire = current_module->wires_[str];
chunk.wire = wire;
@@ -985,8 +994,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
while (left_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { }
while (right_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { }
if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT)
- log_error("Unsupported expression on dynamic range select on signal `%s' at %s:%d!\n",
- str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Unsupported expression on dynamic range select on signal `%s'!\n",
+ str.c_str());
int width = left_at_zero_ast->integer - right_at_zero_ast->integer + 1;
AstNode *fake_ast = new AstNode(AST_NONE, clone(), children[0]->children.size() >= 2 ?
children[0]->children[1]->clone() : children[0]->children[0]->clone());
@@ -1014,11 +1023,11 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
chunk.offset = (id2ast->range_left - id2ast->range_right + 1) - (chunk.offset + chunk.width);
if (chunk.offset >= source_width || chunk.offset + chunk.width < 0) {
if (chunk.width == 1)
- log_warning("Range select out of bounds on signal `%s' at %s:%d: Setting result bit to undef.\n",
- str.c_str(), filename.c_str(), linenum);
+ log_file_warning(filename, linenum, "Range select out of bounds on signal `%s': Setting result bit to undef.\n",
+ str.c_str());
else
- log_warning("Range select out of bounds on signal `%s' at %s:%d: Setting all %d result bits to undef.\n",
- str.c_str(), filename.c_str(), linenum, chunk.width);
+ log_file_warning(filename, linenum, "Range select out of bounds on signal `%s': Setting all %d result bits to undef.\n",
+ str.c_str(), chunk.width);
chunk = RTLIL::SigChunk(RTLIL::State::Sx, chunk.width);
} else {
if (chunk.width + chunk.offset > source_width) {
@@ -1031,11 +1040,11 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
chunk.offset += add_undef_bits_lsb;
}
if (add_undef_bits_lsb)
- log_warning("Range select out of bounds on signal `%s' at %s:%d: Setting %d LSB bits to undef.\n",
- str.c_str(), filename.c_str(), linenum, add_undef_bits_lsb);
+ log_file_warning(filename, linenum, "Range select out of bounds on signal `%s': Setting %d LSB bits to undef.\n",
+ str.c_str(), add_undef_bits_lsb);
if (add_undef_bits_msb)
- log_warning("Range select out of bounds on signal `%s' at %s:%d: Setting %d MSB bits to undef.\n",
- str.c_str(), filename.c_str(), linenum, add_undef_bits_msb);
+ log_file_warning(filename, linenum, "Range select out of bounds on signal `%s': Setting %d MSB bits to undef.\n",
+ str.c_str(), add_undef_bits_msb);
}
}
}
@@ -1074,7 +1083,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
RTLIL::SigSpec left = children[0]->genRTLIL();
RTLIL::SigSpec right = children[1]->genRTLIL();
if (!left.is_fully_const())
- log_error("Left operand of replicate expression is not constant at %s:%d!\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Left operand of replicate expression is not constant!\n");
int count = left.as_int();
RTLIL::SigSpec sig;
for (int i = 0; i < count; i++)
@@ -1291,6 +1300,9 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(0);
cell->parameters["\\TRANSPARENT"] = RTLIL::Const(0);
+ if (!sign_hint)
+ is_signed = false;
+
return RTLIL::SigSpec(wire);
}
@@ -1310,7 +1322,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
int num_words = 1;
if (type == AST_MEMINIT) {
if (children[2]->type != AST_CONSTANT)
- log_error("Memory init with non-constant word count at %s:%d!\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Memory init with non-constant word count!\n");
num_words = int(children[2]->asInt(false));
cell->parameters["\\WORDS"] = RTLIL::Const(num_words);
}
@@ -1367,8 +1379,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
for (auto &attr : attributes) {
if (attr.second->type != AST_CONSTANT)
- log_error("Attribute `%s' with non-constant value at %s:%d!\n",
- attr.first.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n",
+ attr.first.c_str());
cell->attributes[attr.first] = attr.second->asAttrConst();
}
@@ -1389,10 +1401,10 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
new_left.append(left[i]);
new_right.append(right[i]);
}
- log_warning("Ignoring assignment to constant bits at %s:%d:\n"
- " 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));
+ log_file_warning(filename, linenum, "Ignoring assignment to constant bits:\n"
+ " old assignment: %s = %s\n new assignment: %s = %s.\n",
+ log_signal(left), log_signal(right),
+ log_signal(new_left), log_signal(new_right));
left = new_left;
right = new_right;
}
@@ -1406,8 +1418,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
int port_counter = 0, para_counter = 0;
if (current_module->count_id(str) != 0)
- log_error("Re-definition of cell `%s' at %s:%d!\n",
- str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Re-definition of cell `%s'!\n", str.c_str());
RTLIL::Cell *cell = current_module->addCell(str, "");
cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
@@ -1423,16 +1434,15 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
if (child->type == AST_PARASET) {
IdString paraname = child->str.empty() ? stringf("$%d", ++para_counter) : child->str;
if (child->children[0]->type == AST_REALVALUE) {
- log_warning("Replacing floating point parameter %s.%s = %f with string at %s:%d.\n",
- log_id(cell), log_id(paraname), child->children[0]->realvalue,
- filename.c_str(), linenum);
+ log_file_warning(filename, linenum, "Replacing floating point parameter %s.%s = %f with string.\n",
+ log_id(cell), log_id(paraname), child->children[0]->realvalue);
auto strnode = AstNode::mkconst_str(stringf("%f", child->children[0]->realvalue));
strnode->cloneInto(child->children[0]);
delete strnode;
}
if (child->children[0]->type != AST_CONSTANT)
- log_error("Parameter %s.%s with non-constant value at %s:%d!\n",
- log_id(cell), log_id(paraname), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Parameter %s.%s with non-constant value!\n",
+ log_id(cell), log_id(paraname));
cell->parameters[paraname] = child->children[0]->asParaConst();
continue;
}
@@ -1453,8 +1463,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
}
for (auto &attr : attributes) {
if (attr.second->type != AST_CONSTANT)
- log_error("Attribute `%s' with non-constant value at %s:%d!\n",
- attr.first.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n",
+ attr.first.c_str());
cell->attributes[attr.first] = attr.second->asAttrConst();
}
}
@@ -1481,19 +1491,19 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
int width = width_hint;
if (GetSize(children) > 1)
- log_error("System function %s got %d arguments, expected 1 or 0 at %s:%d.\n",
- RTLIL::unescape_id(str).c_str(), GetSize(children), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "System function %s got %d arguments, expected 1 or 0.\n",
+ RTLIL::unescape_id(str).c_str(), GetSize(children));
if (GetSize(children) == 1) {
if (children[0]->type != AST_CONSTANT)
- log_error("System function %s called with non-const argument at %s:%d!\n",
- RTLIL::unescape_id(str).c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "System function %s called with non-const argument!\n",
+ RTLIL::unescape_id(str).c_str());
width = children[0]->asInt(true);
}
if (width <= 0)
- log_error("Failed to detect width of %s at %s:%d!\n",
- RTLIL::unescape_id(str).c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Failed to detect width of %s!\n",
+ RTLIL::unescape_id(str).c_str());
Cell *cell = current_module->addCell(myid, str.substr(1));
cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
@@ -1502,7 +1512,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
if (attributes.count("\\reg")) {
auto &attr = attributes.at("\\reg");
if (attr->type != AST_CONSTANT)
- log_error("Attribute `reg' with non-constant value at %s:%d!\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Attribute `reg' with non-constant value!\n");
cell->attributes["\\reg"] = attr->asAttrConst();
}
@@ -1520,8 +1530,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
for (auto f : log_files)
current_ast->dumpAst(f, "verilog-ast> ");
type_name = type2str(type);
- log_error("Don't know how to generate RTLIL code for %s node at %s:%d!\n",
- type_name.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Don't know how to generate RTLIL code for %s node!\n",
+ type_name.c_str());
}
return RTLIL::SigSpec();
@@ -1551,4 +1561,3 @@ RTLIL::SigSpec AstNode::genWidthRTLIL(int width, const dict<RTLIL::SigBit, RTLIL
}
YOSYS_NAMESPACE_END
-
diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc
index a9608369c..f6f16e985 100644
--- a/frontends/ast/simplify.cc
+++ b/frontends/ast/simplify.cc
@@ -177,13 +177,13 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
// note that $display, $finish, and $stop are used for synthesis-time DRC so they're not in this list
if ((type == AST_FCALL || type == AST_TCALL) && (str == "$strobe" || str == "$monitor" || str == "$time" ||
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);
+ log_file_warning(filename, linenum, "Ignoring call to system %s %s.\n", type == AST_FCALL ? "function" : "task", str.c_str());
delete_children();
str = std::string();
}
if ((type == AST_TCALL) && (str == "$display" || str == "$write") && (!current_always || current_always->type != AST_INITIAL)) {
- log_warning("System task `%s' outside initial block is unsupported at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
+ log_file_warning(filename, linenum, "System task `%s' outside initial block is unsupported.\n", str.c_str());
delete_children();
str = std::string();
}
@@ -195,14 +195,14 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
{
int nargs = GetSize(children);
if (nargs < 1)
- log_error("System task `%s' got %d arguments, expected >= 1 at %s:%d.\n",
- str.c_str(), int(children.size()), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "System task `%s' got %d arguments, expected >= 1.\n",
+ str.c_str(), int(children.size()));
// First argument is the format string
AstNode *node_string = children[0];
while (node_string->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
if (node_string->type != AST_CONSTANT)
- log_error("Failed to evaluate system task `%s' with non-constant 1st argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Failed to evaluate system task `%s' with non-constant 1st argument.\n", str.c_str());
std::string sformat = node_string->bitsAsConst().decode_string();
// Other arguments are placeholders. Process the string as we go through it
@@ -215,7 +215,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
{
// If there's no next character, that's a problem
if (i+1 >= sformat.length())
- log_error("System task `%s' called with `%%' at end of string at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "System task `%s' called with `%%' at end of string.\n", str.c_str());
char cformat = sformat[++i];
@@ -239,13 +239,13 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
case 'x':
case 'X':
if (next_arg >= GetSize(children))
- log_error("Missing argument for %%%c format specifier in system task `%s' at %s:%d.\n",
- cformat, str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Missing argument for %%%c format specifier in system task `%s'.\n",
+ cformat, str.c_str());
node_arg = children[next_arg++];
while (node_arg->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
if (node_arg->type != AST_CONSTANT)
- log_error("Failed to evaluate system task `%s' with non-constant argument at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Failed to evaluate system task `%s' with non-constant argument.\n", str.c_str());
break;
case 'm':
@@ -253,7 +253,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
break;
default:
- log_error("System task `%s' called with invalid/unsupported format specifier at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "System task `%s' called with invalid/unsupported format specifier.\n", str.c_str());
break;
}
@@ -378,7 +378,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
continue;
wires_are_incompatible:
if (stage > 1)
- log_error("Incompatible re-declaration of wire %s at %s:%d.\n", node->str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Incompatible re-declaration of wire %s.\n", node->str.c_str());
continue;
}
this_wire_scope[node->str] = node;
@@ -406,7 +406,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (type == AST_ALWAYS || type == AST_INITIAL)
{
if (current_always != nullptr)
- log_error("Invalid nesting of always blocks and/or initializations at %s:%d.\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Invalid nesting of always blocks and/or initializations.\n");
current_always = this;
current_always_clocked = false;
@@ -465,7 +465,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
while (!children[1]->basic_prep && children[1]->simplify(false, false, false, stage, -1, false, true) == true)
did_something = true;
if (!children[1]->range_valid)
- log_error("Non-constant width range on parameter decl at %s:%d.\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Non-constant width range on parameter decl.\n");
width_hint = max(width_hint, children[1]->range_left - children[1]->range_right + 1);
}
break;
@@ -709,7 +709,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (type == AST_DEFPARAM && !children.empty())
{
if (children[0]->type != AST_IDENTIFIER)
- log_error("Module name in defparam at %s:%d contains non-constant expressions!\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Module name in defparam contains non-constant expressions!\n");
string modname, paramname = children[0]->str;
@@ -726,13 +726,13 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
}
if (pos == std::string::npos)
- log_error("Can't find object for defparam `%s` at %s:%d!\n", RTLIL::unescape_id(paramname).c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Can't find object for defparam `%s`!\n", RTLIL::unescape_id(paramname).c_str());
paramname = "\\" + paramname.substr(pos+1);
if (current_scope.at(modname)->type != AST_CELL)
- log_error("Defparam argument `%s . %s` does not match a cell at %s:%d!\n",
- RTLIL::unescape_id(modname).c_str(), RTLIL::unescape_id(paramname).c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Defparam argument `%s . %s` does not match a cell!\n",
+ RTLIL::unescape_id(modname).c_str(), RTLIL::unescape_id(paramname).c_str());
AstNode *paraset = new AstNode(AST_PARASET, children[1]->clone(), GetSize(children) > 2 ? children[2]->clone() : NULL);
paraset->str = paramname;
@@ -746,7 +746,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (type == AST_PREFIX) {
if (children[0]->type != AST_CONSTANT) {
// dumpAst(NULL, "> ");
- log_error("Index in generate block prefix syntax at %s:%d is not constant!\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Index in generate block prefix syntax is not constant!\n");
}
if (children[1]->type == AST_PREFIX)
children[1]->simplify(const_fold, at_zero, in_lvalue, stage, width_hint, sign_hint, in_param);
@@ -762,9 +762,9 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
// evaluate TO_BITS nodes
if (type == AST_TO_BITS) {
if (children[0]->type != AST_CONSTANT)
- log_error("Left operand of to_bits expression is not constant at %s:%d!\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Left operand of to_bits expression is not constant!\n");
if (children[1]->type != AST_CONSTANT)
- log_error("Right operand of to_bits expression is not constant at %s:%d!\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Right operand of to_bits expression is not constant!\n");
RTLIL::Const new_value = children[1]->bitsAsConst(children[0]->bitsAsConst().as_int(), children[1]->is_signed);
newNode = mkconst_bits(new_value.bits, children[1]->is_signed);
goto apply_newNode;
@@ -828,7 +828,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
multirange_dimensions.clear();
for (auto range : children[1]->children) {
if (!range->range_valid)
- log_error("Non-constant range on memory decl at %s:%d.\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Non-constant range on memory decl.\n");
multirange_dimensions.push_back(min(range->range_left, range->range_right));
multirange_dimensions.push_back(max(range->range_left, range->range_right) - min(range->range_left, range->range_right) + 1);
total_size *= multirange_dimensions.back();
@@ -846,7 +846,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
for (int i = 0; 2*i < GetSize(id2ast->multirange_dimensions); 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);
+ log_file_error(filename, linenum, "Insufficient number of array indices for %s.\n", log_id(str));
AstNode *new_index_expr = children[0]->children[i]->children.at(0)->clone();
@@ -875,12 +875,12 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (type == AST_PARAMETER || type == AST_LOCALPARAM) {
if (children.size() > 1 && children[1]->type == AST_RANGE) {
if (!children[1]->range_valid)
- log_error("Non-constant width range on parameter decl at %s:%d.\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Non-constant width range on parameter decl.\n");
int width = std::abs(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",
- children[0]->realvalue, log_signal(constvalue), filename.c_str(), linenum);
+ log_file_warning(filename, linenum, "converting real value %e to binary %s.\n",
+ children[0]->realvalue, log_signal(constvalue));
delete children[0];
children[0] = mkconst_bits(constvalue.bits, sign_hint);
did_something = true;
@@ -938,7 +938,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (type == AST_IDENTIFIER && children.size() == 2 && children[0]->type == AST_RANGE && children[1]->type == AST_RANGE && !in_lvalue)
{
if (id2ast == NULL || id2ast->type != AST_MEMORY || children[0]->children.size() != 1)
- log_error("Invalid bit-select on memory access at %s:%d!\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Invalid bit-select on memory access!\n");
int mem_width, mem_size, addr_bits;
id2ast->meminfo(mem_width, mem_size, addr_bits);
@@ -988,10 +988,10 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
}
if (type == AST_WHILE)
- log_error("While loops are only allowed in constant functions at %s:%d!\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "While loops are only allowed in constant functions!\n");
if (type == AST_REPEAT)
- log_error("Repeat loops are only allowed in constant functions at %s:%d!\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Repeat loops are only allowed in constant functions!\n");
// unroll for loops and generate-for blocks
if ((type == AST_GENFOR || type == AST_FOR) && children.size() != 0)
@@ -1006,31 +1006,31 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
body_ast = body_ast->children.at(0);
if (init_ast->type != AST_ASSIGN_EQ)
- log_error("Unsupported 1st expression of generate for-loop at %s:%d!\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Unsupported 1st expression of generate for-loop!\n");
if (next_ast->type != AST_ASSIGN_EQ)
- log_error("Unsupported 3rd expression of generate for-loop at %s:%d!\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Unsupported 3rd expression of generate for-loop!\n");
if (type == AST_GENFOR) {
if (init_ast->children[0]->id2ast == NULL || init_ast->children[0]->id2ast->type != AST_GENVAR)
- log_error("Left hand side of 1st expression of generate for-loop at %s:%d is not a gen var!\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Left hand side of 1st expression of generate for-loop is not a gen var!\n");
if (next_ast->children[0]->id2ast == NULL || next_ast->children[0]->id2ast->type != AST_GENVAR)
- log_error("Left hand side of 3rd expression of generate for-loop at %s:%d is not a gen var!\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Left hand side of 3rd expression of generate for-loop is not a gen var!\n");
} else {
if (init_ast->children[0]->id2ast == NULL || init_ast->children[0]->id2ast->type != AST_WIRE)
- log_error("Left hand side of 1st expression of generate for-loop at %s:%d is not a register!\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Left hand side of 1st expression of generate for-loop is not a register!\n");
if (next_ast->children[0]->id2ast == NULL || next_ast->children[0]->id2ast->type != AST_WIRE)
- log_error("Left hand side of 3rd expression of generate for-loop at %s:%d is not a register!\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Left hand side of 3rd expression of generate for-loop is not a register!\n");
}
if (init_ast->children[0]->id2ast != next_ast->children[0]->id2ast)
- log_error("Incompatible left-hand sides in 1st and 3rd expression of generate for-loop at %s:%d!\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Incompatible left-hand sides in 1st and 3rd expression of generate for-loop!\n");
// eval 1st expression
AstNode *varbuf = init_ast->children[1]->clone();
while (varbuf->simplify(true, false, false, stage, 32, true, false)) { }
if (varbuf->type != AST_CONSTANT)
- log_error("Right hand side of 1st expression of generate for-loop at %s:%d is not constant!\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Right hand side of 1st expression of generate for-loop is not constant!\n");
varbuf = new AstNode(AST_LOCALPARAM, varbuf);
varbuf->str = init_ast->children[0]->str;
@@ -1052,7 +1052,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
while (buf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
if (buf->type != AST_CONSTANT)
- log_error("2nd expression of generate for-loop at %s:%d is not constant!\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "2nd expression of generate for-loop is not constant!\n");
if (buf->integer == 0) {
delete buf;
@@ -1093,7 +1093,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
while (buf->simplify(true, false, false, stage, 32, true, false)) { }
if (buf->type != AST_CONSTANT)
- log_error("Right hand side of 3rd expression of generate for-loop at %s:%d is not constant!\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Right hand side of 3rd expression of generate for-loop is not constant!\n");
delete varbuf->children[0];
varbuf->children[0] = buf;
@@ -1110,8 +1110,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
{
for (size_t i = 0; i < children.size(); i++)
if (children[i]->type == AST_WIRE || children[i]->type == AST_MEMORY || children[i]->type == AST_PARAMETER || children[i]->type == AST_LOCALPARAM)
- log_error("Local declaration in unnamed block at %s:%d is an unsupported SystemVerilog feature!\n",
- children[i]->filename.c_str(), children[i]->linenum);
+ log_file_error(children[i]->filename, children[i]->linenum, "Local declaration in unnamed block is an unsupported SystemVerilog feature!\n");
}
// transform block with name
@@ -1159,7 +1158,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (buf->type != AST_CONSTANT) {
// for (auto f : log_files)
// dumpAst(f, "verilog-ast> ");
- log_error("Condition for generate if at %s:%d is not constant!\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Condition for generate if is not constant!\n");
}
if (buf->asBool() != 0) {
delete buf;
@@ -1200,7 +1199,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (buf->type != AST_CONSTANT) {
// for (auto f : log_files)
// dumpAst(f, "verilog-ast> ");
- log_error("Condition for generate case at %s:%d is not constant!\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Condition for generate case is not constant!\n");
}
bool ref_signed = buf->is_signed;
@@ -1234,7 +1233,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (buf->type != AST_CONSTANT) {
// for (auto f : log_files)
// dumpAst(f, "verilog-ast> ");
- log_error("Expression in generate case at %s:%d is not constant!\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Expression in generate case is not constant!\n");
}
bool is_selected = RTLIL::const_eq(ref_value, buf->bitsAsConst(), ref_signed && buf->is_signed, ref_signed && buf->is_signed, 1).as_bool();
@@ -1275,7 +1274,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (type == AST_CELLARRAY)
{
if (!children.at(0)->range_valid)
- log_error("Non-constant array range on cell array at %s:%d.\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Non-constant array range on cell array.\n");
newNode = new AstNode(AST_GENBLOCK);
int num = max(children.at(0)->range_left, children.at(0)->range_right) - min(children.at(0)->range_left, children.at(0)->range_right) + 1;
@@ -1286,7 +1285,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
newNode->children.push_back(new_cell);
new_cell->str += stringf("[%d]", idx);
if (new_cell->type == AST_PRIMITIVE) {
- log_error("Cell arrays of primitives are currently not supported at %s:%d.\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Cell arrays of primitives are currently not supported.\n");
} else {
log_assert(new_cell->children.at(0)->type == AST_CELLTYPE);
new_cell->children.at(0)->str = stringf("$array:%d:%d:%s", i, num, new_cell->children.at(0)->str.c_str());
@@ -1300,8 +1299,8 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (type == AST_PRIMITIVE)
{
if (children.size() < 2)
- log_error("Insufficient number of arguments for primitive `%s' at %s:%d!\n",
- str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Insufficient number of arguments for primitive `%s'!\n",
+ str.c_str());
std::vector<AstNode*> children_list;
for (auto child : children) {
@@ -1316,8 +1315,8 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (str == "bufif0" || str == "bufif1" || str == "notif0" || str == "notif1")
{
if (children_list.size() != 3)
- log_error("Invalid number of arguments for primitive `%s' at %s:%d!\n",
- str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Invalid number of arguments for primitive `%s'!\n",
+ str.c_str());
std::vector<RTLIL::State> z_const(1, RTLIL::State::Sz);
@@ -1402,8 +1401,8 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
while (left_at_zero_ast->simplify(true, true, false, stage, -1, false, false)) { }
while (right_at_zero_ast->simplify(true, true, false, stage, -1, false, false)) { }
if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT)
- log_error("Unsupported expression on dynamic range select on signal `%s' at %s:%d!\n",
- str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Unsupported expression on dynamic range select on signal `%s'!\n",
+ str.c_str());
result_width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1;
}
did_something = true;
@@ -1676,7 +1675,7 @@ skip_dynamic_range_lvalue_expansion:;
while (left_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { }
while (right_at_zero_ast->simplify(true, true, false, 1, -1, false, false)) { }
if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT)
- log_error("Unsupported expression on dynamic range select on signal `%s' at %s:%d!\n", str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str());
int width = left_at_zero_ast->integer - right_at_zero_ast->integer + 1;
assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER),
@@ -1772,19 +1771,19 @@ skip_dynamic_range_lvalue_expansion:;
int num_steps = 1;
if (GetSize(children) != 1 && GetSize(children) != 2)
- log_error("System function %s got %d arguments, expected 1 or 2 at %s:%d.\n",
- RTLIL::unescape_id(str).c_str(), int(children.size()), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "System function %s got %d arguments, expected 1 or 2.\n",
+ RTLIL::unescape_id(str).c_str(), int(children.size()));
if (!current_always_clocked)
- log_error("System function %s is only allowed in clocked blocks at %s:%d.\n",
- RTLIL::unescape_id(str).c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "System function %s is only allowed in clocked blocks.\n",
+ RTLIL::unescape_id(str).c_str());
if (GetSize(children) == 2)
{
AstNode *buf = children[1]->clone();
while (buf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
if (buf->type != AST_CONSTANT)
- log_error("Failed to evaluate system function `%s' with non-constant value at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-constant value.\n", str.c_str());
num_steps = buf->asInt(true);
delete buf;
@@ -1840,12 +1839,12 @@ skip_dynamic_range_lvalue_expansion:;
if (str == "\\$stable" || str == "\\$rose" || str == "\\$fell")
{
if (GetSize(children) != 1)
- log_error("System function %s got %d arguments, expected 1 at %s:%d.\n",
- RTLIL::unescape_id(str).c_str(), int(children.size()), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "System function %s got %d arguments, expected 1.\n",
+ RTLIL::unescape_id(str).c_str(), int(children.size()));
if (!current_always_clocked)
- log_error("System function %s is only allowed in clocked blocks at %s:%d.\n",
- RTLIL::unescape_id(str).c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "System function %s is only allowed in clocked blocks.\n",
+ RTLIL::unescape_id(str).c_str());
AstNode *present = children.at(0)->clone();
AstNode *past = clone();
@@ -1875,13 +1874,13 @@ skip_dynamic_range_lvalue_expansion:;
if (str == "\\$clog2")
{
if (children.size() != 1)
- log_error("System function %s got %d arguments, expected 1 at %s:%d.\n",
- RTLIL::unescape_id(str).c_str(), int(children.size()), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "System function %s got %d arguments, expected 1.\n",
+ RTLIL::unescape_id(str).c_str(), int(children.size()));
AstNode *buf = children[0]->clone();
while (buf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
if (buf->type != AST_CONSTANT)
- log_error("Failed to evaluate system function `%s' with non-constant value at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-constant value.\n", str.c_str());
RTLIL::Const arg_value = buf->bitsAsConst();
if (arg_value.as_bool())
@@ -1900,12 +1899,12 @@ skip_dynamic_range_lvalue_expansion:;
if (str == "\\$size" || str == "\\$bits")
{
if (str == "\\$bits" && children.size() != 1)
- log_error("System function %s got %d arguments, expected 1 at %s:%d.\n",
- RTLIL::unescape_id(str).c_str(), int(children.size()), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "System function %s got %d arguments, expected 1.\n",
+ RTLIL::unescape_id(str).c_str(), int(children.size()));
if (str == "\\$size" && children.size() != 1 && children.size() != 2)
- log_error("System function %s got %d arguments, expected 1 or 2 at %s:%d.\n",
- RTLIL::unescape_id(str).c_str(), int(children.size()), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "System function %s got %d arguments, expected 1 or 2.\n",
+ RTLIL::unescape_id(str).c_str(), int(children.size()));
int dim = 1;
if (str == "\\$size" && children.size() == 2) {
@@ -1928,7 +1927,7 @@ skip_dynamic_range_lvalue_expansion:;
if (id_ast == NULL && current_scope.count(buf->str))
id_ast = current_scope.at(buf->str);
if (!id_ast)
- log_error("Failed to resolve identifier %s for width detection at %s:%d!\n", buf->str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Failed to resolve identifier %s for width detection!\n", buf->str.c_str());
if (id_ast->type == AST_MEMORY) {
// We got here only if the argument is a memory
// Otherwise $size() and $bits() return the expression width
@@ -1936,15 +1935,15 @@ skip_dynamic_range_lvalue_expansion:;
if (str == "\\$bits") {
if (mem_range->type == AST_RANGE) {
if (!mem_range->range_valid)
- log_error("Failed to detect width of memory access `%s' at %s:%d!\n", buf->str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Failed to detect width of memory access `%s'!\n", buf->str.c_str());
mem_depth = mem_range->range_left - mem_range->range_right + 1;
} else
- log_error("Unknown memory depth AST type in `%s' at %s:%d!\n", buf->str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Unknown memory depth AST type in `%s'!\n", buf->str.c_str());
} else {
// $size()
if (mem_range->type == AST_RANGE) {
if (!mem_range->range_valid)
- log_error("Failed to detect width of memory access `%s' at %s:%d!\n", buf->str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Failed to detect width of memory access `%s'!\n", buf->str.c_str());
int dims;
if (id_ast->multirange_dimensions.empty())
dims = 1;
@@ -1955,9 +1954,9 @@ skip_dynamic_range_lvalue_expansion:;
else if (dim <= dims) {
width_hint = id_ast->multirange_dimensions[2*dim-1];
} else if ((dim > dims+1) || (dim < 0))
- log_error("Dimension %d out of range in `%s', as it only has dimensions 1..%d at %s:%d!\n", dim, buf->str.c_str(), dims+1, filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Dimension %d out of range in `%s', as it only has dimensions 1..%d!\n", dim, buf->str.c_str(), dims+1);
} else
- log_error("Unknown memory depth AST type in `%s' at %s:%d!\n", buf->str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Unknown memory depth AST type in `%s'!\n", buf->str.c_str());
}
}
}
@@ -1978,19 +1977,19 @@ skip_dynamic_range_lvalue_expansion:;
if (func_with_two_arguments) {
if (children.size() != 2)
- log_error("System function %s got %d arguments, expected 2 at %s:%d.\n",
- RTLIL::unescape_id(str).c_str(), int(children.size()), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "System function %s got %d arguments, expected 2.\n",
+ RTLIL::unescape_id(str).c_str(), int(children.size()));
} else {
if (children.size() != 1)
- log_error("System function %s got %d arguments, expected 1 at %s:%d.\n",
- RTLIL::unescape_id(str).c_str(), int(children.size()), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "System function %s got %d arguments, expected 1.\n",
+ RTLIL::unescape_id(str).c_str(), int(children.size()));
}
if (children.size() >= 1) {
while (children[0]->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
if (!children[0]->isConst())
- log_error("Failed to evaluate system function `%s' with non-constant argument at %s:%d.\n",
- RTLIL::unescape_id(str).c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-constant argument.\n",
+ RTLIL::unescape_id(str).c_str());
int child_width_hint = width_hint;
bool child_sign_hint = sign_hint;
children[0]->detectSignWidth(child_width_hint, child_sign_hint);
@@ -2000,8 +1999,8 @@ skip_dynamic_range_lvalue_expansion:;
if (children.size() >= 2) {
while (children[1]->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
if (!children[1]->isConst())
- log_error("Failed to evaluate system function `%s' with non-constant argument at %s:%d.\n",
- RTLIL::unescape_id(str).c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-constant argument.\n",
+ RTLIL::unescape_id(str).c_str());
int child_width_hint = width_hint;
bool child_sign_hint = sign_hint;
children[1]->detectSignWidth(child_width_hint, child_sign_hint);
@@ -2053,14 +2052,14 @@ skip_dynamic_range_lvalue_expansion:;
for (int i = 2; i < GetSize(dpi_decl->children); i++)
{
if (i-2 >= GetSize(children))
- log_error("Insufficient number of arguments in DPI function call at %s:%d.\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Insufficient number of arguments in DPI function call.\n");
argtypes.push_back(RTLIL::unescape_id(dpi_decl->children.at(i)->str));
args.push_back(children.at(i-2)->clone());
while (args.back()->simplify(true, false, false, stage, -1, false, true)) { }
if (args.back()->type != AST_CONSTANT && args.back()->type != AST_REALVALUE)
- log_error("Failed to evaluate DPI function with non-constant argument at %s:%d.\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Failed to evaluate DPI function with non-constant argument.\n");
}
newNode = dpi_call(rtype, fname, argtypes, args);
@@ -2072,7 +2071,7 @@ skip_dynamic_range_lvalue_expansion:;
}
if (current_scope.count(str) == 0 || current_scope[str]->type != AST_FUNCTION)
- log_error("Can't resolve function name `%s' at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Can't resolve function name `%s'.\n", str.c_str());
}
if (type == AST_TCALL)
@@ -2080,26 +2079,26 @@ skip_dynamic_range_lvalue_expansion:;
if (str == "$finish" || str == "$stop")
{
if (!current_always || current_always->type != AST_INITIAL)
- log_error("System task `%s' outside initial block is unsupported at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "System task `%s' outside initial block is unsupported.\n", str.c_str());
- log_error("System task `%s' executed at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "System task `%s' executed.\n", str.c_str());
}
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);
+ log_file_error(filename, linenum, "System function %s got %d arguments, expected 2-4.\n",
+ RTLIL::unescape_id(str).c_str(), int(children.size()));
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);
+ log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-constant 1st argument.\n", str.c_str());
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);
+ log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-memory 2nd argument.\n", str.c_str());
int start_addr = -1, finish_addr = -1;
@@ -2107,7 +2106,7 @@ skip_dynamic_range_lvalue_expansion:;
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);
+ log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-constant 3rd argument.\n", str.c_str());
start_addr = int(node_addr->asInt(false));
}
@@ -2115,7 +2114,7 @@ skip_dynamic_range_lvalue_expansion:;
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);
+ log_file_error(filename, linenum, "Failed to evaluate system function `%s' with non-constant 4th argument.\n", str.c_str());
finish_addr = int(node_addr->asInt(false));
}
@@ -2141,7 +2140,7 @@ skip_dynamic_range_lvalue_expansion:;
}
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);
+ log_file_error(filename, linenum, "Can't resolve task name `%s'.\n", str.c_str());
}
AstNode *decl = current_scope[str];
@@ -2169,9 +2168,9 @@ skip_dynamic_range_lvalue_expansion:;
}
if (in_param)
- log_error("Non-constant function call in constant expression at %s:%d.\n", filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Non-constant function call in constant expression.\n");
if (require_const_eval)
- log_error("Function %s can only be called with constant arguments at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Function %s can only be called with constant arguments.\n", str.c_str());
}
size_t arg_count = 0;
@@ -2288,7 +2287,7 @@ skip_dynamic_range_lvalue_expansion:;
goto tcall_incompatible_wires;
} else {
tcall_incompatible_wires:
- log_error("Incompatible re-declaration of wire %s at %s:%d.\n", child->str.c_str(), filename.c_str(), linenum);
+ log_file_error(filename, linenum, "Incompatible re-declaration of wire %s.\n", child->str.c_str());
}
}
}
@@ -2676,7 +2675,7 @@ AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *m
yosys_input_files.insert(mem_filename);
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_file_error(filename, linenum, "Can not open file `%s` for %s.\n", mem_filename.c_str(), str.c_str());
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;
@@ -2722,7 +2721,7 @@ AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *m
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);
+ log_file_error(filename, linenum, "Can not parse address `%s` for %s.\n", nptr, str.c_str());
continue;
}
@@ -2978,7 +2977,7 @@ bool AstNode::mem2reg_check(pool<AstNode*> &mem2reg_set)
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);
+ log_file_error(filename, linenum, "Invalid array access.\n");
return true;
}
@@ -3333,16 +3332,16 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
continue;
if (stmt->children.at(1)->type != AST_CONSTANT)
- log_error("Non-constant expression in constant function at %s:%d (called from %s:%d). X\n",
- stmt->filename.c_str(), stmt->linenum, fcall->filename.c_str(), fcall->linenum);
+ log_file_error(stmt->filename, stmt->linenum, "Non-constant expression in constant function (called from %s:%d). X\n",
+ fcall->filename.c_str(), fcall->linenum);
if (stmt->children.at(0)->type != AST_IDENTIFIER)
- log_error("Unsupported composite left hand side in constant function at %s:%d (called from %s:%d).\n",
- stmt->filename.c_str(), stmt->linenum, fcall->filename.c_str(), fcall->linenum);
+ log_file_error(stmt->filename, stmt->linenum, "Unsupported composite left hand side in constant function (called from %s:%d).\n",
+ fcall->filename.c_str(), fcall->linenum);
if (!variables.count(stmt->children.at(0)->str))
- log_error("Assignment to non-local variable in constant function at %s:%d (called from %s:%d).\n",
- stmt->filename.c_str(), stmt->linenum, fcall->filename.c_str(), fcall->linenum);
+ log_file_error(stmt->filename, stmt->linenum, "Assignment to non-local variable in constant function (called from %s:%d).\n",
+ fcall->filename.c_str(), fcall->linenum);
if (stmt->children.at(0)->children.empty()) {
variables[stmt->children.at(0)->str].val = stmt->children.at(1)->bitsAsConst(variables[stmt->children.at(0)->str].val.bits.size());
@@ -3381,8 +3380,8 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
while (cond->simplify(true, false, false, 1, -1, false, true)) { }
if (cond->type != AST_CONSTANT)
- log_error("Non-constant expression in constant function at %s:%d (called from %s:%d).\n",
- stmt->filename.c_str(), stmt->linenum, fcall->filename.c_str(), fcall->linenum);
+ log_file_error(stmt->filename, stmt->linenum, "Non-constant expression in constant function (called from %s:%d).\n",
+ fcall->filename.c_str(), fcall->linenum);
if (cond->asBool()) {
block->children.insert(block->children.begin(), stmt->children.at(1)->clone());
@@ -3402,8 +3401,8 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
while (num->simplify(true, false, false, 1, -1, false, true)) { }
if (num->type != AST_CONSTANT)
- log_error("Non-constant expression in constant function at %s:%d (called from %s:%d).\n",
- stmt->filename.c_str(), stmt->linenum, fcall->filename.c_str(), fcall->linenum);
+ log_file_error(stmt->filename, stmt->linenum, "Non-constant expression in constant function (called from %s:%d).\n",
+ fcall->filename.c_str(), fcall->linenum);
block->children.erase(block->children.begin());
for (int i = 0; i < num->bitsAsConst().as_int(); i++)
@@ -3440,8 +3439,8 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
while (cond->simplify(true, false, false, 1, -1, false, true)) { }
if (cond->type != AST_CONSTANT)
- log_error("Non-constant expression in constant function at %s:%d (called from %s:%d).\n",
- stmt->filename.c_str(), stmt->linenum, fcall->filename.c_str(), fcall->linenum);
+ log_file_error(stmt->filename, stmt->linenum, "Non-constant expression in constant function (called from %s:%d).\n",
+ fcall->filename.c_str(), fcall->linenum);
found_match = cond->asBool();
delete cond;
@@ -3470,8 +3469,8 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
continue;
}
- log_error("Unsupported language construct in constant function at %s:%d (called from %s:%d).\n",
- stmt->filename.c_str(), stmt->linenum, fcall->filename.c_str(), fcall->linenum);
+ log_file_error(stmt->filename, stmt->linenum, "Unsupported language construct in constant function (called from %s:%d).\n",
+ fcall->filename.c_str(), fcall->linenum);
log_abort();
}
@@ -3488,4 +3487,3 @@ AstNode *AstNode::eval_const_function(AstNode *fcall)
}
YOSYS_NAMESPACE_END
-
diff --git a/frontends/blif/blifparse.cc b/frontends/blif/blifparse.cc
index e6bb99954..26cd14033 100644
--- a/frontends/blif/blifparse.cc
+++ b/frontends/blif/blifparse.cc
@@ -83,7 +83,9 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo
RTLIL::Module *module = nullptr;
RTLIL::Const *lutptr = NULL;
RTLIL::Cell *sopcell = NULL;
+ RTLIL::Cell *lastcell = nullptr;
RTLIL::State lut_default_state = RTLIL::State::Sx;
+ std::string err_reason;
int blif_maxnum = 0, sopmode = -1;
auto blif_wire = [&](const std::string &wire_name) -> Wire*
@@ -159,6 +161,7 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo
if (module != nullptr)
goto error;
module = new RTLIL::Module;
+ lastcell = nullptr;
module->name = RTLIL::escape_id(strtok(NULL, " \t\r\n"));
obj_attributes = &module->attributes;
obj_parameters = nullptr;
@@ -232,6 +235,7 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo
}
module = nullptr;
+ lastcell = nullptr;
obj_attributes = nullptr;
obj_parameters = nullptr;
continue;
@@ -264,6 +268,22 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo
continue;
}
+ if (!strcmp(cmd, ".cname"))
+ {
+ char *p = strtok(NULL, " \t\r\n");
+ if (p == NULL)
+ goto error;
+
+ if(lastcell == nullptr || module == nullptr)
+ {
+ err_reason = stringf("No primative object to attach .cname %s.", p);
+ goto error_with_reason;
+ }
+
+ module->rename(lastcell, p);
+ continue;
+ }
+
if (!strcmp(cmd, ".attr") || !strcmp(cmd, ".param")) {
char *n = strtok(NULL, " \t\r\n");
char *v = strtok(NULL, "\r\n");
@@ -281,12 +301,16 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo
const_v.bits[i] = v[n-i-1] != '0' ? State::S1 : State::S0;
}
if (!strcmp(cmd, ".attr")) {
- if (obj_attributes == nullptr)
- goto error;
+ if (obj_attributes == nullptr) {
+ err_reason = stringf("No object to attach .attr too.");
+ goto error_with_reason;
+ }
(*obj_attributes)[id_n] = const_v;
} else {
- if (obj_parameters == nullptr)
- goto error;
+ if (obj_parameters == nullptr) {
+ err_reason = stringf("No object to attach .param too.");
+ goto error_with_reason;
+ }
(*obj_parameters)[id_n] = const_v;
}
continue;
@@ -331,6 +355,7 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo
}
}
+ lastcell = cell;
obj_attributes = &cell->attributes;
obj_parameters = &cell->parameters;
continue;
@@ -383,6 +408,7 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo
cell->setPort(it.first, sig);
}
+ lastcell = cell;
obj_attributes = &cell->attributes;
obj_parameters = &cell->parameters;
continue;
@@ -391,7 +417,7 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo
obj_attributes = nullptr;
obj_parameters = nullptr;
- if (!strcmp(cmd, ".barbuf"))
+ if (!strcmp(cmd, ".barbuf") || !strcmp(cmd, ".conn"))
{
char *p = strtok(NULL, " \t\r\n");
if (p == NULL)
@@ -459,6 +485,7 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo
sopcell->setPort("\\A", input_sig);
sopcell->setPort("\\Y", output_sig);
sopmode = -1;
+ lastcell = sopcell;
}
else
{
@@ -469,6 +496,7 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo
cell->setPort("\\Y", output_sig);
lutptr = &cell->parameters.at("\\LUT");
lut_default_state = RTLIL::State::Sx;
+ lastcell = cell;
}
continue;
}
@@ -546,6 +574,8 @@ void parse_blif(RTLIL::Design *design, std::istream &f, std::string dff_name, bo
error:
log_error("Syntax error in line %d!\n", line_count);
+error_with_reason:
+ log_error("Syntax error in line %d: %s\n", line_count, err_reason.c_str());
}
struct BlifFrontend : public Frontend {
diff --git a/frontends/liberty/liberty.cc b/frontends/liberty/liberty.cc
index af80c2921..b9e53a4be 100644
--- a/frontends/liberty/liberty.cc
+++ b/frontends/liberty/liberty.cc
@@ -148,7 +148,7 @@ static bool parse_func_reduce(RTLIL::Module *module, std::vector<token_t> &stack
}
if (0 <= top && stack[top].type == 2) {
- if (next_token.type == '*' || next_token.type == '&' || next_token.type == 0 || next_token.type == '(')
+ if (next_token.type == '*' || next_token.type == '&' || next_token.type == 0 || next_token.type == '(' || next_token.type == '!')
return false;
stack[top].type = 3;
return true;
@@ -188,7 +188,7 @@ static RTLIL::SigSpec parse_func_expr(RTLIL::Module *module, const char *expr)
}
token_t next_token(0);
- if (*expr == '(' || *expr == ')' || *expr == '\'' || *expr == '!' || *expr == '^' || *expr == '*' || *expr == '+' || *expr == '|')
+ if (*expr == '(' || *expr == ')' || *expr == '\'' || *expr == '!' || *expr == '^' || *expr == '*' || *expr == '+' || *expr == '|' || *expr == '&')
next_token = token_t(*(expr++));
else
next_token = token_t(0, parse_func_identifier(module, expr));
@@ -463,9 +463,13 @@ struct LibertyFrontend : public Frontend {
log(" -lib\n");
log(" only create empty blackbox modules\n");
log("\n");
- log(" -ignore_redef\n");
+ log(" -nooverwrite\n");
log(" ignore re-definitions of modules. (the default behavior is to\n");
- log(" create an error message.)\n");
+ log(" create an error message if the existing module is not a blackbox\n");
+ log(" module, and overwrite the existing module if it is a blackbox module.)\n");
+ log("\n");
+ log(" -overwrite\n");
+ log(" overwrite existing modules with the same name\n");
log("\n");
log(" -ignore_miss_func\n");
log(" ignore cells with missing function specification of outputs\n");
@@ -484,7 +488,8 @@ struct LibertyFrontend : public Frontend {
virtual void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
{
bool flag_lib = false;
- bool flag_ignore_redef = false;
+ bool flag_nooverwrite = false;
+ bool flag_overwrite = false;
bool flag_ignore_miss_func = false;
bool flag_ignore_miss_dir = false;
bool flag_ignore_miss_data_latch = false;
@@ -499,8 +504,14 @@ struct LibertyFrontend : public Frontend {
flag_lib = true;
continue;
}
- if (arg == "-ignore_redef") {
- flag_ignore_redef = true;
+ if (arg == "-ignore_redef" || arg == "-nooverwrite") {
+ flag_nooverwrite = true;
+ flag_overwrite = false;
+ continue;
+ }
+ if (arg == "-overwrite") {
+ flag_nooverwrite = false;
+ flag_overwrite = true;
continue;
}
if (arg == "-ignore_miss_func") {
@@ -537,9 +548,16 @@ struct LibertyFrontend : public Frontend {
std::string cell_name = RTLIL::escape_id(cell->args.at(0));
if (design->has(cell_name)) {
- if (flag_ignore_redef)
+ Module *existing_mod = design->module(cell_name);
+ if (!flag_nooverwrite && !flag_overwrite && !existing_mod->get_bool_attribute("\\blackbox")) {
+ log_error("Re-definition of of cell/module %s!\n", log_id(cell_name));
+ } else if (flag_nooverwrite) {
+ log("Ignoring re-definition of module %s.\n", log_id(cell_name));
continue;
- log_error("Duplicate definition of cell/module %s.\n", RTLIL::unescape_id(cell_name).c_str());
+ } else {
+ log("Replacing existing%s module %s.\n", existing_mod->get_bool_attribute("\\blackbox") ? " blackbox" : "", log_id(cell_name));
+ design->remove(existing_mod);
+ }
}
// log("Processing cell type %s.\n", RTLIL::unescape_id(cell_name).c_str());
diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc
index 7b5dac309..b8dd72b98 100644
--- a/frontends/verific/verific.cc
+++ b/frontends/verific/verific.cc
@@ -62,8 +62,11 @@ using namespace Verific;
YOSYS_NAMESPACE_BEGIN
int verific_verbose;
+bool verific_import_pending;
string verific_error_msg;
+vector<string> verific_incdirs, verific_libdirs;
+
void msg_func(msg_type_t msg_type, const char *message_id, linefile_type linefile, const char *msg, va_list args)
{
string message_prefix = stringf("VERIFIC-%s [%s] ",
@@ -99,9 +102,9 @@ string get_full_netlist_name(Netlist *nl)
// ==================================================================
-VerificImporter::VerificImporter(bool mode_gates, bool mode_keep, bool mode_nosva, bool mode_names, bool mode_verific) :
+VerificImporter::VerificImporter(bool mode_gates, bool mode_keep, bool mode_nosva, bool mode_names, bool mode_verific, bool mode_autocover) :
mode_gates(mode_gates), mode_keep(mode_keep), mode_nosva(mode_nosva),
- mode_names(mode_names), mode_verific(mode_verific)
+ mode_names(mode_names), mode_verific(mode_verific), mode_autocover(mode_autocover)
{
}
@@ -123,8 +126,11 @@ void VerificImporter::import_attributes(dict<RTLIL::IdString, RTLIL::Const> &att
attributes["\\src"] = stringf("%s:%d", LineFile::GetFileName(obj->Linefile()), LineFile::GetLineNo(obj->Linefile()));
// FIXME: Parse numeric attributes
- FOREACH_ATTRIBUTE(obj, mi, attr)
+ FOREACH_ATTRIBUTE(obj, mi, attr) {
+ if (attr->Key()[0] == ' ' || attr->Value() == nullptr)
+ continue;
attributes[RTLIL::escape_id(attr->Key())] = RTLIL::Const(std::string(attr->Value()));
+ }
}
RTLIL::SigSpec VerificImporter::operatorInput(Instance *inst)
@@ -186,12 +192,12 @@ RTLIL::SigSpec VerificImporter::operatorInport(Instance *inst, const char *portn
}
}
-RTLIL::SigSpec VerificImporter::operatorOutput(Instance *inst)
+RTLIL::SigSpec VerificImporter::operatorOutput(Instance *inst, const pool<Net*, hash_ptr_ops> *any_all_nets)
{
RTLIL::SigSpec sig;
RTLIL::Wire *dummy_wire = NULL;
for (int i = int(inst->OutputSize())-1; i >= 0; i--)
- if (inst->GetOutputBit(i)) {
+ if (inst->GetOutputBit(i) && (!any_all_nets || !any_all_nets->count(inst->GetOutputBit(i)))) {
sig.append(net_map_at(inst->GetOutputBit(i)));
dummy_wire = NULL;
} else {
@@ -241,7 +247,9 @@ bool VerificImporter::import_netlist_instance_gates(Instance *inst, RTLIL::IdStr
}
if (inst->Type() == PRIM_BUF) {
- module->addBufGate(inst_name, net_map_at(inst->GetInput()), net_map_at(inst->GetOutput()));
+ auto outnet = inst->GetOutput();
+ if (!any_all_nets.count(outnet))
+ module->addBufGate(inst_name, net_map_at(inst->GetInput()), net_map_at(outnet));
return true;
}
@@ -391,6 +399,7 @@ bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdStr
#define IN1 operatorInput1(inst)
#define IN2 operatorInput2(inst)
#define OUT operatorOutput(inst)
+ #define FILTERED_OUT operatorOutput(inst, &any_all_nets)
#define SIGNED inst->View()->IsSigned()
if (inst->Type() == OPER_ADDER) {
@@ -522,7 +531,7 @@ bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdStr
}
if (inst->Type() == OPER_WIDE_BUF) {
- module->addPos(inst_name, IN, OUT, SIGNED);
+ module->addPos(inst_name, IN, FILTERED_OUT, SIGNED);
return true;
}
@@ -786,8 +795,9 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se
module->fixup_ports();
dict<Net*, char, hash_ptr_ops> init_nets;
- pool<Net*, hash_ptr_ops> anyconst_nets;
- pool<Net*, hash_ptr_ops> anyseq_nets;
+ pool<Net*, hash_ptr_ops> anyconst_nets, anyseq_nets;
+ pool<Net*, hash_ptr_ops> allconst_nets, allseq_nets;
+ any_all_nets.clear();
FOREACH_NET_OF_NETLIST(nl, mi, net)
{
@@ -862,11 +872,36 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se
const char *rand_const_attr = net->GetAttValue(" rand_const");
const char *rand_attr = net->GetAttValue(" rand");
- if (rand_const_attr != nullptr && !strcmp(rand_const_attr, "1"))
- anyconst_nets.insert(net);
+ const char *anyconst_attr = net->GetAttValue("anyconst");
+ const char *anyseq_attr = net->GetAttValue("anyseq");
+
+ const char *allconst_attr = net->GetAttValue("allconst");
+ const char *allseq_attr = net->GetAttValue("allseq");
- else if (rand_attr != nullptr && !strcmp(rand_attr, "1"))
+ if (rand_const_attr != nullptr && (!strcmp(rand_const_attr, "1") || !strcmp(rand_const_attr, "'1'"))) {
+ anyconst_nets.insert(net);
+ any_all_nets.insert(net);
+ }
+ else if (rand_attr != nullptr && (!strcmp(rand_attr, "1") || !strcmp(rand_attr, "'1'"))) {
+ anyseq_nets.insert(net);
+ any_all_nets.insert(net);
+ }
+ else if (anyconst_attr != nullptr && (!strcmp(anyconst_attr, "1") || !strcmp(anyconst_attr, "'1'"))) {
+ anyconst_nets.insert(net);
+ any_all_nets.insert(net);
+ }
+ else if (anyseq_attr != nullptr && (!strcmp(anyseq_attr, "1") || !strcmp(anyseq_attr, "'1'"))) {
anyseq_nets.insert(net);
+ any_all_nets.insert(net);
+ }
+ else if (allconst_attr != nullptr && (!strcmp(allconst_attr, "1") || !strcmp(allconst_attr, "'1'"))) {
+ allconst_nets.insert(net);
+ any_all_nets.insert(net);
+ }
+ else if (allseq_attr != nullptr && (!strcmp(allseq_attr, "1") || !strcmp(allseq_attr, "'1'"))) {
+ allseq_nets.insert(net);
+ any_all_nets.insert(net);
+ }
if (net_map.count(net)) {
if (verific_verbose)
@@ -951,6 +986,8 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se
SigSpec anyconst_sig;
SigSpec anyseq_sig;
+ SigSpec allconst_sig;
+ SigSpec allseq_sig;
for (int i = netbus->RightIndex();; i += netbus->IsUp() ? -1 : +1) {
net = netbus->ElementAtIndex(i);
@@ -962,6 +999,14 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se
anyseq_sig.append(net_map_at(net));
anyseq_nets.erase(net);
}
+ if (net != nullptr && allconst_nets.count(net)) {
+ allconst_sig.append(net_map_at(net));
+ allconst_nets.erase(net);
+ }
+ if (net != nullptr && allseq_nets.count(net)) {
+ allseq_sig.append(net_map_at(net));
+ allseq_nets.erase(net);
+ }
if (i == netbus->LeftIndex())
break;
}
@@ -971,6 +1016,12 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se
if (GetSize(anyseq_sig))
module->connect(anyseq_sig, module->Anyseq(NEW_ID, GetSize(anyseq_sig)));
+
+ if (GetSize(allconst_sig))
+ module->connect(allconst_sig, module->Allconst(NEW_ID, GetSize(allconst_sig)));
+
+ if (GetSize(allseq_sig))
+ module->connect(allseq_sig, module->Allseq(NEW_ID, GetSize(allseq_sig)));
}
for (auto it : init_nets)
@@ -1027,7 +1078,9 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se
}
if (inst->Type() == PRIM_BUF) {
- module->addBufGate(inst_name, net_map_at(inst->GetInput()), net_map_at(inst->GetOutput()));
+ auto outnet = inst->GetOutput();
+ if (!any_all_nets.count(outnet))
+ module->addBufGate(inst_name, net_map_at(inst->GetInput()), net_map_at(outnet));
continue;
}
@@ -1044,23 +1097,30 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se
if (inst->Type() == OPER_READ_PORT)
{
RTLIL::Memory *memory = module->memories.at(RTLIL::escape_id(inst->GetInput()->Name()));
- if (memory->width != int(inst->OutputSize()))
- log_error("Import of asymetric memories from Verific is not supported yet: %s %s\n", inst->Name(), inst->GetInput()->Name());
+ int numchunks = int(inst->OutputSize()) / memory->width;
+ int chunksbits = ceil_log2(numchunks);
- RTLIL::SigSpec addr = operatorInput1(inst);
- RTLIL::SigSpec data = operatorOutput(inst);
+ if ((numchunks * memory->width) != int(inst->OutputSize()) || (numchunks & (numchunks - 1)) != 0)
+ log_error("Import of asymmetric memories of this type is not supported yet: %s %s\n", inst->Name(), inst->GetInput()->Name());
- RTLIL::Cell *cell = module->addCell(inst_name, "$memrd");
- cell->parameters["\\MEMID"] = memory->name.str();
- cell->parameters["\\CLK_ENABLE"] = false;
- cell->parameters["\\CLK_POLARITY"] = true;
- cell->parameters["\\TRANSPARENT"] = false;
- cell->parameters["\\ABITS"] = GetSize(addr);
- cell->parameters["\\WIDTH"] = GetSize(data);
- cell->setPort("\\CLK", RTLIL::State::Sx);
- cell->setPort("\\EN", RTLIL::State::Sx);
- cell->setPort("\\ADDR", addr);
- cell->setPort("\\DATA", data);
+ for (int i = 0; i < numchunks; i++)
+ {
+ RTLIL::SigSpec addr = {operatorInput1(inst), RTLIL::Const(i, chunksbits)};
+ RTLIL::SigSpec data = operatorOutput(inst).extract(i * memory->width, memory->width);
+
+ RTLIL::Cell *cell = module->addCell(numchunks == 1 ? inst_name :
+ RTLIL::IdString(stringf("%s_%d", inst_name.c_str(), i)), "$memrd");
+ cell->parameters["\\MEMID"] = memory->name.str();
+ cell->parameters["\\CLK_ENABLE"] = false;
+ cell->parameters["\\CLK_POLARITY"] = true;
+ cell->parameters["\\TRANSPARENT"] = false;
+ cell->parameters["\\ABITS"] = GetSize(addr);
+ cell->parameters["\\WIDTH"] = GetSize(data);
+ cell->setPort("\\CLK", RTLIL::State::Sx);
+ cell->setPort("\\EN", RTLIL::State::Sx);
+ cell->setPort("\\ADDR", addr);
+ cell->setPort("\\DATA", data);
+ }
continue;
}
@@ -1068,7 +1128,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se
{
RTLIL::Memory *memory = module->memories.at(RTLIL::escape_id(inst->GetOutput()->Name()));
if (memory->width != int(inst->Input2Size()))
- log_error("Import of asymetric memories from Verific is not supported yet: %s %s\n", inst->Name(), inst->GetInput()->Name());
+ log_error("Import of asymmetric memories of this type is not supported yet: %s %s\n", inst->Name(), inst->GetInput()->Name());
RTLIL::SigSpec addr = operatorInput1(inst);
RTLIL::SigSpec data = operatorInput2(inst);
@@ -1214,11 +1274,27 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se
continue;
}
- if (inst->IsPrimitive())
+ if (inst->Type() == PRIM_HDL_ASSERTION)
{
- if (inst->Type() == PRIM_HDL_ASSERTION)
- continue;
+ SigBit cond = net_map_at(inst->GetInput());
+ if (verific_verbose)
+ log(" assert condition %s.\n", log_signal(cond));
+
+ const char *assume_attr = nullptr; // inst->GetAttValue("assume");
+
+ Cell *cell = nullptr;
+ if (assume_attr != nullptr && !strcmp(assume_attr, "1"))
+ cell = module->addAssume(NEW_ID, cond, State::S1);
+ else
+ cell = module->addAssert(NEW_ID, cond, State::S1);
+
+ import_attributes(cell->attributes, inst);
+ continue;
+ }
+
+ if (inst->IsPrimitive())
+ {
if (!mode_keep)
log_error("Unsupported Verific primitive %s of type %s\n", inst->Name(), inst->View()->Owner()->Name());
@@ -1272,8 +1348,11 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se
if (!mode_nosva)
{
- for (auto inst : sva_asserts)
+ for (auto inst : sva_asserts) {
+ if (mode_autocover)
+ verific_import_sva_cover(this, inst);
verific_import_sva_assert(this, inst);
+ }
for (auto inst : sva_assumes)
verific_import_sva_assume(this, inst);
@@ -1290,7 +1369,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se
// ==================================================================
-VerificClocking::VerificClocking(VerificImporter *importer, Net *net)
+VerificClocking::VerificClocking(VerificImporter *importer, Net *net, bool sva_at_only)
{
module = importer->module;
@@ -1313,8 +1392,14 @@ VerificClocking::VerificClocking(VerificImporter *importer, Net *net)
body_net = body_inst->GetInput2();
}
}
+ else
+ {
+ if (sva_at_only)
+ return;
+ }
- if (inst != nullptr && inst->Type() == PRIM_SVA_POSEDGE)
+ // Use while() instead of if() to work around VIPER #13453
+ while (inst != nullptr && inst->Type() == PRIM_SVA_POSEDGE)
{
net = inst->GetInput();
inst = net->Driver();;
@@ -1388,6 +1473,10 @@ VerificClocking::VerificClocking(VerificImporter *importer, Net *net)
clock_net = net;
clock_sig = importer->net_map_at(clock_net);
+
+ const char *gclk_attr = clock_net->GetAttValue("gclk");
+ if (gclk_attr != nullptr && (!strcmp(gclk_attr, "1") || !strcmp(gclk_attr, "'1'")))
+ gclk = true;
}
Cell *VerificClocking::addDff(IdString name, SigSpec sig_d, SigSpec sig_q, Const init_value)
@@ -1410,15 +1499,20 @@ Cell *VerificClocking::addDff(IdString name, SigSpec sig_d, SigSpec sig_q, Const
sig_d = module->Mux(NEW_ID, sig_q, sig_d, enable_sig);
if (disable_sig != State::S0) {
+ log_assert(gclk == false);
log_assert(GetSize(sig_q) == GetSize(init_value));
return module->addAdff(name, clock_sig, disable_sig, sig_d, sig_q, init_value, posedge);
}
+ if (gclk)
+ return module->addFf(name, sig_d, sig_q);
+
return module->addDff(name, clock_sig, sig_d, sig_q, posedge);
}
Cell *VerificClocking::addAdff(IdString name, RTLIL::SigSpec sig_arst, SigSpec sig_d, SigSpec sig_q, Const arst_value)
{
+ log_assert(gclk == false);
log_assert(disable_sig == State::S0);
if (enable_sig != State::S1)
@@ -1429,6 +1523,7 @@ Cell *VerificClocking::addAdff(IdString name, RTLIL::SigSpec sig_arst, SigSpec s
Cell *VerificClocking::addDffsr(IdString name, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr, SigSpec sig_d, SigSpec sig_q)
{
+ log_assert(gclk == false);
log_assert(disable_sig == State::S0);
if (enable_sig != State::S1)
@@ -1521,11 +1616,73 @@ struct VerificExtNets
}
};
+void verific_import(Design *design, std::string top)
+{
+ std::set<Netlist*> nl_todo, nl_done;
+
+ {
+ VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary("work", 1);
+ VeriLibrary *veri_lib = veri_file::GetLibrary("work", 1);
+
+ Array veri_libs, vhdl_libs;
+ if (vhdl_lib) vhdl_libs.InsertLast(vhdl_lib);
+ if (veri_lib) veri_libs.InsertLast(veri_lib);
+
+ Array *netlists = hier_tree::ElaborateAll(&veri_libs, &vhdl_libs);
+ Netlist *nl;
+ int i;
+
+ FOREACH_ARRAY_ITEM(netlists, i, nl) {
+ if (top.empty() || nl->Owner()->Name() == top)
+ nl_todo.insert(nl);
+ }
+
+ delete netlists;
+ }
+
+ if (!verific_error_msg.empty())
+ log_error("%s\n", verific_error_msg.c_str());
+
+ VerificExtNets worker;
+ for (auto nl : nl_todo)
+ worker.run(nl);
+
+ while (!nl_todo.empty()) {
+ Netlist *nl = *nl_todo.begin();
+ if (nl_done.count(nl) == 0) {
+ VerificImporter importer(false, false, false, false, false, false);
+ importer.import_netlist(design, nl, nl_todo);
+ }
+ nl_todo.erase(nl);
+ nl_done.insert(nl);
+ }
+
+ veri_file::Reset();
+ vhdl_file::Reset();
+ Libset::Reset();
+ verific_incdirs.clear();
+ verific_libdirs.clear();
+ verific_import_pending = false;
+
+ if (!verific_error_msg.empty())
+ log_error("%s\n", verific_error_msg.c_str());
+}
+
YOSYS_NAMESPACE_END
#endif /* YOSYS_ENABLE_VERIFIC */
PRIVATE_NAMESPACE_BEGIN
+bool check_noverific_env()
+{
+ const char *e = getenv("YOSYS_NOVERIFIC");
+ if (e == nullptr)
+ return false;
+ if (atoi(e) == 0)
+ return false;
+ return true;
+}
+
struct VerificPass : public Pass {
VerificPass() : Pass("verific", "load Verilog and VHDL designs using Verific") { }
virtual void help()
@@ -1536,6 +1693,18 @@ struct VerificPass : public Pass {
log("\n");
log("Load the specified Verilog/SystemVerilog files into Verific.\n");
log("\n");
+ log("All files specified in one call to this command are one compilation unit.\n");
+ log("Files passed to different calls to this command are treated as belonging to\n");
+ log("different compilation units.\n");
+ log("\n");
+ log("Additional -D<macro>[=<value>] options may be added after the option indicating\n");
+ log("the language version (and before file names) to set additional verilog defines.\n");
+ log("The macros SYNTHESIS and VERIFIC are defined implicitly.\n");
+ log("\n");
+ log("\n");
+ log(" verific -formal <verilog-file>..\n");
+ log("\n");
+ log("Like -sv, but define FORMAL instead of SYNTHESIS.\n");
log("\n");
log(" verific {-vhdl87|-vhdl93|-vhdl2k|-vhdl2008|-vhdl} <vhdl-file>..\n");
log("\n");
@@ -1555,7 +1724,12 @@ struct VerificPass : public Pass {
log("\n");
log(" verific -vlog-define <macro>[=<value>]..\n");
log("\n");
- log("Add Verilog defines. (The macros SYNTHESIS and VERIFIC are defined implicitly.)\n");
+ log("Add Verilog defines.\n");
+ log("\n");
+ log("\n");
+ log(" verific -vlog-undef <macro>..\n");
+ log("\n");
+ log("Remove Verilog defines previously set with -vlog-define.\n");
log("\n");
log("\n");
log(" verific -import [options] <top-module>..\n");
@@ -1578,6 +1752,9 @@ struct VerificPass : public Pass {
log(" -extnets\n");
log(" Resolve references to external nets by adding module ports as needed.\n");
log("\n");
+ log(" -autocover\n");
+ log(" Generate automatic cover statements for all asserts\n");
+ log("\n");
log(" -v, -vv\n");
log(" Verbose log messages. (-vv is even more verbose than -v.)\n");
log("\n");
@@ -1609,6 +1786,9 @@ struct VerificPass : public Pass {
#ifdef YOSYS_ENABLE_VERIFIC
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
+ if (check_noverific_env())
+ log_cmd_error("This version of Yosys is built without Verific support.\n");
+
log_header(design, "Executing VERIFIC (loading SystemVerilog and VHDL designs using Verific).\n");
Message::SetConsoleOutput(0);
@@ -1616,8 +1796,12 @@ struct VerificPass : public Pass {
RuntimeFlags::SetVar("db_preserve_user_nets", 1);
RuntimeFlags::SetVar("db_allow_external_nets", 1);
RuntimeFlags::SetVar("vhdl_ignore_assertion_statements", 0);
- veri_file::DefineCmdLineMacro("VERIFIC");
- veri_file::DefineCmdLineMacro("SYNTHESIS");
+ RuntimeFlags::SetVar("veri_extract_dualport_rams", 0);
+ RuntimeFlags::SetVar("veri_extract_multiport_rams", 1);
+ RuntimeFlags::SetVar("db_infer_wide_operators", 1);
+
+ // WARNING: instantiating unknown module 'XYZ' (VERI-1063)
+ Message::SetMessageType("VERI-1063", VERIFIC_ERROR);
verific_verbose = 0;
@@ -1637,13 +1821,13 @@ struct VerificPass : public Pass {
if (GetSize(args) > argidx && args[argidx] == "-vlog-incdir") {
for (argidx++; argidx < GetSize(args); argidx++)
- veri_file::AddIncludeDir(args[argidx].c_str());
+ verific_incdirs.push_back(args[argidx]);
goto check_error;
}
if (GetSize(args) > argidx && args[argidx] == "-vlog-libdir") {
for (argidx++; argidx < GetSize(args); argidx++)
- veri_file::AddYDir(args[argidx].c_str());
+ verific_libdirs.push_back(args[argidx]);
goto check_error;
}
@@ -1662,38 +1846,65 @@ struct VerificPass : public Pass {
goto check_error;
}
- if (GetSize(args) > argidx && args[argidx] == "-vlog95") {
- for (argidx++; argidx < GetSize(args); argidx++)
- if (!veri_file::Analyze(args[argidx].c_str(), veri_file::VERILOG_95))
- log_cmd_error("Reading `%s' in VERILOG_95 mode failed.\n", args[argidx].c_str());
+ if (GetSize(args) > argidx && args[argidx] == "-vlog-undef") {
+ for (argidx++; argidx < GetSize(args); argidx++) {
+ string name = args[argidx];
+ veri_file::UndefineMacro(name.c_str());
+ }
goto check_error;
}
- if (GetSize(args) > argidx && args[argidx] == "-vlog2k") {
- for (argidx++; argidx < GetSize(args); argidx++)
- if (!veri_file::Analyze(args[argidx].c_str(), veri_file::VERILOG_2K))
- log_cmd_error("Reading `%s' in VERILOG_2K mode failed.\n", args[argidx].c_str());
- goto check_error;
- }
+ if (GetSize(args) > argidx && (args[argidx] == "-vlog95" || args[argidx] == "-vlog2k" || args[argidx] == "-sv2005" ||
+ args[argidx] == "-sv2009" || args[argidx] == "-sv2012" || args[argidx] == "-sv" || args[argidx] == "-formal"))
+ {
+ Array file_names;
+ unsigned verilog_mode;
+
+ if (args[argidx] == "-vlog95")
+ verilog_mode = veri_file::VERILOG_95;
+ else if (args[argidx] == "-vlog2k")
+ verilog_mode = veri_file::VERILOG_2K;
+ else if (args[argidx] == "-sv2005")
+ verilog_mode = veri_file::SYSTEM_VERILOG_2005;
+ else if (args[argidx] == "-sv2009")
+ verilog_mode = veri_file::SYSTEM_VERILOG_2009;
+ else if (args[argidx] == "-sv2012" || args[argidx] == "-sv" || args[argidx] == "-formal")
+ verilog_mode = veri_file::SYSTEM_VERILOG;
+ else
+ log_abort();
- if (GetSize(args) > argidx && args[argidx] == "-sv2005") {
- for (argidx++; argidx < GetSize(args); argidx++)
- if (!veri_file::Analyze(args[argidx].c_str(), veri_file::SYSTEM_VERILOG_2005))
- log_cmd_error("Reading `%s' in SYSTEM_VERILOG_2005 mode failed.\n", args[argidx].c_str());
- goto check_error;
- }
+ veri_file::DefineMacro("VERIFIC");
+ veri_file::DefineMacro(args[argidx] == "-formal" ? "FORMAL" : "SYNTHESIS");
- if (GetSize(args) > argidx && args[argidx] == "-sv2009") {
- for (argidx++; argidx < GetSize(args); argidx++)
- if (!veri_file::Analyze(args[argidx].c_str(), veri_file::SYSTEM_VERILOG_2009))
- log_cmd_error("Reading `%s' in SYSTEM_VERILOG_2009 mode failed.\n", args[argidx].c_str());
- goto check_error;
- }
+ for (argidx++; argidx < GetSize(args) && GetSize(args[argidx]) >= 2 && args[argidx].substr(0, 2) == "-D"; argidx++) {
+ std::string name = args[argidx].substr(2);
+ if (args[argidx] == "-D") {
+ if (++argidx >= GetSize(args))
+ break;
+ name = args[argidx];
+ }
+ size_t equal = name.find('=');
+ if (equal != std::string::npos) {
+ string value = name.substr(equal+1);
+ name = name.substr(0, equal);
+ veri_file::DefineMacro(name.c_str(), value.c_str());
+ } else {
+ veri_file::DefineMacro(name.c_str());
+ }
+ }
- if (GetSize(args) > argidx && (args[argidx] == "-sv2012" || args[argidx] == "-sv")) {
- for (argidx++; argidx < GetSize(args); argidx++)
- if (!veri_file::Analyze(args[argidx].c_str(), veri_file::SYSTEM_VERILOG))
- log_cmd_error("Reading `%s' in SYSTEM_VERILOG mode failed.\n", args[argidx].c_str());
+ for (auto &dir : verific_incdirs)
+ veri_file::AddIncludeDir(dir.c_str());
+ for (auto &dir : verific_libdirs)
+ veri_file::AddYDir(dir.c_str());
+
+ while (argidx < GetSize(args))
+ file_names.Insert(args[argidx++].c_str());
+
+ if (!veri_file::AnalyzeMultipleFiles(&file_names, verilog_mode, "work", veri_file::MFCU))
+ log_cmd_error("Reading Verilog/SystemVerilog sources failed.\n");
+
+ verific_import_pending = true;
goto check_error;
}
@@ -1702,6 +1913,7 @@ struct VerificPass : public Pass {
for (argidx++; argidx < GetSize(args); argidx++)
if (!vhdl_file::Analyze(args[argidx].c_str(), "work", vhdl_file::VHDL_87))
log_cmd_error("Reading `%s' in VHDL_87 mode failed.\n", args[argidx].c_str());
+ verific_import_pending = true;
goto check_error;
}
@@ -1710,6 +1922,7 @@ struct VerificPass : public Pass {
for (argidx++; argidx < GetSize(args); argidx++)
if (!vhdl_file::Analyze(args[argidx].c_str(), "work", vhdl_file::VHDL_93))
log_cmd_error("Reading `%s' in VHDL_93 mode failed.\n", args[argidx].c_str());
+ verific_import_pending = true;
goto check_error;
}
@@ -1718,6 +1931,7 @@ struct VerificPass : public Pass {
for (argidx++; argidx < GetSize(args); argidx++)
if (!vhdl_file::Analyze(args[argidx].c_str(), "work", vhdl_file::VHDL_2K))
log_cmd_error("Reading `%s' in VHDL_2K mode failed.\n", args[argidx].c_str());
+ verific_import_pending = true;
goto check_error;
}
@@ -1726,6 +1940,7 @@ struct VerificPass : public Pass {
for (argidx++; argidx < GetSize(args); argidx++)
if (!vhdl_file::Analyze(args[argidx].c_str(), "work", vhdl_file::VHDL_2008))
log_cmd_error("Reading `%s' in VHDL_2008 mode failed.\n", args[argidx].c_str());
+ verific_import_pending = true;
goto check_error;
}
@@ -1734,6 +1949,7 @@ struct VerificPass : public Pass {
std::set<Netlist*> nl_todo, nl_done;
bool mode_all = false, mode_gates = false, mode_keep = false;
bool mode_nosva = false, mode_names = false, mode_verific = false;
+ bool mode_autocover = false;
bool flatten = false, extnets = false;
string dumpfile;
@@ -1766,6 +1982,10 @@ struct VerificPass : public Pass {
mode_names = true;
continue;
}
+ if (args[argidx] == "-autocover") {
+ mode_autocover = true;
+ continue;
+ }
if (args[argidx] == "-V") {
mode_verific = true;
continue;
@@ -1898,6 +2118,9 @@ struct VerificPass : public Pass {
#endif
}
+ if (!verific_error_msg.empty())
+ goto check_error;
+
if (flatten) {
for (auto nl : nl_todo)
nl->Flatten();
@@ -1918,7 +2141,7 @@ struct VerificPass : public Pass {
Netlist *nl = *nl_todo.begin();
if (nl_done.count(nl) == 0) {
VerificImporter importer(mode_gates, mode_keep, mode_nosva,
- mode_names, mode_verific);
+ mode_names, mode_verific, mode_autocover);
importer.import_netlist(design, nl, nl_todo);
}
nl_todo.erase(nl);
@@ -1928,6 +2151,9 @@ struct VerificPass : public Pass {
veri_file::Reset();
vhdl_file::Reset();
Libset::Reset();
+ verific_incdirs.clear();
+ verific_libdirs.clear();
+ verific_import_pending = false;
goto check_error;
}
@@ -1945,5 +2171,133 @@ struct VerificPass : public Pass {
#endif
} VerificPass;
-PRIVATE_NAMESPACE_END
+struct ReadPass : public Pass {
+ ReadPass() : Pass("read", "load HDL designs") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" read {-vlog95|-vlog2k|-sv2005|-sv2009|-sv2012|-sv|-formal} <verilog-file>..\n");
+ log("\n");
+ log("Load the specified Verilog/SystemVerilog files. (Full SystemVerilog support\n");
+ log("is only available via Verific.)\n");
+ log("\n");
+ log("Additional -D<macro>[=<value>] options may be added after the option indicating\n");
+ log("the language version (and before file names) to set additional verilog defines.\n");
+ log("\n");
+ log("\n");
+ log(" read {-vhdl87|-vhdl93|-vhdl2k|-vhdl2008|-vhdl} <vhdl-file>..\n");
+ log("\n");
+ log("Load the specified VHDL files. (Requires Verific.)\n");
+ log("\n");
+ log("\n");
+ log(" read -define <macro>[=<value>]..\n");
+ log("\n");
+ log("Set global Verilog/SystemVerilog defines.\n");
+ log("\n");
+ log("\n");
+ log(" read -undef <macro>..\n");
+ log("\n");
+ log("Unset global Verilog/SystemVerilog defines.\n");
+ log("\n");
+ log("\n");
+ log(" read -incdir <directory>\n");
+ log("\n");
+ log("Add directory to global Verilog/SystemVerilog include directories.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ if (args.size() < 2)
+ log_cmd_error("Missing mode parameter.\n");
+
+ if (args.size() < 3)
+ log_cmd_error("Missing file name parameter.\n");
+
+#ifdef YOSYS_ENABLE_VERIFIC
+ bool use_verific = !check_noverific_env();
+#else
+ bool use_verific = false;
+#endif
+
+ if (args[1] == "-vlog95" || args[1] == "-vlog2k") {
+ if (use_verific) {
+ args[0] = "verific";
+ } else {
+ args[0] = "read_verilog";
+ args.erase(args.begin()+1, args.begin()+2);
+ }
+ Pass::call(design, args);
+ return;
+ }
+ if (args[1] == "-sv2005" || args[1] == "-sv2009" || args[1] == "-sv2012" || args[1] == "-sv" || args[1] == "-formal") {
+ if (use_verific) {
+ args[0] = "verific";
+ } else {
+ args[0] = "read_verilog";
+ if (args[1] == "-formal")
+ args.insert(args.begin()+1, std::string());
+ args[1] = "-sv";
+ }
+ Pass::call(design, args);
+ return;
+ }
+
+ if (args[1] == "-vhdl87" || args[1] == "-vhdl93" || args[1] == "-vhdl2k" || args[1] == "-vhdl2008" || args[1] == "-vhdl") {
+ if (use_verific) {
+ args[0] = "verific";
+ Pass::call(design, args);
+ } else {
+ log_cmd_error("This version of Yosys is built without Verific support.\n");
+ }
+ return;
+ }
+
+ if (args[1] == "-define") {
+ if (use_verific) {
+ args[0] = "verific";
+ args[1] = "-vlog-define";
+ Pass::call(design, args);
+ }
+ args[0] = "verilog_defines";
+ args.erase(args.begin()+1, args.begin()+2);
+ for (int i = 1; i < GetSize(args); i++)
+ args[i] = "-D" + args[i];
+ Pass::call(design, args);
+ return;
+ }
+
+ if (args[1] == "-undef") {
+ if (use_verific) {
+ args[0] = "verific";
+ args[1] = "-vlog-undef";
+ Pass::call(design, args);
+ }
+ args[0] = "verilog_defines";
+ args.erase(args.begin()+1, args.begin()+2);
+ for (int i = 1; i < GetSize(args); i++)
+ args[i] = "-U" + args[i];
+ Pass::call(design, args);
+ return;
+ }
+
+ if (args[1] == "-incdir") {
+ if (use_verific) {
+ args[0] = "verific";
+ args[1] = "-vlog-incdir";
+ Pass::call(design, args);
+ }
+ args[0] = "verilog_defaults";
+ args[1] = "-add";
+ for (int i = 2; i < GetSize(args); i++)
+ args[i] = "-I" + args[i];
+ Pass::call(design, args);
+ return;
+ }
+
+ log_cmd_error("Missing or unsupported mode parameter.\n");
+ }
+} ReadPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/frontends/verific/verific.h b/frontends/verific/verific.h
index 877d79057..cbd9314db 100644
--- a/frontends/verific/verific.h
+++ b/frontends/verific/verific.h
@@ -25,6 +25,9 @@ YOSYS_NAMESPACE_BEGIN
extern int verific_verbose;
+extern bool verific_import_pending;
+extern void verific_import(Design *design, std::string top = std::string());
+
extern pool<int> verific_sva_prims;
struct VerificImporter;
@@ -40,9 +43,10 @@ struct VerificClocking {
SigBit enable_sig = State::S1;
SigBit disable_sig = State::S0;
bool posedge = true;
+ bool gclk = false;
VerificClocking() { }
- VerificClocking(VerificImporter *importer, Verific::Net *net);
+ VerificClocking(VerificImporter *importer, Verific::Net *net, bool sva_at_only = false);
RTLIL::Cell *addDff(IdString name, SigSpec sig_d, SigSpec sig_q, Const init_value = Const());
RTLIL::Cell *addAdff(IdString name, RTLIL::SigSpec sig_arst, SigSpec sig_d, SigSpec sig_q, Const arst_value);
RTLIL::Cell *addDffsr(IdString name, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr, SigSpec sig_d, SigSpec sig_q);
@@ -65,10 +69,12 @@ struct VerificImporter
std::map<Verific::Net*, RTLIL::SigBit> net_map;
std::map<Verific::Net*, Verific::Net*> sva_posedge_map;
+ pool<Verific::Net*, hash_ptr_ops> any_all_nets;
bool mode_gates, mode_keep, mode_nosva, mode_names, mode_verific;
+ bool mode_autocover;
- VerificImporter(bool mode_gates, bool mode_keep, bool mode_nosva, bool mode_names, bool mode_verific);
+ VerificImporter(bool mode_gates, bool mode_keep, bool mode_nosva, bool mode_names, bool mode_verific, bool mode_autocover);
RTLIL::SigBit net_map_at(Verific::Net *net);
@@ -78,7 +84,7 @@ struct VerificImporter
RTLIL::SigSpec operatorInput1(Verific::Instance *inst);
RTLIL::SigSpec operatorInput2(Verific::Instance *inst);
RTLIL::SigSpec operatorInport(Verific::Instance *inst, const char *portname);
- RTLIL::SigSpec operatorOutput(Verific::Instance *inst);
+ RTLIL::SigSpec operatorOutput(Verific::Instance *inst, const pool<Verific::Net*, hash_ptr_ops> *any_all_nets = nullptr);
bool import_netlist_instance_gates(Verific::Instance *inst, RTLIL::IdString inst_name);
bool import_netlist_instance_cells(Verific::Instance *inst, RTLIL::IdString inst_name);
diff --git a/frontends/verific/verificsva.cc b/frontends/verific/verificsva.cc
index 5abe0eb35..85b842186 100644
--- a/frontends/verific/verificsva.cc
+++ b/frontends/verific/verificsva.cc
@@ -21,14 +21,52 @@
// Currently supported SVA sequence and property syntax:
// http://symbiyosys.readthedocs.io/en/latest/verific.html
//
-// Todos:
-// property and property
-// sequence |-> always sequence
-// sequence |-> eventually sequence
-// sequence implies sequence
-// sequence iff sequence
-// accept_on (expr) prop
-// reject_on (expr) prop
+// Next gen property syntax:
+// basic_property
+// [antecedent_condition] property
+// [antecedent_condition] always.. property
+// [antecedent_condition] eventually.. basic_property
+// [antecedent_condition] property until.. expression
+// [antecedent_condition] basic_property until.. basic_property (assert/assume only)
+//
+// antecedent_condition:
+// sequence |->
+// sequence |=>
+//
+// basic_property:
+// sequence
+// not basic_property
+// sequence #-# basic_property
+// sequence #=# basic_property
+// basic_property or basic_property (cover only)
+// basic_property and basic_property (assert/assume only)
+// basic_property implies basic_property
+// basic_property iff basic_property
+//
+// sequence:
+// expression
+// sequence ##N sequence
+// sequence ##[*] sequence
+// sequence ##[+] sequence
+// sequence ##[N:M] sequence
+// sequence ##[N:$] sequence
+// expression [*]
+// expression [+]
+// expression [*N]
+// expression [*N:M]
+// expression [*N:$]
+// sequence or sequence
+// sequence and sequence
+// expression throughout sequence
+// sequence intersect sequence
+// sequence within sequence
+// first_match( sequence )
+// expression [=N]
+// expression [=N:M]
+// expression [=N:$]
+// expression [->N]
+// expression [->N:M]
+// expression [->N:$]
#include "kernel/yosys.h"
@@ -942,7 +980,6 @@ struct VerificSvaImporter
bool mode_assume = false;
bool mode_cover = false;
bool mode_trigger = false;
- bool eventually = false;
Instance *net_to_ast_driver(Net *n)
{
@@ -1100,6 +1137,97 @@ struct VerificSvaImporter
log_abort();
}
+ bool check_zero_consecutive_repeat(Net *net)
+ {
+ Instance *inst = net_to_ast_driver(net);
+
+ if (inst == nullptr)
+ return false;
+
+ if (inst->Type() != PRIM_SVA_CONSECUTIVE_REPEAT)
+ return false;
+
+ const char *sva_low_s = inst->GetAttValue("sva:low");
+ int sva_low = atoi(sva_low_s);
+
+ return sva_low == 0;
+ }
+
+ int parse_consecutive_repeat(SvaFsm &fsm, int start_node, Net *net, bool add_pre_delay, bool add_post_delay)
+ {
+ Instance *inst = net_to_ast_driver(net);
+
+ log_assert(inst->Type() == PRIM_SVA_CONSECUTIVE_REPEAT);
+
+ const char *sva_low_s = inst->GetAttValue("sva:low");
+ const char *sva_high_s = inst->GetAttValue("sva:high");
+
+ int sva_low = atoi(sva_low_s);
+ int sva_high = atoi(sva_high_s);
+ bool sva_inf = !strcmp(sva_high_s, "$");
+
+ Net *body_net = inst->GetInput();
+
+ if (add_pre_delay || add_post_delay)
+ log_assert(sva_low == 0);
+
+ if (sva_low == 0) {
+ if (!add_pre_delay && !add_post_delay)
+ parser_error("Possibly zero-length consecutive repeat must follow or precede a delay of at least one cycle", inst);
+ sva_low++;
+ }
+
+ int node = fsm.createNode(start_node);
+ start_node = node;
+
+ if (add_pre_delay) {
+ node = fsm.createNode(start_node);
+ fsm.createEdge(start_node, node);
+ }
+
+ int prev_node = node;
+ node = parse_sequence(fsm, node, body_net);
+
+ for (int i = 1; i < sva_low; i++)
+ {
+ int next_node = fsm.createNode();
+ fsm.createEdge(node, next_node);
+
+ prev_node = node;
+ node = parse_sequence(fsm, next_node, body_net);
+ }
+
+ if (sva_inf)
+ {
+ log_assert(prev_node >= 0);
+ fsm.createEdge(node, prev_node);
+ }
+ else
+ {
+ for (int i = sva_low; i < sva_high; i++)
+ {
+ int next_node = fsm.createNode();
+ fsm.createEdge(node, next_node);
+
+ prev_node = node;
+ node = parse_sequence(fsm, next_node, body_net);
+
+ fsm.createLink(prev_node, node);
+ }
+ }
+
+ if (add_post_delay) {
+ int next_node = fsm.createNode();
+ fsm.createEdge(node, next_node);
+ node = next_node;
+ }
+
+ if (add_pre_delay || add_post_delay)
+ fsm.createLink(start_node, node);
+
+ return node;
+ }
+
int parse_sequence(SvaFsm &fsm, int start_node, Net *net)
{
if (check_expression(net)) {
@@ -1144,7 +1272,20 @@ struct VerificSvaImporter
int sva_high = atoi(sva_high_s);
bool sva_inf = !strcmp(sva_high_s, "$");
- int node = parse_sequence(fsm, start_node, inst->GetInput1());
+ int node = -1;
+ bool past_add_delay = false;
+
+ if (check_zero_consecutive_repeat(inst->GetInput1()) && sva_low > 0) {
+ node = parse_consecutive_repeat(fsm, start_node, inst->GetInput1(), false, true);
+ sva_low--, sva_high--;
+ } else {
+ node = parse_sequence(fsm, start_node, inst->GetInput1());
+ }
+
+ if (check_zero_consecutive_repeat(inst->GetInput2()) && sva_low > 0) {
+ past_add_delay = true;
+ sva_low--, sva_high--;
+ }
for (int i = 0; i < sva_low; i++) {
int next_node = fsm.createNode();
@@ -1167,62 +1308,17 @@ struct VerificSvaImporter
}
}
- node = parse_sequence(fsm, node, inst->GetInput2());
+ if (past_add_delay)
+ node = parse_consecutive_repeat(fsm, node, inst->GetInput2(), true, false);
+ else
+ node = parse_sequence(fsm, node, inst->GetInput2());
return node;
}
if (inst->Type() == PRIM_SVA_CONSECUTIVE_REPEAT)
{
- const char *sva_low_s = inst->GetAttValue("sva:low");
- const char *sva_high_s = inst->GetAttValue("sva:high");
-
- int sva_low = atoi(sva_low_s);
- int sva_high = atoi(sva_high_s);
- bool sva_inf = !strcmp(sva_high_s, "$");
-
- Net *body_net = inst->GetInput();
- int node = fsm.createNode(start_node);
-
- for (int i = 0; i < sva_low; i++)
- {
- int next_node = fsm.createNode();
-
- if (i == 0)
- fsm.createLink(node, next_node);
- else
- fsm.createEdge(node, next_node);
-
- node = parse_sequence(fsm, next_node, body_net);
- }
-
- if (sva_inf)
- {
- int next_node = fsm.createNode();
- fsm.createEdge(node, next_node);
-
- next_node = parse_sequence(fsm, next_node, body_net);
- fsm.createLink(next_node, node);
- }
- else
- {
- for (int i = sva_low; i < sva_high; i++)
- {
- int next_node = fsm.createNode();
-
- if (i == 0)
- fsm.createLink(node, next_node);
- else
- fsm.createEdge(node, next_node);
-
- next_node = parse_sequence(fsm, next_node, body_net);
-
- fsm.createLink(node, next_node);
- node = next_node;
- }
- }
-
- return node;
+ return parse_consecutive_repeat(fsm, start_node, net, false, false);
}
if (inst->Type() == PRIM_SVA_NON_CONSECUTIVE_REPEAT || inst->Type() == PRIM_SVA_GOTO_REPEAT)
@@ -1390,6 +1486,72 @@ struct VerificSvaImporter
fsm.getFirstAcceptReject(accept_p, reject_p);
}
+ bool eventually_property(Net *&net, SigBit &trig)
+ {
+ Instance *inst = net_to_ast_driver(net);
+
+ if (inst == nullptr)
+ return false;
+
+ if (clocking.cond_net != nullptr)
+ trig = importer->net_map_at(clocking.cond_net);
+ else
+ trig = State::S1;
+
+ if (inst->Type() == PRIM_SVA_S_EVENTUALLY || inst->Type() == PRIM_SVA_EVENTUALLY)
+ {
+ if (mode_cover || mode_trigger)
+ parser_error(inst);
+
+ net = inst->GetInput();
+ clocking.cond_net = nullptr;
+
+ return true;
+ }
+
+ if (inst->Type() == PRIM_SVA_OVERLAPPED_IMPLICATION ||
+ inst->Type() == PRIM_SVA_NON_OVERLAPPED_IMPLICATION)
+ {
+ Net *antecedent_net = inst->GetInput1();
+ Net *consequent_net = inst->GetInput2();
+
+ Instance *consequent_inst = net_to_ast_driver(consequent_net);
+
+ if (consequent_inst == nullptr)
+ return false;
+
+ if (consequent_inst->Type() != PRIM_SVA_S_EVENTUALLY && consequent_inst->Type() != PRIM_SVA_EVENTUALLY)
+ return false;
+
+ if (mode_cover || mode_trigger)
+ parser_error(consequent_inst);
+
+ int node;
+
+ SvaFsm antecedent_fsm(clocking, trig);
+ node = parse_sequence(antecedent_fsm, antecedent_fsm.createStartNode(), antecedent_net);
+ if (inst->Type() == PRIM_SVA_NON_OVERLAPPED_IMPLICATION) {
+ int next_node = antecedent_fsm.createNode();
+ antecedent_fsm.createEdge(node, next_node);
+ node = next_node;
+ }
+ antecedent_fsm.createLink(node, antecedent_fsm.acceptNode);
+
+ trig = antecedent_fsm.getAccept();
+ net = consequent_inst->GetInput();
+ clocking.cond_net = nullptr;
+
+ if (verific_verbose) {
+ log(" Eventually Antecedent FSM:\n");
+ antecedent_fsm.dump();
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
void parse_property(Net *net, SigBit *accept_p, SigBit *reject_p)
{
Instance *inst = net_to_ast_driver(net);
@@ -1505,20 +1667,65 @@ struct VerificSvaImporter
RTLIL::IdString root_name = module->uniquify(importer->mode_names || root->IsUserDeclared() ? RTLIL::escape_id(root->Name()) : NEW_ID);
- clocking = VerificClocking(importer, root->GetInput());
+ // parse SVA sequence into trigger signal
+
+ clocking = VerificClocking(importer, root->GetInput(), true);
+ SigBit accept_bit = State::S0, reject_bit = State::S0;
if (clocking.body_net == nullptr)
- parser_error(stringf("Failed to parse SVA clocking"), root);
+ {
+ if (clocking.clock_net != nullptr || clocking.enable_net != nullptr || clocking.disable_net != nullptr || clocking.cond_net != nullptr)
+ parser_error(stringf("Failed to parse SVA clocking"), root);
- // parse SVA sequence into trigger signal
+ if (mode_assert || mode_assume) {
+ reject_bit = module->Not(NEW_ID, parse_expression(root->GetInput()));
+ } else {
+ accept_bit = parse_expression(root->GetInput());
+ }
+ }
+ else
+ {
+ Net *net = clocking.body_net;
+ SigBit trig;
- Net *net = clocking.body_net;
- SigBit accept_bit = State::S0, reject_bit = State::S0;
+ if (eventually_property(net, trig))
+ {
+ SigBit sig_a, sig_en = trig;
+ parse_property(net, &sig_a, nullptr);
- if (mode_assert || mode_assume) {
- parse_property(net, nullptr, &reject_bit);
- } else {
- parse_property(net, &accept_bit, nullptr);
+ // add final FF stage
+
+ SigBit sig_a_q, sig_en_q;
+
+ if (clocking.body_net == nullptr) {
+ sig_a_q = sig_a;
+ sig_en_q = sig_en;
+ } else {
+ sig_a_q = module->addWire(NEW_ID);
+ sig_en_q = module->addWire(NEW_ID);
+ clocking.addDff(NEW_ID, sig_a, sig_a_q, State::S0);
+ clocking.addDff(NEW_ID, sig_en, sig_en_q, State::S0);
+ }
+
+ // generate fair/live cell
+
+ RTLIL::Cell *c = nullptr;
+
+ if (mode_assert) c = module->addLive(root_name, sig_a_q, sig_en_q);
+ if (mode_assume) c = module->addFair(root_name, sig_a_q, sig_en_q);
+
+ importer->import_attributes(c->attributes, root);
+
+ return;
+ }
+ else
+ {
+ if (mode_assert || mode_assume) {
+ parse_property(net, nullptr, &reject_bit);
+ } else {
+ parse_property(net, &accept_bit, nullptr);
+ }
+ }
}
if (mode_trigger)
@@ -1532,10 +1739,17 @@ struct VerificSvaImporter
// add final FF stage
- SigBit sig_a_q = module->addWire(NEW_ID);
- SigBit sig_en_q = module->addWire(NEW_ID);
- clocking.addDff(NEW_ID, sig_a, sig_a_q, State::S0);
- clocking.addDff(NEW_ID, sig_en, sig_en_q, State::S0);
+ SigBit sig_a_q, sig_en_q;
+
+ if (clocking.body_net == nullptr) {
+ sig_a_q = sig_a;
+ sig_en_q = sig_en;
+ } else {
+ sig_a_q = module->addWire(NEW_ID);
+ sig_en_q = module->addWire(NEW_ID);
+ clocking.addDff(NEW_ID, sig_a, sig_a_q, State::S0);
+ clocking.addDff(NEW_ID, sig_en, sig_en_q, State::S0);
+ }
// generate assert/assume/cover cell
diff --git a/frontends/verilog/const2ast.cc b/frontends/verilog/const2ast.cc
index 4a58357bf..7848c626d 100644
--- a/frontends/verilog/const2ast.cc
+++ b/frontends/verilog/const2ast.cc
@@ -49,8 +49,7 @@ static int my_decimal_div_by_two(std::vector<uint8_t> &digits)
int carry = 0;
for (size_t i = 0; i < digits.size(); i++) {
if (digits[i] >= 10)
- log_error("Invalid use of [a-fxz?] in decimal constant at %s:%d.\n",
- current_filename.c_str(), get_line_num());
+ log_file_error(current_filename, get_line_num(), "Invalid use of [a-fxz?] in decimal constant.\n");
digits[i] += carry * 10;
carry = digits[i] % 2;
digits[i] /= 2;
@@ -105,8 +104,8 @@ static void my_strtobin(std::vector<RTLIL::State> &data, const char *str, int le
int bits_per_digit = my_ilog2(base-1);
for (auto it = digits.rbegin(), e = digits.rend(); it != e; it++) {
if (*it > (base-1) && *it < 0xf0)
- log_error("Digit larger than %d used in in base-%d constant at %s:%d.\n",
- base-1, base, current_filename.c_str(), get_line_num());
+ log_file_error(current_filename, get_line_num(), "Digit larger than %d used in in base-%d constant.\n",
+ base-1, base);
for (int i = 0; i < bits_per_digit; i++) {
int bitmask = 1 << i;
if (*it == 0xf0)
@@ -238,4 +237,3 @@ AstNode *VERILOG_FRONTEND::const2ast(std::string code, char case_type, bool warn
}
YOSYS_NAMESPACE_END
-
diff --git a/frontends/verilog/preproc.cc b/frontends/verilog/preproc.cc
index c43ff4e3a..dea22ee8a 100644
--- a/frontends/verilog/preproc.cc
+++ b/frontends/verilog/preproc.cc
@@ -183,8 +183,9 @@ static std::string next_token(bool pass_newline = false)
const char *ok = "abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ$0123456789";
if (ch == '`' || strchr(ok, ch) != NULL)
{
+ char first = ch;
ch = next_char();
- if (ch == '"') {
+ if (first == '`' && (ch == '"' || ch == '`')) {
token += ch;
} else do {
if (strchr(ok, ch) == NULL) {
@@ -244,6 +245,7 @@ static bool try_expand_macro(std::set<std::string> &defines_with_args,
args.push_back(std::string());
while (1)
{
+ skip_spaces();
tok = next_token(true);
if (tok == ")" || tok == "}" || tok == "]")
level--;
@@ -264,6 +266,9 @@ static bool try_expand_macro(std::set<std::string> &defines_with_args,
}
insert_input(defines_map[name]);
return true;
+ } else if (tok == "``") {
+ // Swallow `` in macro expansion
+ return true;
} else return false;
}
diff --git a/frontends/verilog/verilog_frontend.cc b/frontends/verilog/verilog_frontend.cc
index e5917b97e..be925fea2 100644
--- a/frontends/verilog/verilog_frontend.cc
+++ b/frontends/verilog/verilog_frontend.cc
@@ -42,7 +42,7 @@ static std::list<std::vector<std::string>> verilog_defaults_stack;
static void error_on_dpi_function(AST::AstNode *node)
{
if (node->type == AST::AST_DPI_FUNCTION)
- log_error("Found DPI function %s at %s:%d.\n", node->str.c_str(), node->filename.c_str(), node->linenum);
+ log_file_error(node->filename, node->linenum, "Found DPI function %s.\n", node->str.c_str());
for (auto child : node->children)
error_on_dpi_function(child);
}
@@ -137,9 +137,13 @@ struct VerilogFrontend : public Frontend {
log(" -icells\n");
log(" interpret cell types starting with '$' as internal cell types\n");
log("\n");
- log(" -ignore_redef\n");
+ log(" -nooverwrite\n");
log(" ignore re-definitions of modules. (the default behavior is to\n");
- log(" create an error message.)\n");
+ log(" create an error message if the existing module is not a black box\n");
+ log(" module, and overwrite the existing module otherwise.)\n");
+ log("\n");
+ log(" -overwrite\n");
+ log(" overwrite existing modules with the same name\n");
log("\n");
log(" -defer\n");
log(" only read the abstract syntax tree and defer actual compilation\n");
@@ -191,7 +195,8 @@ struct VerilogFrontend : public Frontend {
bool flag_nodpi = false;
bool flag_noopt = false;
bool flag_icells = false;
- bool flag_ignore_redef = false;
+ bool flag_nooverwrite = false;
+ bool flag_overwrite = false;
bool flag_defer = false;
std::map<std::string, std::string> defines_map;
std::list<std::string> include_dirs;
@@ -289,8 +294,14 @@ struct VerilogFrontend : public Frontend {
flag_icells = true;
continue;
}
- if (arg == "-ignore_redef") {
- flag_ignore_redef = true;
+ if (arg == "-ignore_redef" || arg == "-nooverwrite") {
+ flag_nooverwrite = true;
+ flag_overwrite = false;
+ continue;
+ }
+ if (arg == "-overwrite") {
+ flag_nooverwrite = false;
+ flag_overwrite = true;
continue;
}
if (arg == "-defer") {
@@ -370,7 +381,7 @@ struct VerilogFrontend : public Frontend {
if (flag_nodpi)
error_on_dpi_function(current_ast);
- AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, flag_dump_rtlil, flag_nolatches, flag_nomeminit, flag_nomem2reg, flag_mem2reg, lib_mode, flag_noopt, flag_icells, flag_ignore_redef, flag_defer, default_nettype_wire);
+ AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_dump_vlog, flag_dump_rtlil, flag_nolatches, flag_nomeminit, flag_nomem2reg, flag_mem2reg, lib_mode, flag_noopt, flag_icells, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire);
if (!flag_nopp)
delete lexin;
@@ -508,13 +519,11 @@ void frontend_verilog_yyerror(char const *fmt, ...)
va_list ap;
char buffer[1024];
char *p = buffer;
- p += snprintf(p, buffer + sizeof(buffer) - p, "Parser error in line %s:%d: ",
- YOSYS_NAMESPACE_PREFIX AST::current_filename.c_str(), frontend_verilog_yyget_lineno());
va_start(ap, fmt);
p += vsnprintf(p, buffer + sizeof(buffer) - p, fmt, ap);
va_end(ap);
p += snprintf(p, buffer + sizeof(buffer) - p, "\n");
- YOSYS_NAMESPACE_PREFIX log_error("%s", buffer);
+ YOSYS_NAMESPACE_PREFIX log_file_error(YOSYS_NAMESPACE_PREFIX AST::current_filename, frontend_verilog_yyget_lineno(),
+ "%s", buffer);
exit(1);
}
-
diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l
index 8aa123e1e..0134416c1 100644
--- a/frontends/verilog/verilog_lexer.l
+++ b/frontends/verilog/verilog_lexer.l
@@ -145,6 +145,9 @@ YOSYS_NAMESPACE_END
"endfunction" { return TOK_ENDFUNCTION; }
"task" { return TOK_TASK; }
"endtask" { return TOK_ENDTASK; }
+"specify" { return TOK_SPECIFY; }
+"endspecify" { return TOK_ENDSPECIFY; }
+"specparam" { return TOK_SPECPARAM; }
"package" { SV_KEYWORD(TOK_PACKAGE); }
"endpackage" { SV_KEYWORD(TOK_ENDPACKAGE); }
"parameter" { return TOK_PARAMETER; }
@@ -238,10 +241,18 @@ YOSYS_NAMESPACE_END
while (yystr[i]) {
if (yystr[i] == '\\' && yystr[i + 1]) {
i++;
- if (yystr[i] == 'n')
+ if (yystr[i] == 'a')
+ yystr[i] = '\a';
+ else if (yystr[i] == 'f')
+ yystr[i] = '\f';
+ else if (yystr[i] == 'n')
yystr[i] = '\n';
+ else if (yystr[i] == 'r')
+ yystr[i] = '\r';
else if (yystr[i] == 't')
yystr[i] = '\t';
+ else if (yystr[i] == 'v')
+ yystr[i] = '\v';
else if ('0' <= yystr[i] && yystr[i] <= '7') {
yystr[i] = yystr[i] - '0';
if ('0' <= yystr[i + 1] && yystr[i + 1] <= '7') {
diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y
index dfdeabbdb..78cac5543 100644
--- a/frontends/verilog/verilog_parser.y
+++ b/frontends/verilog/verilog_parser.y
@@ -110,7 +110,7 @@ static void free_attr(std::map<std::string, AstNode*> *al)
%token TOK_BEGIN TOK_END TOK_IF TOK_ELSE TOK_FOR TOK_WHILE TOK_REPEAT
%token TOK_DPI_FUNCTION TOK_POSEDGE TOK_NEGEDGE TOK_OR TOK_AUTOMATIC
%token TOK_CASE TOK_CASEX TOK_CASEZ TOK_ENDCASE TOK_DEFAULT
-%token TOK_FUNCTION TOK_ENDFUNCTION TOK_TASK TOK_ENDTASK
+%token TOK_FUNCTION TOK_ENDFUNCTION TOK_TASK TOK_ENDTASK TOK_SPECIFY TOK_ENDSPECIFY TOK_SPECPARAM
%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
@@ -376,9 +376,10 @@ wire_type:
};
wire_type_token_list:
- wire_type_token | wire_type_token_list wire_type_token;
+ wire_type_token | wire_type_token_list wire_type_token |
+ wire_type_token_io ;
-wire_type_token:
+wire_type_token_io:
TOK_INPUT {
astbuf3->is_input = true;
} |
@@ -388,7 +389,9 @@ wire_type_token:
TOK_INOUT {
astbuf3->is_input = true;
astbuf3->is_output = true;
- } |
+ };
+
+wire_type_token:
TOK_WIRE {
} |
TOK_REG {
@@ -479,7 +482,7 @@ module_body:
/* empty */;
module_body_stmt:
- task_func_decl | param_decl | localparam_decl | defparam_decl | wire_decl | assign_stmt | cell_stmt |
+ task_func_decl | specify_block |param_decl | localparam_decl | defparam_decl | specparam_declaration | wire_decl | assign_stmt | cell_stmt |
always_stmt | TOK_GENERATE module_gen_body TOK_ENDGENERATE | defattr | assert_property | checker_decl;
checker_decl:
@@ -638,6 +641,171 @@ task_func_body:
task_func_body behavioral_stmt |
/* empty */;
+specify_block:
+ TOK_SPECIFY specify_item_opt TOK_ENDSPECIFY |
+ TOK_SPECIFY TOK_ENDSPECIFY ;
+
+specify_item_opt:
+ specify_item_opt specify_item |
+ specify_item ;
+
+specify_item:
+ specparam_declaration
+ // | pulsestyle_declaration
+ // | showcancelled_declaration
+ | path_declaration
+ // | system_timing_declaration
+ ;
+
+specparam_declaration:
+ TOK_SPECPARAM list_of_specparam_assignments ';' |
+ TOK_SPECPARAM specparam_range list_of_specparam_assignments ';' ;
+
+// IEEE 1364-2005 calls this sinmply 'range' but the current 'range' rule allows empty match
+// and the 'non_opt_range' rule allows index ranges not allowed by 1364-2005
+// exxxxtending this for SV specparam would change this anyhow
+specparam_range:
+ '[' constant_expression ':' constant_expression ']' ;
+
+list_of_specparam_assignments:
+ specparam_assignment | list_of_specparam_assignments ',' specparam_assignment;
+
+specparam_assignment:
+ TOK_ID '=' constant_mintypmax_expression ;
+
+/*
+pulsestyle_declaration :
+ ;
+
+showcancelled_declaration :
+ ;
+*/
+
+path_declaration :
+ simple_path_declaration
+ // | edge_sensitive_path_declaration
+ // | state_dependent_path_declaration
+ ;
+
+simple_path_declaration :
+ parallel_path_description '=' path_delay_value ';'
+ // | full_path_description '=' path_delay_value ';'
+ ;
+
+path_delay_value :
+ //list_of_path_delay_expressions
+ '(' list_of_path_delay_expressions ')'
+ ;
+
+list_of_path_delay_expressions :
+/*
+ t_path_delay_expression
+ | trise_path_delay_expression ',' tfall_path_delay_expression
+ | trise_path_delay_expression ',' tfall_path_delay_expression ',' tz_path_delay_expression
+ | t01_path_delay_expression ',' t10_path_delay_expression ',' t0z_path_delay_expression ','
+ tz1_path_delay_expression ',' t1z_path_delay_expression ',' tz0_path_delay_expression
+ | t01_path_delay_expression ',' t10_path_delay_expression ',' t0z_path_delay_expression ','
+ tz1_path_delay_expression ',' t1z_path_delay_expression ',' tz0_path_delay_expression ','
+ t0x_path_delay_expression ',' tx1_path_delay_expression ',' t1x_path_delay_expression ','
+ tx0_path_delay_expression ',' txz_path_delay_expression ',' tzx_path_delay_expression
+*/
+ path_delay_expression
+ | path_delay_expression ',' path_delay_expression
+ | path_delay_expression ',' path_delay_expression ',' path_delay_expression
+ | path_delay_expression ',' path_delay_expression ',' path_delay_expression ','
+ path_delay_expression ',' path_delay_expression ',' path_delay_expression
+ | path_delay_expression ',' path_delay_expression ',' path_delay_expression ','
+ path_delay_expression ',' path_delay_expression ',' path_delay_expression ','
+ path_delay_expression ',' path_delay_expression ',' path_delay_expression ','
+ path_delay_expression ',' path_delay_expression ',' path_delay_expression
+ ;
+
+parallel_path_description :
+ '(' specify_input_terminal_descriptor opt_polarity_operator '=' '>' specify_output_terminal_descriptor ')' ;
+
+opt_polarity_operator :
+ '+'
+ | '-'
+ | ;
+
+// Good enough for the time being
+specify_input_terminal_descriptor :
+ TOK_ID ;
+
+// Good enough for the time being
+specify_output_terminal_descriptor :
+ TOK_ID ;
+
+/*
+system_timing_declaration :
+ ;
+*/
+
+/*
+t_path_delay_expression :
+ path_delay_expression;
+
+trise_path_delay_expression :
+ path_delay_expression;
+
+tfall_path_delay_expression :
+ path_delay_expression;
+
+tz_path_delay_expression :
+ path_delay_expression;
+
+t01_path_delay_expression :
+ path_delay_expression;
+
+t10_path_delay_expression :
+ path_delay_expression;
+
+t0z_path_delay_expression :
+ path_delay_expression;
+
+tz1_path_delay_expression :
+ path_delay_expression;
+
+t1z_path_delay_expression :
+ path_delay_expression;
+
+tz0_path_delay_expression :
+ path_delay_expression;
+
+t0x_path_delay_expression :
+ path_delay_expression;
+
+tx1_path_delay_expression :
+ path_delay_expression;
+
+t1x_path_delay_expression :
+ path_delay_expression;
+
+tx0_path_delay_expression :
+ path_delay_expression;
+
+txz_path_delay_expression :
+ path_delay_expression;
+
+tzx_path_delay_expression :
+ path_delay_expression;
+*/
+
+path_delay_expression :
+ constant_mintypmax_expression;
+
+constant_mintypmax_expression :
+ constant_expression
+ | constant_expression ':' constant_expression ':' constant_expression
+ ;
+
+// for the time being this is OK, but we may write our own expr here.
+// as I'm not sure it is legal to use a full expr here (probably not)
+// On the other hand, other rules requiring constant expressions also use 'expr'
+// (such as param assignment), so we may leave this as-is, perhaps assing runtime checks for constant-ness
+constant_expression:
+ expr ;
+
param_signed:
TOK_SIGNED {
astbuf1->is_signed = true;
@@ -772,11 +940,43 @@ wire_name_list:
wire_name_and_opt_assign:
wire_name {
- if (current_wire_rand) {
+ bool attr_anyconst = false;
+ bool attr_anyseq = false;
+ bool attr_allconst = false;
+ bool attr_allseq = false;
+ if (ast_stack.back()->children.back()->get_bool_attribute("\\anyconst")) {
+ delete ast_stack.back()->children.back()->attributes.at("\\anyconst");
+ ast_stack.back()->children.back()->attributes.erase("\\anyconst");
+ attr_anyconst = true;
+ }
+ if (ast_stack.back()->children.back()->get_bool_attribute("\\anyseq")) {
+ delete ast_stack.back()->children.back()->attributes.at("\\anyseq");
+ ast_stack.back()->children.back()->attributes.erase("\\anyseq");
+ attr_anyseq = true;
+ }
+ if (ast_stack.back()->children.back()->get_bool_attribute("\\allconst")) {
+ delete ast_stack.back()->children.back()->attributes.at("\\allconst");
+ ast_stack.back()->children.back()->attributes.erase("\\allconst");
+ attr_allconst = true;
+ }
+ if (ast_stack.back()->children.back()->get_bool_attribute("\\allseq")) {
+ delete ast_stack.back()->children.back()->attributes.at("\\allseq");
+ ast_stack.back()->children.back()->attributes.erase("\\allseq");
+ attr_allseq = true;
+ }
+ if (current_wire_rand || attr_anyconst || attr_anyseq || attr_allconst || attr_allseq) {
AstNode *wire = new AstNode(AST_IDENTIFIER);
AstNode *fcall = new AstNode(AST_FCALL);
wire->str = ast_stack.back()->children.back()->str;
fcall->str = current_wire_const ? "\\$anyconst" : "\\$anyseq";
+ if (attr_anyconst)
+ fcall->str = "\\$anyconst";
+ if (attr_anyseq)
+ fcall->str = "\\$anyseq";
+ if (attr_allconst)
+ fcall->str = "\\$allconst";
+ if (attr_allseq)
+ fcall->str = "\\$allseq";
fcall->attributes["\\reg"] = AstNode::mkconst_str(RTLIL::unescape_id(wire->str));
ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, wire, fcall));
}
@@ -1044,39 +1244,45 @@ opt_label:
$$ = NULL;
};
+opt_property:
+ TOK_PROPERTY | /* empty */;
+
+opt_stmt_label:
+ TOK_ID ':' | /* empty */;
+
assert:
- TOK_ASSERT '(' expr ')' ';' {
- ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $3));
+ opt_stmt_label TOK_ASSERT opt_property '(' expr ')' ';' {
+ ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $5));
} |
- TOK_ASSUME '(' expr ')' ';' {
- ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $3));
+ opt_stmt_label TOK_ASSUME opt_property '(' expr ')' ';' {
+ ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $5));
} |
- TOK_ASSERT '(' TOK_EVENTUALLY expr ')' ';' {
- ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $4));
+ opt_stmt_label TOK_ASSERT opt_property '(' TOK_EVENTUALLY expr ')' ';' {
+ ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $6));
} |
- TOK_ASSUME '(' TOK_EVENTUALLY expr ')' ';' {
- ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $4));
+ opt_stmt_label TOK_ASSUME opt_property '(' TOK_EVENTUALLY expr ')' ';' {
+ ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $6));
} |
- TOK_COVER '(' expr ')' ';' {
- ast_stack.back()->children.push_back(new AstNode(AST_COVER, $3));
+ opt_stmt_label TOK_COVER opt_property '(' expr ')' ';' {
+ ast_stack.back()->children.push_back(new AstNode(AST_COVER, $5));
} |
- TOK_COVER '(' ')' ';' {
+ opt_stmt_label TOK_COVER opt_property '(' ')' ';' {
ast_stack.back()->children.push_back(new AstNode(AST_COVER, AstNode::mkconst_int(1, false)));
} |
- TOK_COVER ';' {
+ opt_stmt_label TOK_COVER ';' {
ast_stack.back()->children.push_back(new AstNode(AST_COVER, AstNode::mkconst_int(1, false)));
} |
- TOK_RESTRICT '(' expr ')' ';' {
+ opt_stmt_label TOK_RESTRICT opt_property '(' expr ')' ';' {
if (norestrict_mode)
- delete $3;
+ delete $5;
else
- ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $3));
+ ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $5));
} |
- TOK_RESTRICT '(' TOK_EVENTUALLY expr ')' ';' {
+ opt_stmt_label TOK_RESTRICT opt_property '(' TOK_EVENTUALLY expr ')' ';' {
if (norestrict_mode)
- delete $4;
+ delete $6;
else
- ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $4));
+ ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $6));
};
assert_property:
diff --git a/kernel/driver.cc b/kernel/driver.cc
index 97a78cd16..178641101 100644
--- a/kernel/driver.cc
+++ b/kernel/driver.cc
@@ -34,11 +34,17 @@
#include <limits.h>
#include <errno.h>
-#ifdef __linux__
+#if defined (__linux__) || defined(__FreeBSD__)
+# include <sys/resource.h>
# include <sys/types.h>
# include <unistd.h>
#endif
+#ifdef __FreeBSD__
+# include <sys/sysctl.h>
+# include <sys/user.h>
+#endif
+
#if !defined(_WIN32) || defined(__MINGW32__)
# include <unistd.h>
#else
@@ -79,20 +85,37 @@ USING_YOSYS_NAMESPACE
#ifdef EMSCRIPTEN
# include <sys/stat.h>
# include <sys/types.h>
+# include <emscripten.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**)
+int main(int argc, char **argv)
{
+ EM_ASM(
+ if (ENVIRONMENT_IS_NODE)
+ {
+ FS.mkdir('/hostcwd');
+ FS.mount(NODEFS, { root: '.' }, '/hostcwd');
+ FS.mkdir('/hostfs');
+ FS.mount(NODEFS, { root: '/' }, '/hostfs');
+ }
+ );
+
mkdir("/work", 0777);
chdir("/work");
log_files.push_back(stdout);
log_error_stderr = true;
yosys_banner();
yosys_setup();
+
+ if (argc == 2)
+ {
+ // Run the first argument as a script file
+ run_frontend(argv[1], "script", 0, 0, 0);
+ }
}
void run(const char *command)
@@ -254,9 +277,13 @@ int main(int argc, char **argv)
printf(" print a warning for all log messages matching the regex.\n");
printf("\n");
printf(" -w regex\n");
- printf(" if a warning message matches the regex, it is printes as regular\n");
+ printf(" if a warning message matches the regex, it is printed as regular\n");
printf(" message instead.\n");
printf("\n");
+ printf(" -e regex\n");
+ printf(" if a warning message matches the regex, it is printed as error\n");
+ printf(" message instead and the tool terminates with a nonzero return code.\n");
+ printf("\n");
printf(" -E <depsfile>\n");
printf(" write a Makefile dependencies file with in- and output file names\n");
printf("\n");
@@ -280,7 +307,7 @@ int main(int argc, char **argv)
}
int opt;
- while ((opt = getopt(argc, argv, "MXAQTVSm:f:Hh:b:o:p:l:L:qv:tds:c:W:w:D:E:")) != -1)
+ while ((opt = getopt(argc, argv, "MXAQTVSm:f:Hh:b:o:p:l:L:qv:tds:c:W:w:e:D:E:")) != -1)
{
switch (opt)
{
@@ -374,6 +401,12 @@ int main(int argc, char **argv)
std::regex_constants::optimize |
std::regex_constants::egrep));
break;
+ case 'e':
+ log_werror_regexes.push_back(std::regex(optarg,
+ std::regex_constants::nosubs |
+ std::regex_constants::optimize |
+ std::regex_constants::egrep));
+ break;
case 'D':
{
auto args = split_tokens(optarg, ":");
@@ -416,6 +449,18 @@ int main(int argc, char **argv)
if (print_stats)
log_hasher = new SHA1;
+#if defined(__linux__)
+ // set stack size to >= 128 MB
+ {
+ struct rlimit rl;
+ const rlim_t stack_size = 128L * 1024L * 1024L;
+ if (getrlimit(RLIMIT_STACK, &rl) == 0 && rl.rlim_cur < stack_size) {
+ rl.rlim_cur = stack_size;
+ setrlimit(RLIMIT_STACK, &rl);
+ }
+ }
+#endif
+
yosys_setup();
log_error_atexit = yosys_atexit;
@@ -487,7 +532,7 @@ int main(int argc, char **argv)
#else
std::string meminfo;
std::string stats_divider = ", ";
-# ifdef __linux__
+# if defined(__linux__)
std::ifstream statm;
statm.open(stringf("/proc/%lld/statm", (long long)getpid()));
if (statm.is_open()) {
@@ -498,6 +543,19 @@ int main(int argc, char **argv)
sz_resident * (getpagesize() / 1024.0 / 1024.0));
stats_divider = "\n";
}
+# elif defined(__FreeBSD__)
+ pid_t pid = getpid();
+ int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, (int)pid};
+ struct kinfo_proc kip;
+ size_t kip_len = sizeof(kip);
+ if (sysctl(mib, 4, &kip, &kip_len, NULL, 0) == 0) {
+ vm_size_t sz_total = kip.ki_size;
+ segsz_t sz_resident = kip.ki_rssize;
+ meminfo = stringf(", MEM: %.2f MB total, %.2f MB resident",
+ (int)sz_total / 1024.0 / 1024.0,
+ (int)sz_resident * (getpagesize() / 1024.0 / 1024.0));
+ stats_divider = "\n";
+ }
# endif
struct rusage ru_buffer;
@@ -541,7 +599,7 @@ int main(int argc, char **argv)
}
}
-#if defined(YOSYS_ENABLE_COVER) && defined(__linux__)
+#if defined(YOSYS_ENABLE_COVER) && (defined(__linux__) || defined(__FreeBSD__))
if (getenv("YOSYS_COVER_DIR") || getenv("YOSYS_COVER_FILE"))
{
string filename;
diff --git a/kernel/log.cc b/kernel/log.cc
index de564cb36..0ee2170a0 100644
--- a/kernel/log.cc
+++ b/kernel/log.cc
@@ -25,7 +25,7 @@
# include <sys/time.h>
#endif
-#ifdef __linux__
+#if defined(__linux__) || defined(__FreeBSD__)
# include <dlfcn.h>
#endif
@@ -41,7 +41,7 @@ YOSYS_NAMESPACE_BEGIN
std::vector<FILE*> log_files;
std::vector<std::ostream*> log_streams;
std::map<std::string, std::set<std::string>> log_hdump;
-std::vector<std::regex> log_warn_regexes, log_nowarn_regexes;
+std::vector<std::regex> log_warn_regexes, log_nowarn_regexes, log_werror_regexes;
std::set<std::string> log_warnings;
int log_warnings_count = 0;
bool log_hdump_all = false;
@@ -203,7 +203,8 @@ void logv_header(RTLIL::Design *design, const char *format, va_list ap)
log_files.pop_back();
}
-void logv_warning(const char *format, va_list ap)
+static void logv_warning_with_prefix(const char *prefix,
+ const char *format, va_list ap)
{
std::string message = vstringf(format, ap);
bool suppressed = false;
@@ -214,13 +215,17 @@ void logv_warning(const char *format, va_list ap)
if (suppressed)
{
- log("Suppressed warning: %s", message.c_str());
+ log("Suppressed %s%s", prefix, message.c_str());
}
else
{
+ for (auto &re : log_werror_regexes)
+ if (std::regex_search(message, re))
+ log_error("%s", message.c_str());
+
if (log_warnings.count(message))
{
- log("Warning: %s", message.c_str());
+ log("%s%s", prefix, message.c_str());
log_flush();
}
else
@@ -228,7 +233,7 @@ void logv_warning(const char *format, va_list ap)
if (log_errfile != NULL && !log_quiet_warnings)
log_files.push_back(log_errfile);
- log("Warning: %s", message.c_str());
+ log("%s%s", prefix, message.c_str());
log_flush();
if (log_errfile != NULL && !log_quiet_warnings)
@@ -241,45 +246,30 @@ void logv_warning(const char *format, va_list ap)
}
}
-void logv_warning_noprefix(const char *format, va_list ap)
+void logv_warning(const char *format, va_list ap)
{
- std::string message = vstringf(format, ap);
- bool suppressed = false;
-
- for (auto &re : log_nowarn_regexes)
- if (std::regex_search(message, re))
- suppressed = true;
-
- if (suppressed)
- {
- log("%s", message.c_str());
- }
- else
- {
- if (log_warnings.count(message))
- {
- log("%s", message.c_str());
- log_flush();
- }
- else
- {
- if (log_errfile != NULL && !log_quiet_warnings)
- log_files.push_back(log_errfile);
-
- log("%s", message.c_str());
- log_flush();
-
- if (log_errfile != NULL && !log_quiet_warnings)
- log_files.pop_back();
+ logv_warning_with_prefix("Warning: ", format, ap);
+}
- log_warnings.insert(message);
- }
+void logv_warning_noprefix(const char *format, va_list ap)
+{
+ logv_warning_with_prefix("", format, ap);
+}
- log_warnings_count++;
- }
+void log_file_warning(const std::string &filename, int lineno,
+ const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ std::string prefix = stringf("%s:%d: Warning: ",
+ filename.c_str(), lineno);
+ logv_warning_with_prefix(prefix.c_str(), format, ap);
+ va_end(ap);
}
-void logv_error(const char *format, va_list ap)
+YS_ATTRIBUTE(noreturn)
+static void logv_error_with_prefix(const char *prefix,
+ const char *format, va_list ap)
{
#ifdef EMSCRIPTEN
auto backup_log_files = log_files;
@@ -294,7 +284,7 @@ void logv_error(const char *format, va_list ap)
f = stderr;
log_last_error = vstringf(format, ap);
- log("ERROR: %s", log_last_error.c_str());
+ log("%s%s", prefix, log_last_error.c_str());
log_flush();
if (log_error_atexit)
@@ -310,6 +300,21 @@ void logv_error(const char *format, va_list ap)
#endif
}
+void logv_error(const char *format, va_list ap)
+{
+ logv_error_with_prefix("ERROR: ", format, ap);
+}
+
+void log_file_error(const string &filename, int lineno,
+ const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ std::string prefix = stringf("%s:%d: ERROR: ",
+ filename.c_str(), lineno);
+ logv_error_with_prefix(prefix.c_str(), format, ap);
+}
+
void log(const char *format, ...)
{
va_list ap;
@@ -384,7 +389,7 @@ void log_pop()
log_flush();
}
-#if defined(__linux__) && defined(YOSYS_ENABLE_PLUGINS)
+#if (defined(__linux__) || defined(__FreeBSD__)) && defined(YOSYS_ENABLE_PLUGINS)
void log_backtrace(const char *prefix, int levels)
{
if (levels <= 0) return;
@@ -579,7 +584,7 @@ void log_wire(RTLIL::Wire *wire, std::string indent)
// ---------------------------------------------------
// This is the magic behind the code coverage counters
// ---------------------------------------------------
-#if defined(YOSYS_ENABLE_COVER) && defined(__linux__)
+#if defined(YOSYS_ENABLE_COVER) && (defined(__linux__) || defined(__FreeBSD__))
dict<std::string, std::pair<std::string, int>> extra_coverage_data;
@@ -628,4 +633,3 @@ dict<std::string, std::pair<std::string, int>> get_coverage_data()
#endif
YOSYS_NAMESPACE_END
-
diff --git a/kernel/log.h b/kernel/log.h
index 90a12df36..0b4905c3a 100644
--- a/kernel/log.h
+++ b/kernel/log.h
@@ -49,7 +49,7 @@ struct log_cmd_error_exception { };
extern std::vector<FILE*> log_files;
extern std::vector<std::ostream*> log_streams;
extern std::map<std::string, std::set<std::string>> log_hdump;
-extern std::vector<std::regex> log_warn_regexes, log_nowarn_regexes;
+extern std::vector<std::regex> log_warn_regexes, log_nowarn_regexes, log_werror_regexes;
extern std::set<std::string> log_warnings;
extern int log_warnings_count;
extern bool log_hdump_all;
@@ -73,8 +73,13 @@ YS_NORETURN void logv_error(const char *format, va_list ap) YS_ATTRIBUTE(noretur
void log(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2));
void log_header(RTLIL::Design *design, const char *format, ...) YS_ATTRIBUTE(format(printf, 2, 3));
void log_warning(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2));
+
+// Log with filename to report a problem in a source file.
+void log_file_warning(const std::string &filename, int lineno, const char *format, ...) YS_ATTRIBUTE(format(printf, 3, 4));
+
void log_warning_noprefix(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2));
YS_NORETURN void log_error(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2), noreturn);
+void log_file_error(const string &filename, int lineno, const char *format, ...) YS_ATTRIBUTE(format(printf, 3, 4), noreturn);
YS_NORETURN void log_cmd_error(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2), noreturn);
void log_spacer();
@@ -114,7 +119,7 @@ static inline void log_assert_worker(bool cond, const char *expr, const char *fi
// This is the magic behind the code coverage counters
// ---------------------------------------------------
-#if defined(YOSYS_ENABLE_COVER) && defined(__linux__)
+#if defined(YOSYS_ENABLE_COVER) && (defined(__linux__) || defined(__FreeBSD__))
#define cover(_id) do { \
static CoverData __d __attribute__((section("yosys_cover_list"), aligned(1), used)) = { __FILE__, __FUNCTION__, _id, __LINE__, 0 }; \
diff --git a/kernel/yosys.cc b/kernel/yosys.cc
index cade09048..dca277532 100644
--- a/kernel/yosys.cc
+++ b/kernel/yosys.cc
@@ -46,10 +46,15 @@
# include <unistd.h>
# include <dirent.h>
# include <sys/types.h>
+# include <sys/wait.h>
# include <sys/stat.h>
# include <glob.h>
#endif
+#ifdef __FreeBSD__
+# include <sys/sysctl.h>
+#endif
+
#include <limits.h>
#include <errno.h>
@@ -72,7 +77,7 @@ std::vector<void*> memhasher_store;
void memhasher_on()
{
-#ifdef __linux__
+#if defined(__linux__) || defined(__FreeBSD__)
memhasher_rng += time(NULL) << 16 ^ getpid();
#endif
memhasher_store.resize(0x10000);
@@ -598,6 +603,8 @@ static int tcl_yosys_cmd(ClientData, Tcl_Interp *interp, int argc, const char *a
std::string tcl_command_name = it.first;
if (tcl_command_name == "proc")
tcl_command_name = "procs";
+ else if (tcl_command_name == "rename")
+ tcl_command_name = "renames";
Tcl_CmdInfo info;
if (Tcl_GetCommandInfo(interp, tcl_command_name.c_str(), &info) != 0) {
log("[TCL: yosys -import] Command name collision: found pre-existing command `%s' -> skip.\n", it.first.c_str());
@@ -637,9 +644,9 @@ struct TclPass : public Pass {
log("Use 'yosys cmd' to run the yosys command 'cmd' from tcl.\n");
log("\n");
log("The tcl command 'yosys -import' can be used to import all yosys\n");
- log("commands directly as tcl commands to the tcl shell. The yosys\n");
- log("command 'proc' is wrapped using the tcl command 'procs' in order\n");
- log("to avoid a name collision with the tcl builtin command 'proc'.\n");
+ log("commands directly as tcl commands to the tcl shell. Yosys commands\n");
+ log("'proc' and 'rename' are wrapped to tcl commands 'procs' and 'renames'\n");
+ log("in order to avoid a name collision with the built in commands.\n");
log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) {
@@ -665,6 +672,26 @@ std::string proc_self_dirname()
buflen--;
return std::string(path, buflen);
}
+#elif defined(__FreeBSD__)
+std::string proc_self_dirname()
+{
+ int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
+ size_t buflen;
+ char *buffer;
+ std::string path;
+ if (sysctl(mib, 4, NULL, &buflen, NULL, 0) != 0)
+ log_error("sysctl failed: %s\n", strerror(errno));
+ buffer = (char*)malloc(buflen);
+ if (buffer == NULL)
+ log_error("malloc failed: %s\n", strerror(errno));
+ if (sysctl(mib, 4, buffer, &buflen, NULL, 0) != 0)
+ log_error("sysctl failed: %s\n", strerror(errno));
+ while (buflen > 0 && buffer[buflen-1] != '/')
+ buflen--;
+ path.assign(buffer, buflen);
+ free(buffer);
+ return path;
+}
#elif defined(__APPLE__)
std::string proc_self_dirname()
{
@@ -712,7 +739,7 @@ std::string proc_self_dirname()
#ifdef EMSCRIPTEN
std::string proc_share_dirname()
{
- return "/share";
+ return "/share/";
}
#else
std::string proc_share_dirname()
@@ -798,6 +825,8 @@ void run_frontend(std::string filename, std::string command, std::string *backen
command = "vhdl";
else if (filename.size() > 4 && filename.substr(filename.size()-5) == ".blif")
command = "blif";
+ else if (filename.size() > 5 && filename.substr(filename.size()-6) == ".eblif")
+ command = "blif";
else if (filename.size() > 4 && filename.substr(filename.size()-5) == ".json")
command = "json";
else if (filename.size() > 3 && filename.substr(filename.size()-3) == ".il")
diff --git a/misc/yosys.proto b/misc/yosys.proto
new file mode 100644
index 000000000..2870176cb
--- /dev/null
+++ b/misc/yosys.proto
@@ -0,0 +1,175 @@
+//
+// yosys -- Yosys Open SYnthesis Suite
+//
+// Copyright (C) 2018 Serge Bazanski <q3k@symbioticeda.com>
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+//
+
+/// Protobuf definition of Yosys RTLIL dump/restore format for RTL designs.
+
+syntax = "proto3";
+
+package yosys.pb;
+
+// Port direction.
+enum Direction {
+ DIRECTION_INVALID = 0;
+ DIRECTION_INPUT = 1;
+ DIRECTION_OUTPUT = 2;
+ DIRECTION_INOUT = 3;
+}
+
+// A freeform parameter/attribute value.
+message Parameter {
+ oneof value {
+ int64 int = 1;
+ string str = 2;
+ }
+}
+
+// A signal in the design - either a unique identifier for one, or a constant
+// driver (low or high).
+message Signal {
+ // A constant signal driver in the design.
+ enum ConstantDriver {
+ CONSTANT_DRIVER_INVALID = 0;
+ CONSTANT_DRIVER_LOW = 1;
+ CONSTANT_DRIVER_HIGH = 2;
+ CONSTANT_DRIVER_Z = 3;
+ CONSTANT_DRIVER_X = 4;
+ }
+ oneof type {
+ // Signal uniquely identified by ID number.
+ int64 id = 1;
+ // Constant driver.
+ ConstantDriver constant = 2;
+ }
+}
+
+// A vector of signals.
+message BitVector {
+ repeated Signal signal = 1;
+}
+
+// A netlist module.
+message Module {
+ // Freeform attributes.
+ map<string, Parameter> attribute = 1;
+
+ // Named ports in this module.
+ message Port {
+ Direction direction = 1;
+ BitVector bits = 2;
+ }
+ map<string, Port> port = 2;
+
+ // Named cells in this module.
+ message Cell {
+ // Set to true when the name of this cell is automatically created and
+ // likely not of interest for a regular user.
+ bool hide_name = 1;
+ string type = 2;
+ // Set if this module has an AIG model available.
+ string model = 3;
+ // Freeform parameters.
+ map<string, Parameter> parameter = 4;
+ // Freeform attributes.
+ map<string, Parameter> attribute = 5;
+
+ /// Ports of the cell.
+ // Direction of the port, if interface is known.
+ map<string, Direction> port_direction = 6;
+ // Connection of named port to signal(s).
+ map<string, BitVector> connection = 7;
+ }
+ map<string, Cell> cell = 3;
+
+ // Nets in this module.
+ message Netname {
+ // Set to true when the name of this net is automatically created and
+ // likely not of interest for a regular user.
+ bool hide_name = 1;
+ // Signal(s) that make up this net.
+ BitVector bits = 2;
+ // Freeform attributes.
+ map<string, Parameter> attributes = 3;
+ }
+ repeated Netname netname = 4;
+}
+
+// And-Inverter-Graph model.
+message Model {
+ message Node {
+ // Type of AIG node - or, what its' value is.
+ enum Type {
+ TYPE_INVALID = 0;
+ // The node's value is the value of the specified input port bit.
+ TYPE_PORT = 1;
+ // The node's value is the inverted value of the specified input
+ // port bit.
+ TYPE_NPORT = 2;
+ // The node's value is the ANDed value of specified nodes.
+ TYPE_AND = 3;
+ // The node's value is the NANDed value of specified nodes.
+ TYPE_NAND = 4;
+ // The node's value is a constant 1.
+ TYPE_TRUE = 5;
+ // The node's value is a constant 0.
+ TYPE_FALSE = 6;
+ };
+ Type type = 1;
+
+ message Port {
+ // Name of port.
+ string portname = 1;
+ // Bit index in port.
+ int64 bitindex = 2;
+ }
+ message Gate {
+ // Node index of left side of operation.
+ int64 left = 1;
+ // Node index of right side of operation.
+ int64 right = 2;
+ }
+ oneof node {
+ // Set for PORT, NPORT
+ Port port = 2;
+ // Set for AND, NAND.
+ Gate gate = 3;
+ }
+
+ // Set when the node drives given output port(s).
+ message OutPort {
+ // Name of port.
+ string name = 1;
+ // Bit index in port.
+ int64 bit_index = 2;
+ }
+ repeated OutPort out_port = 4;
+ }
+
+ // List of AIG nodes - each is explicitely numbered by its' index in this
+ // array.
+ repeated Node node = 1;
+}
+
+// A Yosys design netlist dumped from RTLIL.
+message Design {
+ // Human-readable freeform 'remark' string.
+ string creator = 1;
+ // List of named modules in design.
+ map<string, Module> modules = 2;
+ // List of named AIG models in design (if AIG export enabled).
+ map<string, Model> models = 3;
+}
diff --git a/passes/cmds/cover.cc b/passes/cmds/cover.cc
index 1475475c3..ef4f3f7d0 100644
--- a/passes/cmds/cover.cc
+++ b/passes/cmds/cover.cc
@@ -128,7 +128,7 @@ struct CoverPass : public Pass {
log("\n");
}
-#if defined(YOSYS_ENABLE_COVER) && defined(__linux__)
+#if defined(YOSYS_ENABLE_COVER) && (defined(__linux__) || defined(__FreeBSD__))
for (auto &it : get_coverage_data()) {
if (!patterns.empty()) {
for (auto &p : patterns)
diff --git a/passes/cmds/setundef.cc b/passes/cmds/setundef.cc
index 9827ac0b1..3a3ebedf1 100644
--- a/passes/cmds/setundef.cc
+++ b/passes/cmds/setundef.cc
@@ -23,6 +23,13 @@
#include "kernel/rtlil.h"
#include "kernel/log.h"
+#define MODE_ZERO 0
+#define MODE_ONE 1
+#define MODE_UNDEF 2
+#define MODE_RANDOM 3
+#define MODE_ANYSEQ 4
+#define MODE_ANYCONST 5
+
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
@@ -34,24 +41,32 @@ struct SetundefWorker
RTLIL::State next_bit()
{
- if (next_bit_mode == 0)
+ if (next_bit_mode == MODE_ZERO)
return RTLIL::State::S0;
- if (next_bit_mode == 1)
+ if (next_bit_mode == MODE_ONE)
return RTLIL::State::S1;
- // xorshift32
- next_bit_state ^= next_bit_state << 13;
- next_bit_state ^= next_bit_state >> 17;
- next_bit_state ^= next_bit_state << 5;
- log_assert(next_bit_state != 0);
+ if (next_bit_mode == MODE_UNDEF)
+ return RTLIL::State::Sx;
+
+ if (next_bit_mode == MODE_RANDOM)
+ {
+ // xorshift32
+ next_bit_state ^= next_bit_state << 13;
+ next_bit_state ^= next_bit_state >> 17;
+ next_bit_state ^= next_bit_state << 5;
+ log_assert(next_bit_state != 0);
- return ((next_bit_state >> (next_bit_state & 15)) & 16) ? RTLIL::State::S0 : RTLIL::State::S1;
+ return ((next_bit_state >> (next_bit_state & 15)) & 16) ? RTLIL::State::S0 : RTLIL::State::S1;
+ }
+
+ log_abort();
}
void operator()(RTLIL::SigSpec &sig)
{
- if (next_bit_mode == 2) {
+ if (next_bit_mode == MODE_ANYSEQ || next_bit_mode == MODE_ANYCONST) {
siglist.push_back(&sig);
return;
}
@@ -81,9 +96,15 @@ struct SetundefPass : public Pass {
log(" -one\n");
log(" replace with bits set (1)\n");
log("\n");
+ log(" -undef\n");
+ log(" replace with undef (x) bits, may be used with -undriven\n");
+ log("\n");
log(" -anyseq\n");
log(" replace with $anyseq drivers (for formal)\n");
log("\n");
+ log(" -anyconst\n");
+ log(" replace with $anyconst drivers (for formal)\n");
+ log("\n");
log(" -random <seed>\n");
log(" replace with random bits using the specified integer als seed\n");
log(" value for the random number generator.\n");
@@ -110,17 +131,32 @@ struct SetundefPass : public Pass {
}
if (args[argidx] == "-zero") {
got_value = true;
- worker.next_bit_mode = 0;
+ worker.next_bit_mode = MODE_ZERO;
+ worker.next_bit_state = 0;
continue;
}
if (args[argidx] == "-one") {
got_value = true;
- worker.next_bit_mode = 1;
+ worker.next_bit_mode = MODE_ONE;
+ worker.next_bit_state = 0;
continue;
}
if (args[argidx] == "-anyseq") {
got_value = true;
- worker.next_bit_mode = 2;
+ worker.next_bit_mode = MODE_ANYSEQ;
+ worker.next_bit_state = 0;
+ continue;
+ }
+ if (args[argidx] == "-anyconst") {
+ got_value = true;
+ worker.next_bit_mode = MODE_ANYCONST;
+ worker.next_bit_state = 0;
+ continue;
+ }
+ if (args[argidx] == "-undef") {
+ got_value = true;
+ worker.next_bit_mode = MODE_UNDEF;
+ worker.next_bit_state = 0;
continue;
}
if (args[argidx] == "-init") {
@@ -129,7 +165,7 @@ struct SetundefPass : public Pass {
}
if (args[argidx] == "-random" && !got_value && argidx+1 < args.size()) {
got_value = true;
- worker.next_bit_mode = 3;
+ worker.next_bit_mode = MODE_RANDOM;
worker.next_bit_state = atoi(args[++argidx].c_str()) + 1;
for (int i = 0; i < 10; i++)
worker.next_bit();
@@ -140,7 +176,10 @@ struct SetundefPass : public Pass {
extra_args(args, argidx, design);
if (!got_value)
- log_cmd_error("One of the options -zero, -one, -anyseq, or -random <seed> must be specified.\n");
+ log_cmd_error("One of the options -zero, -one, -anyseq, -anyconst, or -random <seed> must be specified.\n");
+
+ if (init_mode && (worker.next_bit_mode == MODE_ANYSEQ || worker.next_bit_mode == MODE_ANYCONST))
+ log_cmd_error("The options -init and -anyseq / -anyconst are exclusive.\n");
for (auto module : design->selected_modules())
{
@@ -168,8 +207,13 @@ struct SetundefPass : public Pass {
RTLIL::SigSpec sig = undriven_signals.export_all();
for (auto &c : sig.chunks()) {
RTLIL::SigSpec bits;
- for (int i = 0; i < c.width; i++)
- bits.append(worker.next_bit());
+ if (worker.next_bit_mode == MODE_ANYSEQ)
+ bits = module->Anyseq(NEW_ID, c.width);
+ else if (worker.next_bit_mode == MODE_ANYCONST)
+ bits = module->Anyconst(NEW_ID, c.width);
+ else
+ for (int i = 0; i < c.width; i++)
+ bits.append(worker.next_bit());
module->connect(RTLIL::SigSig(c, bits));
}
}
@@ -256,7 +300,7 @@ struct SetundefPass : public Pass {
module->rewrite_sigspecs(worker);
- if (worker.next_bit_mode == 2)
+ if (worker.next_bit_mode == MODE_ANYSEQ || worker.next_bit_mode == MODE_ANYCONST)
{
vector<SigSpec*> siglist;
siglist.swap(worker.siglist);
@@ -273,7 +317,10 @@ struct SetundefPass : public Pass {
width++;
if (width > 0) {
- sig.replace(cursor, module->Anyseq(NEW_ID, width));
+ if (worker.next_bit_mode == MODE_ANYSEQ)
+ sig.replace(cursor, module->Anyseq(NEW_ID, width));
+ else
+ sig.replace(cursor, module->Anyconst(NEW_ID, width));
cursor += width;
} else {
cursor++;
diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc
index e52a192db..f1d958a1a 100644
--- a/passes/cmds/stat.cc
+++ b/passes/cmds/stat.cc
@@ -142,7 +142,7 @@ struct statdata_t
}
}
- void log_data()
+ void log_data(RTLIL::IdString mod_name, bool top_mod)
{
log(" Number of wires: %6d\n", num_wires);
log(" Number of wire bits: %6d\n", num_wire_bits);
@@ -163,7 +163,7 @@ struct statdata_t
if (area != 0) {
log("\n");
- log(" Chip area for this module: %f\n", area);
+ log(" Chip area for %smodule '%s': %f\n", (top_mod) ? "top " : "", mod_name.c_str(), area);
}
}
};
@@ -275,7 +275,7 @@ struct StatPass : public Pass {
log("\n");
log("=== %s%s ===\n", RTLIL::id2cstr(mod->name), design->selected_whole_module(mod->name) ? "" : " (partially selected)");
log("\n");
- data.log_data();
+ data.log_data(mod->name, false);
}
if (top_mod != NULL && GetSize(mod_stat) > 1)
@@ -288,7 +288,7 @@ struct StatPass : public Pass {
statdata_t data = hierarchy_worker(mod_stat, top_mod->name, 0);
log("\n");
- data.log_data();
+ data.log_data(top_mod->name, true);
}
log("\n");
diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc
index 898763c64..e61851481 100644
--- a/passes/hierarchy/hierarchy.cc
+++ b/passes/hierarchy/hierarchy.cc
@@ -18,6 +18,7 @@
*/
#include "kernel/yosys.h"
+#include "frontends/verific/verific.h"
#include <stdlib.h>
#include <stdio.h>
#include <set>
@@ -138,7 +139,7 @@ void generate(RTLIL::Design *design, const std::vector<std::string> &celltypes,
}
}
-bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check, std::vector<std::string> &libdirs)
+bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check, bool flag_simcheck, std::vector<std::string> &libdirs)
{
bool did_something = false;
std::map<RTLIL::Cell*, std::pair<int, int>> array_cells;
@@ -173,20 +174,24 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check
for (auto &dir : libdirs)
{
- filename = dir + "/" + RTLIL::unescape_id(cell->type) + ".v";
- if (check_file_exists(filename)) {
- Frontend::frontend_call(design, NULL, filename, "verilog");
- goto loaded_module;
- }
+ static const vector<pair<string, string>> extensions_list =
+ {
+ {".v", "verilog"},
+ {".sv", "verilog -sv"},
+ {".il", "ilang"}
+ };
- filename = dir + "/" + RTLIL::unescape_id(cell->type) + ".il";
- if (check_file_exists(filename)) {
- Frontend::frontend_call(design, NULL, filename, "ilang");
- goto loaded_module;
+ for (auto &ext : extensions_list)
+ {
+ filename = dir + "/" + RTLIL::unescape_id(cell->type) + ext.first;
+ if (check_file_exists(filename)) {
+ Frontend::frontend_call(design, NULL, filename, ext.second);
+ goto loaded_module;
+ }
}
}
- if (flag_check && cell->type[0] != '$')
+ if ((flag_check || flag_simcheck) && cell->type[0] != '$')
log_error("Module `%s' referenced in module `%s' in cell `%s' is not part of the design.\n",
cell->type.c_str(), module->name.c_str(), cell->name.c_str());
continue;
@@ -196,7 +201,7 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check
log_error("File `%s' from libdir does not declare module `%s'.\n", filename.c_str(), cell->type.c_str());
did_something = true;
} else
- if (flag_check)
+ if (flag_check || flag_simcheck)
{
RTLIL::Module *mod = design->module(cell->type);
for (auto &conn : cell->connections())
@@ -214,10 +219,14 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check
log_id(cell->type), log_id(module), log_id(cell), log_id(param.first));
}
- if (cell->parameters.size() == 0)
+ if (design->modules_.at(cell->type)->get_bool_attribute("\\blackbox")) {
+ if (flag_simcheck)
+ log_error("Module `%s' referenced in module `%s' in cell `%s' is a blackbox module.\n",
+ cell->type.c_str(), module->name.c_str(), cell->name.c_str());
continue;
+ }
- if (design->modules_.at(cell->type)->get_bool_attribute("\\blackbox"))
+ if (cell->parameters.size() == 0)
continue;
RTLIL::Module *mod = design->modules_[cell->type];
@@ -250,7 +259,7 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check
if (mod->wires_.count(portname) == 0)
log_error("Array cell `%s.%s' connects to unknown port `%s'.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(conn.first));
int port_size = mod->wires_.at(portname)->width;
- if (conn_size == port_size)
+ if (conn_size == port_size || conn_size == 0)
continue;
if (conn_size != port_size*num)
log_error("Array cell `%s.%s' has invalid port vs. signal size for port `%s'.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(conn.first));
@@ -350,6 +359,10 @@ struct HierarchyPass : public Pass {
log(" also check the design hierarchy. this generates an error when\n");
log(" an unknown module is used as cell type.\n");
log("\n");
+ log(" -simcheck\n");
+ log(" like -check, but also thow an error if blackbox modules are\n");
+ log(" instantiated, and throw an error if the design has no top module\n");
+ log("\n");
log(" -purge_lib\n");
log(" by default the hierarchy command will not remove library (blackbox)\n");
log(" modules. use this option to also remove unused blackbox modules.\n");
@@ -406,8 +419,10 @@ struct HierarchyPass : public Pass {
log_header(design, "Executing HIERARCHY pass (managing design hierarchy).\n");
bool flag_check = false;
+ bool flag_simcheck = false;
bool purge_lib = false;
RTLIL::Module *top_mod = NULL;
+ std::string load_top_mod;
std::vector<std::string> libdirs;
bool auto_top_mode = false;
@@ -421,7 +436,7 @@ struct HierarchyPass : public Pass {
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
- if (args[argidx] == "-generate" && !flag_check && !top_mod) {
+ if (args[argidx] == "-generate" && !flag_check && !flag_simcheck && !top_mod) {
generate_mode = true;
log("Entering generate mode.\n");
while (++argidx < args.size()) {
@@ -464,6 +479,10 @@ struct HierarchyPass : public Pass {
flag_check = true;
continue;
}
+ if (args[argidx] == "-simcheck") {
+ flag_simcheck = true;
+ continue;
+ }
if (args[argidx] == "-purge_lib") {
purge_lib = true;
continue;
@@ -494,7 +513,7 @@ struct HierarchyPass : public Pass {
top_mod = design->modules_.count(RTLIL::escape_id(args[argidx])) ? design->modules_.at(RTLIL::escape_id(args[argidx])) : NULL;
}
if (top_mod == NULL)
- log_cmd_error("Module `%s' not found!\n", args[argidx].c_str());
+ load_top_mod = args[argidx];
continue;
}
if (args[argidx] == "-auto-top") {
@@ -505,6 +524,22 @@ struct HierarchyPass : public Pass {
}
extra_args(args, argidx, design, false);
+ if (!load_top_mod.empty()) {
+#ifdef YOSYS_ENABLE_VERIFIC
+ if (verific_import_pending) {
+ verific_import(design, load_top_mod);
+ top_mod = design->module(RTLIL::escape_id(load_top_mod));
+ }
+#endif
+ if (top_mod == NULL)
+ log_cmd_error("Module `%s' not found!\n", load_top_mod.c_str());
+ } else {
+#ifdef YOSYS_ENABLE_VERIFIC
+ if (verific_import_pending)
+ verific_import(design);
+#endif
+ }
+
if (generate_mode) {
generate(design, generate_cells, generate_ports);
return;
@@ -530,6 +565,9 @@ struct HierarchyPass : public Pass {
log("Automatically selected %s as design top module.\n", log_id(top_mod));
}
+ if (flag_simcheck && top_mod == nullptr)
+ log_error("Design has no top module.\n");
+
bool did_something = true;
while (did_something)
{
@@ -545,7 +583,7 @@ struct HierarchyPass : public Pass {
}
for (auto module : used_modules) {
- if (expand_module(design, module, flag_check, libdirs))
+ if (expand_module(design, module, flag_check, flag_simcheck, libdirs))
did_something = true;
}
}
diff --git a/passes/memory/memory_dff.cc b/passes/memory/memory_dff.cc
index 40691d160..6e036397d 100644
--- a/passes/memory/memory_dff.cc
+++ b/passes/memory/memory_dff.cc
@@ -33,8 +33,20 @@ struct MemoryDffWorker
dict<SigBit, int> sigbit_users_count;
dict<SigSpec, Cell*> mux_cells_a, mux_cells_b;
pool<Cell*> forward_merged_dffs, candidate_dffs;
+ pool<SigBit> init_bits;
- MemoryDffWorker(Module *module) : module(module), sigmap(module) { }
+ MemoryDffWorker(Module *module) : module(module), sigmap(module)
+ {
+ for (auto wire : module->wires()) {
+ if (wire->attributes.count("\\init") == 0)
+ continue;
+ SigSpec sig = sigmap(wire);
+ Const initval = wire->attributes.count("\\init");
+ for (int i = 0; i < GetSize(sig) && i < GetSize(initval); i++)
+ if (initval[i] == State::S0 || initval[i] == State::S1)
+ init_bits.insert(sig[i]);
+ }
+ }
bool find_sig_before_dff(RTLIL::SigSpec &sig, RTLIL::SigSpec &clk, bool &clk_polarity, bool after = false)
{
@@ -45,6 +57,9 @@ struct MemoryDffWorker
if (bit.wire == NULL)
continue;
+ if (!after && init_bits.count(sigmap(bit)))
+ return false;
+
for (auto cell : dff_cells)
{
if (after && forward_merged_dffs.count(cell))
@@ -72,6 +87,9 @@ struct MemoryDffWorker
if (d.size() != 1)
continue;
+ if (after && init_bits.count(d))
+ return false;
+
bit = d;
clk = this_clk;
clk_polarity = this_clk_polarity;
diff --git a/passes/memory/memory_nordff.cc b/passes/memory/memory_nordff.cc
index 5f87e8b79..87ab7c623 100644
--- a/passes/memory/memory_nordff.cc
+++ b/passes/memory/memory_nordff.cc
@@ -61,49 +61,59 @@ struct MemoryNordffPass : public Pass {
SigSpec rd_addr = cell->getPort("\\RD_ADDR");
SigSpec rd_data = cell->getPort("\\RD_DATA");
+ SigSpec rd_clk = cell->getPort("\\RD_CLK");
+ SigSpec rd_en = cell->getPort("\\RD_EN");
Const rd_clk_enable = cell->getParam("\\RD_CLK_ENABLE");
+ Const rd_clk_polarity = cell->getParam("\\RD_CLK_POLARITY");
for (int i = 0; i < rd_ports; i++)
{
bool clk_enable = rd_clk_enable[i] == State::S1;
- if (!clk_enable)
- continue;
+ if (clk_enable)
+ {
+ bool clk_polarity = cell->getParam("\\RD_CLK_POLARITY")[i] == State::S1;
+ bool transparent = cell->getParam("\\RD_TRANSPARENT")[i] == State::S1;
- bool clk_polarity = cell->getParam("\\RD_CLK_POLARITY")[i] == State::S1;
- bool transparent = cell->getParam("\\RD_TRANSPARENT")[i] == State::S1;
+ SigSpec clk = cell->getPort("\\RD_CLK")[i] ;
+ SigSpec en = cell->getPort("\\RD_EN")[i];
+ Cell *c;
- SigSpec clk = cell->getPort("\\RD_CLK")[i] ;
- SigSpec en = cell->getPort("\\RD_EN")[i];
- Cell *c;
+ if (transparent)
+ {
+ SigSpec sig_q = module->addWire(NEW_ID, abits);
+ SigSpec sig_d = rd_addr.extract(abits * i, abits);
+ rd_addr.replace(abits * i, sig_q);
+ if (en != State::S1)
+ sig_d = module->Mux(NEW_ID, sig_q, sig_d, en);
+ c = module->addDff(NEW_ID, clk, sig_d, sig_q, clk_polarity);
+ }
+ else
+ {
+ SigSpec sig_d = module->addWire(NEW_ID, width);
+ SigSpec sig_q = rd_data.extract(width * i, width);
+ rd_data.replace(width *i, sig_d);
+ if (en != State::S1)
+ sig_d = module->Mux(NEW_ID, sig_q, sig_d, en);
+ c = module->addDff(NEW_ID, clk, sig_d, sig_q, clk_polarity);
+ }
- if (transparent)
- {
- SigSpec sig_q = module->addWire(NEW_ID, abits);
- SigSpec sig_d = rd_addr.extract(abits * i, abits);
- rd_addr.replace(abits * i, sig_q);
- if (en != State::S1)
- sig_d = module->Mux(NEW_ID, sig_q, sig_d, en);
- c = module->addDff(NEW_ID, clk, sig_d, sig_q, clk_polarity);
- }
- else
- {
- SigSpec sig_d = module->addWire(NEW_ID, width);
- SigSpec sig_q = rd_data.extract(width * i, width);
- rd_data.replace(width *i, sig_d);
- if (en != State::S1)
- sig_d = module->Mux(NEW_ID, sig_q, sig_d, en);
- c = module->addDff(NEW_ID, clk, sig_d, sig_q, clk_polarity);
+ log("Extracted %s FF from read port %d of %s.%s: %s\n", transparent ? "addr" : "data",
+ i, log_id(module), log_id(cell), log_id(c));
}
- log("Extracted %s FF from read port %d of %s.%s: %s\n", transparent ? "addr" : "data",
- i, log_id(module), log_id(cell), log_id(c));
+ rd_en[i] = State::S1;
+ rd_clk[i] = State::S0;
rd_clk_enable[i] = State::S0;
+ rd_clk_polarity[i] = State::S1;
}
cell->setPort("\\RD_ADDR", rd_addr);
cell->setPort("\\RD_DATA", rd_data);
+ cell->setPort("\\RD_CLK", rd_clk);
+ cell->setPort("\\RD_EN", rd_en);
cell->setParam("\\RD_CLK_ENABLE", rd_clk_enable);
+ cell->setParam("\\RD_CLK_POLARITY", rd_clk_polarity);
}
}
} MemoryNordffPass;
diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc
index 45331aa0b..a54a5c6b8 100644
--- a/passes/opt/opt_expr.cc
+++ b/passes/opt/opt_expr.cc
@@ -718,6 +718,23 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
}
}
+ if (cell->type == "$_TBUF_" || cell->type == "$tribuf") {
+ RTLIL::SigSpec input = cell->getPort(cell->type == "$_TBUF_" ? "\\E" : "\\EN");
+ RTLIL::SigSpec a = cell->getPort("\\A");
+ assign_map.apply(input);
+ assign_map.apply(a);
+ if (input == State::S1)
+ ACTION_DO("\\Y", cell->getPort("\\A"));
+ if (input == State::S0 && !a.is_fully_undef()) {
+ cover("opt.opt_expr.action_" S__LINE__);
+ log("Replacing data input of %s cell `%s' in module `%s' with constant undef.\n",
+ cell->type.c_str(), cell->name.c_str(), module->name.c_str());
+ cell->setPort("\\A", SigSpec(State::Sx, GetSize(a)));
+ did_something = true;
+ goto next_cell;
+ }
+ }
+
if (cell->type == "$eq" || cell->type == "$ne" || cell->type == "$eqx" || cell->type == "$nex")
{
RTLIL::SigSpec a = cell->getPort("\\A");
diff --git a/passes/sat/Makefile.inc b/passes/sat/Makefile.inc
index 4fcce2fad..8ab0280c0 100644
--- a/passes/sat/Makefile.inc
+++ b/passes/sat/Makefile.inc
@@ -7,4 +7,5 @@ OBJS += passes/sat/miter.o
OBJS += passes/sat/expose.o
OBJS += passes/sat/assertpmux.o
OBJS += passes/sat/clk2fflogic.o
+OBJS += passes/sat/async2sync.o
diff --git a/passes/sat/async2sync.cc b/passes/sat/async2sync.cc
new file mode 100644
index 000000000..85933acc2
--- /dev/null
+++ b/passes/sat/async2sync.cc
@@ -0,0 +1,147 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct Async2syncPass : public Pass {
+ Async2syncPass() : Pass("async2sync", "convert async FF inputs to sync circuits") { }
+ virtual void help()
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" async2sync [options] [selection]\n");
+ log("\n");
+ log("This command replaces async FF inputs with sync circuits emulating the same\n");
+ log("behavior for when the async signals are actually synchronized to the clock.\n");
+ log("\n");
+ log("This pass assumes negative hold time for the async FF inputs. For example when\n");
+ log("a reset deasserts with the clock edge, then the FF output will still drive the\n");
+ log("reset value in the next cycle regardless of the data-in value at the time of\n");
+ log("the clock edge.\n");
+ log("\n");
+ log("Currently only $adff cells are supported by this pass.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ // bool flag_noinit = false;
+
+ log_header(design, "Executing ASYNC2SYNC pass.\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ // if (args[argidx] == "-noinit") {
+ // flag_noinit = true;
+ // continue;
+ // }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ for (auto module : design->selected_modules())
+ {
+ SigMap sigmap(module);
+ dict<SigBit, State> initbits;
+ pool<SigBit> del_initbits;
+
+ for (auto wire : module->wires())
+ if (wire->attributes.count("\\init") > 0)
+ {
+ Const initval = wire->attributes.at("\\init");
+ SigSpec initsig = sigmap(wire);
+
+ for (int i = 0; i < GetSize(initval) && i < GetSize(initsig); i++)
+ if (initval[i] == State::S0 || initval[i] == State::S1)
+ initbits[initsig[i]] = initval[i];
+ }
+
+ for (auto cell : vector<Cell*>(module->selected_cells()))
+ {
+ if (cell->type.in("$adff"))
+ {
+ // bool clk_pol = cell->parameters["\\CLK_POLARITY"].as_bool();
+ bool arst_pol = cell->parameters["\\ARST_POLARITY"].as_bool();
+ Const arst_val = cell->parameters["\\ARST_VALUE"];
+
+ SigSpec sig_clk = cell->getPort("\\CLK");
+ SigSpec sig_arst = cell->getPort("\\ARST");
+ SigSpec sig_d = cell->getPort("\\D");
+ SigSpec sig_q = cell->getPort("\\Q");
+
+ log("Replacing %s.%s (%s): ARST=%s, D=%s, Q=%s\n",
+ log_id(module), log_id(cell), log_id(cell->type),
+ log_signal(sig_arst), log_signal(sig_d), log_signal(sig_q));
+
+ Const init_val;
+ for (int i = 0; i < GetSize(sig_q); i++) {
+ SigBit bit = sigmap(sig_q[i]);
+ init_val.bits.push_back(initbits.count(bit) ? initbits.at(bit) : State::Sx);
+ del_initbits.insert(bit);
+ }
+
+ Wire *new_d = module->addWire(NEW_ID, GetSize(sig_d));
+ Wire *new_q = module->addWire(NEW_ID, GetSize(sig_q));
+ new_q->attributes["\\init"] = init_val;
+
+ if (arst_pol) {
+ module->addMux(NEW_ID, sig_d, arst_val, sig_arst, new_d);
+ module->addMux(NEW_ID, new_q, arst_val, sig_arst, sig_q);
+ } else {
+ module->addMux(NEW_ID, arst_val, sig_d, sig_arst, new_d);
+ module->addMux(NEW_ID, arst_val, new_q, sig_arst, sig_q);
+ }
+
+ cell->setPort("\\D", new_d);
+ cell->setPort("\\Q", new_q);
+ cell->unsetPort("\\ARST");
+ cell->unsetParam("\\ARST_POLARITY");
+ cell->unsetParam("\\ARST_VALUE");
+ cell->type = "$dff";
+ continue;
+ }
+ }
+
+ for (auto wire : module->wires())
+ if (wire->attributes.count("\\init") > 0)
+ {
+ bool delete_initattr = true;
+ Const initval = wire->attributes.at("\\init");
+ SigSpec initsig = sigmap(wire);
+
+ for (int i = 0; i < GetSize(initval) && i < GetSize(initsig); i++)
+ if (del_initbits.count(initsig[i]) > 0)
+ initval[i] = State::Sx;
+ else if (initval[i] != State::Sx)
+ delete_initattr = false;
+
+ if (delete_initattr)
+ wire->attributes.erase("\\init");
+ else
+ wire->attributes.at("\\init") = initval;
+ }
+ }
+ }
+} Async2syncPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/sat/expose.cc b/passes/sat/expose.cc
index 9427547f3..fa8f0c6be 100644
--- a/passes/sat/expose.cc
+++ b/passes/sat/expose.cc
@@ -236,6 +236,10 @@ struct ExposePass : public Pass {
log(" when exposing a wire, create an input/output pair and cut the internal\n");
log(" signal path at that wire.\n");
log("\n");
+ log(" -input\n");
+ log(" when exposing a wire, create an input port and disconnect the internal\n");
+ log(" driver.\n");
+ log("\n");
log(" -shared\n");
log(" only expose those signals that are shared among the selected modules.\n");
log(" this is useful for preparing modules for equivalence checking.\n");
@@ -259,6 +263,7 @@ struct ExposePass : public Pass {
bool flag_evert = false;
bool flag_dff = false;
bool flag_cut = false;
+ bool flag_input = false;
bool flag_evert_dff = false;
std::string sep = ".";
@@ -279,10 +284,14 @@ struct ExposePass : public Pass {
flag_dff = true;
continue;
}
- if (args[argidx] == "-cut") {
+ if (args[argidx] == "-cut" && !flag_input) {
flag_cut = true;
continue;
}
+ if (args[argidx] == "-input" && !flag_cut) {
+ flag_input = true;
+ continue;
+ }
if (args[argidx] == "-evert-dff") {
flag_evert_dff = true;
continue;
@@ -464,16 +473,42 @@ struct ExposePass : public Pass {
continue;
}
- if (!it.second->port_output) {
- it.second->port_output = true;
- log("New module port: %s/%s\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(it.second->name));
+ if (flag_input)
+ {
+ if (!it.second->port_input) {
+ it.second->port_input = true;
+ log("New module port: %s/%s\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(it.second->name));
+ RTLIL::Wire *w = module->addWire(NEW_ID, GetSize(it.second));
+ out_to_in_map.add(it.second, w);
+ }
+ }
+ else
+ {
+ if (!it.second->port_output) {
+ it.second->port_output = true;
+ log("New module port: %s/%s\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(it.second->name));
+ }
+
+ if (flag_cut) {
+ RTLIL::Wire *in_wire = add_new_wire(module, it.second->name.str() + sep + "i", it.second->width);
+ in_wire->port_input = true;
+ out_to_in_map.add(sigmap(it.second), in_wire);
+ }
}
+ }
- if (flag_cut) {
- RTLIL::Wire *in_wire = add_new_wire(module, it.second->name.str() + sep + "i", it.second->width);
- in_wire->port_input = true;
- out_to_in_map.add(sigmap(it.second), in_wire);
+ if (flag_input)
+ {
+ for (auto &it : module->cells_) {
+ if (!ct.cell_known(it.second->type))
+ continue;
+ for (auto &conn : it.second->connections_)
+ if (ct.cell_output(it.second->type, conn.first))
+ conn.second = out_to_in_map(sigmap(conn.second));
}
+
+ for (auto &conn : module->connections_)
+ conn.first = out_to_in_map(sigmap(conn.first));
}
if (flag_cut)
diff --git a/passes/sat/sat.cc b/passes/sat/sat.cc
index a6ac7afd4..6c0834deb 100644
--- a/passes/sat/sat.cc
+++ b/passes/sat/sat.cc
@@ -691,7 +691,6 @@ struct SatHelper
// VCD has some limits on internal (non-display) identifier names, so make legal ones
std::map<std::string, std::string> vcdnames;
- fprintf(f, "$timescale 1ns\n"); // arbitrary time scale since actual clock period is unknown/unimportant
fprintf(f, "$scope module %s $end\n", module->name.c_str());
for (auto &info : modelInfo)
{
diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc
index 140a9f892..4faa0ab00 100644
--- a/passes/techmap/Makefile.inc
+++ b/passes/techmap/Makefile.inc
@@ -35,6 +35,7 @@ OBJS += passes/techmap/insbuf.o
OBJS += passes/techmap/attrmvcp.o
OBJS += passes/techmap/attrmap.o
OBJS += passes/techmap/zinit.o
+OBJS += passes/techmap/dff2dffs.o
endif
GENFILES += passes/techmap/techmap.inc
@@ -57,4 +58,3 @@ yosys-filterlib$(EXE): passes/techmap/filterlib.o
$(Q) mkdir -p $(dir $@)
$(P) $(LD) -o yosys-filterlib$(EXE) $(LDFLAGS) $^ $(LDLIBS)
endif
-
diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc
index be86f642a..18868c6d7 100644
--- a/passes/techmap/abc.cc
+++ b/passes/techmap/abc.cc
@@ -60,6 +60,10 @@
#include "frontends/blif/blifparse.h"
+#ifdef YOSYS_LINK_ABC
+extern "C" int Abc_RealMain(int argc, char *argv[]);
+#endif
+
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
@@ -546,11 +550,13 @@ std::string replace_tempdir(std::string text, std::string tempdir_name, bool sho
}
std::string selfdir_name = proc_self_dirname();
- while (1) {
- size_t pos = text.find(selfdir_name);
- if (pos == std::string::npos)
- break;
- text = text.substr(0, pos) + "<yosys-exe-dir>/" + text.substr(pos + GetSize(selfdir_name));
+ if (selfdir_name != "/") {
+ while (1) {
+ size_t pos = text.find(selfdir_name);
+ if (pos == std::string::npos)
+ break;
+ text = text.substr(0, pos) + "<yosys-exe-dir>/" + text.substr(pos + GetSize(selfdir_name));
+ }
}
return text;
@@ -943,8 +949,24 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
buffer = stringf("%s -s -f %s/abc.script 2>&1", exe_file.c_str(), tempdir_name.c_str());
log("Running ABC command: %s\n", replace_tempdir(buffer, tempdir_name, show_tempdir).c_str());
+#ifndef YOSYS_LINK_ABC
abc_output_filter filt(tempdir_name, show_tempdir);
int ret = run_command(buffer, std::bind(&abc_output_filter::next_line, filt, std::placeholders::_1));
+#else
+ // These needs to be mutable, supposedly due to getopt
+ char *abc_argv[5];
+ string tmp_script_name = stringf("%s/abc.script", tempdir_name.c_str());
+ abc_argv[0] = strdup(exe_file.c_str());
+ abc_argv[1] = strdup("-s");
+ abc_argv[2] = strdup("-f");
+ abc_argv[3] = strdup(tmp_script_name.c_str());
+ abc_argv[4] = 0;
+ int ret = Abc_RealMain(4, abc_argv);
+ free(abc_argv[0]);
+ free(abc_argv[1]);
+ free(abc_argv[2]);
+ free(abc_argv[3]);
+#endif
if (ret != 0)
log_error("ABC: execution of command \"%s\" failed: return code %d.\n", buffer.c_str(), ret);
@@ -1388,8 +1410,12 @@ struct AbcPass : public Pass {
log("When neither -liberty nor -lut is used, the Yosys standard cell library is\n");
log("loaded into ABC before the ABC script is executed.\n");
log("\n");
- log("This pass does not operate on modules with unprocessed processes in it.\n");
- log("(I.e. the 'proc' pass should be used first to convert processes to netlists.)\n");
+ log("Note that this is a logic optimization pass within Yosys that is calling ABC\n");
+ log("internally. This is not going to \"run ABC on your design\". It will instead run\n");
+ log("ABC on logic snippets extracted from your design. You will not get any useful\n");
+ log("output when passing an ABC script that writes a file. Instead write your full\n");
+ log("design as BLIF file with write_blif and the load that into ABC externally if\n");
+ log("you want to use ABC to convert your design into another format.\n");
log("\n");
log("[1] http://www.eecs.berkeley.edu/~alanmi/abc/\n");
log("\n");
diff --git a/passes/techmap/deminout.cc b/passes/techmap/deminout.cc
index ed4e45762..0b8fd5246 100644
--- a/passes/techmap/deminout.cc
+++ b/passes/techmap/deminout.cc
@@ -57,7 +57,7 @@ struct DeminoutPass : public Pass {
for (auto module : design->selected_modules())
{
SigMap sigmap(module);
- pool<SigBit> bits_written, bits_used, bits_inout;
+ pool<SigBit> bits_written, bits_used, bits_inout, bits_tribuf;
dict<SigBit, int> bits_numports;
for (auto wire : module->wires())
@@ -82,6 +82,25 @@ struct DeminoutPass : public Pass {
if (cellport_in)
for (auto bit : sigmap(conn.second))
bits_used.insert(bit);
+
+ if (conn.first == "\\Y" && cell->type.in("$mux", "$pmux", "$_MUX_", "$_TBUF_"))
+ {
+ bool tribuf = (cell->type == "$_TBUF_");
+
+ if (!tribuf) {
+ for (auto &c : cell->connections()) {
+ if (!c.first.in("\\A", "\\B"))
+ continue;
+ for (auto b : sigmap(c.second))
+ if (b == State::Sz)
+ tribuf = true;
+ }
+ }
+
+ if (tribuf)
+ for (auto bit : sigmap(conn.second))
+ bits_tribuf.insert(bit);
+ }
}
for (auto wire : module->selected_wires())
@@ -95,10 +114,15 @@ struct DeminoutPass : public Pass {
if (bits_numports[bit] > 1 || bits_inout.count(bit))
new_input = true, new_output = true;
- if (bits_written.count(bit))
+ if (bits_written.count(bit)) {
new_output = true;
- else if (bits_used.count(bit))
- new_input = true;
+ if (bits_tribuf.count(bit))
+ goto tribuf_bit;
+ } else {
+ tribuf_bit:
+ if (bits_used.count(bit))
+ new_input = true;
+ }
}
if (new_input != new_output) {
diff --git a/passes/techmap/dff2dffe.cc b/passes/techmap/dff2dffe.cc
index 1b8920bb7..4d515f174 100644
--- a/passes/techmap/dff2dffe.cc
+++ b/passes/techmap/dff2dffe.cc
@@ -279,8 +279,9 @@ struct Dff2dffePass : public Pass {
log(" -direct-match <pattern>\n");
log(" like -direct for all DFF cell types matching the expression.\n");
log(" this will use $__DFFE_* as <external_gate_type> matching the\n");
- log(" internal gate type $_DFF_*_, except for $_DFF_[NP]_, which is\n");
- log(" converted to $_DFFE_[NP]_.\n");
+ log(" internal gate type $_DFF_*_, and $__DFFSE_* for those matching\n");
+ log(" $_DFFS_*_, except for $_DFF_[NP]_, which is converted to \n");
+ log(" $_DFFE_[NP]_.\n");
log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
@@ -315,6 +316,15 @@ struct Dff2dffePass : public Pass {
if (patmatch(pattern, "$_DFF_PN1_")) found_match = true, direct_dict["$_DFF_PN1_"] = "$__DFFE_PN1";
if (patmatch(pattern, "$_DFF_PP0_")) found_match = true, direct_dict["$_DFF_PP0_"] = "$__DFFE_PP0";
if (patmatch(pattern, "$_DFF_PP1_")) found_match = true, direct_dict["$_DFF_PP1_"] = "$__DFFE_PP1";
+
+ if (patmatch(pattern, "$__DFFS_NN0_")) found_match = true, direct_dict["$__DFFS_NN0_"] = "$__DFFSE_NN0";
+ if (patmatch(pattern, "$__DFFS_NN1_")) found_match = true, direct_dict["$__DFFS_NN1_"] = "$__DFFSE_NN1";
+ if (patmatch(pattern, "$__DFFS_NP0_")) found_match = true, direct_dict["$__DFFS_NP0_"] = "$__DFFSE_NP0";
+ if (patmatch(pattern, "$__DFFS_NP1_")) found_match = true, direct_dict["$__DFFS_NP1_"] = "$__DFFSE_NP1";
+ if (patmatch(pattern, "$__DFFS_PN0_")) found_match = true, direct_dict["$__DFFS_PN0_"] = "$__DFFSE_PN0";
+ if (patmatch(pattern, "$__DFFS_PN1_")) found_match = true, direct_dict["$__DFFS_PN1_"] = "$__DFFSE_PN1";
+ if (patmatch(pattern, "$__DFFS_PP0_")) found_match = true, direct_dict["$__DFFS_PP0_"] = "$__DFFSE_PP0";
+ if (patmatch(pattern, "$__DFFS_PP1_")) found_match = true, direct_dict["$__DFFS_PP1_"] = "$__DFFSE_PP1";
if (!found_match)
log_cmd_error("No cell types matched pattern '%s'.\n", pattern);
continue;
diff --git a/passes/techmap/dff2dffs.cc b/passes/techmap/dff2dffs.cc
new file mode 100644
index 000000000..0bfbdc965
--- /dev/null
+++ b/passes/techmap/dff2dffs.cc
@@ -0,0 +1,142 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2018 David Shah <dave@ds0.me>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct Dff2dffsPass : public Pass {
+ Dff2dffsPass() : Pass("dff2dffs", "process sync set/reset with SR over CE priority") { }
+ virtual void help()
+ {
+ log("\n");
+ log(" dff2dffs [options] [selection]\n");
+ log("\n");
+ log("Merge synchronous set/reset $_MUX_ cells to create $__DFFS_[NP][NP][01], to be run before\n");
+ log("dff2dffe for SR over CE priority.\n");
+ log("\n");
+ }
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
+ {
+ log_header(design, "Executing dff2dffs pass (merge synchronous set/reset into FF cells).\n");
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ // if (args[argidx] == "-singleton") {
+ // singleton_mode = true;
+ // continue;
+ // }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ pool<IdString> dff_types;
+ dff_types.insert("$_DFF_N_");
+ dff_types.insert("$_DFF_P_");
+
+ for (auto module : design->selected_modules())
+ {
+ log("Merging set/reset $_MUX_ cells into DFFs in %s.\n", log_id(module));
+
+ SigMap sigmap(module);
+ dict<SigBit, Cell*> sr_muxes;
+ vector<Cell*> ff_cells;
+
+ for (auto cell : module->selected_cells())
+ {
+ if (dff_types.count(cell->type)) {
+ ff_cells.push_back(cell);
+ continue;
+ }
+
+ if (cell->type != "$_MUX_")
+ continue;
+
+ SigBit bit_a = sigmap(cell->getPort("\\A"));
+ SigBit bit_b = sigmap(cell->getPort("\\B"));
+
+ if (bit_a.wire == nullptr || bit_b.wire == nullptr)
+ sr_muxes[sigmap(cell->getPort("\\Y"))] = cell;
+ }
+
+ for (auto cell : ff_cells)
+ {
+ SigSpec sig_d = cell->getPort("\\D");
+
+ if (GetSize(sig_d) < 1)
+ continue;
+
+ SigBit bit_d = sigmap(sig_d[0]);
+
+ if (sr_muxes.count(bit_d) == 0)
+ continue;
+
+ Cell *mux_cell = sr_muxes.at(bit_d);
+ SigBit bit_a = sigmap(mux_cell->getPort("\\A"));
+ SigBit bit_b = sigmap(mux_cell->getPort("\\B"));
+ SigBit bit_s = sigmap(mux_cell->getPort("\\S"));
+
+ log(" Merging %s (A=%s, B=%s, S=%s) into %s (%s).\n", log_id(mux_cell),
+ log_signal(bit_a), log_signal(bit_b), log_signal(bit_s), log_id(cell), log_id(cell->type));
+
+ SigBit sr_val, sr_sig;
+ bool invert_sr;
+ sr_sig = bit_s;
+ if (bit_a.wire == nullptr) {
+ bit_d = bit_b;
+ sr_val = bit_a;
+ invert_sr = true;
+ } else {
+ log_assert(bit_b.wire == nullptr);
+ bit_d = bit_a;
+ sr_val = bit_b;
+ invert_sr = false;
+ }
+
+ if (sr_val == State::S1) {
+ if (cell->type == "$_DFF_N_") {
+ if (invert_sr) cell->type = "$__DFFS_NN1_";
+ else cell->type = "$__DFFS_NP1_";
+ } else {
+ log_assert(cell->type == "$_DFF_P_");
+ if (invert_sr) cell->type = "$__DFFS_PN1_";
+ else cell->type = "$__DFFS_PP1_";
+ }
+ } else {
+ if (cell->type == "$_DFF_N_") {
+ if (invert_sr) cell->type = "$__DFFS_NN0_";
+ else cell->type = "$__DFFS_NP0_";
+ } else {
+ log_assert(cell->type == "$_DFF_P_");
+ if (invert_sr) cell->type = "$__DFFS_PN0_";
+ else cell->type = "$__DFFS_PP0_";
+ }
+ }
+ cell->setPort("\\R", sr_sig);
+ cell->setPort("\\D", bit_d);
+ }
+ }
+ }
+} Dff2dffsPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/techmap/dfflibmap.cc b/passes/techmap/dfflibmap.cc
index 4cb1489a8..5ccb770c4 100644
--- a/passes/techmap/dfflibmap.cc
+++ b/passes/techmap/dfflibmap.cc
@@ -240,6 +240,10 @@ static void find_cell_sr(LibertyAst *ast, std::string cell_type, bool clkpol, bo
if (cell->id != "cell" || cell->args.size() != 1)
continue;
+ LibertyAst *dn = cell->find("dont_use");
+ if (dn != NULL && dn->value == "true")
+ continue;
+
LibertyAst *ff = cell->find("ff");
if (ff == NULL)
continue;
diff --git a/passes/techmap/extract_reduce.cc b/passes/techmap/extract_reduce.cc
index cc21c8665..0ce596fda 100644
--- a/passes/techmap/extract_reduce.cc
+++ b/passes/techmap/extract_reduce.cc
@@ -19,6 +19,7 @@
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
+#include <deque>
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
diff --git a/passes/techmap/iopadmap.cc b/passes/techmap/iopadmap.cc
index 4acbf7c0d..690ba87ed 100644
--- a/passes/techmap/iopadmap.cc
+++ b/passes/techmap/iopadmap.cc
@@ -146,11 +146,37 @@ struct IopadmapPass : public Pass {
for (auto module : design->selected_modules())
{
dict<IdString, pool<int>> skip_wires;
+ pool<SigBit> skip_wire_bits;
+ SigMap sigmap(module);
+
+ for (auto cell : module->cells())
+ {
+ if (cell->type == RTLIL::escape_id(inpad_celltype) && cell->hasPort(RTLIL::escape_id(inpad_portname2)))
+ for (auto bit : sigmap(cell->getPort(RTLIL::escape_id(inpad_portname2))))
+ skip_wire_bits.insert(bit);
+
+ if (cell->type == RTLIL::escape_id(outpad_celltype) && cell->hasPort(RTLIL::escape_id(outpad_portname2)))
+ for (auto bit : sigmap(cell->getPort(RTLIL::escape_id(outpad_portname2))))
+ skip_wire_bits.insert(bit);
+
+ if (cell->type == RTLIL::escape_id(inoutpad_celltype) && cell->hasPort(RTLIL::escape_id(inoutpad_portname2)))
+ for (auto bit : sigmap(cell->getPort(RTLIL::escape_id(inoutpad_portname2))))
+ skip_wire_bits.insert(bit);
+
+ if (cell->type == RTLIL::escape_id(toutpad_celltype) && cell->hasPort(RTLIL::escape_id(toutpad_portname3)))
+ for (auto bit : sigmap(cell->getPort(RTLIL::escape_id(toutpad_portname3))))
+ skip_wire_bits.insert(bit);
+
+ if (cell->type == RTLIL::escape_id(tinoutpad_celltype) && cell->hasPort(RTLIL::escape_id(tinoutpad_portname4)))
+ for (auto bit : sigmap(cell->getPort(RTLIL::escape_id(tinoutpad_portname4))))
+ skip_wire_bits.insert(bit);
+ }
if (!toutpad_celltype.empty() || !tinoutpad_celltype.empty())
{
- SigMap sigmap(module);
dict<SigBit, pair<IdString, pool<IdString>>> tbuf_bits;
+ pool<pair<IdString, IdString>> norewrites;
+ SigMap rewrites;
for (auto cell : module->cells())
if (cell->type == "$_TBUF_") {
@@ -177,6 +203,9 @@ struct IopadmapPass : public Pass {
if (tbuf_bits.count(mapped_wire_bit) == 0)
continue;
+ if (skip_wire_bits.count(mapped_wire_bit))
+ continue;
+
auto &tbuf_cache = tbuf_bits.at(mapped_wire_bit);
Cell *tbuf_cell = module->cell(tbuf_cache.first);
@@ -219,6 +248,9 @@ struct IopadmapPass : public Pass {
module->remove(tbuf_cell);
skip_wires[wire->name].insert(i);
+
+ norewrites.insert(make_pair(cell->name, RTLIL::escape_id(tinoutpad_portname4)));
+ rewrites.add(sigmap(wire_bit), owire);
continue;
}
@@ -256,6 +288,22 @@ struct IopadmapPass : public Pass {
}
}
}
+
+ if (GetSize(norewrites))
+ {
+ for (auto cell : module->cells())
+ for (auto port : cell->connections())
+ {
+ if (norewrites.count(make_pair(cell->name, port.first)))
+ continue;
+
+ SigSpec orig_sig = sigmap(port.second);
+ SigSpec new_sig = rewrites(orig_sig);
+
+ if (orig_sig != new_sig)
+ cell->setPort(port.first, new_sig);
+ }
+ }
}
for (auto wire : module->selected_wires())
@@ -272,6 +320,13 @@ struct IopadmapPass : public Pass {
skip_bit_indices = skip_wires.at(wire->name);
}
+ for (int i = 0; i < GetSize(wire); i++)
+ if (skip_wire_bits.count(sigmap(SigBit(wire, i))))
+ skip_bit_indices.insert(i);
+
+ if (GetSize(wire) == GetSize(skip_bit_indices))
+ continue;
+
if (wire->port_input && !wire->port_output) {
if (inpad_celltype.empty()) {
log("Don't map input port %s.%s: Missing option -inpad.\n", RTLIL::id2cstr(module->name), RTLIL::id2cstr(wire->name));
diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc
index 02d0d47e8..1908ae8b5 100644
--- a/passes/techmap/techmap.cc
+++ b/passes/techmap/techmap.cc
@@ -933,7 +933,7 @@ struct TechmapPass : public Pass {
log(" -D <define>, -I <incdir>\n");
log(" this options are passed as-is to the Verilog frontend for loading the\n");
log(" map file. Note that the Verilog frontend is also called with the\n");
- log(" '-ignore_redef' option set.\n");
+ log(" '-nooverwrite' option set.\n");
log("\n");
log("When a module in the map file has the 'techmap_celltype' attribute set, it will\n");
log("match cells with a type that match the text value of this attribute. Otherwise\n");
@@ -1031,7 +1031,7 @@ struct TechmapPass : public Pass {
simplemap_get_mappers(worker.simplemap_mappers);
std::vector<std::string> map_files;
- std::string verilog_frontend = "verilog -ignore_redef";
+ std::string verilog_frontend = "verilog -nooverwrite";
int max_iter = -1;
size_t argidx;
diff --git a/techlibs/achronix/Makefile.inc b/techlibs/achronix/Makefile.inc
index affe0334a..994cf0015 100755
--- a/techlibs/achronix/Makefile.inc
+++ b/techlibs/achronix/Makefile.inc
@@ -1,5 +1,5 @@
-OBJS += techlibs/achronix/synth_speedster.o
+OBJS += techlibs/achronix/synth_achronix.o
$(eval $(call add_share_file,share/achronix/speedster22i/,techlibs/achronix/speedster22i/cells_sim.v))
$(eval $(call add_share_file,share/achronix/speedster22i/,techlibs/achronix/speedster22i/cells_map.v))
diff --git a/techlibs/achronix/speedster22i/cells_map.v b/techlibs/achronix/speedster22i/cells_map.v
index 90f87826d..95f5d59c5 100755
--- a/techlibs/achronix/speedster22i/cells_map.v
+++ b/techlibs/achronix/speedster22i/cells_map.v
@@ -16,53 +16,25 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
-// Normal mode DFF negedge clk, negedge reset
-module \$_DFF_N_ (input D, C, output Q);
- parameter WYSIWYG="TRUE";
- dffeas #(.is_wysiwyg(WYSIWYG)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(1'b1), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
-endmodule
-// Normal mode DFF
-module \$_DFF_P_ (input D, C, output Q);
- parameter WYSIWYG="TRUE";
- dffeas #(.is_wysiwyg(WYSIWYG)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(1'b1), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
-endmodule
-
-// Async Active Low Reset DFF
-module \$_DFF_PN0_ (input D, C, R, output Q);
- parameter WYSIWYG="TRUE";
- dffeas #(.is_wysiwyg(WYSIWYG)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
-endmodule
-// Async Active High Reset DFF
-module \$_DFF_PP0_ (input D, C, R, output Q);
- parameter WYSIWYG="TRUE";
- wire R_i = ~ R;
- dffeas #(.is_wysiwyg(WYSIWYG)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R_i), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
-endmodule
-// Async Active Low Reset DFF
-module \$_DFF_PN0_ (input D, C, R, output Q);
- parameter WYSIWYG="TRUE";
- dffeas #(.is_wysiwyg(WYSIWYG)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
-endmodule
-/* */
-module \$__DFFE_PP0 (input D, C, E, R, output Q);
- parameter WYSIWYG="TRUE";
- wire E_i = ~ E;
- dffeas #(.is_wysiwyg(WYSIWYG)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(E_i), .sload(1'b0));
-endmodule
+// > c60k28 (Viacheslav, VT) [at] yandex [dot] com
+// > Achronix eFPGA technology mapping. User must first simulate the generated \
+// > netlist before going to test it on board/custom chip.
+// > Input/Output buffers <
// Input buffer map
module \$__inpad (input I, output O);
PADIN _TECHMAP_REPLACE_ (.padout(O), .padin(I));
endmodule
-
// Output buffer map
module \$__outpad (input I, output O);
PADOUT _TECHMAP_REPLACE_ (.padout(O), .padin(I), .oe(1'b1));
endmodule
+// > end buffers <
+// > Look-Up table <
+// > VT: I still think Achronix folks would have choosen a better \
+// > logic architecture.
// LUT Map
-/* 0 -> datac
- 1 -> cin */
module \$lut (A, Y);
parameter WIDTH = 0;
parameter LUT = 0;
@@ -70,19 +42,31 @@ module \$lut (A, Y);
output Y;
generate
if (WIDTH == 1) begin
- assign Y = ~A[0]; // Not need to spend 1 logic cell for such an easy function
+ // VT: This is not consistent and ACE will complain: assign Y = ~A[0];
+ LUT4 #(.lut_function({4{LUT}})) _TECHMAP_REPLACE_
+ (.dout(Y), .din0(A[0]), .din1(1'b0), .din2(1'b0), .din3(1'b0));
end else
if (WIDTH == 2) begin
- LUT4 #(.lut_function({4{LUT}})) _TECHMAP_REPLACE_ (.dout(Y), .din0(A[0]), .din1(A[1]), .din2(1'b0),.din3(1'b0));
+ LUT4 #(.lut_function({4{LUT}})) _TECHMAP_REPLACE_
+ (.dout(Y), .din0(A[0]), .din1(A[1]), .din2(1'b0), .din3(1'b0));
end else
if(WIDTH == 3) begin
- LUT4 #(.lut_function({2{LUT}})) _TECHMAP_REPLACE_ (.dout(Y), .din0(A[0]), .din1(A[1]), .din2(A[2]),.din3(1'b0));
+ LUT4 #(.lut_function({2{LUT}})) _TECHMAP_REPLACE_
+ (.dout(Y), .din0(A[0]), .din1(A[1]), .din2(A[2]), .din3(1'b0));
end else
if(WIDTH == 4) begin
- LUT4 #(.lut_function(LUT)) _TECHMAP_REPLACE_ (.dout(Y), .din0(A[0]), .din1(A[1]), .din2(A[2]), .din3(A[3]));
+ LUT4 #(.lut_function(LUT)) _TECHMAP_REPLACE_
+ (.dout(Y), .din0(A[0]), .din1(A[1]), .din2(A[2]), .din3(A[3]));
end else
wire _TECHMAP_FAIL_ = 1;
endgenerate
-endmodule //
+endmodule
+// > end LUT <
+// > Flops <
+// DFF flop
+module \$_DFF_P_ (input D, C, output Q);
+ DFF _TECHMAP_REPLACE_
+ (.q(Q), .d(D), .ck(C));
+endmodule
diff --git a/techlibs/achronix/speedster22i/cells_sim.v b/techlibs/achronix/speedster22i/cells_sim.v
index 24c57c41a..da23fed7e 100755
--- a/techlibs/achronix/speedster22i/cells_sim.v
+++ b/techlibs/achronix/speedster22i/cells_sim.v
@@ -16,50 +16,31 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
+// > c60k28 (Viacheslav, VT) [at] yandex [dot] com
+// > Achronix eFPGA technology sim models. User must first simulate the generated \
+// > netlist before going to test it on board/custom chip.
+// > Changelog: 1) Removed unused VCC/GND modules
+// > 2) Altera comments here (?). Removed.
+// > 3) Reusing LUT sim model, removed wrong wires and parameters.
-module VCC (output V);
- assign V = 1'b1;
-endmodule // VCC
-
-module GND (output G);
- assign G = 1'b0;
-endmodule // GND
-
-/* Altera MAX10 devices Input Buffer Primitive */
module PADIN (output padout, input padin);
assign padout = padin;
-endmodule // fiftyfivenm_io_ibuf
+endmodule
-/* Altera MAX10 devices Output Buffer Primitive */
module PADOUT (output padout, input padin, input oe);
assign padout = padin;
assign oe = oe;
-endmodule // fiftyfivenm_io_obuf
+endmodule
-/* Altera MAX10 4-input non-fracturable LUT Primitive */
module LUT4 (output dout,
input din0, din1, din2, din3);
-/* Internal parameters which define the behaviour
- of the LUT primitive.
- lut_mask define the lut function, can be expressed in 16-digit bin or hex.
- sum_lutc_input define the type of LUT (combinational | arithmetic).
- dont_touch for retiming || carry options.
- lpm_type for WYSIWYG */
-
-parameter lut_function = 16'hFFFF;
-//parameter dont_touch = "off";
-//parameter lpm_type = "fiftyfivenm_lcell_comb";
-//parameter sum_lutc_input = "datac";
-
-reg [1:0] lut_type;
-reg cout_rt;
+parameter [15:0] lut_function = 16'hFFFF;
reg combout_rt;
wire dataa_w;
wire datab_w;
wire datac_w;
wire datad_w;
-wire cin_w;
assign dataa_w = din0;
assign datab_w = din1;
@@ -78,49 +59,21 @@ reg [1:0] s1;
s1 = datab ? s2[3:2] : s2[1:0];
lut_data = dataa ? s1[1] : s1[0];
end
-
endfunction
-initial begin
- /*if (sum_lutc_input == "datac")*/ lut_type = 0;
- /*else
- if (sum_lutc_input == "cin") lut_type = 1;
- else begin
- $error("Error in sum_lutc_input. Parameter %s is not a valid value.\n", sum_lutc_input);
- $finish();
- end*/
-end
-
always @(dataa_w or datab_w or datac_w or datad_w or cin_w) begin
- if (lut_type == 0) begin // logic function
- combout_rt = lut_data(lut_function, dataa_w, datab_w,
- datac_w, datad_w);
- end
- else if (lut_type == 1) begin // arithmetic function
- combout_rt = lut_data(lut_function, dataa_w, datab_w,
- cin_w, datad_w);
- end
- cout_rt = lut_data(lut_function, dataa_w, datab_w, cin_w, 'b0);
+ combout_rt = lut_data(lut_function, dataa_w, datab_w,
+ datac_w, datad_w);
end
-
assign dout = combout_rt & 1'b1;
-//assign cout = cout_rt & 1'b1;
-
-endmodule // fiftyfivenm_lcell_comb
-
-/* Altera MAX10 D Flip-Flop Primitive */
-// TODO: Implement advanced simulation functions
-module dffeas ( output q,
- input d, clk, clrn, prn, ena,
- input asdata, aload, sclr, sload );
-
-parameter power_up="dontcare";
-parameter is_wysiwyg="false";
- reg q;
-
- always @(posedge clk)
- q <= d;
-
+endmodule
+
+module DFF (output q,
+ input d, ck);
+ reg q;
+ always @(posedge ck)
+ q <= d;
+
endmodule
diff --git a/techlibs/achronix/synth_speedster.cc b/techlibs/achronix/synth_achronix.cc
index 3808af6f1..7f4503070 100755
--- a/techlibs/achronix/synth_speedster.cc
+++ b/techlibs/achronix/synth_achronix.cc
@@ -25,14 +25,14 @@
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
-struct SynthIntelPass : public ScriptPass {
- SynthIntelPass() : ScriptPass("synth_speedster", "synthesis for Acrhonix Speedster22i FPGAs.") { }
+struct SynthAchronixPass : public ScriptPass {
+ SynthAchronixPass() : ScriptPass("synth_achronix", "synthesis for Acrhonix Speedster22i FPGAs.") { }
virtual void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
- log(" synth_speedster [options]\n");
+ log(" synth_achronix [options]\n");
log("\n");
log("This command runs synthesis for Achronix Speedster eFPGAs. This work is still experimental.\n");
log("\n");
@@ -110,7 +110,7 @@ struct SynthIntelPass : public ScriptPass {
if (!design->full_selection())
log_cmd_error("This comannd only operates on fully selected designs!\n");
- log_header(design, "Executing SYNTH_SPEEDSTER pass.\n");
+ log_header(design, "Executing SYNTH_ACHRONIX pass.\n");
log_push();
run_script(design, run_from, run_to);
@@ -146,9 +146,9 @@ struct SynthIntelPass : public ScriptPass {
run("opt -undriven -fine");
run("dffsr2dff");
run("dff2dffe -direct-match $_DFF_*");
- run("opt -full");
+ run("opt -fine");
run("techmap -map +/techmap.v");
- run("opt -fast");
+ run("opt -full");
run("clean -purge");
run("setundef -undriven -zero");
if (retime || help_mode)
@@ -157,7 +157,7 @@ struct SynthIntelPass : public ScriptPass {
if (check_label("map_luts"))
{
- run("abc -luts 2:2,3,6:5,10,20" + string(retime ? " -dff" : ""));
+ run("abc -lut 4" + string(retime ? " -dff" : ""));
run("clean");
}
@@ -165,7 +165,7 @@ struct SynthIntelPass : public ScriptPass {
{
run("iopadmap -bits -outpad $__outpad I:O -inpad $__inpad O:I");
run("techmap -map +/achronix/speedster22i/cells_map.v");
- run("dffinit -ff dffeas Q INIT");
+ // VT: not done yet run("dffinit -highlow -ff DFF q power_up");
run("clean -purge");
}
@@ -179,10 +179,10 @@ struct SynthIntelPass : public ScriptPass {
if (check_label("vout"))
{
if (!vout_file.empty() || help_mode)
- run(stringf("write_verilog -nodec -attr2comment -defparam -nohex -renameprefix yosys_ %s",
+ run(stringf("write_verilog -nodec -attr2comment -defparam -renameprefix syn_ %s",
help_mode ? "<file-name>" : vout_file.c_str()));
}
}
-} SynthIntelPass;
+} SynthAchronixPass;
PRIVATE_NAMESPACE_END
diff --git a/techlibs/common/prep.cc b/techlibs/common/prep.cc
index 3dfc60383..cc977f97e 100644
--- a/techlibs/common/prep.cc
+++ b/techlibs/common/prep.cc
@@ -55,13 +55,14 @@ struct PrepPass : public ScriptPass
log("\n");
log(" -memx\n");
log(" simulate verilog simulation behavior for out-of-bounds memory accesses\n");
- log(" using the 'memory_memx' pass. This option implies -nordff.\n");
+ log(" using the 'memory_memx' pass.\n");
log("\n");
log(" -nomem\n");
log(" do not run any of the memory_* passes\n");
log("\n");
- log(" -nordff\n");
- log(" passed to 'memory_dff'. prohibits merging of FFs into memory read ports\n");
+ log(" -rdff\n");
+ log(" do not pass -nordff to 'memory_dff'. This enables merging of FFs into\n");
+ log(" memory read ports.\n");
log("\n");
log(" -nokeepdc\n");
log(" do not call opt_* with -keepdc\n");
@@ -77,13 +78,12 @@ struct PrepPass : public ScriptPass
log("\n");
}
- string top_module, fsm_opts, memory_opts;
- bool autotop, flatten, ifxmode, memxmode, nomemmode, nokeepdc;
+ string top_module, fsm_opts;
+ bool autotop, flatten, ifxmode, memxmode, nomemmode, nokeepdc, nordff;
virtual void clear_flags() YS_OVERRIDE
{
top_module.clear();
- memory_opts.clear();
autotop = false;
flatten = false;
@@ -91,6 +91,7 @@ struct PrepPass : public ScriptPass
memxmode = false;
nomemmode = false;
nokeepdc = false;
+ nordff = true;
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
@@ -129,7 +130,6 @@ struct PrepPass : public ScriptPass
}
if (args[argidx] == "-memx") {
memxmode = true;
- memory_opts += " -nordff";
continue;
}
if (args[argidx] == "-nomem") {
@@ -137,7 +137,11 @@ struct PrepPass : public ScriptPass
continue;
}
if (args[argidx] == "-nordff") {
- memory_opts += " -nordff";
+ nordff = true;
+ continue;
+ }
+ if (args[argidx] == "-rdff") {
+ nordff = false;
continue;
}
if (args[argidx] == "-nokeepdc") {
@@ -196,7 +200,7 @@ struct PrepPass : public ScriptPass
run(memxmode ? "wreduce -memx" : "wreduce");
}
if (!nomemmode) {
- run("memory_dff" + (help_mode ? " [-nordff]" : memory_opts));
+ run(string("memory_dff") + (help_mode ? " [-nordff]" : nordff ? " -nordff" : ""));
if (help_mode || memxmode)
run("memory_memx", "(if -memx)");
run("opt_clean");
diff --git a/techlibs/coolrunner2/Makefile.inc b/techlibs/coolrunner2/Makefile.inc
index 96bbb0f47..d62c9960c 100644
--- a/techlibs/coolrunner2/Makefile.inc
+++ b/techlibs/coolrunner2/Makefile.inc
@@ -4,4 +4,5 @@ OBJS += techlibs/coolrunner2/coolrunner2_sop.o
$(eval $(call add_share_file,share/coolrunner2,techlibs/coolrunner2/cells_latch.v))
$(eval $(call add_share_file,share/coolrunner2,techlibs/coolrunner2/cells_sim.v))
+$(eval $(call add_share_file,share/coolrunner2,techlibs/coolrunner2/tff_extract.v))
$(eval $(call add_share_file,share/coolrunner2,techlibs/coolrunner2/xc2_dff.lib))
diff --git a/techlibs/coolrunner2/coolrunner2_sop.cc b/techlibs/coolrunner2/coolrunner2_sop.cc
index b57214ccb..431e0a127 100644
--- a/techlibs/coolrunner2/coolrunner2_sop.cc
+++ b/techlibs/coolrunner2/coolrunner2_sop.cc
@@ -250,6 +250,64 @@ struct Coolrunner2SopPass : public Pass {
}
}
+ // In some cases we can get a FF feeding straight into an FF. This is not possible, so we need to insert
+ // some AND/XOR cells in the middle to make it actually work.
+
+ // Find all the FF outputs
+ pool<SigBit> sig_fed_by_ff;
+ for (auto cell : module->selected_cells())
+ {
+ if (cell->type == "\\FDCP" || cell->type == "\\FDCP_N" || cell->type == "\\FDDCP" ||
+ cell->type == "\\LDCP" || cell->type == "\\LDCP_N" ||
+ cell->type == "\\FTCP" || cell->type == "\\FTCP_N" || cell->type == "\\FTDCP" ||
+ cell->type == "\\FDCPE" || cell->type == "\\FDCPE_N" || cell->type == "\\FDDCPE")
+ {
+ auto output = sigmap(cell->getPort("\\Q")[0]);
+ sig_fed_by_ff.insert(output);
+ }
+ }
+
+ // Look at all the FF inputs
+ for (auto cell : module->selected_cells())
+ {
+ if (cell->type == "\\FDCP" || cell->type == "\\FDCP_N" || cell->type == "\\FDDCP" ||
+ cell->type == "\\LDCP" || cell->type == "\\LDCP_N" ||
+ cell->type == "\\FTCP" || cell->type == "\\FTCP_N" || cell->type == "\\FTDCP" ||
+ cell->type == "\\FDCPE" || cell->type == "\\FDCPE_N" || cell->type == "\\FDDCPE")
+ {
+ SigBit input;
+ if (cell->type == "\\FTCP" || cell->type == "\\FTCP_N" || cell->type == "\\FTDCP")
+ input = sigmap(cell->getPort("\\T")[0]);
+ else
+ input = sigmap(cell->getPort("\\D")[0]);
+
+ if (sig_fed_by_ff[input])
+ {
+ printf("Buffering input to \"%s\"\n", cell->name.c_str());
+
+ auto and_to_xor_wire = module->addWire(NEW_ID);
+ auto xor_to_ff_wire = module->addWire(NEW_ID);
+
+ auto and_cell = module->addCell(NEW_ID, "\\ANDTERM");
+ and_cell->setParam("\\TRUE_INP", 1);
+ and_cell->setParam("\\COMP_INP", 0);
+ and_cell->setPort("\\OUT", and_to_xor_wire);
+ and_cell->setPort("\\IN", input);
+ and_cell->setPort("\\IN_B", SigSpec());
+
+ auto xor_cell = module->addCell(NEW_ID, "\\MACROCELL_XOR");
+ xor_cell->setParam("\\INVERT_OUT", false);
+ xor_cell->setPort("\\IN_PTC", and_to_xor_wire);
+ xor_cell->setPort("\\OUT", xor_to_ff_wire);
+
+ if (cell->type == "\\FTCP" || cell->type == "\\FTCP_N" || cell->type == "\\FTDCP")
+ cell->setPort("\\T", xor_to_ff_wire);
+ else
+ cell->setPort("\\D", xor_to_ff_wire);
+ }
+ }
+ }
+
// Actually do the removal now that we aren't iterating
for (auto cell : cells_to_remove)
{
diff --git a/techlibs/coolrunner2/synth_coolrunner2.cc b/techlibs/coolrunner2/synth_coolrunner2.cc
index 183282629..2e94c3449 100644
--- a/techlibs/coolrunner2/synth_coolrunner2.cc
+++ b/techlibs/coolrunner2/synth_coolrunner2.cc
@@ -149,6 +149,16 @@ struct SynthCoolrunner2Pass : public ScriptPass
run("dfflibmap -prepare -liberty +/coolrunner2/xc2_dff.lib");
}
+ if (check_label("map_tff"))
+ {
+ // This is quite hacky. By telling abc that it can only use AND and XOR gates, abc will try and use XOR
+ // gates "whenever possible." This will hopefully cause toggle flip-flop structures to turn into an XOR
+ // connected to a D flip-flop. We then match on these and convert them into XC2 TFF cells.
+ run("abc -g AND,XOR");
+ run("clean");
+ run("extract -map +/coolrunner2/tff_extract.v");
+ }
+
if (check_label("map_pla"))
{
run("abc -sop -I 40 -P 56");
@@ -160,12 +170,15 @@ struct SynthCoolrunner2Pass : public ScriptPass
run("dfflibmap -liberty +/coolrunner2/xc2_dff.lib");
run("dffinit -ff FDCP Q INIT");
run("dffinit -ff FDCP_N Q INIT");
+ run("dffinit -ff FTCP Q INIT");
+ run("dffinit -ff FTCP_N Q INIT");
run("dffinit -ff LDCP Q INIT");
run("dffinit -ff LDCP_N Q INIT");
run("coolrunner2_sop");
run("iopadmap -bits -inpad IBUF O:I -outpad IOBUFE I:IO -inoutpad IOBUFE O:IO -toutpad IOBUFE E:I:IO -tinoutpad IOBUFE E:O:I:IO");
run("attrmvcp -attr src -attr LOC t:IOBUFE n:*");
run("attrmvcp -attr src -attr LOC -driven t:IBUF n:*");
+ run("splitnets");
run("clean");
}
diff --git a/techlibs/coolrunner2/tff_extract.v b/techlibs/coolrunner2/tff_extract.v
new file mode 100644
index 000000000..b4237dd18
--- /dev/null
+++ b/techlibs/coolrunner2/tff_extract.v
@@ -0,0 +1,41 @@
+module FTCP (C, PRE, CLR, T, Q);
+ input C, PRE, CLR, T;
+ output wire Q;
+
+ wire xorout;
+
+ $_XOR_ xorgate (
+ .A(T),
+ .B(Q),
+ .Y(xorout),
+ );
+
+ $_DFFSR_PPP_ dff (
+ .C(C),
+ .D(xorout),
+ .Q(Q),
+ .S(PRE),
+ .R(CLR),
+ );
+endmodule
+
+module FTCP_N (C, PRE, CLR, T, Q);
+ input C, PRE, CLR, T;
+ output wire Q;
+
+ wire xorout;
+
+ $_XOR_ xorgate (
+ .A(T),
+ .B(Q),
+ .Y(xorout),
+ );
+
+ $_DFFSR_NPP_ dff (
+ .C(C),
+ .D(xorout),
+ .Q(Q),
+ .S(PRE),
+ .R(CLR),
+ );
+endmodule
diff --git a/techlibs/ecp5/Makefile.inc b/techlibs/ecp5/Makefile.inc
new file mode 100644
index 000000000..9d3247347
--- /dev/null
+++ b/techlibs/ecp5/Makefile.inc
@@ -0,0 +1,8 @@
+
+OBJS += techlibs/ecp5/synth_ecp5.o
+
+$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_map.v))
+$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_sim.v))
+$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/drams_map.v))
+$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/dram.txt))
+$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/arith_map.v))
diff --git a/techlibs/ecp5/arith_map.v b/techlibs/ecp5/arith_map.v
new file mode 100644
index 000000000..1094c5f8a
--- /dev/null
+++ b/techlibs/ecp5/arith_map.v
@@ -0,0 +1,79 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2018 David Shah <dave@ds0.me>
+ *
+ * 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.
+ *
+ */
+
+(* techmap_celltype = "$alu" *)
+module _80_ecp5_alu (A, B, CI, BI, X, Y, CO);
+ parameter A_SIGNED = 0;
+ parameter B_SIGNED = 0;
+ parameter A_WIDTH = 1;
+ parameter B_WIDTH = 1;
+ parameter Y_WIDTH = 1;
+
+ input [A_WIDTH-1:0] A;
+ input [B_WIDTH-1:0] B;
+ output [Y_WIDTH-1:0] X, Y;
+
+ input CI, BI;
+ output [Y_WIDTH-1:0] CO;
+
+ wire _TECHMAP_FAIL_ = Y_WIDTH <= 2;
+
+ wire [Y_WIDTH-1:0] A_buf, B_buf;
+ \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
+ \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
+
+ function integer round_up2;
+ input integer N;
+ begin
+ round_up2 = ((N + 1) / 2) * 2;
+ end
+ endfunction
+
+ localparam Y_WIDTH2 = round_up2(Y_WIDTH);
+
+ wire [Y_WIDTH2-1:0] AA = A_buf;
+ wire [Y_WIDTH2-1:0] BB = BI ? ~B_buf : B_buf;
+ wire [Y_WIDTH2-1:0] C = {CO, CI};
+ wire [Y_WIDTH2-1:0] FCO, Y1;
+
+ genvar i;
+ generate for (i = 0; i < Y_WIDTH2; i = i + 2) begin:slice
+ CCU2C #(
+ .INIT0(16'b0110011010101010),
+ .INIT1(16'b0110011010101010),
+ .INJECT1_0("NO"),
+ .INJECT1_1("NO")
+ ) ccu2c_i (
+ .CIN(C[i]),
+ .A0(AA[i]), .B0(BB[i]), .C0(1'b0), .D0(1'b1),
+ .A1(AA[i+1]), .B1(BB[i+1]), .C1(1'b0), .D1(1'b1),
+ .S0(Y[i]), .S1(Y1[i]),
+ .COUT(FCO[i])
+ );
+
+ assign CO[i] = (AA[i] && BB[i]) || (C[i] && (AA[i] || BB[i]));
+ if (i+1 < Y_WIDTH) begin
+ assign CO[i+1] = FCO[i];
+ assign Y[i+1] = Y1[i];
+ end
+ end endgenerate
+
+ assign X = AA ^ BB;
+endmodule
diff --git a/techlibs/ecp5/cells_map.v b/techlibs/ecp5/cells_map.v
new file mode 100644
index 000000000..48162a4dc
--- /dev/null
+++ b/techlibs/ecp5/cells_map.v
@@ -0,0 +1,135 @@
+module \$_DFF_N_ (input D, C, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(1'b0), .DI(D), .Q(Q)); endmodule
+module \$_DFF_P_ (input D, C, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(1'b0), .DI(D), .Q(Q)); endmodule
+
+module \$_DFFE_NN_ (input D, C, E, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("INV"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); endmodule
+module \$_DFFE_PN_ (input D, C, E, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("INV"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); endmodule
+
+module \$_DFFE_NP_ (input D, C, E, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); endmodule
+module \$_DFFE_PP_ (input D, C, E, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(1'b0), .DI(D), .Q(Q)); endmodule
+
+module \$_DFF_NN0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("INV"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
+module \$_DFF_NN1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("INV"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
+module \$_DFF_PN0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("INV"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
+module \$_DFF_PN1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("INV"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
+
+module \$_DFF_NP0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
+module \$_DFF_NP1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
+module \$_DFF_PP0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
+module \$_DFF_PP1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
+
+module \$__DFFS_NN0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("INV"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
+module \$__DFFS_NN1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("INV"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
+module \$__DFFS_PN0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("INV"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
+module \$__DFFS_PN1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("INV"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
+
+module \$__DFFS_NP0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
+module \$__DFFS_NP1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
+module \$__DFFS_PP0_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
+module \$__DFFS_PP1_ (input D, C, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(R), .DI(D), .Q(Q)); endmodule
+
+module \$__DFFE_NN0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("INV"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
+module \$__DFFE_NN1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("INV"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
+module \$__DFFE_PN0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("INV"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
+module \$__DFFE_PN1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("INV"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
+
+module \$__DFFE_NP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
+module \$__DFFE_NP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
+module \$__DFFE_PP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
+module \$__DFFE_PP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
+
+module \$__DFFSE_NN0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("INV"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
+module \$__DFFSE_NN1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("INV"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
+module \$__DFFSE_PN0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("INV"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
+module \$__DFFSE_PN1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("INV"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
+
+module \$__DFFSE_NP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
+module \$__DFFSE_NP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
+module \$__DFFSE_PP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
+module \$__DFFSE_PP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule
+
+`ifndef NO_LUT
+module \$lut (A, Y);
+ parameter WIDTH = 0;
+ parameter LUT = 0;
+
+ input [WIDTH-1:0] A;
+ output Y;
+
+ generate
+ if (WIDTH == 1) begin
+ LUT4 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.Z(Y),
+ .A(A[0]), .B(1'b0), .C(1'b0), .D(1'b0));
+ end else
+ if (WIDTH == 2) begin
+ LUT4 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.Z(Y),
+ .A(A[0]), .B(A[1]), .C(1'b0), .D(1'b0));
+ end else
+ if (WIDTH == 3) begin
+ LUT4 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.Z(Y),
+ .A(A[0]), .B(A[1]), .C(A[2]), .D(1'b0));
+ end else
+ if (WIDTH == 4) begin
+ LUT4 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.Z(Y),
+ .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+ `ifndef NO_PFUMUX
+ end else
+ if (WIDTH == 5) begin
+ wire f0, f1;
+ LUT4 #(.INIT(LUT[15: 0])) lut0 (.Z(f0),
+ .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+ LUT4 #(.INIT(LUT[31:16])) lut1 (.Z(f1),
+ .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+ PFUMX mux5(.ALUT(f1), .BLUT(f0), .C0(A[4]), .Z(Y));
+ end else
+ if (WIDTH == 6) begin
+ wire f0, f1, f2, f3, g0, g1;
+ LUT4 #(.INIT(LUT[15: 0])) lut0 (.Z(f0),
+ .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+ LUT4 #(.INIT(LUT[31:16])) lut1 (.Z(f1),
+ .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+
+ LUT4 #(.INIT(LUT[47:32])) lut2 (.Z(f2),
+ .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+ LUT4 #(.INIT(LUT[63:48])) lut3 (.Z(f3),
+ .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+
+ PFUMX mux50(.ALUT(f1), .BLUT(f0), .C0(A[4]), .Z(g0));
+ PFUMX mux51(.ALUT(f3), .BLUT(f2), .C0(A[4]), .Z(g1));
+ L6MUX21 mux6 (.D0(g0), .D1(g1), .SD(A[5]), .Z(Y));
+ end else
+ if (WIDTH == 7) begin
+ wire f0, f1, f2, f3, f4, f5, f6, f7, g0, g1, g2, g3, h0, h1;
+ LUT4 #(.INIT(LUT[15: 0])) lut0 (.Z(f0),
+ .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+ LUT4 #(.INIT(LUT[31:16])) lut1 (.Z(f1),
+ .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+
+ LUT4 #(.INIT(LUT[47:32])) lut2 (.Z(f2),
+ .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+ LUT4 #(.INIT(LUT[63:48])) lut3 (.Z(f3),
+ .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+
+ LUT4 #(.INIT(LUT[79:64])) lut4 (.Z(f4),
+ .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+ LUT4 #(.INIT(LUT[95:80])) lut5 (.Z(f5),
+ .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+
+ LUT4 #(.INIT(LUT[111: 96])) lut6 (.Z(f6),
+ .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+ LUT4 #(.INIT(LUT[127:112])) lut7 (.Z(f7),
+ .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3]));
+
+ PFUMX mux50(.ALUT(f1), .BLUT(f0), .C0(A[4]), .Z(g0));
+ PFUMX mux51(.ALUT(f3), .BLUT(f2), .C0(A[4]), .Z(g1));
+ PFUMX mux52(.ALUT(f5), .BLUT(f4), .C0(A[4]), .Z(g2));
+ PFUMX mux53(.ALUT(f7), .BLUT(f6), .C0(A[4]), .Z(g3));
+ L6MUX21 mux60 (.D0(g0), .D1(g1), .SD(A[5]), .Z(h0));
+ L6MUX21 mux61 (.D0(g2), .D1(g3), .SD(A[5]), .Z(h1));
+ L6MUX21 mux7 (.D0(h0), .D1(h1), .SD(A[6]), .Z(Y));
+ `endif
+ end else begin
+ wire _TECHMAP_FAIL_ = 1;
+ end
+ endgenerate
+endmodule
+`endif
diff --git a/techlibs/ecp5/cells_sim.v b/techlibs/ecp5/cells_sim.v
new file mode 100644
index 000000000..1700694e8
--- /dev/null
+++ b/techlibs/ecp5/cells_sim.v
@@ -0,0 +1,448 @@
+// ---------------------------------------
+
+module LUT4(input A, B, C, D, output Z);
+ parameter [15:0] INIT = 16'h0000;
+ wire [7:0] s3 = D ? INIT[15:8] : INIT[7:0];
+ wire [3:0] s2 = C ? s3[ 7:4] : s3[3:0];
+ wire [1:0] s1 = B ? s2[ 3:2] : s2[1:0];
+ assign Z = A ? s1[1] : s1[0];
+endmodule
+
+// ---------------------------------------
+
+module L6MUX21 (input D0, D1, SD, output Z);
+ assign Z = SD ? D1 : D0;
+endmodule
+
+// ---------------------------------------
+
+module CCU2C(input CIN, A0, B0, C0, D0, A1, B1, C1, D1,
+ output S0, S1, COUT);
+
+ parameter [15:0] INIT0 = 16'h0000;
+ parameter [15:0] INIT1 = 16'h0000;
+ parameter INJECT1_0 = "YES";
+ parameter INJECT1_1 = "YES";
+
+ // First half
+ wire LUT4_0, LUT2_0;
+ LUT4 #(.INIT(INIT0)) lut4_0(.A(A0), .B(B0), .C(C0), .D(D0), .Z(LUT4_0));
+ LUT2 #(.INIT(INIT0[3:0])) lut2_0(.A(A0), .B(B0), .Z(LUT2_0));
+
+ wire gated_cin_0 = (INJECT1_0 == "YES") ? 1'b0 : CIN;
+ assign S0 = LUT4_0 ^ gated_cin_0;
+
+ wire gated_lut2_0 = (INJECT1_0 == "YES") ? 1'b0 : LUT2_0;
+ wire cout_0 = (~LUT4_0 & gated_lut2_0) | (LUT4_0 & CIN);
+
+ // Second half
+ wire LUT4_1, LUT2_1;
+ LUT4 #(.INIT(INIT1)) lut4_1(.A(A1), .B(B1), .C(C1), .D(D1), .Z(LUT4_1));
+ LUT2 #(.INIT(INIT1[3:0])) lut2_1(.A(A1), .B(B1), .Z(LUT2_1));
+
+ wire gated_cin_1 = (INJECT1_1 == "YES") ? 1'b0 : cout_0;
+ assign S1 = LUT4_1 ^ gated_cin_1;
+
+ wire gated_lut2_1 = (INJECT1_1 == "YES") ? 1'b0 : LUT2_1;
+ assign COUT = (~LUT4_1 & gated_lut2_1) | (LUT4_1 & cout_0);
+
+endmodule
+
+// ---------------------------------------
+
+module TRELLIS_RAM16X2 (
+ input DI0, DI1,
+ input WAD0, WAD1, WAD2, WAD3,
+ input WRE, WCK,
+ input RAD0, RAD1, RAD2, RAD3,
+ output DO0, DO1
+);
+ parameter WCKMUX = "WCK";
+ parameter WREMUX = "WRE";
+ parameter INITVAL_0 = 16'h0000;
+ parameter INITVAL_1 = 16'h0000;
+
+ reg [1:0] mem[15:0];
+
+ integer i;
+ initial begin
+ for (i = 0; i < 16; i = i + 1)
+ mem[i] <= {INITVAL_1[i], INITVAL_0[i]};
+ end
+
+ wire muxwck = (WCKMUX == "INV") ? ~WCK : WCK;
+
+ reg muxwre;
+ always @(*)
+ case (WREMUX)
+ "1": muxwre = 1'b1;
+ "0": muxwre = 1'b0;
+ "INV": muxwre = ~WRE;
+ default: muxwre = WRE;
+ endcase
+
+
+ always @(posedge muxwck)
+ if (muxwre)
+ mem[{WAD3, WAD2, WAD1, WAD0}] <= {DI1, DI0};
+
+ assign {DO1, DO0} = mem[{RAD3, RAD2, RAD1, RAD0}];
+endmodule
+
+// ---------------------------------------
+
+module PFUMX (input ALUT, BLUT, C0, output Z);
+ assign Z = C0 ? ALUT : BLUT;
+endmodule
+
+// ---------------------------------------
+
+module TRELLIS_DPR16X4 (
+ input [3:0] DI,
+ input [3:0] WAD,
+ input WRE, WCK,
+ input [3:0] RAD,
+ output [3:0] DO
+);
+ parameter WCKMUX = "WCK";
+ parameter WREMUX = "WRE";
+ parameter [63:0] INITVAL = 64'h0000000000000000;
+
+ reg [3:0] mem[15:0];
+
+ integer i;
+ initial begin
+ for (i = 0; i < 16; i = i + 1)
+ mem[i] <= {INITVAL[i+3], INITVAL[i+2], INITVAL[i+1], INITVAL[i]};
+ end
+
+ wire muxwck = (WCKMUX == "INV") ? ~WCK : WCK;
+
+ reg muxwre;
+ always @(*)
+ case (WREMUX)
+ "1": muxwre = 1'b1;
+ "0": muxwre = 1'b0;
+ "INV": muxwre = ~WRE;
+ default: muxwre = WRE;
+ endcase
+
+ always @(posedge muxwck)
+ if (muxwre)
+ mem[WAD] <= DI;
+
+ assign DO = mem[RAD];
+endmodule
+
+// ---------------------------------------
+
+module DPR16X4C (
+ input [3:0] DI,
+ input WCK, WRE,
+ input [3:0] RAD,
+ input [3:0] WAD,
+ output [3:0] DO
+);
+ // For legacy Lattice compatibility, INITIVAL is a hex
+ // string rather than a numeric parameter
+ parameter INITVAL = "0x0000000000000000";
+
+ function [63:0] convert_initval;
+ input [143:0] hex_initval;
+ reg done;
+ reg [63:0] temp;
+ reg [7:0] char;
+ integer i;
+ begin
+ done = 1'b0;
+ temp = 0;
+ for (i = 0; i < 16; i = i + 1) begin
+ if (!done) begin
+ char = hex_initval[8*i +: 8];
+ if (char == "x") begin
+ done = 1'b1;
+ end else begin
+ if (char >= "0" && char <= "9")
+ temp[4*i +: 4] = char - "0";
+ else if (char >= "A" && char <= "F")
+ temp[4*i +: 4] = 10 + char - "A";
+ else if (char >= "a" && char <= "f")
+ temp[4*i +: 4] = 10 + char - "a";
+ end
+ end
+ end
+ convert_initval = temp;
+ end
+ endfunction
+
+ localparam conv_initval = convert_initval(INITVAL);
+
+ reg [3:0] ram[0:15];
+ integer i;
+ initial begin
+ for (i = 0; i < 15; i = i + 1) begin
+ ram[i] <= conv_initval[4*i +: 4];
+ end
+ end
+
+ always @(posedge WCK)
+ if (WRE)
+ ram[WAD] <= DI;
+
+ assign DO = ram[RAD];
+
+endmodule
+
+// ---------------------------------------
+
+module LUT2(input A, B, output Z);
+ parameter [3:0] INIT = 4'h0;
+ wire [1:0] s1 = B ? INIT[ 3:2] : INIT[1:0];
+ assign Z = A ? s1[1] : s1[0];
+endmodule
+
+// ---------------------------------------
+
+module TRELLIS_FF(input CLK, LSR, CE, DI, output reg Q);
+ parameter GSR = "ENABLED";
+ parameter [127:0] CEMUX = "1";
+ parameter CLKMUX = "CLK";
+ parameter LSRMUX = "LSR";
+ parameter SRMODE = "LSR_OVER_CE";
+ parameter REGSET = "RESET";
+
+ reg muxce;
+ always @(*)
+ case (CEMUX)
+ "1": muxce = 1'b1;
+ "0": muxce = 1'b0;
+ "INV": muxce = ~CE;
+ default: muxce = CE;
+ endcase
+
+ wire muxlsr = (LSRMUX == "INV") ? ~LSR : LSR;
+ wire muxclk = (CLKMUX == "INV") ? ~CLK : CLK;
+
+ localparam srval = (REGSET == "SET") ? 1'b1 : 1'b0;
+
+ initial Q = srval;
+
+ generate
+ if (SRMODE == "ASYNC") begin
+ always @(posedge muxclk, posedge muxlsr)
+ if (muxlsr)
+ Q <= srval;
+ else if (muxce)
+ Q <= DI;
+ end else begin
+ always @(posedge muxclk)
+ if (muxlsr)
+ Q <= srval;
+ else if (muxce)
+ Q <= DI;
+ end
+ endgenerate
+endmodule
+
+// ---------------------------------------
+
+module OBZ(input I, T, output O);
+assign O = T ? 1'bz : I;
+endmodule
+
+// ---------------------------------------
+
+module IB(input I, output O);
+assign O = I;
+endmodule
+
+// ---------------------------------------
+
+module TRELLIS_IO(
+ inout B,
+ input I,
+ input T,
+ output O
+);
+ parameter DIR = "INPUT";
+
+ generate
+ if (DIR == "INPUT") begin
+ assign B = 1'bz;
+ assign O = B;
+ end else if (DIR == "OUTPUT") begin
+ assign B = T ? 1'bz : I;
+ assign O = 1'bx;
+ end else if (DIR == "INOUT") begin
+ assign B = T ? 1'bz : I;
+ assign O = B;
+ end else begin
+ ERROR_UNKNOWN_IO_MODE error();
+ end
+ endgenerate
+
+endmodule
+
+// ---------------------------------------
+
+module OB(input I, output O);
+assign O = I;
+endmodule
+
+// ---------------------------------------
+
+module BB(input I, T, output O, inout B);
+assign B = T ? 1'bz : I;
+assign O = B;
+endmodule
+
+// ---------------------------------------
+
+module INV(input A, output Z);
+ assign Z = !A;
+endmodule
+
+// ---------------------------------------
+
+module TRELLIS_SLICE(
+ input A0, B0, C0, D0,
+ input A1, B1, C1, D1,
+ input M0, M1,
+ input FCI, FXA, FXB,
+
+ input CLK, LSR, CE,
+ input DI0, DI1,
+
+ input WD0, WD1,
+ input WAD0, WAD1, WAD2, WAD3,
+ input WRE, WCK,
+
+ output F0, Q0,
+ output F1, Q1,
+ output FCO, OFX0, OFX1,
+
+ output WDO0, WDO1, WDO2, WDO3,
+ output WADO0, WADO1, WADO2, WADO3
+);
+
+ parameter MODE = "LOGIC";
+ parameter GSR = "ENABLED";
+ parameter SRMODE = "LSR_OVER_CE";
+ parameter [127:0] CEMUX = "1";
+ parameter CLKMUX = "CLK";
+ parameter LSRMUX = "LSR";
+ parameter LUT0_INITVAL = 16'h0000;
+ parameter LUT1_INITVAL = 16'h0000;
+ parameter REG0_SD = "0";
+ parameter REG1_SD = "0";
+ parameter REG0_REGSET = "RESET";
+ parameter REG1_REGSET = "RESET";
+ parameter [127:0] CCU2_INJECT1_0 = "NO";
+ parameter [127:0] CCU2_INJECT1_1 = "NO";
+ parameter WREMUX = "WRE";
+
+ function [15:0] permute_initval;
+ input [15:0] initval;
+ integer i;
+ begin
+ for (i = 0; i < 16; i = i + 1) begin
+ permute_initval[{i[0], i[2], i[1], i[3]}] = initval[i];
+ end
+ end
+ endfunction
+
+ generate
+ if (MODE == "LOGIC") begin
+ // LUTs
+ LUT4 #(
+ .INIT(LUT0_INITVAL)
+ ) lut4_0 (
+ .A(A0), .B(B0), .C(C0), .D(D0),
+ .Z(F0)
+ );
+ LUT4 #(
+ .INIT(LUT1_INITVAL)
+ ) lut4_1 (
+ .A(A1), .B(B1), .C(C1), .D(D1),
+ .Z(F1)
+ );
+ // LUT expansion muxes
+ PFUMX lut5_mux (.ALUT(F1), .BLUT(F0), .C0(M0), .Z(OFX0));
+ L6MUX21 lutx_mux (.D0(FXA), .D1(FXB), .SD(M1), .Z(OFX1));
+ end else if (MODE == "CCU2") begin
+ CCU2C #(
+ .INIT0(LUT0_INITVAL),
+ .INIT1(LUT1_INITVAL),
+ .INJECT1_0(CCU2_INJECT1_0),
+ .INJECT1_1(CCU2_INJECT1_1)
+ ) ccu2c_i (
+ .CIN(FCI),
+ .A0(A0), .B0(B0), .C0(C0), .D0(D0),
+ .A1(A1), .B1(B1), .C1(C1), .D1(D1),
+ .S0(F0), .S1(F1),
+ .COUT(FCO)
+ );
+ end else if (MODE == "RAMW") begin
+ assign WDO0 = C1;
+ assign WDO1 = A1;
+ assign WDO2 = D1;
+ assign WDO3 = B1;
+ assign WADO0 = D0;
+ assign WADO1 = B0;
+ assign WADO2 = C0;
+ assign WADO3 = A0;
+ end else if (MODE == "DPRAM") begin
+ TRELLIS_RAM16X2 #(
+ .INITVAL_0(permute_initval(LUT0_INITVAL)),
+ .INITVAL_1(permute_initval(LUT1_INITVAL)),
+ .WREMUX(WREMUX)
+ ) ram_i (
+ .DI0(WD0), .DI1(WD1),
+ .WAD0(WAD0), .WAD1(WAD1), .WAD2(WAD2), .WAD3(WAD3),
+ .WRE(WRE), .WCK(WCK),
+ .RAD0(D0), .RAD1(B0), .RAD2(C0), .RAD3(A0),
+ .DO0(F0), .DO1(F1)
+ );
+ // TODO: confirm RAD and INITVAL ordering
+ // DPRAM mode contract?
+ always @(*) begin
+ assert(A0==A1);
+ assert(B0==B1);
+ assert(C0==C1);
+ assert(D0==D1);
+ end
+ end else begin
+ ERROR_UNKNOWN_SLICE_MODE error();
+ end
+ endgenerate
+
+ // FF input selection muxes
+ wire muxdi0 = (REG0_SD == "1") ? DI0 : M0;
+ wire muxdi1 = (REG1_SD == "1") ? DI1 : M1;
+ // Flipflops
+ TRELLIS_FF #(
+ .GSR(GSR),
+ .CEMUX(CEMUX),
+ .CLKMUX(CLKMUX),
+ .LSRMUX(LSRMUX),
+ .SRMODE(SRMODE),
+ .REGSET(REG0_REGSET)
+ ) ff_0 (
+ .CLK(CLK), .LSR(LSR), .CE(CE),
+ .DI(muxdi0),
+ .Q(Q0)
+ );
+ TRELLIS_FF #(
+ .GSR(GSR),
+ .CEMUX(CEMUX),
+ .CLKMUX(CLKMUX),
+ .LSRMUX(LSRMUX),
+ .SRMODE(SRMODE),
+ .REGSET(REG1_REGSET)
+ ) ff_1 (
+ .CLK(CLK), .LSR(LSR), .CE(CE),
+ .DI(muxdi1),
+ .Q(Q1)
+ );
+endmodule
+
diff --git a/techlibs/ecp5/dram.txt b/techlibs/ecp5/dram.txt
new file mode 100644
index 000000000..b3252fa9a
--- /dev/null
+++ b/techlibs/ecp5/dram.txt
@@ -0,0 +1,16 @@
+bram $__TRELLIS_DPR16X4
+ init 1
+ abits 4
+ dbits 4
+ groups 2
+ ports 1 1
+ wrmode 0 1
+ enable 0 1
+ transp 0 0
+ clocks 0 1
+ clkpol 0 2
+endbram
+
+match $__TRELLIS_DPR16X4
+ make_outreg
+endmatch
diff --git a/techlibs/ecp5/drams_map.v b/techlibs/ecp5/drams_map.v
new file mode 100644
index 000000000..3b3de831f
--- /dev/null
+++ b/techlibs/ecp5/drams_map.v
@@ -0,0 +1,28 @@
+module \$__TRELLIS_DPR16X4 (CLK1, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
+ parameter [63:0] INIT = 64'bx;
+ parameter CLKPOL2 = 1;
+ input CLK1;
+
+ input [3:0] A1ADDR;
+ output [3:0] A1DATA;
+
+ input [3:0] B1ADDR;
+ input [3:0] B1DATA;
+ input B1EN;
+
+ localparam WCKMUX = CLKPOL2 ? "WCK" : "INV";
+
+ TRELLIS_DPR16X4 #(
+ .INITVAL(INIT),
+ .WCKMUX(WCKMUX),
+ .WREMUX("WRE")
+ ) _TECHMAP_REPLACE_ (
+ .RAD(A1ADDR),
+ .DO(A1DATA),
+
+ .WAD(B1ADDR),
+ .DI(B1DATA),
+ .WCK(CLK1),
+ .WRE(B1EN)
+ );
+endmodule
diff --git a/techlibs/ecp5/synth_ecp5.cc b/techlibs/ecp5/synth_ecp5.cc
new file mode 100644
index 000000000..76051d1a2
--- /dev/null
+++ b/techlibs/ecp5/synth_ecp5.cc
@@ -0,0 +1,331 @@
+/*
+ * yosys -- Yosys Open SYnthesis Suite
+ *
+ * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
+ * Copyright (C) 2018 Clifford Wolf <dave@ds0.me>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/register.h"
+#include "kernel/celltypes.h"
+#include "kernel/rtlil.h"
+#include "kernel/log.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct SynthEcp5Pass : public ScriptPass
+{
+ SynthEcp5Pass() : ScriptPass("synth_ecp5", "synthesis for ECP5 FPGAs") { }
+
+ virtual void help() YS_OVERRIDE
+ {
+ // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+ log("\n");
+ log(" synth_ecp5 [options]\n");
+ log("\n");
+ log("This command runs synthesis for ECP5 FPGAs.\n");
+ log("\n");
+ log(" -top <module>\n");
+ log(" use the specified module as top module\n");
+ log("\n");
+ log(" -blif <file>\n");
+ log(" write the design to the specified BLIF file. writing of an output file\n");
+ log(" is omitted if this parameter is not specified.\n");
+ log("\n");
+ log(" -edif <file>\n");
+ log(" write the design to the specified EDIF file. writing of an output file\n");
+ log(" is omitted if this parameter is not specified.\n");
+ log("\n");
+ log(" -json <file>\n");
+ log(" write the design to the specified JSON file. writing of an output file\n");
+ log(" is omitted if this parameter is not specified.\n");
+ log("\n");
+ log(" -run <from_label>:<to_label>\n");
+ log(" only run the commands between the labels (see below). an empty\n");
+ log(" from label is synonymous to 'begin', and empty to label is\n");
+ log(" synonymous to the end of the command list.\n");
+ log("\n");
+ log(" -noflatten\n");
+ log(" do not flatten design before synthesis\n");
+ log("\n");
+ log(" -retime\n");
+ log(" run 'abc' with -dff option\n");
+ log("\n");
+ log(" -noccu2\n");
+ log(" do not use CCU2 cells in output netlist\n");
+ log("\n");
+ log(" -nodffe\n");
+ log(" do not use flipflops with CE in output netlist\n");
+ log("\n");
+ log(" -nobram\n");
+ log(" do not use BRAM cells in output netlist\n");
+ log("\n");
+ log(" -nodram\n");
+ log(" do not use distributed RAM cells in output netlist\n");
+ log("\n");
+ log(" -nomux\n");
+ log(" do not use PFU muxes to implement LUTs larger than LUT4s\n");
+ log("\n");
+ log(" -abc2\n");
+ log(" run two passes of 'abc' for slightly improved logic density\n");
+ log("\n");
+ log(" -vpr\n");
+ log(" generate an output netlist (and BLIF file) suitable for VPR\n");
+ log(" (this feature is experimental and incomplete)\n");
+ log("\n");
+ log("\n");
+ log("The following commands are executed by this synthesis command:\n");
+ help_script();
+ log("\n");
+ }
+
+ string top_opt, blif_file, edif_file, json_file;
+ bool noccu2, nodffe, nobram, nodram, nomux, flatten, retime, abc2, vpr;
+
+ virtual void clear_flags() YS_OVERRIDE
+ {
+ top_opt = "-auto-top";
+ blif_file = "";
+ edif_file = "";
+ json_file = "";
+ noccu2 = false;
+ nodffe = false;
+ nobram = false;
+ nodram = false;
+ nomux = false;
+ flatten = true;
+ retime = false;
+ abc2 = false;
+ vpr = false;
+ }
+
+ virtual void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
+ {
+ string run_from, run_to;
+ clear_flags();
+
+ size_t argidx;
+ for (argidx = 1; argidx < args.size(); argidx++)
+ {
+ if (args[argidx] == "-top" && argidx+1 < args.size()) {
+ top_opt = "-top " + args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-blif" && argidx+1 < args.size()) {
+ blif_file = args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-edif" && argidx+1 < args.size()) {
+ edif_file = args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-json" && argidx+1 < args.size()) {
+ json_file = args[++argidx];
+ continue;
+ }
+ if (args[argidx] == "-run" && argidx+1 < args.size()) {
+ size_t pos = args[argidx+1].find(':');
+ if (pos == std::string::npos)
+ break;
+ run_from = args[++argidx].substr(0, pos);
+ run_to = args[argidx].substr(pos+1);
+ continue;
+ }
+ if (args[argidx] == "-flatten") {
+ flatten = true;
+ continue;
+ }
+ if (args[argidx] == "-noflatten") {
+ flatten = false;
+ continue;
+ }
+ if (args[argidx] == "-retime") {
+ retime = true;
+ continue;
+ }
+ if (args[argidx] == "-noccu2") {
+ noccu2 = true;
+ continue;
+ }
+ if (args[argidx] == "-nodffe") {
+ nodffe = true;
+ continue;
+ }
+ if (args[argidx] == "-nobram") {
+ nobram = true;
+ continue;
+ }
+ if (args[argidx] == "-nodram") {
+ nodram = true;
+ continue;
+ }
+ if (args[argidx] == "-nomux") {
+ nomux = true;
+ continue;
+ }
+ if (args[argidx] == "-abc2") {
+ abc2 = true;
+ continue;
+ }
+ if (args[argidx] == "-vpr") {
+ vpr = true;
+ continue;
+ }
+ break;
+ }
+ extra_args(args, argidx, design);
+
+ if (!design->full_selection())
+ log_cmd_error("This comannd only operates on fully selected designs!\n");
+
+ log_header(design, "Executing SYNTH_ECP5 pass.\n");
+ log_push();
+
+ run_script(design, run_from, run_to);
+
+ log_pop();
+ }
+
+ virtual void script() YS_OVERRIDE
+ {
+ if (check_label("begin"))
+ {
+ run("read_verilog -lib +/ecp5/cells_sim.v");
+ run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str()));
+ }
+
+ if (flatten && check_label("flatten", "(unless -noflatten)"))
+ {
+ run("proc");
+ run("flatten");
+ run("tribuf -logic");
+ run("deminout");
+ }
+
+ if (check_label("coarse"))
+ {
+ run("synth -run coarse");
+ }
+
+ if (!nobram && check_label("bram", "(skip if -nobram)"))
+ {
+ //TODO
+#if 0
+ run("memory_bram -rules +/ecp5/brams.txt");
+ run("techmap -map +/ecp5/brams_map.v");
+#endif
+ }
+
+ if (!nodram && check_label("dram", "(skip if -nodram)"))
+ {
+ run("memory_bram -rules +/ecp5/dram.txt");
+ run("techmap -map +/ecp5/drams_map.v");
+ }
+
+ if (check_label("fine"))
+ {
+ run("opt -fast -mux_undef -undriven -fine");
+ run("memory_map");
+ run("opt -undriven -fine");
+ if (noccu2)
+ run("techmap");
+ else
+ run("techmap -map +/techmap.v -map +/ecp5/arith_map.v");
+ if (retime || help_mode)
+ run("abc -dff", "(only if -retime)");
+ }
+
+ if (check_label("map_ffs"))
+ {
+ run("dffsr2dff");
+ run("dff2dffs");
+ run("opt_clean");
+ if (!nodffe)
+ run("dff2dffe -direct-match $_DFF_* -direct-match $__DFFS_*");
+ run("techmap -D NO_LUT -map +/ecp5/cells_map.v");
+ run("opt_expr -mux_undef");
+ run("simplemap");
+ // TODO
+#if 0
+ run("ecp5_ffinit");
+#endif
+ }
+
+ if (check_label("map_luts"))
+ {
+ if (abc2 || help_mode) {
+ run("abc", " (only if -abc2)");
+ }
+ //TODO
+#if 0
+ run("techmap -map +/ecp5/latches_map.v");
+#endif
+ if (nomux)
+ run("abc -lut 4");
+ else
+ run("abc -lut 4:7");
+ run("clean");
+ }
+
+ if (check_label("map_cells"))
+ {
+ if (vpr)
+ run("techmap -D NO_LUT -map +/ecp5/cells_map.v");
+ else
+ run("techmap -map +/ecp5/cells_map.v", "(with -D NO_LUT in vpr mode)");
+
+ run("clean");
+ }
+
+ if (check_label("check"))
+ {
+ run("hierarchy -check");
+ run("stat");
+ run("check -noinit");
+ }
+
+ if (check_label("blif"))
+ {
+ if (!blif_file.empty() || help_mode) {
+ if (vpr || help_mode) {
+ run(stringf("opt_clean -purge"),
+ " (vpr mode)");
+ run(stringf("write_blif -attr -cname -conn -param %s",
+ help_mode ? "<file-name>" : blif_file.c_str()),
+ " (vpr mode)");
+ }
+ if (!vpr)
+ run(stringf("write_blif -gates -attr -param %s",
+ help_mode ? "<file-name>" : blif_file.c_str()),
+ " (non-vpr mode)");
+ }
+ }
+
+ if (check_label("edif"))
+ {
+ if (!edif_file.empty() || help_mode)
+ run(stringf("write_edif %s", help_mode ? "<file-name>" : edif_file.c_str()));
+ }
+
+ if (check_label("json"))
+ {
+ if (!json_file.empty() || help_mode)
+ run(stringf("write_json %s", help_mode ? "<file-name>" : json_file.c_str()));
+ }
+ }
+} SynthEcp5Pass;
+
+PRIVATE_NAMESPACE_END
diff --git a/techlibs/ice40/cells_map.v b/techlibs/ice40/cells_map.v
index 6550b75cf..d0ddfd02e 100644
--- a/techlibs/ice40/cells_map.v
+++ b/techlibs/ice40/cells_map.v
@@ -27,7 +27,7 @@ module \$__DFFE_NP1 (input D, C, E, R, output Q); SB_DFFNES _TECHMAP_REPLACE_ (
module \$__DFFE_PP0 (input D, C, E, R, output Q); SB_DFFER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(R)); endmodule
module \$__DFFE_PP1 (input D, C, E, R, output Q); SB_DFFES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(R)); endmodule
-`ifndef NO_SB_LUT4
+`ifndef NO_LUT
module \$lut (A, Y);
parameter WIDTH = 0;
parameter LUT = 0;
diff --git a/techlibs/ice40/cells_sim.v b/techlibs/ice40/cells_sim.v
index 814895e70..9f73aeb07 100644
--- a/techlibs/ice40/cells_sim.v
+++ b/techlibs/ice40/cells_sim.v
@@ -1,6 +1,6 @@
-`define SB_DFF_REG reg Q = 0;
-// `define SB_DFF_REG reg Q;
+`define SB_DFF_REG reg Q = 0
+// `define SB_DFF_REG reg Q
// SiliconBlue IO Cells
@@ -132,21 +132,18 @@ endmodule
// Positive Edge SiliconBlue FF Cells
-module SB_DFF (output Q, input C, D);
- `SB_DFF_REG
+module SB_DFF (output `SB_DFF_REG, input C, D);
always @(posedge C)
Q <= D;
endmodule
-module SB_DFFE (output Q, input C, E, D);
- `SB_DFF_REG
+module SB_DFFE (output `SB_DFF_REG, input C, E, D);
always @(posedge C)
if (E)
Q <= D;
endmodule
-module SB_DFFSR (output Q, input C, R, D);
- `SB_DFF_REG
+module SB_DFFSR (output `SB_DFF_REG, input C, R, D);
always @(posedge C)
if (R)
Q <= 0;
@@ -154,8 +151,7 @@ module SB_DFFSR (output Q, input C, R, D);
Q <= D;
endmodule
-module SB_DFFR (output Q, input C, R, D);
- `SB_DFF_REG
+module SB_DFFR (output `SB_DFF_REG, input C, R, D);
always @(posedge C, posedge R)
if (R)
Q <= 0;
@@ -163,8 +159,7 @@ module SB_DFFR (output Q, input C, R, D);
Q <= D;
endmodule
-module SB_DFFSS (output Q, input C, S, D);
- `SB_DFF_REG
+module SB_DFFSS (output `SB_DFF_REG, input C, S, D);
always @(posedge C)
if (S)
Q <= 1;
@@ -172,8 +167,7 @@ module SB_DFFSS (output Q, input C, S, D);
Q <= D;
endmodule
-module SB_DFFS (output Q, input C, S, D);
- `SB_DFF_REG
+module SB_DFFS (output `SB_DFF_REG, input C, S, D);
always @(posedge C, posedge S)
if (S)
Q <= 1;
@@ -181,8 +175,7 @@ module SB_DFFS (output Q, input C, S, D);
Q <= D;
endmodule
-module SB_DFFESR (output Q, input C, E, R, D);
- `SB_DFF_REG
+module SB_DFFESR (output `SB_DFF_REG, input C, E, R, D);
always @(posedge C)
if (E) begin
if (R)
@@ -192,8 +185,7 @@ module SB_DFFESR (output Q, input C, E, R, D);
end
endmodule
-module SB_DFFER (output Q, input C, E, R, D);
- `SB_DFF_REG
+module SB_DFFER (output `SB_DFF_REG, input C, E, R, D);
always @(posedge C, posedge R)
if (R)
Q <= 0;
@@ -201,8 +193,7 @@ module SB_DFFER (output Q, input C, E, R, D);
Q <= D;
endmodule
-module SB_DFFESS (output Q, input C, E, S, D);
- `SB_DFF_REG
+module SB_DFFESS (output `SB_DFF_REG, input C, E, S, D);
always @(posedge C)
if (E) begin
if (S)
@@ -212,8 +203,7 @@ module SB_DFFESS (output Q, input C, E, S, D);
end
endmodule
-module SB_DFFES (output Q, input C, E, S, D);
- `SB_DFF_REG
+module SB_DFFES (output `SB_DFF_REG, input C, E, S, D);
always @(posedge C, posedge S)
if (S)
Q <= 1;
@@ -223,21 +213,18 @@ endmodule
// Negative Edge SiliconBlue FF Cells
-module SB_DFFN (output Q, input C, D);
- `SB_DFF_REG
+module SB_DFFN (output `SB_DFF_REG, input C, D);
always @(negedge C)
Q <= D;
endmodule
-module SB_DFFNE (output Q, input C, E, D);
- `SB_DFF_REG
+module SB_DFFNE (output `SB_DFF_REG, input C, E, D);
always @(negedge C)
if (E)
Q <= D;
endmodule
-module SB_DFFNSR (output Q, input C, R, D);
- `SB_DFF_REG
+module SB_DFFNSR (output `SB_DFF_REG, input C, R, D);
always @(negedge C)
if (R)
Q <= 0;
@@ -245,8 +232,7 @@ module SB_DFFNSR (output Q, input C, R, D);
Q <= D;
endmodule
-module SB_DFFNR (output Q, input C, R, D);
- `SB_DFF_REG
+module SB_DFFNR (output `SB_DFF_REG, input C, R, D);
always @(negedge C, posedge R)
if (R)
Q <= 0;
@@ -254,8 +240,7 @@ module SB_DFFNR (output Q, input C, R, D);
Q <= D;
endmodule
-module SB_DFFNSS (output Q, input C, S, D);
- `SB_DFF_REG
+module SB_DFFNSS (output `SB_DFF_REG, input C, S, D);
always @(negedge C)
if (S)
Q <= 1;
@@ -263,8 +248,7 @@ module SB_DFFNSS (output Q, input C, S, D);
Q <= D;
endmodule
-module SB_DFFNS (output Q, input C, S, D);
- `SB_DFF_REG
+module SB_DFFNS (output `SB_DFF_REG, input C, S, D);
always @(negedge C, posedge S)
if (S)
Q <= 1;
@@ -272,8 +256,7 @@ module SB_DFFNS (output Q, input C, S, D);
Q <= D;
endmodule
-module SB_DFFNESR (output Q, input C, E, R, D);
- `SB_DFF_REG
+module SB_DFFNESR (output `SB_DFF_REG, input C, E, R, D);
always @(negedge C)
if (E) begin
if (R)
@@ -283,8 +266,7 @@ module SB_DFFNESR (output Q, input C, E, R, D);
end
endmodule
-module SB_DFFNER (output Q, input C, E, R, D);
- `SB_DFF_REG
+module SB_DFFNER (output `SB_DFF_REG, input C, E, R, D);
always @(negedge C, posedge R)
if (R)
Q <= 0;
@@ -292,8 +274,7 @@ module SB_DFFNER (output Q, input C, E, R, D);
Q <= D;
endmodule
-module SB_DFFNESS (output Q, input C, E, S, D);
- `SB_DFF_REG
+module SB_DFFNESS (output `SB_DFF_REG, input C, E, S, D);
always @(negedge C)
if (E) begin
if (S)
@@ -303,8 +284,7 @@ module SB_DFFNESS (output Q, input C, E, S, D);
end
endmodule
-module SB_DFFNES (output Q, input C, E, S, D);
- `SB_DFF_REG
+module SB_DFFNES (output `SB_DFF_REG, input C, E, S, D);
always @(negedge C, posedge S)
if (S)
Q <= 1;
@@ -677,7 +657,12 @@ module ICESTORM_LC (
parameter [0:0] SET_NORESET = 0;
parameter [0:0] ASYNC_SR = 0;
- wire COUT = CARRY_ENABLE ? (I1 && I2) || ((I1 || I2) && CIN) : 1'bx;
+ parameter [0:0] CIN_CONST = 0;
+ parameter [0:0] CIN_SET = 0;
+
+ wire mux_cin = CIN_CONST ? CIN_SET : CIN;
+
+ assign COUT = CARRY_ENABLE ? (I1 && I2) || ((I1 || I2) && mux_cin) : 1'bx;
wire [7:0] lut_s3 = I3 ? LUT_INIT[15:8] : LUT_INIT[7:0];
wire [3:0] lut_s2 = I2 ? lut_s3[ 7:4] : lut_s3[3:0];
@@ -1246,4 +1231,3 @@ module SB_IO_OD (
endgenerate
`endif
endmodule
-
diff --git a/techlibs/ice40/ice40_opt.cc b/techlibs/ice40/ice40_opt.cc
index ae72f5d64..7af60f297 100644
--- a/techlibs/ice40/ice40_opt.cc
+++ b/techlibs/ice40/ice40_opt.cc
@@ -26,6 +26,13 @@
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
+static SigBit get_bit_or_zero(const SigSpec &sig)
+{
+ if (GetSize(sig) == 0)
+ return State::S0;
+ return sig[0];
+}
+
static void run_ice40_opts(Module *module, bool unlut_mode)
{
pool<SigBit> optimized_co;
@@ -45,7 +52,11 @@ static void run_ice40_opts(Module *module, bool unlut_mode)
SigSpec non_const_inputs, replacement_output;
int count_zeros = 0, count_ones = 0;
- SigBit inbit[3] = {cell->getPort("\\I0"), cell->getPort("\\I1"), cell->getPort("\\CI")};
+ SigBit inbit[3] = {
+ get_bit_or_zero(cell->getPort("\\I0")),
+ get_bit_or_zero(cell->getPort("\\I1")),
+ get_bit_or_zero(cell->getPort("\\CI"))
+ };
for (int i = 0; i < 3; i++)
if (inbit[i].wire == nullptr) {
if (inbit[i] == State::S1)
@@ -63,8 +74,8 @@ static void run_ice40_opts(Module *module, bool unlut_mode)
replacement_output = non_const_inputs;
if (GetSize(replacement_output)) {
- optimized_co.insert(sigmap(cell->getPort("\\CO")));
- module->connect(cell->getPort("\\CO"), replacement_output);
+ optimized_co.insert(sigmap(cell->getPort("\\CO")[0]));
+ module->connect(cell->getPort("\\CO")[0], replacement_output);
module->design->scratchpad_set_bool("opt.did_something", true);
log("Optimized away SB_CARRY cell %s.%s: CO=%s\n",
log_id(module), log_id(cell), log_signal(replacement_output));
@@ -78,10 +89,10 @@ static void run_ice40_opts(Module *module, bool unlut_mode)
{
SigSpec inbits;
- inbits.append(cell->getPort("\\I0"));
- inbits.append(cell->getPort("\\I1"));
- inbits.append(cell->getPort("\\I2"));
- inbits.append(cell->getPort("\\I3"));
+ inbits.append(get_bit_or_zero(cell->getPort("\\I0")));
+ inbits.append(get_bit_or_zero(cell->getPort("\\I1")));
+ inbits.append(get_bit_or_zero(cell->getPort("\\I2")));
+ inbits.append(get_bit_or_zero(cell->getPort("\\I3")));
sigmap.apply(inbits);
if (unlut_mode)
@@ -104,8 +115,13 @@ static void run_ice40_opts(Module *module, bool unlut_mode)
cell->setParam("\\LUT", cell->getParam("\\LUT_INIT"));
cell->unsetParam("\\LUT_INIT");
- cell->setPort("\\A", SigSpec({cell->getPort("\\I3"), cell->getPort("\\I2"), cell->getPort("\\I1"), cell->getPort("\\I0")}));
- cell->setPort("\\Y", cell->getPort("\\O"));
+ cell->setPort("\\A", SigSpec({
+ get_bit_or_zero(cell->getPort("\\I3")),
+ get_bit_or_zero(cell->getPort("\\I2")),
+ get_bit_or_zero(cell->getPort("\\I1")),
+ get_bit_or_zero(cell->getPort("\\I0"))
+ }));
+ cell->setPort("\\Y", cell->getPort("\\O")[0]);
cell->unsetPort("\\I0");
cell->unsetPort("\\I1");
cell->unsetPort("\\I2");
diff --git a/techlibs/ice40/synth_ice40.cc b/techlibs/ice40/synth_ice40.cc
index 0bb0fb139..abd890a56 100644
--- a/techlibs/ice40/synth_ice40.cc
+++ b/techlibs/ice40/synth_ice40.cc
@@ -45,7 +45,11 @@ struct SynthIce40Pass : public ScriptPass
log(" is omitted if this parameter is not specified.\n");
log("\n");
log(" -edif <file>\n");
- log(" write the design to the specified edif file. writing of an output file\n");
+ log(" write the design to the specified EDIF file. writing of an output file\n");
+ log(" is omitted if this parameter is not specified.\n");
+ log("\n");
+ log(" -json <file>\n");
+ log(" write the design to the specified JSON file. writing of an output file\n");
log(" is omitted if this parameter is not specified.\n");
log("\n");
log(" -run <from_label>:<to_label>\n");
@@ -62,6 +66,9 @@ struct SynthIce40Pass : public ScriptPass
log(" -nocarry\n");
log(" do not use SB_CARRY cells in output netlist\n");
log("\n");
+ log(" -nodffe\n");
+ log(" do not use SB_DFFE* cells in output netlist\n");
+ log("\n");
log(" -nobram\n");
log(" do not use SB_RAM40_4K* cells in output netlist\n");
log("\n");
@@ -78,15 +85,17 @@ struct SynthIce40Pass : public ScriptPass
log("\n");
}
- string top_opt, blif_file, edif_file;
- bool nocarry, nobram, flatten, retime, abc2, vpr;
+ string top_opt, blif_file, edif_file, json_file;
+ bool nocarry, nodffe, nobram, flatten, retime, abc2, vpr;
virtual void clear_flags() YS_OVERRIDE
{
top_opt = "-auto-top";
blif_file = "";
edif_file = "";
+ json_file = "";
nocarry = false;
+ nodffe = false;
nobram = false;
flatten = true;
retime = false;
@@ -114,6 +123,10 @@ struct SynthIce40Pass : public ScriptPass
edif_file = args[++argidx];
continue;
}
+ if (args[argidx] == "-json" && argidx+1 < args.size()) {
+ json_file = args[++argidx];
+ continue;
+ }
if (args[argidx] == "-run" && argidx+1 < args.size()) {
size_t pos = args[argidx+1].find(':');
if (pos == std::string::npos)
@@ -138,6 +151,10 @@ struct SynthIce40Pass : public ScriptPass
nocarry = true;
continue;
}
+ if (args[argidx] == "-nodffe") {
+ nodffe = true;
+ continue;
+ }
if (args[argidx] == "-nobram") {
nobram = true;
continue;
@@ -209,8 +226,9 @@ struct SynthIce40Pass : public ScriptPass
if (check_label("map_ffs"))
{
run("dffsr2dff");
- run("dff2dffe -direct-match $_DFF_*");
- run("techmap -D NO_SB_LUT4 -map +/ice40/cells_map.v");
+ if (!nodffe)
+ run("dff2dffe -direct-match $_DFF_*");
+ run("techmap -D NO_LUT -map +/ice40/cells_map.v");
run("opt_expr -mux_undef");
run("simplemap");
run("ice40_ffinit");
@@ -232,9 +250,9 @@ struct SynthIce40Pass : public ScriptPass
if (check_label("map_cells"))
{
if (vpr)
- run("techmap -D NO_SB_LUT4 -map +/ice40/cells_map.v");
+ run("techmap -D NO_LUT -map +/ice40/cells_map.v");
else
- run("techmap -map +/ice40/cells_map.v", "(with -D NO_SB_LUT4 in vpr mode)");
+ run("techmap -map +/ice40/cells_map.v", "(with -D NO_LUT in vpr mode)");
run("clean");
}
@@ -251,13 +269,15 @@ struct SynthIce40Pass : public ScriptPass
if (!blif_file.empty() || help_mode) {
if (vpr || help_mode) {
run(stringf("opt_clean -purge"),
- " (vpr mode)");
- run(stringf("write_blif %s", help_mode ? "<file-name>" : blif_file.c_str()),
- " (vpr mode)");
+ " (vpr mode)");
+ run(stringf("write_blif -attr -cname -conn -param %s",
+ help_mode ? "<file-name>" : blif_file.c_str()),
+ " (vpr mode)");
}
if (!vpr)
run(stringf("write_blif -gates -attr -param %s",
- help_mode ? "<file-name>" : blif_file.c_str()), "(non-vpr mode)");
+ help_mode ? "<file-name>" : blif_file.c_str()),
+ " (non-vpr mode)");
}
}
@@ -266,6 +286,12 @@ struct SynthIce40Pass : public ScriptPass
if (!edif_file.empty() || help_mode)
run(stringf("write_edif %s", help_mode ? "<file-name>" : edif_file.c_str()));
}
+
+ if (check_label("json"))
+ {
+ if (!json_file.empty() || help_mode)
+ run(stringf("write_json %s", help_mode ? "<file-name>" : json_file.c_str()));
+ }
}
} SynthIce40Pass;
diff --git a/techlibs/intel/cyclone10/cells_map.v b/techlibs/intel/cyclone10/cells_map.v
index 8ac5a55ec..c2f6f403c 100644
--- a/techlibs/intel/cyclone10/cells_map.v
+++ b/techlibs/intel/cyclone10/cells_map.v
@@ -16,33 +16,43 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
+// > c60k28 (Viacheslav, VT) [at] yandex [dot] com
+// > Intel FPGA technology mapping. User must first simulate the generated \
+// > netlist before going to test it on board.
+// > Changelog: 1) The missing power_up parameter in the techmap introduces a problem in Quartus mapper. Fixed.
+
// Normal mode DFF negedge clk, negedge reset
module \$_DFF_N_ (input D, C, output Q);
parameter WYSIWYG="TRUE";
- dffeas #(.is_wysiwyg(WYSIWYG)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(1'b1), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
+ parameter power_up=1'bx;
+ dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(1'b1), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
endmodule
// Normal mode DFF
module \$_DFF_P_ (input D, C, output Q);
parameter WYSIWYG="TRUE";
- dffeas #(.is_wysiwyg(WYSIWYG)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(1'b1), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
+ parameter power_up=1'bx;
+ dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(1'b1), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
endmodule
// Async Active Low Reset DFF
module \$_DFF_PN0_ (input D, C, R, output Q);
parameter WYSIWYG="TRUE";
- dffeas #(.is_wysiwyg(WYSIWYG)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
+ parameter power_up=1'bx;
+ dffeas #(.is_wysiwyg(WYSIWYG), .power_up("power_up")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
endmodule
// Async Active High Reset DFF
module \$_DFF_PP0_ (input D, C, R, output Q);
parameter WYSIWYG="TRUE";
+ parameter power_up=1'bx;
wire R_i = ~ R;
- dffeas #(.is_wysiwyg(WYSIWYG)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R_i), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
+ dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R_i), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
endmodule
module \$__DFFE_PP0 (input D, C, E, R, output Q);
parameter WYSIWYG="TRUE";
+ parameter power_up=1'bx;
wire E_i = ~ E;
- dffeas #(.is_wysiwyg(WYSIWYG)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(E_i), .sload(1'b0));
+ dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(E_i), .sload(1'b0));
endmodule
// Input buffer map
diff --git a/techlibs/intel/cycloneiv/cells_map.v b/techlibs/intel/cycloneiv/cells_map.v
index b991fbae7..191488430 100644
--- a/techlibs/intel/cycloneiv/cells_map.v
+++ b/techlibs/intel/cycloneiv/cells_map.v
@@ -16,33 +16,43 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
+// > c60k28 (Viacheslav, VT) [at] yandex [dot] com
+// > Intel FPGA technology mapping. User must first simulate the generated \
+// > netlist before going to test it on board.
+// > Changelog: 1) The missing power_up parameter in the techmap introduces a problem in Quartus mapper. Fixed.
+
// Normal mode DFF negedge clk, negedge reset
module \$_DFF_N_ (input D, C, output Q);
parameter WYSIWYG="TRUE";
- dffeas #(.is_wysiwyg(WYSIWYG)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(1'b1), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
+ parameter power_up=1'bx;
+ dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(1'b1), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
endmodule
// Normal mode DFF
module \$_DFF_P_ (input D, C, output Q);
parameter WYSIWYG="TRUE";
- dffeas #(.is_wysiwyg(WYSIWYG)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(1'b1), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
+ parameter power_up=1'bx;
+ dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(1'b1), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
endmodule
// Async Active Low Reset DFF
module \$_DFF_PN0_ (input D, C, R, output Q);
parameter WYSIWYG="TRUE";
- dffeas #(.is_wysiwyg(WYSIWYG)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
+ parameter power_up=1'bx;
+ dffeas #(.is_wysiwyg(WYSIWYG), .power_up("power_up")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
endmodule
// Async Active High Reset DFF
module \$_DFF_PP0_ (input D, C, R, output Q);
parameter WYSIWYG="TRUE";
+ parameter power_up=1'bx;
wire R_i = ~ R;
- dffeas #(.is_wysiwyg(WYSIWYG)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R_i), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
+ dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R_i), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
endmodule
module \$__DFFE_PP0 (input D, C, E, R, output Q);
parameter WYSIWYG="TRUE";
+ parameter power_up=1'bx;
wire E_i = ~ E;
- dffeas #(.is_wysiwyg(WYSIWYG)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(E_i), .sload(1'b0));
+ dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(E_i), .sload(1'b0));
endmodule
// Input buffer map
diff --git a/techlibs/intel/cycloneive/arith_map.v b/techlibs/intel/cycloneive/arith_map.v
index 634cec789..b3a11272b 100644
--- a/techlibs/intel/cycloneive/arith_map.v
+++ b/techlibs/intel/cycloneive/arith_map.v
@@ -16,6 +16,48 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
+/* TODO: Describe the following mode */
+module fa
+ (input a_c,
+ input b_c,
+ input cin_c,
+ output cout_t,
+ output sum_x);
+
+ wire a_c;
+ wire b_c;
+ wire cout_t;
+ wire cin_c;
+ wire sum_x;
+ wire VCC;
+
+ assign VCC = 1'b1;
+
+ cycloneiv_lcell_comb gen_sum_0 (.combout(sum_x),
+ .dataa(a_c),
+ .datab(b_c),
+ .datac(cin_c),
+ .datad(VCC));
+ defparam syn__05_.lut_mask = 16'b1001011010010110;
+ defparam syn__05_.sum_lutc_input = "datac";
+
+ cycloneiv_lcell_comb gen_cout_0 (.combout(cout_t),
+ .dataa(cin_c),
+ .datab(b_c),
+ .datac(a_c),
+ .datad(VCC));
+ defparam syn__06_.lut_mask = 16'b1110000011100000;
+ defparam syn__06_.sum_lutc_input = "datac";
+
+endmodule // fa
+
+module f_stage();
+
+endmodule // f_stage
+
+module f_end();
+
+endmodule // f_end
module _80_cycloneive_alu (A, B, CI, BI, X, Y, CO);
parameter A_SIGNED = 0;
@@ -41,8 +83,13 @@ module _80_cycloneive_alu (A, B, CI, BI, X, Y, CO);
wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf;
wire [Y_WIDTH:0] C = {CO, CI};
- cycloneive_lcell_comb #(.lut_mask(16'b0110_0110_1000_1000), .sum_lutc_input("cin")) carry_start (.cout(CO[0]), .dataa(BB[0]), .datab(1'b1), .datac(1'b1), .datad(1'b1));
- genvar i;
+ fa f0 (.a_c(AA[0]),
+ .b_c(BB[0]),
+ .cin_c(C[0]),
+ .cout_t(C0[1]),
+ .sum_x(Y[0]));
+
+ genvar i;
generate for (i = 1; i < Y_WIDTH; i = i + 1) begin:slice
cycloneive_lcell_comb #(.lut_mask(16'b0101_1010_0101_0000), .sum_lutc_input("cin")) arith_cell (.combout(Y[i]), .cout(CO[i]), .dataa(BB[i]), .datab(1'b1), .datac(1'b1), .datad(1'b1), .cin(C[i]));
end endgenerate
diff --git a/techlibs/intel/cycloneive/cells_map.v b/techlibs/intel/cycloneive/cells_map.v
index bf87f5525..abeb92eef 100644
--- a/techlibs/intel/cycloneive/cells_map.v
+++ b/techlibs/intel/cycloneive/cells_map.v
@@ -16,32 +16,43 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
+// > c60k28 (Viacheslav, VT) [at] yandex [dot] com
+// > Intel FPGA technology mapping. User must first simulate the generated \
+// > netlist before going to test it on board.
+// > Changelog: 1) The missing power_up parameter in the techmap introduces a problem in Quartus mapper. Fixed.
+
// Normal mode DFF negedge clk, negedge reset
module \$_DFF_N_ (input D, C, output Q);
parameter WYSIWYG="TRUE";
- dffeas #(.is_wysiwyg(WYSIWYG)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(1'b1), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
+ parameter power_up=1'bx;
+ dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(1'b1), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
endmodule
// Normal mode DFF
module \$_DFF_P_ (input D, C, output Q);
parameter WYSIWYG="TRUE";
- dffeas #(.is_wysiwyg(WYSIWYG)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(1'b1), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
+ parameter power_up=1'bx;
+ dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(1'b1), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
endmodule
+
// Async Active Low Reset DFF
module \$_DFF_PN0_ (input D, C, R, output Q);
parameter WYSIWYG="TRUE";
- dffeas #(.is_wysiwyg(WYSIWYG)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
+ parameter power_up=1'bx;
+ dffeas #(.is_wysiwyg(WYSIWYG), .power_up("power_up")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
endmodule
// Async Active High Reset DFF
module \$_DFF_PP0_ (input D, C, R, output Q);
parameter WYSIWYG="TRUE";
+ parameter power_up=1'bx;
wire R_i = ~ R;
- dffeas #(.is_wysiwyg(WYSIWYG)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R_i), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
+ dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R_i), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
endmodule
module \$__DFFE_PP0 (input D, C, E, R, output Q);
parameter WYSIWYG="TRUE";
+ parameter power_up=1'bx;
wire E_i = ~ E;
- dffeas #(.is_wysiwyg(WYSIWYG)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(E_i), .sload(1'b0));
+ dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(E_i), .sload(1'b0));
endmodule
// Input buffer map
diff --git a/techlibs/intel/cyclonev/cells_map.v b/techlibs/intel/cyclonev/cells_map.v
index 9fe8db2da..bd60d4e17 100644
--- a/techlibs/intel/cyclonev/cells_map.v
+++ b/techlibs/intel/cyclonev/cells_map.v
@@ -16,33 +16,45 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
+// > c60k28 (Viacheslav, VT) [at] yandex [dot] com
+// > Intel FPGA technology mapping. User must first simulate the generated \
+// > netlist before going to test it on board.
+// > Changelog: 1) The missing power_up parameter in the techmap introduces a problem in Quartus mapper. Fixed.
+// 2) Cyclone V 7-input LUT function was wrong implemented. Removed abc option to map this function \
+// and added the explanation in this file instead. Such function needs to be implemented.
+
// Normal mode DFF negedge clk, negedge reset
module \$_DFF_N_ (input D, C, output Q);
parameter WYSIWYG="TRUE";
- dffeas #(.is_wysiwyg(WYSIWYG)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(1'b1), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
+ parameter power_up=1'bx;
+ dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(1'b1), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
endmodule
// Normal mode DFF
module \$_DFF_P_ (input D, C, output Q);
parameter WYSIWYG="TRUE";
- dffeas #(.is_wysiwyg(WYSIWYG)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(1'b1), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
+ parameter power_up=1'bx;
+ dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(1'b1), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
endmodule
// Async Active Low Reset DFF
module \$_DFF_PN0_ (input D, C, R, output Q);
parameter WYSIWYG="TRUE";
- dffeas #(.is_wysiwyg(WYSIWYG)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
+ parameter power_up=1'bx;
+ dffeas #(.is_wysiwyg(WYSIWYG), .power_up("power_up")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
endmodule
// Async Active High Reset DFF
module \$_DFF_PP0_ (input D, C, R, output Q);
parameter WYSIWYG="TRUE";
+ parameter power_up=1'bx;
wire R_i = ~ R;
- dffeas #(.is_wysiwyg(WYSIWYG)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R_i), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
+ dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R_i), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
endmodule
module \$__DFFE_PP0 (input D, C, E, R, output Q);
parameter WYSIWYG="TRUE";
+ parameter power_up=1'bx;
wire E_i = ~ E;
- dffeas #(.is_wysiwyg(WYSIWYG)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(E_i), .sload(1'b0));
+ dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(E_i), .sload(1'b0));
endmodule
// Input buffer map
@@ -61,6 +73,10 @@ module \$lut (A, Y);
parameter LUT = 0;
input [WIDTH-1:0] A;
output Y;
+ wire VCC;
+ wire GND;
+ assign {VCC,GND} = {1'b1,1'b0};
+
generate
if (WIDTH == 1) begin
assign Y = ~A[0]; // Not need to spend 1 logic cell for such an easy function
@@ -72,11 +88,11 @@ module \$lut (A, Y);
(.combout(Y),
.dataa(A[0]),
.datab(A[1]),
- .datac(1'b1),
- .datad(1'b1),
- .datae(1'b1),
- .dataf(1'b1),
- .datag(1'b1));
+ .datac(VCC),
+ .datad(VCC),
+ .datae(VCC),
+ .dataf(VCC),
+ .datag(VCC));
end
else
if(WIDTH == 3) begin
@@ -86,10 +102,10 @@ module \$lut (A, Y);
.dataa(A[0]),
.datab(A[1]),
.datac(A[2]),
- .datad(1'b1),
- .datae(1'b1),
- .dataf(1'b1),
- .datag(1'b1));
+ .datad(VCC),
+ .datae(VCC),
+ .dataf(VCC),
+ .datag(VCC));
end
else
if(WIDTH == 4) begin
@@ -100,9 +116,9 @@ module \$lut (A, Y);
.datab(A[1]),
.datac(A[2]),
.datad(A[3]),
- .datae(1'b1),
- .dataf(1'b1),
- .datag(1'b1));
+ .datae(VCC),
+ .dataf(VCC),
+ .datag(VCC));
end
else
if(WIDTH == 5) begin
@@ -114,8 +130,8 @@ module \$lut (A, Y);
.datac(A[2]),
.datad(A[3]),
.datae(A[4]),
- .dataf(1'b1),
- .datag(1'b1));
+ .dataf(VCC),
+ .datag(VCC));
end
else
if(WIDTH == 6) begin
@@ -128,21 +144,16 @@ module \$lut (A, Y);
.datad(A[3]),
.datae(A[4]),
.dataf(A[5]),
- .datag(1'b1));
+ .datag(VCC));
end
- else
+ /*else
if(WIDTH == 7) begin
- cyclonev_lcell_comb #(.lut_mask(LUT), .shared_arith("off"), .extended_lut("off"))
- _TECHMAP_REPLACE_
- (.combout(Y),
- .dataa(A[0]),
- .datab(A[1]),
- .datac(A[2]),
- .datad(A[3]),
- .datae(A[4]),
- .dataf(A[5]),
- .datag(A[6]));
- end
+ TODO: There's not a just 7-input function on Cyclone V, see the following note:
+ **Extended LUT Mode**
+ Use extended LUT mode to implement a specific set of 7-input functions. The set must
+ be a 2-to-1 multiplexer fed by two arbitrary 5-input functions sharing four inputs.
+ [source](Device Interfaces and Integration Basics for Cyclone V Devices).
+ end*/
else
wire _TECHMAP_FAIL_ = 1;
endgenerate
diff --git a/techlibs/intel/max10/cells_map.v b/techlibs/intel/max10/cells_map.v
index 9229fae51..6d604e072 100644
--- a/techlibs/intel/max10/cells_map.v
+++ b/techlibs/intel/max10/cells_map.v
@@ -16,43 +16,53 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
+// > c60k28 (Viacheslav, VT) [at] yandex [dot] com
+// > Intel FPGA technology mapping. User must first simulate the generated \
+// > netlist before going to test it on board.
+// > Changelog: 1) The missing power_up parameter in the techmap introduces a problem in Quartus mapper. Fixed.
+
// Normal mode DFF negedge clk, negedge reset
module \$_DFF_N_ (input D, C, output Q);
parameter WYSIWYG="TRUE";
- dffeas #(.is_wysiwyg(WYSIWYG)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(1'b1), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
+ parameter power_up=1'bx;
+ dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(1'b1), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
endmodule
// Normal mode DFF
module \$_DFF_P_ (input D, C, output Q);
parameter WYSIWYG="TRUE";
- dffeas #(.is_wysiwyg(WYSIWYG)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(1'b1), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
+ parameter power_up=1'bx;
+ dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(1'b1), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
endmodule
// Async Active Low Reset DFF
module \$_DFF_PN0_ (input D, C, R, output Q);
parameter WYSIWYG="TRUE";
- dffeas #(.is_wysiwyg(WYSIWYG)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
+ parameter power_up=1'bx;
+ dffeas #(.is_wysiwyg(WYSIWYG), .power_up("power_up")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
endmodule
// Async Active High Reset DFF
module \$_DFF_PP0_ (input D, C, R, output Q);
parameter WYSIWYG="TRUE";
+ parameter power_up=1'bx;
wire R_i = ~ R;
- dffeas #(.is_wysiwyg(WYSIWYG)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R_i), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
+ dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R_i), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(1'b0), .sload(1'b0));
endmodule
module \$__DFFE_PP0 (input D, C, E, R, output Q);
parameter WYSIWYG="TRUE";
+ parameter power_up=1'bx;
wire E_i = ~ E;
- dffeas #(.is_wysiwyg(WYSIWYG)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(E_i), .sload(1'b0));
+ dffeas #(.is_wysiwyg(WYSIWYG), .power_up(power_up)) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .clrn(R), .prn(1'b1), .ena(1'b1), .asdata(1'b0), .aload(1'b0), .sclr(E_i), .sload(1'b0));
endmodule
// Input buffer map
module \$__inpad (input I, output O);
- fiftyfivenm_io_ibuf _TECHMAP_REPLACE_ (.o(O), .i(I), .ibar(1'b0));
+ fiftyfivenm_io_ibuf _TECHMAP_REPLACE_ (.o(O), .i(I), .ibar(1'b0));
endmodule
// Output buffer map
module \$__outpad (input I, output O);
- fiftyfivenm_io_obuf _TECHMAP_REPLACE_ (.o(O), .i(I), .oe(1'b1));
+ fiftyfivenm_io_obuf _TECHMAP_REPLACE_ (.o(O), .i(I), .oe(1'b1));
endmodule
// LUT Map
diff --git a/techlibs/intel/synth_intel.cc b/techlibs/intel/synth_intel.cc
index 9e632c861..c51949bd4 100644
--- a/techlibs/intel/synth_intel.cc
+++ b/techlibs/intel/synth_intel.cc
@@ -36,7 +36,7 @@ struct SynthIntelPass : public ScriptPass {
log("\n");
log("This command runs synthesis for Intel FPGAs.\n");
log("\n");
- log(" -family < max10 | a10gx | cyclonev | cycloneiv | cycloneive>\n");
+ log(" -family < max10 | a10gx | cyclone10 | cyclonev | cycloneiv | cycloneive>\n");
log(" generate the synthesis netlist for the specified family.\n");
log(" MAX10 is the default target if not family argument specified.\n");
log(" For Cyclone GX devices, use cycloneiv argument; For Cyclone E, use cycloneive.\n");
@@ -49,11 +49,19 @@ struct SynthIntelPass : public ScriptPass {
log(" write the design to the specified Verilog Quartus Mapping File. Writing of an\n");
log(" output file is omitted if this parameter is not specified.\n");
log("\n");
+ log(" -vpr <file>\n");
+ log(" write BLIF files for VPR flow experiments. The synthesized BLIF output file is not\n");
+ log(" compatible with the Quartus flow. Writing of an\n");
+ log(" output file is omitted if this parameter is not specified.\n");
+ log("\n");
log(" -run <from_label>:<to_label>\n");
log(" only run the commands between the labels (see below). an empty\n");
log(" from label is synonymous to 'begin', and empty to label is\n");
log(" synonymous to the end of the command list.\n");
log("\n");
+ log(" -noiopads\n");
+ log(" do not use altsyncram cells in output netlist\n");
+ log("\n");
log(" -nobram\n");
log(" do not use altsyncram cells in output netlist\n");
log("\n");
@@ -68,17 +76,19 @@ struct SynthIntelPass : public ScriptPass {
log("\n");
}
- string top_opt, family_opt, vout_file;
- bool retime, flatten, nobram;
+ string top_opt, family_opt, vout_file, blif_file;
+ bool retime, flatten, nobram, noiopads;
virtual void clear_flags() YS_OVERRIDE
{
top_opt = "-auto-top";
family_opt = "max10";
vout_file = "";
+ blif_file = "";
retime = false;
flatten = true;
nobram = false;
+ noiopads = false;
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
@@ -101,6 +111,10 @@ struct SynthIntelPass : public ScriptPass {
vout_file = args[++argidx];
continue;
}
+ if (args[argidx] == "-vpr" && argidx+1 < args.size()) {
+ blif_file = args[++argidx];
+ continue;
+ }
if (args[argidx] == "-run" && argidx+1 < args.size()) {
size_t pos = args[argidx+1].find(':');
if (pos == std::string::npos)
@@ -109,6 +123,10 @@ struct SynthIntelPass : public ScriptPass {
run_to = args[argidx].substr(pos+1);
continue;
}
+ if (args[argidx] == "-noiopads") {
+ noiopads = true;
+ continue;
+ }
if (args[argidx] == "-nobram") {
nobram = true;
continue;
@@ -198,7 +216,7 @@ struct SynthIntelPass : public ScriptPass {
if (check_label("map_luts"))
{
if(family_opt=="a10gx" || family_opt=="cyclonev")
- run("abc -luts 2:2,3,6:5,10" + string(retime ? " -dff" : ""));
+ run("abc -luts 2:2,3,6:5" + string(retime ? " -dff" : ""));
else
run("abc -lut 4" + string(retime ? " -dff" : ""));
run("clean");
@@ -206,7 +224,8 @@ struct SynthIntelPass : public ScriptPass {
if (check_label("map_cells"))
{
- run("iopadmap -bits -outpad $__outpad I:O -inpad $__inpad O:I");
+ if (!noiopads)
+ run("iopadmap -bits -outpad $__outpad I:O -inpad $__inpad O:I", "(unless -noiopads)");
if(family_opt=="max10")
run("techmap -map +/intel/max10/cells_map.v");
else if(family_opt=="a10gx")
@@ -236,7 +255,16 @@ struct SynthIntelPass : public ScriptPass {
run(stringf("write_verilog -attr2comment -defparam -nohex -decimal -renameprefix syn_ %s",
help_mode ? "<file-name>" : vout_file.c_str()));
}
- }
+
+ if (check_label("vpr"))
+ {
+ if (!blif_file.empty() || help_mode)
+ {
+ run(stringf("opt_clean -purge"));
+ run(stringf("write_blif %s", help_mode ? "<file-name>" : blif_file.c_str()));
+ }
+ }
+ }
} SynthIntelPass;
PRIVATE_NAMESPACE_END
diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v
index 8e5a83ce5..0771be0b9 100644
--- a/techlibs/xilinx/cells_map.v
+++ b/techlibs/xilinx/cells_map.v
@@ -15,6 +15,7 @@ module \$_DFF_NP1_ (input D, C, R, output Q); FDPE #(.INIT(|0), .IS_C_INVERTED(
module \$_DFF_PN1_ (input D, C, R, output Q); FDPE #(.INIT(|0), .IS_C_INVERTED(|0), .IS_D_INVERTED(|0), .IS_PRE_INVERTED(|1)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(R)); endmodule
module \$_DFF_PP1_ (input D, C, R, output Q); FDPE #(.INIT(|0), .IS_C_INVERTED(|0), .IS_D_INVERTED(|0), .IS_PRE_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(R)); endmodule
+`ifndef NO_LUT
module \$lut (A, Y);
parameter WIDTH = 0;
parameter LUT = 0;
@@ -82,3 +83,4 @@ module \$lut (A, Y);
end
endgenerate
endmodule
+`endif
diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc
index b60295ac0..1bc61daef 100644
--- a/techlibs/xilinx/synth_xilinx.cc
+++ b/techlibs/xilinx/synth_xilinx.cc
@@ -34,8 +34,10 @@ bool check_label(bool &active, std::string run_from, std::string run_to, std::st
return active;
}
-struct SynthXilinxPass : public Pass {
+struct SynthXilinxPass : public Pass
+{
SynthXilinxPass() : Pass("synth_xilinx", "synthesis for Xilinx FPGAs") { }
+
virtual void help()
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
@@ -53,6 +55,14 @@ struct SynthXilinxPass : public Pass {
log(" write the design to the specified edif file. writing of an output file\n");
log(" is omitted if this parameter is not specified.\n");
log("\n");
+ log(" -blif <file>\n");
+ log(" write the design to the specified BLIF file. writing of an output file\n");
+ log(" is omitted if this parameter is not specified.\n");
+ log("\n");
+ log(" -vpr\n");
+ log(" generate an output netlist (and BLIF file) suitable for VPR\n");
+ log(" (this feature is experimental and incomplete)\n");
+ log("\n");
log(" -run <from_label>:<to_label>\n");
log(" only run the commands between the labels (see below). an empty\n");
log(" from label is synonymous to 'begin', and empty to label is\n");
@@ -102,7 +112,7 @@ struct SynthXilinxPass : public Pass {
log(" clean\n");
log("\n");
log(" map_cells:\n");
- log(" techmap -map +/xilinx/cells_map.v\n");
+ log(" techmap -map +/xilinx/cells_map.v (with -D NO_LUT in vpr mode)\n");
log(" dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT\n");
log(" clean\n");
log("\n");
@@ -114,14 +124,19 @@ struct SynthXilinxPass : public Pass {
log(" edif: (only if -edif)\n");
log(" write_edif <file-name>\n");
log("\n");
+ log(" blif: (only if -blif)\n");
+ log(" write_blif <file-name>\n");
+ log("\n");
}
virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
{
std::string top_opt = "-auto-top";
std::string edif_file;
+ std::string blif_file;
std::string run_from, run_to;
bool flatten = false;
bool retime = false;
+ bool vpr = false;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
@@ -134,6 +149,10 @@ struct SynthXilinxPass : public Pass {
edif_file = args[++argidx];
continue;
}
+ if (args[argidx] == "-blif" && argidx+1 < args.size()) {
+ blif_file = args[++argidx];
+ continue;
+ }
if (args[argidx] == "-run" && argidx+1 < args.size()) {
size_t pos = args[argidx+1].find(':');
if (pos == std::string::npos)
@@ -150,6 +169,10 @@ struct SynthXilinxPass : public Pass {
retime = true;
continue;
}
+ if (args[argidx] == "-vpr") {
+ vpr = true;
+ continue;
+ }
break;
}
extra_args(args, argidx, design);
@@ -212,7 +235,10 @@ struct SynthXilinxPass : public Pass {
if (check_label(active, run_from, run_to, "map_cells"))
{
- Pass::call(design, "techmap -map +/xilinx/cells_map.v");
+ if (vpr)
+ Pass::call(design, "techmap -D NO_LUT -map +/xilinx/cells_map.v");
+ else
+ Pass::call(design, "techmap -map +/xilinx/cells_map.v");
Pass::call(design, "dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT");
Pass::call(design, "clean");
}
@@ -229,6 +255,11 @@ struct SynthXilinxPass : public Pass {
if (!edif_file.empty())
Pass::call(design, stringf("write_edif %s", edif_file.c_str()));
}
+ if (check_label(active, run_from, run_to, "blif"))
+ {
+ if (!blif_file.empty())
+ Pass::call(design, stringf("write_blif %s", edif_file.c_str()));
+ }
log_pop();
}
diff --git a/tests/simple/specify.v b/tests/simple/specify.v
new file mode 100644
index 000000000..f19418d90
--- /dev/null
+++ b/tests/simple/specify.v
@@ -0,0 +1,31 @@
+module test_specify;
+
+specparam a=1;
+
+specify
+endspecify
+
+specify
+(A => B) = ( 1 ) ;
+(A- => B) = ( 1,2 ) ;
+(A+ => B) = ( 1,2,3 ) ;
+(A => B) = (
+ 1.1, 2, 3,
+ 4, 5.5, 6.6
+) ;
+(A => B) = (
+ 1.1, 2, 3,
+ 4, 5.5, 6.6 ,
+ 7.7, 8.8, 9,
+ 10.1, 11, 12
+) ;
+specparam b=1;
+specparam [1:2] asasa=1;
+endspecify
+
+specify
+specparam c=1:2:3;
+endspecify
+
+endmodule
+
diff --git a/tests/tools/autotest.sh b/tests/tools/autotest.sh
index d0b0a89d7..d6216244f 100755
--- a/tests/tools/autotest.sh
+++ b/tests/tools/autotest.sh
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
libs=""
genvcd=false
@@ -100,7 +100,7 @@ do
echo -n "Test: $bn "
fi
- rm -f ${bn}.{err,log,sikp}
+ rm -f ${bn}.{err,log,skip}
mkdir -p ${bn}.out
rm -rf ${bn}.out/*