Update yosys to latest version + add simulation in fpga_flow

This commit is contained in:
AurelienUoU 2019-05-23 17:55:49 -06:00
parent 555570c15e
commit 1018134726
265 changed files with 17403 additions and 1931 deletions

View File

@ -17,11 +17,11 @@ cd ${pwd_path}/scripts
# SRAM FPGA
# TT case
perl fpga_flow.pl -conf ${config_file} -benchmark ${bench_txt} -rpt ${rpt_file} -N 10 -K 6 -ace_d 0.5 -power -remove_designs -multi_thread 1 -vpr_fpga_x2p_rename_illegal_port -vpr_fpga_verilog -vpr_fpga_verilog_dir $verilog_path -vpr_fpga_bitstream_generator -vpr_fpga_verilog_print_autocheck_top_testbench -vpr_fpga_verilog_include_timing -vpr_fpga_verilog_include_signal_init -vpr_fpga_verilog_formal_verification_top_netlist -fix_route_chan_width-vpr_fpga_verilog_include_icarus_simulator
perl fpga_flow.pl -conf ${config_file} -benchmark ${bench_txt} -rpt ${rpt_file} -N 10 -K 6 -ace_d 0.5 -power -remove_designs -multi_thread 1 -vpr_fpga_x2p_rename_illegal_port -vpr_fpga_verilog -vpr_fpga_verilog_dir $verilog_path -vpr_fpga_bitstream_generator -vpr_fpga_verilog_print_autocheck_top_testbench -vpr_fpga_verilog_include_timing -vpr_fpga_verilog_include_signal_init -vpr_fpga_verilog_formal_verification_top_netlist -fix_route_chan_width-vpr_fpga_verilog_include_icarus_simulator -end_flow_with_test
rm -rf ${pwd_path}/results
rm -rf $verilog_path
cd ${pwd_path}
echo "Netlists successfully generated"
echo "Netlists successfully generated and simulated"
exit 0

79
fpga_flow/scripts/fpga_flow.pl Executable file → Normal file
View File

@ -90,8 +90,6 @@ my @sctgy;
"vpr_power_tags"
);
my $clock_name = "avoid_clk_option";
# ----------Subrountines------------#
# Print TABs and strings
sub tab_print($ $ $)
@ -352,11 +350,13 @@ sub opts_read()
&read_opt_into_hash("vpr_fpga_spice_leakage_only","off","off");
&read_opt_into_hash("vpr_fpga_spice_parasitic_net_estimation_off","off","off");
&read_opt_into_hash("vpr_fpga_spice_testbench_load_extraction_off","off","off");
# FPGA-Verilog options
# Read Opt into Hash(opt_ptr) : "opt_name","with_val","mandatory"
&read_opt_into_hash("vpr_fpga_verilog","off","off");
&read_opt_into_hash("vpr_fpga_verilog_print_top_tb","off","off");
&read_opt_into_hash("vpr_fpga_verilog_print_input_blif_tb","off","off");
&read_opt_into_hash("vpr_fpga_bitstream_generator","off","off");
# AA add for update
&read_opt_into_hash("vpr_fpga_verilog_print_autocheck_top_testbench","off","off");
&read_opt_into_hash("vpr_fpga_verilog_dir","on","off");
&read_opt_into_hash("vpr_fpga_verilog_print_modelsim_autodeck","on","off");
@ -370,6 +370,9 @@ sub opts_read()
&read_opt_into_hash("vpr_fpga_verilog_print_sdc_analysis","off","off");
&read_opt_into_hash("vpr_fpga_verilog_print_user_defined_template","off","off");
# Regression test option
&read_opt_into_hash("end_flow_with_test","off","off");
&print_opts();
return 1;
@ -685,7 +688,8 @@ sub run_yosys_fpgamap($ $ $ $) {
close($YOSYS_CMD_FH);
#
# Create a local copy for the commands
system("./$yosys_name -s $cmd_log > $log");
system("./$yosys_name $cmd_log > $log");
if (!(-e $blif_out)) {
die "ERROR: Fail Yosys for benchmark $bm.\n";
@ -1221,7 +1225,7 @@ sub run_ace($ $ $ $) {
print "Entering $ace_dir\n";
chdir $ace_dir;
system("./$ace_name -b $mpack_vpr_blif -o $act_file -n $ace_new_blif -c $clock_name $ace_customized_opts >> $log");
system("./$ace_name -b $mpack_vpr_blif -o $act_file -n $ace_new_blif -c clk $ace_customized_opts >> $log");
if (!(-e $ace_new_blif)) {
die "ERROR: Fail ACE for benchmark $mpack_vpr_blif.\n";
@ -1232,6 +1236,65 @@ sub run_ace($ $ $ $) {
chdir $cwd;
}
# Run Icarus Verilog Simulation
sub run_icarus_verilog($ $ $ $ $)
{
my ($log_file, $compiled_file, $tb_top, $netlists_path, $include_netlists) = @_;
# Compile and launch simulation
system("iverilog -o $compiled_file $netlists_path$include_netlists -s $tb_top");
system("vvp $compiled_file >> $log_file"); # no -j option but could be added to speed-up the process
# Checking simulation results
open(F, $log_file);
my @lines=<F>;
close F;
my $keyword = "Succeed";
my $results = grep($keyword, @lines);
if($results >= 1){
print "\nVerification succeed!\n\n";
} else {
my $keyword = "Failed";
my $results = grep($keyword, @lines);
if($results >= 1){
print "\nVerification failed\n\n";
} else {
die "\nERROR: Simulation didn't start\n\n";
}
}
return;
}
# Run netlists verification using Icarus Simulator
sub run_netlists_verification($)
{
my ($benchmark) = @_;
my $log_file = "$benchmark"."_sim.log";
my $compiled_file = "compiled_"."$benchmark";
my $include_netlists = "$benchmark"."_include_netlists.v";
my $tb_top_formal = "$benchmark"."_top_formal_verification_random_tb";
my $tb_top_autochecked = "$benchmark"."_autocheck_top_tb";
my $netlists_path = "$opt_ptr->{vpr_fpga_verilog_dir_val}"."/SRC/";
system("rm -f $log_file");
system("rm -f $compiled_file");
if("on" eq $opt_ptr->{vpr_fpga_verilog_include_icarus_simulator}){
if("on" eq $opt_ptr->{vpr_fpga_verilog_print_autocheck_top_testbench}){
if("on" eq $opt_ptr->{vpr_fpga_verilog_formal_verification_top_netlist}){ # Preprogramed FPGA netlist chosen if available to speed-up the process
&run_icarus_verilog($log_file, $compiled_file, $tb_top_formal, $netlists_path, $include_netlists);
} else {
&run_icarus_verilog($log_file, $compiled_file, $tb_top_autochecked, $netlists_path, $include_netlists);
}
} else {
die "ERROR: Cannot run netlist verification without \"-vpr_fpga_verilog_print_autocheck_top_testbench\" token.\n";
}
} else {
die "ERROR: Cannot run netlist verification without \"-vpr_fpga_verilog_include_icarus_simulator\" token.\n";
}
return;
}
sub run_std_vpr($ $ $ $ $ $ $ $ $)
{
my ($blif,$bm,$arch,$net,$place,$route,$fix_chan_width,$log,$act_file) = @_;
@ -1367,7 +1430,7 @@ sub run_std_vpr($ $ $ $ $ $ $ $ $)
if ("on" eq $opt_ptr->{vpr_max_router_iteration}) {
$other_opt .= "--max_router_iterations $opt_ptr->{vpr_max_router_iteration_val} ";
}
print "\n\n./$vpr_name $arch $blif --net_file $net --place_file $place --route_file $route --full_stats --nodisp $power_opts $packer_opts $chan_width_opt $vpr_spice_opts $other_opt > $log\n\n";
system("./$vpr_name $arch $blif --net_file $net --place_file $place --route_file $route --full_stats --nodisp $power_opts $packer_opts $chan_width_opt $vpr_spice_opts $other_opt > $log");
chdir $cwd;
@ -1813,6 +1876,10 @@ sub run_yosys_vpr_flow($ $ $ $ $)
&run_vpr_in_flow($tag, $benchmark, $benchmark_file, $corrected_ace_blif, $vpr_arch, $act_file, $vpr_net, $vpr_place, $vpr_route, $vpr_log, $vpr_reroute_log, $parse_results);
if("on" eq $opt_ptr->{end_flow_with_test}) {
&run_netlists_verification($benchmark);
}
return;
}

View File

@ -16,6 +16,7 @@ Yosys 0.8 .. Yosys 0.8-dev
- Added "gate2lut.v" techmap rule
- Added "rename -src"
- Added "equiv_opt" pass
- "synth_xilinx" to now infer hard shift registers, using new "shregmap -tech xilinx"
Yosys 0.7 .. Yosys 0.8

View File

@ -1,6 +1,6 @@
#CONFIG := clang
CONFIG := gcc
# CONFIG := clang
CONFIG := gcc
# CONFIG := gcc-4.8
# CONFIG := emcc
# CONFIG := mxe
@ -10,6 +10,7 @@
# features (the more the better)
ENABLE_TCL := 1
ENABLE_ABC := 1
ENABLE_GLOB := 1
ENABLE_PLUGINS := 1
ENABLE_READLINE := 1
ENABLE_EDITLINE := 0
@ -18,6 +19,15 @@ ENABLE_COVER := 1
ENABLE_LIBYOSYS := 0
ENABLE_PROTOBUF := 0
# python wrappers
ENABLE_PYOSYS := 0
PYTHON_VERSION_TESTCODE := "import sys;t='{v[0]}.{v[1]}'.format(v=list(sys.version_info[:2]));print(t)"
PYTHON_EXECUTABLE := $(shell if python3 -c ""; then echo "python3"; else echo "python"; fi)
PYTHON_VERSION := $(shell $(PYTHON_EXECUTABLE) -c ""$(PYTHON_VERSION_TESTCODE)"")
PYTHON_MAJOR_VERSION := $(shell echo $(PYTHON_VERSION) | cut -f1 -d.)
PYTHON_PREFIX := `$(PYTHON_EXECUTABLE)-config --prefix`
PYTHON_DESTDIR := $(PYTHON_PREFIX)/lib/python$(PYTHON_VERSION)/site-packages
# other configuration flags
ENABLE_GCOV := 0
ENABLE_GPROF := 0
@ -100,7 +110,7 @@ LDFLAGS += -rdynamic
LDLIBS += -lrt
endif
YOSYS_VER := 0.8+$(shell cd $(YOSYS_SRC) && test -e .git && { git log --author=clifford@clifford.at --oneline 4d4665b.. | wc -l; })
YOSYS_VER := 0.8+$(shell cd $(YOSYS_SRC) && test -e .git && { git log --author=clifford@clifford.at --oneline 4d4665b.. 2> /dev/null | wc -l; })
GIT_REV := $(shell cd $(YOSYS_SRC) && git rev-parse --short HEAD 2> /dev/null || echo UNKNOWN)
OBJS = kernel/version_$(GIT_REV).o
@ -110,7 +120,7 @@ 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 = default
ABCREV = 3709744
ABCPULL = 1
ABCURL ?= https://github.com/berkeley-abc/abc
ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1
@ -260,6 +270,34 @@ ifeq ($(ENABLE_LIBYOSYS),1)
TARGETS += libyosys.so
endif
ifeq ($(ENABLE_PYOSYS),1)
#Detect name of boost_python library. Some distros usbe boost_python-py<version>, other boost_python<version>, some only use the major version number, some a concatenation of major and minor version numbers
BOOST_PYTHON_LIB ?= $(shell \
if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null `$(PYTHON_EXECUTABLE)-config --libs` -lboost_python-py$(subst .,,$(PYTHON_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python-py$(subst .,,$(PYTHON_VERSION))"; else \
if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null `$(PYTHON_EXECUTABLE)-config --libs` -lboost_python-py$(subst .,,$(PYTHON_MAJOR_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python-py$(subst .,,$(PYTHON_MAJOR_VERSION))"; else \
if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null `$(PYTHON_EXECUTABLE)-config --libs` -lboost_python$(subst .,,$(PYTHON_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python$(subst .,,$(PYTHON_VERSION))"; else \
if echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null `$(PYTHON_EXECUTABLE)-config --libs` -lboost_python$(subst .,,$(PYTHON_MAJOR_VERSION)) - > /dev/null 2>&1; then echo "-lboost_python$(subst .,,$(PYTHON_MAJOR_VERSION))"; else \
echo ""; fi; fi; fi; fi;)
ifeq ($(BOOST_PYTHON_LIB),)
$(error BOOST_PYTHON_LIB could not be detected. Please define manualy)
endif
ifeq ($(PYTHON_MAJOR_VERSION),3)
LDLIBS += `$(PYTHON_EXECUTABLE)-config --libs` $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem
CXXFLAGS += `$(PYTHON_EXECUTABLE)-config --includes` -D WITH_PYTHON
else
LDLIBS += `$(PYTHON_EXECUTABLE)-config --libs` $(BOOST_PYTHON_LIB) -lboost_system -lboost_filesystem
CXXFLAGS += `$(PYTHON_EXECUTABLE)-config --includes` -D WITH_PYTHON
endif
PY_WRAPPER_FILE = kernel/python_wrappers
OBJS += $(PY_WRAPPER_FILE).o
PY_GEN_SCRIPT= py_wrap_generator
PY_WRAP_INCLUDES := $(shell python$(PYTHON_VERSION) -c "from misc import $(PY_GEN_SCRIPT); $(PY_GEN_SCRIPT).print_includes()")
endif
ifeq ($(ENABLE_READLINE),1)
CXXFLAGS += -DYOSYS_ENABLE_READLINE
ifeq ($(OS), FreeBSD)
@ -298,6 +336,10 @@ LDLIBS += -ldl
endif
endif
ifeq ($(ENABLE_GLOB),1)
CXXFLAGS += -DYOSYS_ENABLE_GLOB
endif
ifeq ($(ENABLE_TCL),1)
TCL_VERSION ?= tcl$(shell bash -c "tclsh <(echo 'puts [info tclversion]')")
ifeq ($(OS), FreeBSD)
@ -505,6 +547,14 @@ libyosys.so: $(filter-out kernel/driver.o,$(OBJS))
$(Q) mkdir -p $(dir $@)
$(P) $(CXX) -o $@ -c $(CPPFLAGS) $(CXXFLAGS) $<
%.pyh: %.h
$(Q) mkdir -p $(dir $@)
$(P) cat $< | grep -E -v "#[ ]*(include|error)" | $(LD) -x c++ -o $@ -E -P -
$(PY_WRAPPER_FILE).cc: misc/$(PY_GEN_SCRIPT).py $(PY_WRAP_INCLUDES)
$(Q) mkdir -p $(dir $@)
$(P) python$(PYTHON_VERSION) -c "from misc import $(PY_GEN_SCRIPT); $(PY_GEN_SCRIPT).gen_wrappers(\"$(PY_WRAPPER_FILE).cc\")"
%.o: %.cpp
$(Q) mkdir -p $(dir $@)
$(P) $(CXX) -o $@ -c $(CPPFLAGS) $(CXXFLAGS) $<
@ -570,7 +620,7 @@ test: $(TARGETS) $(EXTRA_TARGETS)
+cd tests/simple && bash run-test.sh $(SEEDOPT)
+cd tests/hana && bash run-test.sh $(SEEDOPT)
+cd tests/asicworld && bash run-test.sh $(SEEDOPT)
+cd tests/realmath && bash run-test.sh $(SEEDOPT)
# +cd tests/realmath && bash run-test.sh $(SEEDOPT)
+cd tests/share && bash run-test.sh $(SEEDOPT)
+cd tests/fsm && bash run-test.sh $(SEEDOPT)
+cd tests/techmap && bash run-test.sh
@ -580,6 +630,7 @@ test: $(TARGETS) $(EXTRA_TARGETS)
+cd tests/sat && bash run-test.sh
+cd tests/svinterfaces && bash run-test.sh $(SEEDOPT)
+cd tests/opt && bash run-test.sh
+cd tests/aiger && bash run-test.sh
@echo ""
@echo " Passed \"make test\"."
@echo ""
@ -629,9 +680,14 @@ endif
$(INSTALL_SUDO) mkdir -p $(DESTDIR)$(DATDIR)
$(INSTALL_SUDO) cp -r share/. $(DESTDIR)$(DATDIR)/.
ifeq ($(ENABLE_LIBYOSYS),1)
$(INSTALL_SUDO) cp libyosys.so $(DESTDIR)$(LIBDIR)
$(INSTALL_SUDO) mkdir -p $(DESTDIR)$(LIBDIR)
$(INSTALL_SUDO) cp libyosys.so $(DESTDIR)$(LIBDIR)/
$(INSTALL_SUDO) $(STRIP) -S $(DESTDIR)$(LIBDIR)/libyosys.so
$(INSTALL_SUDO) ldconfig
ifeq ($(ENABLE_PYOSYS),1)
$(INSTALL_SUDO) mkdir -p $(PYTHON_DESTDIR)/pyosys
$(INSTALL_SUDO) cp libyosys.so $(PYTHON_DESTDIR)/pyosys/
$(INSTALL_SUDO) cp misc/__init__.py $(PYTHON_DESTDIR)/pyosys/
endif
endif
uninstall:
@ -639,6 +695,11 @@ uninstall:
$(INSTALL_SUDO) rm -rvf $(DESTDIR)$(DATDIR)
ifeq ($(ENABLE_LIBYOSYS),1)
$(INSTALL_SUDO) rm -vf $(DESTDIR)$(LIBDIR)/libyosys.so
ifeq ($(ENABLE_PYOSYS),1)
$(INSTALL_SUDO) rm -vf $(PYTHON_DESTDIR)/pyosys/libyosys.so
$(INSTALL_SUDO) rm -vf $(PYTHON_DESTDIR)/pyosys/__init__.py
$(INSTALL_SUDO) rmdir $(PYTHON_DESTDIR)/pyosys
endif
endif
update-manual: $(TARGETS) $(EXTRA_TARGETS)
@ -651,8 +712,9 @@ manual: $(TARGETS) $(EXTRA_TARGETS)
clean:
rm -rf share
rm -rf kernel/*.pyh
if test -d manual; then cd manual && sh clean.sh; fi
rm -f $(OBJS) $(GENFILES) $(TARGETS) $(EXTRA_TARGETS) $(EXTRA_OBJS)
rm -f $(OBJS) $(GENFILES) $(TARGETS) $(EXTRA_TARGETS) $(EXTRA_OBJS) $(PY_WRAP_INCLUDES) $(PY_WRAPPER_FILE).cc
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

View File

@ -34,11 +34,24 @@ compatible license that is similar in terms to the MIT license
or the 2-clause BSD license).
Web Site
========
Web Site and Other Resources
============================
More information and documentation can be found on the Yosys web site:
http://www.clifford.at/yosys/
- http://www.clifford.at/yosys/
The "Documentation" page on the web site contains links to more resources,
including a manual that even describes some of the Yosys internals:
- http://www.clifford.at/yosys/documentation.html
The file `CodingReadme` in this directory contains additional information
for people interested in using the Yosys C++ APIs.
Users interested in formal verification might want to use the formal verification
front-end for Yosys, SymbiYosys:
- https://symbiyosys.readthedocs.io/en/latest/
- https://github.com/YosysHQ/SymbiYosys
Setup
======
@ -53,25 +66,26 @@ prerequisites for building yosys:
$ sudo apt-get install build-essential clang bison flex \
libreadline-dev gawk tcl-dev libffi-dev git \
graphviz xdot pkg-config python3
graphviz xdot pkg-config python3 libboost-system-dev \
libboost-python-dev libboost-filesystem-dev
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 graphviz pkgconfig python36
git graphviz pkgconfig python36 boost
On FreeBSD use the following command to install all prerequisites:
# pkg install bison flex readline gawk libffi\
git graphviz pkgconfig python3 python36 tcl-wrapper
git graphviz pkgconfig python3 python36 tcl-wrapper boost-libs
On FreeBSD system use gmake instead of make. To run tests use:
% MAKE=gmake CC=cc gmake test
For Cygwin use the following command to install all prerequisites, or select these additional packages:
setup-x86_64.exe -q --packages=bison,flex,gcc-core,gcc-g++,git,libffi-devel,libreadline-devel,make,pkg-config,python3,tcl-devel
setup-x86_64.exe -q --packages=bison,flex,gcc-core,gcc-g++,git,libffi-devel,libreadline-devel,make,pkg-config,python3,tcl-devel,boost-build
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
@ -92,12 +106,15 @@ Makefile.
To build Yosys simply type 'make' in this directory.
$ make
$ make test
$ sudo make install
Note that this also downloads, builds and installs ABC (using yosys-abc
as executable name).
Tests are located in the tests subdirectory and can be executed using the test target. Note that you need gawk as well as a recent version of iverilog (i.e. build from git). Then, execute tests via:
$ make test
Getting Started
===============
@ -242,11 +259,7 @@ for them:
- The ``tri``, ``triand``, ``trior``, ``wand`` and ``wor`` net types
- The ``config`` keyword and library map files
- The ``disable``, ``primitive`` and ``specify`` statements
- Latched logic (is synthesized as logic with feedback loops)
- The ``config`` and ``disable`` keywords and library map files
Verilog Attributes and non-standard features
@ -294,7 +307,25 @@ Verilog Attributes and non-standard features
that have the same ports as the real thing but do not contain information
on the internal configuration. This modules are only used by the synthesis
passes to identify input and output ports of cells. The Verilog backend
also does not output blackbox modules on default.
also does not output blackbox modules on default. ``read_verilog``, unless
called with ``-noblackbox`` will automatically set the blackbox attribute
on any empty module it reads.
- The ``noblackbox`` attribute set on an empty module prevents ``read_verilog``
from automatically setting the blackbox attribute on the module.
- The ``whitebox`` attribute on modules triggers the same behavior as
``blackbox``, but is for whitebox modules, i.e. library modules that
contain a behavioral model of the cell type.
- The ``lib_whitebox`` attribute overwrites ``whitebox`` when ``read_verilog``
is run in `-lib` mode. Otherwise it's automatically removed.
- The ``dynports`` attribute is used by the Verilog front-end to mark modules
that have ports with a width that depends on a parameter.
- The ``hdlname`` attribute is used by some passes to document the original
(HDL) name of a module when renaming a module.
- The ``keep`` attribute on cells and wires is used to mark objects that should
never be removed by the optimizer. This is used for example for cells that
@ -335,7 +366,7 @@ Verilog Attributes and non-standard features
- When defining a macro with `define, all text between triple double quotes
is interpreted as macro body, even if it contains unescaped newlines. The
tipple double quotes are removed from the macro body. For example:
triple double quotes are removed from the macro body. For example:
`define MY_MACRO(a, b) """
assign a = 23;
@ -385,9 +416,15 @@ Verilog Attributes and non-standard features
expressions as <size>. If the expression is not a simple identifier, it
must be put in parentheses. Examples: ``WIDTH'd42``, ``(4+2)'b101010``
- The system tasks ``$finish`` and ``$display`` are supported in initial blocks
in an unconditional context (only if/case statements on parameters
and constant values). The intended use for this is synthesis-time DRC.
- The system tasks ``$finish``, ``$stop`` and ``$display`` are supported in
initial blocks in an unconditional context (only if/case statements on
expressions over parameters and constant values are allowed). The intended
use for this is synthesis-time DRC.
- There is limited support for converting specify .. endspecify statements to
special ``$specify2``, ``$specify3``, and ``$specrule`` cells, for use in
blackboxes and whiteboxes. Use ``read_verilog -specify`` to enable this
functionality. (By default specify .. endspecify blocks are ignored.)
Non-standard or SystemVerilog features for formal verification
@ -422,7 +459,7 @@ Non-standard or SystemVerilog features for formal verification
supported in any clocked block.
- The syntax ``@($global_clock)`` can be used to create FFs that have no
explicit clock input ($ff cells). The same can be achieved by using
explicit clock input (``$ff`` cells). The same can be achieved by using
``@(posedge <netname>)`` or ``@(negedge <netname>)`` when ``<netname>``
is marked with the ``(* gclk *)`` Verilog attribute.
@ -435,7 +472,7 @@ from SystemVerilog:
- The ``assert`` statement from SystemVerilog is supported in its most basic
form. In module context: ``assert property (<expression>);`` and within an
always block: ``assert(<expression>);``. It is transformed to a $assert cell.
always block: ``assert(<expression>);``. It is transformed to an ``$assert`` cell.
- The ``assume``, ``restrict``, and ``cover`` statements from SystemVerilog are
also supported. The same limitations as with the ``assert`` statement apply.

View File

@ -140,7 +140,7 @@ struct BlifDumper
return "subckt";
if (!design->modules_.count(RTLIL::escape_id(cell_type)))
return "gate";
if (design->modules_.at(RTLIL::escape_id(cell_type))->get_bool_attribute("\\blackbox"))
if (design->modules_.at(RTLIL::escape_id(cell_type))->get_blackbox_attribute())
return "gate";
return "subckt";
}
@ -196,7 +196,7 @@ struct BlifDumper
}
f << stringf("\n");
if (module->get_bool_attribute("\\blackbox")) {
if (module->get_blackbox_attribute()) {
f << stringf(".blackbox\n");
f << stringf(".end\n");
return;
@ -640,7 +640,7 @@ struct BlifBackend : public Backend {
for (auto module_it : design->modules_)
{
RTLIL::Module *module = module_it.second;
if (module->get_bool_attribute("\\blackbox") && !config.blackbox_mode)
if (module->get_blackbox_attribute() && !config.blackbox_mode)
continue;
if (module->processes.size() != 0)

View File

@ -340,7 +340,7 @@ struct BtorWorker
if (cell->type == "$lt") btor_op = "lt";
if (cell->type == "$le") btor_op = "lte";
if (cell->type.in("$eq", "$eqx")) btor_op = "eq";
if (cell->type.in("$ne", "$nex")) btor_op = "ne";
if (cell->type.in("$ne", "$nex")) btor_op = "neq";
if (cell->type == "$ge") btor_op = "gte";
if (cell->type == "$gt") btor_op = "gt";
log_assert(!btor_op.empty());
@ -615,6 +615,7 @@ struct BtorWorker
{
int abits = cell->getParam("\\ABITS").as_int();
int width = cell->getParam("\\WIDTH").as_int();
int nwords = cell->getParam("\\SIZE").as_int();
int rdports = cell->getParam("\\RD_PORTS").as_int();
int wrports = cell->getParam("\\WR_PORTS").as_int();
@ -641,6 +642,52 @@ struct BtorWorker
int data_sid = get_bv_sid(width);
int bool_sid = get_bv_sid(1);
int sid = get_mem_sid(abits, width);
Const initdata = cell->getParam("\\INIT");
initdata.exts(nwords*width);
int nid_init_val = -1;
if (!initdata.is_fully_undef())
{
bool constword = true;
Const firstword = initdata.extract(0, width);
for (int i = 1; i < nwords; i++) {
Const thisword = initdata.extract(i*width, width);
if (thisword != firstword) {
constword = false;
break;
}
}
if (constword)
{
if (verbose)
btorf("; initval = %s\n", log_signal(firstword));
nid_init_val = get_sig_nid(firstword);
}
else
{
int nid_init_val = next_nid++;
btorf("%d state %d\n", nid_init_val, sid);
for (int i = 0; i < nwords; i++) {
Const thisword = initdata.extract(i*width, width);
if (thisword.is_fully_undef())
continue;
Const thisaddr(i, abits);
int nid_thisword = get_sig_nid(thisword);
int nid_thisaddr = get_sig_nid(thisaddr);
int last_nid_init_val = nid_init_val;
nid_init_val = next_nid++;
if (verbose)
btorf("; initval[%d] = %s\n", i, log_signal(thisword));
btorf("%d write %d %d %d %d\n", nid_init_val, sid, last_nid_init_val, nid_thisaddr, nid_thisword);
}
}
}
int nid = next_nid++;
int nid_head = nid;
@ -649,6 +696,12 @@ struct BtorWorker
else
btorf("%d state %d %s\n", nid, sid, log_id(cell));
if (nid_init_val >= 0)
{
int nid_init = next_nid++;
btorf("%d init %d %d %d\n", nid_init, sid, nid, nid_init_val);
}
if (asyncwr)
{
for (int port = 0; port < wrports; port++)
@ -932,9 +985,8 @@ struct BtorWorker
btorf_push(stringf("output %s", log_id(wire)));
int sid = get_bv_sid(GetSize(wire));
int nid = get_sig_nid(wire);
btorf("%d output %d %d %s\n", next_nid++, sid, nid, log_id(wire));
btorf("%d output %d %s\n", next_nid++, nid, log_id(wire));
btorf_pop(stringf("output %s", log_id(wire)));
}

View File

@ -106,6 +106,10 @@ struct EdifBackend : public Backend {
log(" if the design contains constant nets. use \"hilomap\" to map to custom\n");
log(" constant drivers first)\n");
log("\n");
log(" -gndvccy\n");
log(" create \"GND\" and \"VCC\" cells with \"Y\" outputs. (the default is \"G\"\n");
log(" for \"GND\" and \"P\" for \"VCC\".)\n");
log("\n");
log(" -attrprop\n");
log(" create EDIF properties for cell attributes\n");
log("\n");
@ -126,7 +130,7 @@ struct EdifBackend : public Backend {
bool port_rename = false;
bool attr_properties = false;
std::map<RTLIL::IdString, std::map<RTLIL::IdString, int>> lib_cell_ports;
bool nogndvcc = false;
bool nogndvcc = false, gndvccy = false;
CellTypes ct(design);
EdifNames edif_names;
@ -141,6 +145,10 @@ struct EdifBackend : public Backend {
nogndvcc = true;
continue;
}
if (args[argidx] == "-gndvccy") {
gndvccy = true;
continue;
}
if (args[argidx] == "-attrprop") {
attr_properties = true;
continue;
@ -170,7 +178,7 @@ struct EdifBackend : public Backend {
for (auto module_it : design->modules_)
{
RTLIL::Module *module = module_it.second;
if (module->get_bool_attribute("\\blackbox"))
if (module->get_blackbox_attribute())
continue;
if (top_module_name.empty())
@ -184,7 +192,7 @@ struct EdifBackend : public Backend {
for (auto cell_it : module->cells_)
{
RTLIL::Cell *cell = cell_it.second;
if (!design->modules_.count(cell->type) || design->modules_.at(cell->type)->get_bool_attribute("\\blackbox")) {
if (!design->modules_.count(cell->type) || design->modules_.at(cell->type)->get_blackbox_attribute()) {
lib_cell_ports[cell->type];
for (auto p : cell->connections())
lib_cell_ports[cell->type][p.first] = GetSize(p.second);
@ -211,7 +219,7 @@ struct EdifBackend : public Backend {
*f << stringf(" (cellType GENERIC)\n");
*f << stringf(" (view VIEW_NETLIST\n");
*f << stringf(" (viewType NETLIST)\n");
*f << stringf(" (interface (port G (direction OUTPUT)))\n");
*f << stringf(" (interface (port %c (direction OUTPUT)))\n", gndvccy ? 'Y' : 'G');
*f << stringf(" )\n");
*f << stringf(" )\n");
@ -219,7 +227,7 @@ struct EdifBackend : public Backend {
*f << stringf(" (cellType GENERIC)\n");
*f << stringf(" (view VIEW_NETLIST\n");
*f << stringf(" (viewType NETLIST)\n");
*f << stringf(" (interface (port P (direction OUTPUT)))\n");
*f << stringf(" (interface (port %c (direction OUTPUT)))\n", gndvccy ? 'Y' : 'P');
*f << stringf(" )\n");
*f << stringf(" )\n");
}
@ -294,7 +302,7 @@ struct EdifBackend : public Backend {
*f << stringf(" (technology (numberDefinition))\n");
for (auto module : sorted_modules)
{
if (module->get_bool_attribute("\\blackbox"))
if (module->get_blackbox_attribute())
continue;
SigMap sigmap(module);
@ -420,9 +428,9 @@ struct EdifBackend : public Backend {
if (nogndvcc)
log_error("Design contains constant nodes (map with \"hilomap\" first).\n");
if (sig == RTLIL::State::S0)
*f << stringf(" (portRef G (instanceRef GND))\n");
*f << stringf(" (portRef %c (instanceRef GND))\n", gndvccy ? 'Y' : 'G');
if (sig == RTLIL::State::S1)
*f << stringf(" (portRef P (instanceRef VCC))\n");
*f << stringf(" (portRef %c (instanceRef VCC))\n", gndvccy ? 'Y' : 'P');
}
*f << stringf(" ))\n");
}

View File

@ -23,7 +23,11 @@
#include "kernel/celltypes.h"
#include "kernel/cellaigs.h"
#include "kernel/log.h"
#include <algorithm>
#include <string>
#include <regex>
#include <vector>
#include <cmath>
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
@ -37,6 +41,7 @@ static const FDirection FD_NODIRECTION = 0x0;
static const FDirection FD_IN = 0x1;
static const FDirection FD_OUT = 0x2;
static const FDirection FD_INOUT = 0x3;
static const int FIRRTL_MAX_DSH_WIDTH_ERROR = 20; // For historic reasons, this is actually one greater than the maximum allowed shift width
// Get a port direction with respect to a specific module.
FDirection getPortFDirection(IdString id, Module *module)
@ -101,6 +106,125 @@ struct FirrtlWorker
RTLIL::Design *design;
std::string indent;
// Define read/write ports and memories.
// We'll collect their definitions and emit the corresponding FIRRTL definitions at the appropriate point in module construction.
// For the moment, we don't handle $readmemh or $readmemb.
// These will be part of a subsequent PR.
struct read_port {
string name;
bool clk_enable;
bool clk_parity;
bool transparent;
RTLIL::SigSpec clk;
RTLIL::SigSpec ena;
RTLIL::SigSpec addr;
read_port(string name, bool clk_enable, bool clk_parity, bool transparent, RTLIL::SigSpec clk, RTLIL::SigSpec ena, RTLIL::SigSpec addr) : name(name), clk_enable(clk_enable), clk_parity(clk_parity), transparent(transparent), clk(clk), ena(ena), addr(addr) {
// Current (3/13/2019) conventions:
// generate a constant 0 for clock and a constant 1 for enable if they are undefined.
if (!clk.is_fully_def())
this->clk = SigSpec(RTLIL::Const(0, 1));
if (!ena.is_fully_def())
this->ena = SigSpec(RTLIL::Const(1, 1));
}
string gen_read(const char * indent) {
string addr_expr = make_expr(addr);
string ena_expr = make_expr(ena);
string clk_expr = make_expr(clk);
string addr_str = stringf("%s%s.addr <= %s\n", indent, name.c_str(), addr_expr.c_str());
string ena_str = stringf("%s%s.en <= %s\n", indent, name.c_str(), ena_expr.c_str());
string clk_str = stringf("%s%s.clk <= asClock(%s)\n", indent, name.c_str(), clk_expr.c_str());
return addr_str + ena_str + clk_str;
}
};
struct write_port : read_port {
RTLIL::SigSpec mask;
write_port(string name, bool clk_enable, bool clk_parity, bool transparent, RTLIL::SigSpec clk, RTLIL::SigSpec ena, RTLIL::SigSpec addr, RTLIL::SigSpec mask) : read_port(name, clk_enable, clk_parity, transparent, clk, ena, addr), mask(mask) {
if (!clk.is_fully_def())
this->clk = SigSpec(RTLIL::Const(0));
if (!ena.is_fully_def())
this->ena = SigSpec(RTLIL::Const(0));
if (!mask.is_fully_def())
this->ena = SigSpec(RTLIL::Const(1));
}
string gen_read(const char * /* indent */) {
log_error("gen_read called on write_port: %s\n", name.c_str());
return stringf("gen_read called on write_port: %s\n", name.c_str());
}
string gen_write(const char * indent) {
string addr_expr = make_expr(addr);
string ena_expr = make_expr(ena);
string clk_expr = make_expr(clk);
string mask_expr = make_expr(mask);
string mask_str = stringf("%s%s.mask <= %s\n", indent, name.c_str(), mask_expr.c_str());
string addr_str = stringf("%s%s.addr <= %s\n", indent, name.c_str(), addr_expr.c_str());
string ena_str = stringf("%s%s.en <= %s\n", indent, name.c_str(), ena_expr.c_str());
string clk_str = stringf("%s%s.clk <= asClock(%s)\n", indent, name.c_str(), clk_expr.c_str());
return addr_str + ena_str + clk_str + mask_str;
}
};
/* Memories defined within this module. */
struct memory {
Cell *pCell; // for error reporting
string name; // memory name
int abits; // number of address bits
int size; // size (in units) of the memory
int width; // size (in bits) of each element
int read_latency;
int write_latency;
vector<read_port> read_ports;
vector<write_port> write_ports;
std::string init_file;
std::string init_file_srcFileSpec;
string srcLine;
memory(Cell *pCell, string name, int abits, int size, int width) : pCell(pCell), name(name), abits(abits), size(size), width(width), read_latency(0), write_latency(1), init_file(""), init_file_srcFileSpec("") {
// Provide defaults for abits or size if one (but not the other) is specified.
if (this->abits == 0 && this->size != 0) {
this->abits = ceil_log2(this->size);
} else if (this->abits != 0 && this->size == 0) {
this->size = 1 << this->abits;
}
// Sanity-check this construction.
if (this->name == "") {
log_error("Nameless memory%s\n", this->atLine());
}
if (this->abits == 0 && this->size == 0) {
log_error("Memory %s has zero address bits and size%s\n", this->name.c_str(), this->atLine());
}
if (this->width == 0) {
log_error("Memory %s has zero width%s\n", this->name.c_str(), this->atLine());
}
}
// We need a default constructor for the dict insert.
memory() : pCell(0), read_latency(0), write_latency(1), init_file(""), init_file_srcFileSpec(""){}
const char *atLine() {
if (srcLine == "") {
if (pCell) {
auto p = pCell->attributes.find("\\src");
srcLine = " at " + p->second.decode_string();
}
}
return srcLine.c_str();
}
void add_memory_read_port(read_port &rp) {
read_ports.push_back(rp);
}
void add_memory_write_port(write_port &wp) {
write_ports.push_back(wp);
}
void add_memory_file(std::string init_file, std::string init_file_srcFileSpec) {
this->init_file = init_file;
this->init_file_srcFileSpec = init_file_srcFileSpec;
}
};
dict<string, memory> memories;
void register_memory(memory &m)
{
memories[m.name] = m;
}
void register_reverse_wire_map(string id, SigSpec sig)
{
for (int i = 0; i < GetSize(sig); i++)
@ -111,7 +235,7 @@ struct FirrtlWorker
{
}
string make_expr(const SigSpec &sig)
static string make_expr(const SigSpec &sig)
{
string expr;
@ -160,11 +284,9 @@ struct FirrtlWorker
std::string fid(RTLIL::IdString internal_id)
{
const char *str = internal_id.c_str();
return *str == '\\' ? str + 1 : str;
return make_id(internal_id);
}
std::string cellname(RTLIL::Cell *cell)
{
return fid(cell->name).c_str();
@ -173,6 +295,26 @@ struct FirrtlWorker
void process_instance(RTLIL::Cell *cell, vector<string> &wire_exprs)
{
std::string cell_type = fid(cell->type);
std::string instanceOf;
// If this is a parameterized module, its parent module is encoded in the cell type
if (cell->type.substr(0, 8) == "$paramod")
{
std::string::iterator it;
for (it = cell_type.begin(); it < cell_type.end(); it++)
{
switch (*it) {
case '\\': /* FALL_THROUGH */
case '=': /* FALL_THROUGH */
case '\'': /* FALL_THROUGH */
case '$': instanceOf.append("_"); break;
default: instanceOf.append(1, *it); break;
}
}
}
else
{
instanceOf = cell_type;
}
std::string cell_name = cellname(cell);
std::string cell_name_comment;
@ -182,41 +324,75 @@ struct FirrtlWorker
cell_name_comment = "";
// Find the module corresponding to this instance.
auto instModule = design->module(cell->type);
wire_exprs.push_back(stringf("%s" "inst %s%s of %s", indent.c_str(), cell_name.c_str(), cell_name_comment.c_str(), cell_type.c_str()));
// If there is no instance for this, just return.
if (instModule == NULL)
{
log_warning("No instance for %s.%s\n", cell_type.c_str(), cell_name.c_str());
return;
}
wire_exprs.push_back(stringf("%s" "inst %s%s of %s", indent.c_str(), cell_name.c_str(), cell_name_comment.c_str(), instanceOf.c_str()));
for (auto it = cell->connections().begin(); it != cell->connections().end(); ++it) {
if (it->second.size() > 0) {
const SigSpec &secondSig = it->second;
const std::string firstName = cell_name + "." + make_id(it->first);
const std::string secondName = make_expr(secondSig);
const std::string secondExpr = make_expr(secondSig);
// Find the direction for this port.
FDirection dir = getPortFDirection(it->first, instModule);
std::string source, sink;
std::string sourceExpr, sinkExpr;
const SigSpec *sinkSig = nullptr;
switch (dir) {
case FD_INOUT:
log_warning("Instance port connection %s.%s is INOUT; treating as OUT\n", log_id(cell_type), log_signal(it->second));
log_warning("Instance port connection %s.%s is INOUT; treating as OUT\n", cell_type.c_str(), log_signal(it->second));
/* FALLTHRU */
case FD_OUT:
source = firstName;
sink = secondName;
sourceExpr = firstName;
sinkExpr = secondExpr;
sinkSig = &secondSig;
break;
case FD_NODIRECTION:
log_warning("Instance port connection %s.%s is NODIRECTION; treating as IN\n", log_id(cell_type), log_signal(it->second));
/* FALL_THROUGH */
log_warning("Instance port connection %s.%s is NODIRECTION; treating as IN\n", cell_type.c_str(), log_signal(it->second));
/* FALLTHRU */
case FD_IN:
source = secondName;
sink = firstName;
sourceExpr = secondExpr;
sinkExpr = firstName;
break;
default:
log_error("Instance port %s.%s unrecognized connection direction 0x%x !\n", log_id(cell_type), log_signal(it->second), dir);
log_error("Instance port %s.%s unrecognized connection direction 0x%x !\n", cell_type.c_str(), log_signal(it->second), dir);
break;
}
wire_exprs.push_back(stringf("\n%s%s <= %s", indent.c_str(), sink.c_str(), source.c_str()));
// Check for subfield assignment.
std::string bitsString = "bits(";
if (sinkExpr.substr(0, bitsString.length()) == bitsString ) {
if (sinkSig == nullptr)
log_error("Unknown subfield %s.%s\n", cell_type.c_str(), sinkExpr.c_str());
// Don't generate the assignment here.
// Add the source and sink to the "reverse_wire_map" and we'll output the assignment
// as part of the coalesced subfield assignments for this wire.
register_reverse_wire_map(sourceExpr, *sinkSig);
} else {
wire_exprs.push_back(stringf("\n%s%s <= %s", indent.c_str(), sinkExpr.c_str(), sourceExpr.c_str()));
}
}
}
wire_exprs.push_back(stringf("\n"));
}
// Given an expression for a shift amount, and a maximum width,
// generate the FIRRTL expression for equivalent dynamic shift taking into account FIRRTL shift semantics.
std::string gen_dshl(const string b_expr, const int b_padded_width)
{
string result = b_expr;
if (b_padded_width >= FIRRTL_MAX_DSH_WIDTH_ERROR) {
int max_shift_width_bits = FIRRTL_MAX_DSH_WIDTH_ERROR - 1;
string max_shift_string = stringf("UInt<%d>(%d)", max_shift_width_bits, (1<<max_shift_width_bits) - 1);
// Deal with the difference in semantics between FIRRTL and verilog
result = stringf("mux(gt(%s, %s), %s, bits(%s, %d, 0))", b_expr.c_str(), max_shift_string.c_str(), max_shift_string.c_str(), b_expr.c_str(), max_shift_width_bits - 1);
}
return result;
}
void run()
{
f << stringf(" module %s:\n", make_id(module->name));
@ -225,6 +401,12 @@ struct FirrtlWorker
for (auto wire : module->wires())
{
const auto wireName = make_id(wire->name);
// If a wire has initial data, issue a warning since FIRRTL doesn't currently support it.
if (wire->attributes.count("\\init")) {
log_warning("Initial value (%s) for (%s.%s) not supported\n",
wire->attributes.at("\\init").as_string().c_str(),
log_id(module), log_id(wire));
}
if (wire->port_id)
{
if (wire->port_input && wire->port_output)
@ -240,7 +422,8 @@ struct FirrtlWorker
for (auto cell : module->cells())
{
// Is this cell is a module instance?
bool extract_y_bits = false; // Assume no extraction of final bits will be required.
// Is this cell is a module instance?
if (cell->type[0] != '$')
{
process_instance(cell, wire_exprs);
@ -264,21 +447,23 @@ struct FirrtlWorker
}
string primop;
bool always_uint = false;
bool always_uint = false;
if (cell->type == "$not") primop = "not";
if (cell->type == "$neg") primop = "neg";
if (cell->type == "$logic_not") {
else if (cell->type == "$neg") {
primop = "neg";
is_signed = true; // Result of "neg" is signed (an SInt).
} else if (cell->type == "$logic_not") {
primop = "eq";
a_expr = stringf("%s, UInt(0)", a_expr.c_str());
}
if (cell->type == "$reduce_and") primop = "andr";
if (cell->type == "$reduce_or") primop = "orr";
if (cell->type == "$reduce_xor") primop = "xorr";
if (cell->type == "$reduce_xnor") {
else if (cell->type == "$reduce_and") primop = "andr";
else if (cell->type == "$reduce_or") primop = "orr";
else if (cell->type == "$reduce_xor") primop = "xorr";
else if (cell->type == "$reduce_xnor") {
primop = "not";
a_expr = stringf("xorr(%s)", a_expr.c_str());
}
if (cell->type == "$reduce_bool") {
else if (cell->type == "$reduce_bool") {
primop = "neq";
// Use the sign of the a_expr and its width as the type (UInt/SInt) and width of the comparand.
bool a_signed = cell->parameters.at("\\A_SIGNED").as_bool();
@ -297,14 +482,15 @@ struct FirrtlWorker
continue;
}
if (cell->type.in("$add", "$sub", "$mul", "$div", "$mod", "$xor", "$and", "$or", "$eq", "$eqx",
"$gt", "$ge", "$lt", "$le", "$ne", "$nex", "$shr", "$sshr", "$sshl", "$shl",
"$logic_and", "$logic_or"))
"$gt", "$ge", "$lt", "$le", "$ne", "$nex", "$shr", "$sshr", "$sshl", "$shl",
"$logic_and", "$logic_or"))
{
string y_id = make_id(cell->name);
bool is_signed = cell->parameters.at("\\A_SIGNED").as_bool();
int y_width = cell->parameters.at("\\Y_WIDTH").as_int();
string a_expr = make_expr(cell->getPort("\\A"));
string b_expr = make_expr(cell->getPort("\\B"));
int b_padded_width = cell->parameters.at("\\B_WIDTH").as_int();
wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width));
if (cell->parameters.at("\\A_SIGNED").as_bool()) {
@ -315,67 +501,95 @@ struct FirrtlWorker
if (cell->parameters.at("\\B_SIGNED").as_bool()) {
b_expr = "asSInt(" + b_expr + ")";
}
b_expr = stringf("pad(%s, %d)", b_expr.c_str(), y_width);
if (b_padded_width < y_width) {
auto b_sig = cell->getPort("\\B");
b_padded_width = y_width;
}
}
a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width);
auto a_sig = cell->getPort("\\A");
if (cell->parameters.at("\\A_SIGNED").as_bool() & (cell->type == "$shr")) {
a_expr = "asUInt(" + a_expr + ")";
}
string primop;
bool always_uint = false;
bool always_uint = false;
if (cell->type == "$add") primop = "add";
if (cell->type == "$sub") primop = "sub";
if (cell->type == "$mul") primop = "mul";
if (cell->type == "$div") primop = "div";
if (cell->type == "$mod") primop = "rem";
if (cell->type == "$and") {
else if (cell->type == "$sub") primop = "sub";
else if (cell->type == "$mul") primop = "mul";
else if (cell->type == "$div") primop = "div";
else if (cell->type == "$mod") primop = "rem";
else if (cell->type == "$and") {
primop = "and";
always_uint = true;
}
if (cell->type == "$or" ) {
else if (cell->type == "$or" ) {
primop = "or";
always_uint = true;
}
if (cell->type == "$xor") {
else if (cell->type == "$xor") {
primop = "xor";
always_uint = true;
}
if ((cell->type == "$eq") | (cell->type == "$eqx")) {
else if ((cell->type == "$eq") | (cell->type == "$eqx")) {
primop = "eq";
always_uint = true;
}
if ((cell->type == "$ne") | (cell->type == "$nex")) {
else if ((cell->type == "$ne") | (cell->type == "$nex")) {
primop = "neq";
always_uint = true;
}
if (cell->type == "$gt") {
else if (cell->type == "$gt") {
primop = "gt";
always_uint = true;
}
if (cell->type == "$ge") {
else if (cell->type == "$ge") {
primop = "geq";
always_uint = true;
}
if (cell->type == "$lt") {
else if (cell->type == "$lt") {
primop = "lt";
always_uint = true;
}
if (cell->type == "$le") {
else if (cell->type == "$le") {
primop = "leq";
always_uint = true;
}
if ((cell->type == "$shl") | (cell->type == "$sshl")) primop = "dshl";
if ((cell->type == "$shr") | (cell->type == "$sshr")) primop = "dshr";
if ((cell->type == "$logic_and")) {
else if ((cell->type == "$shl") | (cell->type == "$sshl")) {
// FIRRTL will widen the result (y) by the amount of the shift.
// We'll need to offset this by extracting the un-widened portion as Verilog would do.
extract_y_bits = true;
// Is the shift amount constant?
auto b_sig = cell->getPort("\\B");
if (b_sig.is_fully_const()) {
primop = "shl";
b_expr = std::to_string(b_sig.as_int());
} else {
primop = "dshl";
// Convert from FIRRTL left shift semantics.
b_expr = gen_dshl(b_expr, b_padded_width);
}
}
else if ((cell->type == "$shr") | (cell->type == "$sshr")) {
// We don't need to extract a specific range of bits.
extract_y_bits = false;
// Is the shift amount constant?
auto b_sig = cell->getPort("\\B");
if (b_sig.is_fully_const()) {
primop = "shr";
b_expr = std::to_string(b_sig.as_int());
} else {
primop = "dshr";
}
}
else if ((cell->type == "$logic_and")) {
primop = "and";
a_expr = "neq(" + a_expr + ", UInt(0))";
b_expr = "neq(" + b_expr + ", UInt(0))";
always_uint = true;
}
if ((cell->type == "$logic_or")) {
else if ((cell->type == "$logic_or")) {
primop = "or";
a_expr = "neq(" + a_expr + ", UInt(0))";
b_expr = "neq(" + b_expr + ", UInt(0))";
@ -388,6 +602,11 @@ struct FirrtlWorker
string expr = stringf("%s(%s, %s)", primop.c_str(), a_expr.c_str(), b_expr.c_str());
// Deal with FIRRTL's "shift widens" semantics
if (extract_y_bits) {
expr = stringf("bits(%s, %d, 0)", expr.c_str(), y_width - 1);
}
if ((is_signed && !always_uint) || cell->type.in("$sub"))
expr = stringf("asUInt(%s)", expr.c_str());
@ -420,6 +639,7 @@ struct FirrtlWorker
int abits = cell->parameters.at("\\ABITS").as_int();
int width = cell->parameters.at("\\WIDTH").as_int();
int size = cell->parameters.at("\\SIZE").as_int();
memory m(cell, mem_id, abits, size, width);
int rd_ports = cell->parameters.at("\\RD_PORTS").as_int();
int wr_ports = cell->parameters.at("\\WR_PORTS").as_int();
@ -436,33 +656,24 @@ struct FirrtlWorker
if (offset != 0)
log_error("Memory with nonzero offset: %s.%s\n", log_id(module), log_id(cell));
cell_exprs.push_back(stringf(" mem %s:\n", mem_id.c_str()));
cell_exprs.push_back(stringf(" data-type => UInt<%d>\n", width));
cell_exprs.push_back(stringf(" depth => %d\n", size));
for (int i = 0; i < rd_ports; i++)
cell_exprs.push_back(stringf(" reader => r%d\n", i));
for (int i = 0; i < wr_ports; i++)
cell_exprs.push_back(stringf(" writer => w%d\n", i));
cell_exprs.push_back(stringf(" read-latency => 0\n"));
cell_exprs.push_back(stringf(" write-latency => 1\n"));
cell_exprs.push_back(stringf(" read-under-write => undefined\n"));
for (int i = 0; i < rd_ports; i++)
{
if (rd_clk_enable[i] != State::S0)
log_error("Clocked read port %d on memory %s.%s.\n", i, log_id(module), log_id(cell));
SigSpec addr_sig = cell->getPort("\\RD_ADDR").extract(i*abits, abits);
SigSpec data_sig = cell->getPort("\\RD_DATA").extract(i*width, width);
string addr_expr = make_expr(cell->getPort("\\RD_ADDR").extract(i*abits, abits));
cell_exprs.push_back(stringf(" %s.r%d.addr <= %s\n", mem_id.c_str(), i, addr_expr.c_str()));
cell_exprs.push_back(stringf(" %s.r%d.en <= UInt<1>(1)\n", mem_id.c_str(), i));
cell_exprs.push_back(stringf(" %s.r%d.clk <= asClock(UInt<1>(0))\n", mem_id.c_str(), i));
register_reverse_wire_map(stringf("%s.r%d.data", mem_id.c_str(), i), data_sig);
string addr_expr = make_expr(addr_sig);
string name(stringf("%s.r%d", m.name.c_str(), i));
bool clk_enable = false;
bool clk_parity = true;
bool transparency = false;
SigSpec ena_sig = RTLIL::SigSpec(RTLIL::State::S1, 1);
SigSpec clk_sig = RTLIL::SigSpec(RTLIL::State::S0, 1);
read_port rp(name, clk_enable, clk_parity, transparency, clk_sig, ena_sig, addr_sig);
m.add_memory_read_port(rp);
cell_exprs.push_back(rp.gen_read(indent.c_str()));
register_reverse_wire_map(stringf("%s.data", name.c_str()), data_sig);
}
for (int i = 0; i < wr_ports; i++)
@ -473,9 +684,16 @@ struct FirrtlWorker
if (wr_clk_polarity[i] != State::S1)
log_error("Negedge write port %d on memory %s.%s.\n", i, log_id(module), log_id(cell));
string addr_expr = make_expr(cell->getPort("\\WR_ADDR").extract(i*abits, abits));
string data_expr = make_expr(cell->getPort("\\WR_DATA").extract(i*width, width));
string clk_expr = make_expr(cell->getPort("\\WR_CLK").extract(i));
string name(stringf("%s.w%d", m.name.c_str(), i));
bool clk_enable = true;
bool clk_parity = true;
bool transparency = false;
SigSpec addr_sig =cell->getPort("\\WR_ADDR").extract(i*abits, abits);
string addr_expr = make_expr(addr_sig);
SigSpec data_sig =cell->getPort("\\WR_DATA").extract(i*width, width);
string data_expr = make_expr(data_sig);
SigSpec clk_sig = cell->getPort("\\WR_CLK").extract(i);
string clk_expr = make_expr(clk_sig);
SigSpec wen_sig = cell->getPort("\\WR_EN").extract(i*width, width);
string wen_expr = make_expr(wen_sig[0]);
@ -484,13 +702,57 @@ struct FirrtlWorker
if (wen_sig[0] != wen_sig[i])
log_error("Complex write enable on port %d on memory %s.%s.\n", i, log_id(module), log_id(cell));
cell_exprs.push_back(stringf(" %s.w%d.addr <= %s\n", mem_id.c_str(), i, addr_expr.c_str()));
cell_exprs.push_back(stringf(" %s.w%d.data <= %s\n", mem_id.c_str(), i, data_expr.c_str()));
cell_exprs.push_back(stringf(" %s.w%d.en <= %s\n", mem_id.c_str(), i, wen_expr.c_str()));
cell_exprs.push_back(stringf(" %s.w%d.mask <= UInt<1>(1)\n", mem_id.c_str(), i));
cell_exprs.push_back(stringf(" %s.w%d.clk <= asClock(%s)\n", mem_id.c_str(), i, clk_expr.c_str()));
SigSpec mask_sig = RTLIL::SigSpec(RTLIL::State::S1, 1);
write_port wp(name, clk_enable, clk_parity, transparency, clk_sig, wen_sig[0], addr_sig, mask_sig);
m.add_memory_write_port(wp);
cell_exprs.push_back(stringf("%s%s.data <= %s\n", indent.c_str(), name.c_str(), data_expr.c_str()));
cell_exprs.push_back(wp.gen_write(indent.c_str()));
}
register_memory(m);
continue;
}
if (cell->type.in("$memwr", "$memrd", "$meminit"))
{
std::string cell_type = fid(cell->type);
std::string mem_id = make_id(cell->parameters["\\MEMID"].decode_string());
int abits = cell->parameters.at("\\ABITS").as_int();
int width = cell->parameters.at("\\WIDTH").as_int();
memory *mp = nullptr;
if (cell->type == "$meminit" ) {
log_error("$meminit (%s.%s.%s) currently unsupported\n", log_id(module), log_id(cell), mem_id.c_str());
} else {
// It's a $memwr or $memrd. Remember the read/write port parameters for the eventual FIRRTL memory definition.
auto addrSig = cell->getPort("\\ADDR");
auto dataSig = cell->getPort("\\DATA");
auto enableSig = cell->getPort("\\EN");
auto clockSig = cell->getPort("\\CLK");
Const clk_enable = cell->parameters.at("\\CLK_ENABLE");
Const clk_polarity = cell->parameters.at("\\CLK_POLARITY");
// Do we already have an entry for this memory?
if (memories.count(mem_id) == 0) {
memory m(cell, mem_id, abits, 0, width);
register_memory(m);
}
mp = &memories.at(mem_id);
int portNum = 0;
bool transparency = false;
string data_expr = make_expr(dataSig);
if (cell->type.in("$memwr")) {
portNum = (int) mp->write_ports.size();
write_port wp(stringf("%s.w%d", mem_id.c_str(), portNum), clk_enable.as_bool(), clk_polarity.as_bool(), transparency, clockSig, enableSig, addrSig, dataSig);
mp->add_memory_write_port(wp);
cell_exprs.push_back(stringf("%s%s.data <= %s\n", indent.c_str(), wp.name.c_str(), data_expr.c_str()));
cell_exprs.push_back(wp.gen_write(indent.c_str()));
} else if (cell->type.in("$memrd")) {
portNum = (int) mp->read_ports.size();
read_port rp(stringf("%s.r%d", mem_id.c_str(), portNum), clk_enable.as_bool(), clk_polarity.as_bool(), transparency, clockSig, enableSig, addrSig);
mp->add_memory_read_port(rp);
cell_exprs.push_back(rp.gen_read(indent.c_str()));
register_reverse_wire_map(stringf("%s.data", rp.name.c_str()), dataSig);
}
}
continue;
}
@ -513,7 +775,65 @@ struct FirrtlWorker
continue;
}
log_error("Cell type not supported: %s (%s.%s)\n", log_id(cell->type), log_id(module), log_id(cell));
// This may be a parameterized module - paramod.
if (cell->type.substr(0, 8) == "$paramod")
{
process_instance(cell, wire_exprs);
continue;
}
if (cell->type == "$shiftx") {
// assign y = a[b +: y_width];
// We'll extract the correct bits as part of the primop.
string y_id = make_id(cell->name);
int y_width = cell->parameters.at("\\Y_WIDTH").as_int();
string a_expr = make_expr(cell->getPort("\\A"));
// Get the initial bit selector
string b_expr = make_expr(cell->getPort("\\B"));
wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width));
if (cell->getParam("\\B_SIGNED").as_bool()) {
// Use validif to constrain the selection (test the sign bit)
auto b_string = b_expr.c_str();
int b_sign = cell->parameters.at("\\B_WIDTH").as_int() - 1;
b_expr = stringf("validif(not(bits(%s, %d, %d)), %s)", b_string, b_sign, b_sign, b_string);
}
string expr = stringf("dshr(%s, %s)", a_expr.c_str(), b_expr.c_str());
cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), expr.c_str()));
register_reverse_wire_map(y_id, cell->getPort("\\Y"));
continue;
}
if (cell->type == "$shift") {
// assign y = a >> b;
// where b may be negative
string y_id = make_id(cell->name);
int y_width = cell->parameters.at("\\Y_WIDTH").as_int();
string a_expr = make_expr(cell->getPort("\\A"));
string b_expr = make_expr(cell->getPort("\\B"));
auto b_string = b_expr.c_str();
int b_padded_width = cell->parameters.at("\\B_WIDTH").as_int();
string expr;
wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width));
if (cell->getParam("\\B_SIGNED").as_bool()) {
// We generate a left or right shift based on the sign of b.
std::string dshl = stringf("bits(dshl(%s, %s), 0, %d)", a_expr.c_str(), gen_dshl(b_expr, b_padded_width).c_str(), y_width);
std::string dshr = stringf("dshr(%s, %s)", a_expr.c_str(), b_string);
expr = stringf("mux(%s < 0, %s, %s)",
b_string,
dshl.c_str(),
dshr.c_str()
);
} else {
expr = stringf("dshr(%s, %s)", a_expr.c_str(), b_string);
}
cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), expr.c_str()));
register_reverse_wire_map(y_id, cell->getPort("\\Y"));
continue;
}
log_warning("Cell type not supported: %s (%s.%s)\n", log_id(cell->type), log_id(module), log_id(cell));
}
for (auto conn : module->connections())
@ -610,6 +930,24 @@ struct FirrtlWorker
f << stringf("\n");
// If we have any memory definitions, output them.
for (auto kv : memories) {
memory &m = kv.second;
f << stringf(" mem %s:\n", m.name.c_str());
f << stringf(" data-type => UInt<%d>\n", m.width);
f << stringf(" depth => %d\n", m.size);
for (int i = 0; i < (int) m.read_ports.size(); i += 1) {
f << stringf(" reader => r%d\n", i);
}
for (int i = 0; i < (int) m.write_ports.size(); i += 1) {
f << stringf(" writer => w%d\n", i);
}
f << stringf(" read-latency => %d\n", m.read_latency);
f << stringf(" write-latency => %d\n", m.write_latency);
f << stringf(" read-under-write => undefined\n");
}
f << stringf("\n");
for (auto str : cell_exprs)
f << str;
@ -629,38 +967,53 @@ struct FirrtlBackend : public Backend {
log(" write_firrtl [options] [filename]\n");
log("\n");
log("Write a FIRRTL netlist of the current design.\n");
log("The following commands are executed by this command:\n");
log(" pmuxtree\n");
log("\n");
}
void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
// if (args[argidx] == "-aig") {
// aig_mode = true;
// continue;
// }
break;
size_t argidx = args.size(); // We aren't expecting any arguments.
// If we weren't explicitly passed a filename, use the last argument (if it isn't a flag).
if (filename == "") {
if (argidx > 0 && args[argidx - 1][0] != '-') {
// extra_args and friends need to see this argument.
argidx -= 1;
filename = args[argidx];
}
}
extra_args(f, filename, args, argidx);
if (!design->full_selection())
log_cmd_error("This command only operates on fully selected designs!\n");
log_header(design, "Executing FIRRTL backend.\n");
log_push();
Module *top = design->top_module();
if (top == nullptr)
log_error("No top module found!\n");
Pass::call(design, stringf("pmuxtree"));
namecache.clear();
autoid_counter = 0;
// Get the top module, or a reasonable facsimile - we need something for the circuit name.
Module *top = design->top_module();
Module *last = nullptr;
// Generate module and wire names.
for (auto module : design->modules()) {
make_id(module->name);
last = module;
if (top == nullptr && module->get_bool_attribute("\\top")) {
top = module;
}
for (auto wire : module->wires())
if (wire->port_id)
make_id(wire->name);
}
if (top == nullptr)
top = last;
*f << stringf("circuit %s:\n", make_id(top->name));
for (auto module : design->modules())

View File

@ -160,7 +160,10 @@ void ILANG_BACKEND::dump_cell(std::ostream &f, std::string indent, const RTLIL::
}
f << stringf("%s" "cell %s %s\n", indent.c_str(), cell->type.c_str(), cell->name.c_str());
for (auto &it : cell->parameters) {
f << stringf("%s parameter%s %s ", indent.c_str(), (it.second.flags & RTLIL::CONST_FLAG_SIGNED) != 0 ? " signed" : "", it.first.c_str());
f << stringf("%s parameter%s%s %s ", indent.c_str(),
(it.second.flags & RTLIL::CONST_FLAG_SIGNED) != 0 ? " signed" : "",
(it.second.flags & RTLIL::CONST_FLAG_REAL) != 0 ? " real" : "",
it.first.c_str());
dump_const(f, it.second);
f << stringf("\n");
}
@ -204,7 +207,7 @@ void ILANG_BACKEND::dump_proc_switch(std::ostream &f, std::string indent, const
f << stringf("%s case ", indent.c_str());
for (size_t i = 0; i < (*it)->compare.size(); i++) {
if (i > 0)
f << stringf(", ");
f << stringf(" , ");
dump_sigspec(f, (*it)->compare[i]);
}
f << stringf("\n");

View File

@ -127,7 +127,7 @@ struct IntersynthBackend : public Backend {
RTLIL::Module *module = module_it.second;
SigMap sigmap(module);
if (module->get_bool_attribute("\\blackbox"))
if (module->get_blackbox_attribute())
continue;
if (module->memories.size() == 0 && module->processes.size() == 0 && module->cells_.size() == 0)
continue;

View File

@ -48,7 +48,7 @@ struct ProtobufDesignSerializer
ProtobufDesignSerializer(bool use_selection, bool aig_mode) :
aig_mode_(aig_mode), use_selection_(use_selection) { }
string get_name(IdString name)
{
return RTLIL::unescape_id(name);
@ -60,7 +60,7 @@ struct ProtobufDesignSerializer
{
for (auto &param : parameters) {
std::string key = get_name(param.first);
yosys::pb::Parameter pb_param;
@ -207,7 +207,7 @@ struct ProtobufDesignSerializer
(*models)[aig.name] = pb_model;
}
}
void serialize_design(yosys::pb::Design *pb, Design *design)
{
GOOGLE_PROTOBUF_VERIFY_VERSION;

View File

@ -3,14 +3,30 @@ OBJS += backends/smt2/smt2.o
ifneq ($(CONFIG),mxe)
ifneq ($(CONFIG),emcc)
# MSYS targets support yosys-smtbmc, but require a launcher script
ifeq ($(CONFIG),$(filter $(CONFIG),msys2 msys2-64))
TARGETS += yosys-smtbmc.exe yosys-smtbmc-script.py
# Needed to find the Python interpreter for yosys-smtbmc scripts.
# Override if necessary, it is only used for msys2 targets.
PYTHON := $(shell cygpath -w -m $(PREFIX)/bin/python3)
yosys-smtbmc-script.py: backends/smt2/smtbmc.py
$(P) sed -e 's|##yosys-sys-path##|sys.path += [os.path.dirname(os.path.realpath(__file__)) + p for p in ["/share/python3", "/../share/yosys/python3"]]|;' \
-e "s|#!/usr/bin/env python3|#!$(PYTHON)|" < $< > $@
yosys-smtbmc.exe: misc/launcher.c yosys-smtbmc-script.py
$(P) gcc -DGUI=0 -O -s -o $@ $<
# Other targets
else
TARGETS += yosys-smtbmc
yosys-smtbmc: backends/smt2/smtbmc.py
$(P) sed 's|##yosys-sys-path##|sys.path += [os.path.dirname(os.path.realpath(__file__)) + p for p in ["/share/python3", "/../share/yosys/python3"]]|;' < $< > $@.new
$(Q) chmod +x $@.new
$(Q) mv $@.new $@
endif
$(eval $(call add_share_file,share/python3,backends/smt2/smtio.py))
endif
endif

View File

@ -416,6 +416,7 @@ struct Smt2Worker
for (char ch : expr) {
if (ch == 'A') processed_expr += get_bv(sig_a);
else if (ch == 'B') processed_expr += get_bv(sig_b);
else if (ch == 'P') processed_expr += get_bv(cell->getPort("\\B"));
else if (ch == 'L') processed_expr += is_signed ? "a" : "l";
else if (ch == 'U') processed_expr += is_signed ? "s" : "u";
else processed_expr += ch;
@ -554,7 +555,7 @@ struct Smt2Worker
if (cell->type.in("$shift", "$shiftx")) {
if (cell->getParam("\\B_SIGNED").as_bool()) {
return export_bvop(cell, stringf("(ite (bvsge B #b%0*d) "
return export_bvop(cell, stringf("(ite (bvsge P #b%0*d) "
"(bvlshr A B) (bvlshr A (bvneg B)))",
GetSize(cell->getPort("\\B")), 0), 's');
} else {
@ -887,8 +888,8 @@ struct Smt2Worker
string name_a = get_bool(cell->getPort("\\A"));
string name_en = get_bool(cell->getPort("\\EN"));
decls.push_back(stringf("; yosys-smt2-%s %d %s\n", cell->type.c_str() + 1, id,
cell->attributes.count("\\src") ? cell->attributes.at("\\src").decode_string().c_str() : get_id(cell)));
string infostr = (cell->name[0] == '$' && cell->attributes.count("\\src")) ? cell->attributes.at("\\src").decode_string() : get_id(cell);
decls.push_back(stringf("; yosys-smt2-%s %d %s\n", cell->type.c_str() + 1, id, infostr.c_str()));
if (cell->type == "$cover")
decls.push_back(stringf("(define-fun |%s_%c %d| ((state |%s_s|)) Bool (and %s %s)) ; %s\n",
@ -1103,20 +1104,27 @@ struct Smt2Worker
break;
Const initword = init_data.extract(i*width, width, State::Sx);
Const initmask = initword;
bool gen_init_constr = false;
for (auto bit : initword.bits)
if (bit == State::S0 || bit == State::S1)
for (int k = 0; k < GetSize(initword); k++) {
if (initword[k] == State::S0 || initword[k] == State::S1) {
gen_init_constr = true;
initmask[k] = State::S1;
} else {
initmask[k] = State::S0;
initword[k] = State::S0;
}
}
if (gen_init_constr)
{
if (statebv)
/* FIXME */;
else
init_list.push_back(stringf("(= (select (|%s#%d#0| state) #b%s) #b%s) ; %s[%d]",
init_list.push_back(stringf("(= (bvand (select (|%s#%d#0| state) #b%s) #b%s) #b%s) ; %s[%d]",
get_id(module), arrayid, Const(i, abits).as_string().c_str(),
initword.as_string().c_str(), get_id(cell), i));
initmask.as_string().c_str(), initword.as_string().c_str(), get_id(cell), i));
}
}
}
@ -1535,7 +1543,7 @@ struct Smt2Backend : public Backend {
for (auto module : sorted_modules)
{
if (module->get_bool_attribute("\\blackbox") || module->has_memories_warn() || module->has_processes_warn())
if (module->get_blackbox_attribute() || module->has_memories_warn() || module->has_processes_warn())
continue;
log("Creating SMT-LIBv2 representation of module %s.\n", log_id(module));

View File

@ -1484,11 +1484,11 @@ else: # not tempind, covermode
smt_assert_antecedent("(|%s_h| s%d)" % (topmod, i))
smt_assert_antecedent("(|%s_t| s%d s%d)" % (topmod, i-1, i))
smt_assert_consequent(get_constr_expr(constr_assumes, i))
print_msg("Re-solving with appended steps..")
if smt_check_sat() == "unsat":
print("%s Cannot appended steps without violating assumptions!" % smt.timestamp())
retstatus = False
break
print_msg("Re-solving with appended steps..")
if smt_check_sat() == "unsat":
print("%s Cannot appended steps without violating assumptions!" % smt.timestamp())
retstatus = False
break
print_anyconsts(step)
for i in range(step, last_check_step+1):
print_failed_asserts(i)

View File

@ -784,7 +784,7 @@ class SmtIo:
def get_path(self, mod, path):
assert mod in self.modinfo
path = path.split(".")
path = path.replace("\\", "/").split(".")
for i in range(len(path)-1):
first = ".".join(path[0:i+1])

View File

@ -739,7 +739,7 @@ struct SmvBackend : public Backend {
pool<Module*> modules;
for (auto module : design->modules())
if (!module->get_bool_attribute("\\blackbox") && !module->has_memories_warn() && !module->has_processes_warn())
if (!module->get_blackbox_attribute() && !module->has_memories_warn() && !module->has_processes_warn())
modules.insert(module);
if (template_f.is_open())

View File

@ -212,7 +212,7 @@ struct SpiceBackend : public Backend {
for (auto module_it : design->modules_)
{
RTLIL::Module *module = module_it.second;
if (module->get_bool_attribute("\\blackbox"))
if (module->get_blackbox_attribute())
continue;
if (module->processes.size() != 0)

View File

@ -67,7 +67,7 @@ struct TableBackend : public Backend {
for (auto module : design->modules())
{
if (module->get_bool_attribute("\\blackbox"))
if (module->get_blackbox_attribute())
continue;
SigMap sigmap(module);

View File

@ -33,7 +33,7 @@
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
bool verbose, norename, noattr, attr2comment, noexpr, nodec, nohex, nostr, defparam, decimal;
bool verbose, norename, noattr, attr2comment, noexpr, nodec, nohex, nostr, defparam, decimal, siminit;
int auto_name_counter, auto_name_offset, auto_name_digits;
std::map<RTLIL::IdString, int> auto_name_map;
std::set<RTLIL::IdString> reg_wires, reg_ct;
@ -126,6 +126,33 @@ std::string id(RTLIL::IdString internal_id, bool may_rename = true)
break;
}
const pool<string> keywords = {
// IEEE 1800-2017 Annex B
"accept_on", "alias", "always", "always_comb", "always_ff", "always_latch", "and", "assert", "assign", "assume", "automatic", "before",
"begin", "bind", "bins", "binsof", "bit", "break", "buf", "bufif0", "bufif1", "byte", "case", "casex", "casez", "cell", "chandle",
"checker", "class", "clocking", "cmos", "config", "const", "constraint", "context", "continue", "cover", "covergroup", "coverpoint",
"cross", "deassign", "default", "defparam", "design", "disable", "dist", "do", "edge", "else", "end", "endcase", "endchecker",
"endclass", "endclocking", "endconfig", "endfunction", "endgenerate", "endgroup", "endinterface", "endmodule", "endpackage",
"endprimitive", "endprogram", "endproperty", "endsequence", "endspecify", "endtable", "endtask", "enum", "event", "eventually",
"expect", "export", "extends", "extern", "final", "first_match", "for", "force", "foreach", "forever", "fork", "forkjoin", "function",
"generate", "genvar", "global", "highz0", "highz1", "if", "iff", "ifnone", "ignore_bins", "illegal_bins", "implements", "implies",
"import", "incdir", "include", "initial", "inout", "input", "inside", "instance", "int", "integer", "interconnect", "interface",
"intersect", "join", "join_any", "join_none", "large", "let", "liblist", "library", "local", "localparam", "logic", "longint",
"macromodule", "matches", "medium", "modport", "module", "nand", "negedge", "nettype", "new", "nexttime", "nmos", "nor",
"noshowcancelled", "not", "notif0", "notif1", "null", "or", "output", "package", "packed", "parameter", "pmos", "posedge", "primitive",
"priority", "program", "property", "protected", "pull0", "pull1", "pulldown", "pullup", "pulsestyle_ondetect", "pulsestyle_onevent",
"pure", "rand", "randc", "randcase", "randsequence", "rcmos", "real", "realtime", "ref", "reg", "reject_on", "release", "repeat",
"restrict", "return", "rnmos", "rpmos", "rtran", "rtranif0", "rtranif1", "s_always", "s_eventually", "s_nexttime", "s_until",
"s_until_with", "scalared", "sequence", "shortint", "shortreal", "showcancelled", "signed", "small", "soft", "solve", "specify",
"specparam", "static", "string", "strong", "strong0", "strong1", "struct", "super", "supply0", "supply1", "sync_accept_on",
"sync_reject_on", "table", "tagged", "task", "this", "throughout", "time", "timeprecision", "timeunit", "tran", "tranif0", "tranif1",
"tri", "tri0", "tri1", "triand", "trior", "trireg", "type", "typedef", "union", "unique", "unique0", "unsigned", "until", "until_with",
"untyped", "use", "uwire", "var", "vectored", "virtual", "void", "wait", "wait_order", "wand", "weak", "weak0", "weak1", "while",
"wildcard", "wire", "with", "within", "wor", "xnor", "xor",
};
if (keywords.count(str))
do_escape = true;
if (do_escape)
return "\\" + std::string(str) + " ";
return std::string(str);
@ -156,10 +183,15 @@ bool is_reg_wire(RTLIL::SigSpec sig, std::string &reg_name)
return true;
}
void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int offset = 0, bool no_decimal = false, bool set_signed = false, bool escape_comment = false)
void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int offset = 0, bool no_decimal = false, bool escape_comment = false)
{
bool set_signed = (data.flags & RTLIL::CONST_FLAG_SIGNED) != 0;
if (width < 0)
width = data.bits.size() - offset;
if (width == 0) {
f << "\"\"";
return;
}
if (nostr)
goto dump_hex;
if ((data.flags & RTLIL::CONST_FLAG_STRING) == 0 || width != (int)data.bits.size()) {
@ -244,7 +276,8 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o
}
}
} else {
f << stringf("\"");
if ((data.flags & RTLIL::CONST_FLAG_REAL) == 0)
f << stringf("\"");
std::string str = data.decode_string();
for (size_t i = 0; i < str.size(); i++) {
if (str[i] == '\n')
@ -262,7 +295,8 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o
else
f << str[i];
}
f << stringf("\"");
if ((data.flags & RTLIL::CONST_FLAG_REAL) == 0)
f << stringf("\"");
}
}
@ -313,6 +347,10 @@ void dump_sigchunk(std::ostream &f, const RTLIL::SigChunk &chunk, bool no_decima
void dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig)
{
if (GetSize(sig) == 0) {
f << "\"\"";
return;
}
if (sig.is_chunk()) {
dump_sigchunk(f, sig.as_chunk());
} else {
@ -338,7 +376,7 @@ void dump_attributes(std::ostream &f, std::string indent, dict<RTLIL::IdString,
else if (modattr && (it->second == Const(1, 1) || it->second == Const(1)))
f << stringf(" 1 ");
else
dump_const(f, it->second, -1, 0, false, false, attr2comment);
dump_const(f, it->second, -1, 0, false, attr2comment);
f << stringf(" %s%c", attr2comment ? "*/" : "*)", term);
}
}
@ -709,11 +747,14 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
if (cell->type == "$shiftx")
{
std::string temp_id = next_auto_id();
f << stringf("%s" "wire [%d:0] %s = ", indent.c_str(), GetSize(cell->getPort("\\A"))-1, temp_id.c_str());
dump_sigspec(f, cell->getPort("\\A"));
f << stringf(";\n");
f << stringf("%s" "assign ", indent.c_str());
dump_sigspec(f, cell->getPort("\\Y"));
f << stringf(" = ");
dump_sigspec(f, cell->getPort("\\A"));
f << stringf("[");
f << stringf(" = %s[", temp_id.c_str());
if (cell->getParam("\\B_SIGNED").as_bool())
f << stringf("$signed(");
dump_sigspec(f, cell->getPort("\\B"));
@ -786,6 +827,18 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
return true;
}
if (cell->type == "$tribuf")
{
f << stringf("%s" "assign ", indent.c_str());
dump_sigspec(f, cell->getPort("\\Y"));
f << stringf(" = ");
dump_sigspec(f, cell->getPort("\\EN"));
f << stringf(" ? ");
dump_sigspec(f, cell->getPort("\\A"));
f << stringf(" : %d'bz;\n", cell->parameters.at("\\WIDTH").as_int());
return true;
}
if (cell->type == "$slice")
{
f << stringf("%s" "assign ", indent.c_str());
@ -1023,43 +1076,46 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
use_rd_clk = cell->parameters["\\RD_CLK_ENABLE"].extract(i).as_bool();
rd_clk_posedge = cell->parameters["\\RD_CLK_POLARITY"].extract(i).as_bool();
rd_transparent = cell->parameters["\\RD_TRANSPARENT"].extract(i).as_bool();
if (use_rd_clk)
{
std::ostringstream os;
dump_sigspec(os, sig_rd_clk);
clk_domain_str = stringf("%sedge %s", rd_clk_posedge ? "pos" : "neg", os.str().c_str());
if( clk_to_lof_body.count(clk_domain_str) == 0 )
clk_to_lof_body[clk_domain_str] = std::vector<std::string>();
}
if (use_rd_clk && !rd_transparent)
{
// for clocked read ports make something like:
// reg [..] temp_id;
// always @(posedge clk)
// if (rd_en) temp_id <= array_reg[r_addr];
// assign r_data = temp_id;
std::string temp_id = next_auto_id();
lof_reg_declarations.push_back( stringf("reg [%d:0] %s;\n", sig_rd_data.size() - 1, temp_id.c_str()) );
{
std::ostringstream os;
if (sig_rd_en != RTLIL::SigBit(true))
dump_sigspec(os, sig_rd_clk);
clk_domain_str = stringf("%sedge %s", rd_clk_posedge ? "pos" : "neg", os.str().c_str());
if( clk_to_lof_body.count(clk_domain_str) == 0 )
clk_to_lof_body[clk_domain_str] = std::vector<std::string>();
}
if (!rd_transparent)
{
// for clocked read ports make something like:
// reg [..] temp_id;
// always @(posedge clk)
// if (rd_en) temp_id <= array_reg[r_addr];
// assign r_data = temp_id;
std::string temp_id = next_auto_id();
lof_reg_declarations.push_back( stringf("reg [%d:0] %s;\n", sig_rd_data.size() - 1, temp_id.c_str()) );
{
os << stringf("if (");
dump_sigspec(os, sig_rd_en);
os << stringf(") ");
std::ostringstream os;
if (sig_rd_en != RTLIL::SigBit(true))
{
os << stringf("if (");
dump_sigspec(os, sig_rd_en);
os << stringf(") ");
}
os << stringf("%s <= %s[", temp_id.c_str(), mem_id.c_str());
dump_sigspec(os, sig_rd_addr);
os << stringf("];\n");
clk_to_lof_body[clk_domain_str].push_back(os.str());
}
{
std::ostringstream os;
dump_sigspec(os, sig_rd_data);
std::string line = stringf("assign %s = %s;\n", os.str().c_str(), temp_id.c_str());
clk_to_lof_body[""].push_back(line);
}
os << stringf("%s <= %s[", temp_id.c_str(), mem_id.c_str());
dump_sigspec(os, sig_rd_addr);
os << stringf("];\n");
clk_to_lof_body[clk_domain_str].push_back(os.str());
}
else
{
std::ostringstream os;
dump_sigspec(os, sig_rd_data);
std::string line = stringf("assign %s = %s;\n", os.str().c_str(), temp_id.c_str());
clk_to_lof_body[""].push_back(line);
}
} else {
if (rd_transparent) {
// for rd-transparent read-ports make something like:
// reg [..] temp_id;
// always @(posedge clk)
@ -1079,15 +1135,15 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
std::string line = stringf("assign %s = %s[%s];\n", os.str().c_str(), mem_id.c_str(), temp_id.c_str());
clk_to_lof_body[""].push_back(line);
}
} else {
// for non-clocked read-ports make something like:
// assign r_data = array_reg[r_addr];
std::ostringstream os, os2;
dump_sigspec(os, sig_rd_data);
dump_sigspec(os2, sig_rd_addr);
std::string line = stringf("assign %s = %s[%s];\n", os.str().c_str(), mem_id.c_str(), os2.str().c_str());
clk_to_lof_body[""].push_back(line);
}
} else {
// for non-clocked read-ports make something like:
// assign r_data = array_reg[r_addr];
std::ostringstream os, os2;
dump_sigspec(os, sig_rd_data);
dump_sigspec(os2, sig_rd_addr);
std::string line = stringf("assign %s = %s[%s];\n", os.str().c_str(), mem_id.c_str(), os2.str().c_str());
clk_to_lof_body[""].push_back(line);
}
}
@ -1189,6 +1245,118 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
return true;
}
if (cell->type.in("$assert", "$assume", "$cover"))
{
f << stringf("%s" "always @* if (", indent.c_str());
dump_sigspec(f, cell->getPort("\\EN"));
f << stringf(") %s(", cell->type.c_str()+1);
dump_sigspec(f, cell->getPort("\\A"));
f << stringf(");\n");
return true;
}
if (cell->type.in("$specify2", "$specify3"))
{
f << stringf("%s" "specify\n%s ", indent.c_str(), indent.c_str());
SigSpec en = cell->getPort("\\EN");
if (en != State::S1) {
f << stringf("if (");
dump_sigspec(f, cell->getPort("\\EN"));
f << stringf(") ");
}
f << "(";
if (cell->type == "$specify3" && cell->getParam("\\EDGE_EN").as_bool())
f << (cell->getParam("\\EDGE_POL").as_bool() ? "posedge ": "negedge ");
dump_sigspec(f, cell->getPort("\\SRC"));
f << " ";
if (cell->getParam("\\SRC_DST_PEN").as_bool())
f << (cell->getParam("\\SRC_DST_POL").as_bool() ? "+": "-");
f << (cell->getParam("\\FULL").as_bool() ? "*> ": "=> ");
if (cell->type == "$specify3") {
f << "(";
dump_sigspec(f, cell->getPort("\\DST"));
f << " ";
if (cell->getParam("\\DAT_DST_PEN").as_bool())
f << (cell->getParam("\\DAT_DST_POL").as_bool() ? "+": "-");
f << ": ";
dump_sigspec(f, cell->getPort("\\DAT"));
f << ")";
} else {
dump_sigspec(f, cell->getPort("\\DST"));
}
bool bak_decimal = decimal;
decimal = 1;
f << ") = (";
dump_const(f, cell->getParam("\\T_RISE_MIN"));
f << ":";
dump_const(f, cell->getParam("\\T_RISE_TYP"));
f << ":";
dump_const(f, cell->getParam("\\T_RISE_MAX"));
f << ", ";
dump_const(f, cell->getParam("\\T_FALL_MIN"));
f << ":";
dump_const(f, cell->getParam("\\T_FALL_TYP"));
f << ":";
dump_const(f, cell->getParam("\\T_FALL_MAX"));
f << ");\n";
decimal = bak_decimal;
f << stringf("%s" "endspecify\n", indent.c_str());
return true;
}
if (cell->type == "$specrule")
{
f << stringf("%s" "specify\n%s ", indent.c_str(), indent.c_str());
string spec_type = cell->getParam("\\TYPE").decode_string();
f << stringf("%s(", spec_type.c_str());
if (cell->getParam("\\SRC_PEN").as_bool())
f << (cell->getParam("\\SRC_POL").as_bool() ? "posedge ": "negedge ");
dump_sigspec(f, cell->getPort("\\SRC"));
if (cell->getPort("\\SRC_EN") != State::S1) {
f << " &&& ";
dump_sigspec(f, cell->getPort("\\SRC_EN"));
}
f << ", ";
if (cell->getParam("\\DST_PEN").as_bool())
f << (cell->getParam("\\DST_POL").as_bool() ? "posedge ": "negedge ");
dump_sigspec(f, cell->getPort("\\DST"));
if (cell->getPort("\\DST_EN") != State::S1) {
f << " &&& ";
dump_sigspec(f, cell->getPort("\\DST_EN"));
}
bool bak_decimal = decimal;
decimal = 1;
f << ", ";
dump_const(f, cell->getParam("\\T_LIMIT"));
if (spec_type == "$setuphold" || spec_type == "$recrem" || spec_type == "$fullskew") {
f << ", ";
dump_const(f, cell->getParam("\\T_LIMIT2"));
}
f << ");\n";
decimal = bak_decimal;
f << stringf("%s" "endspecify\n", indent.c_str());
return true;
}
// FIXME: $_SR_[PN][PN]_, $_DLATCH_[PN]_, $_DLATCHSR_[PN][PN][PN]_
// FIXME: $sr, $dlatch, $memrd, $memwr, $fsm
@ -1211,8 +1379,7 @@ void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell)
if (it != cell->parameters.begin())
f << stringf(",");
f << stringf("\n%s .%s(", indent.c_str(), id(it->first).c_str());
bool is_signed = (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0;
dump_const(f, it->second, -1, 0, false, is_signed);
dump_const(f, it->second);
f << stringf(")");
}
f << stringf("\n%s" ")", indent.c_str());
@ -1259,12 +1426,20 @@ void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell)
if (defparam && cell->parameters.size() > 0) {
for (auto it = cell->parameters.begin(); it != cell->parameters.end(); ++it) {
f << stringf("%sdefparam %s.%s = ", indent.c_str(), cell_name.c_str(), id(it->first).c_str());
bool is_signed = (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0;
dump_const(f, it->second, -1, 0, false, is_signed);
dump_const(f, it->second);
f << stringf(";\n");
}
}
if (siminit && reg_ct.count(cell->type) && cell->hasPort("\\Q")) {
std::stringstream ss;
dump_reg_init(ss, cell->getPort("\\Q"));
if (!ss.str().empty()) {
f << stringf("%sinitial %s.Q", indent.c_str(), cell_name.c_str());
f << ss.str();
f << ";\n";
}
}
}
void dump_conn(std::ostream &f, std::string indent, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right)
@ -1443,7 +1618,8 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module)
SigSpec sig = active_sigmap(wire);
Const val = wire->attributes.at("\\init");
for (int i = 0; i < GetSize(sig) && i < GetSize(val); i++)
active_initdata[sig[i]] = val.bits.at(i);
if (val[i] == State::S0 || val[i] == State::S1)
active_initdata[sig[i]] = val[i];
}
if (!module->processes.empty())
@ -1553,6 +1729,10 @@ struct VerilogBackend : public Backend {
log(" without this option all internal cells are converted to Verilog\n");
log(" expressions.\n");
log("\n");
log(" -siminit\n");
log(" add initial statements with hierarchical refs to initialize FFs when\n");
log(" in -noexpr mode.\n");
log("\n");
log(" -nodec\n");
log(" 32-bit constant values are by default dumped as decimal numbers,\n");
log(" not bit pattern. This option deactivates this feature and instead\n");
@ -1609,11 +1789,14 @@ struct VerilogBackend : public Backend {
nostr = false;
defparam = false;
decimal = false;
siminit = false;
auto_prefix = "";
bool blackboxes = false;
bool selected = false;
auto_name_map.clear();
reg_wires.clear();
reg_ct.clear();
reg_ct.insert("$dff");
@ -1685,6 +1868,10 @@ struct VerilogBackend : public Backend {
decimal = true;
continue;
}
if (arg == "-siminit") {
siminit = true;
continue;
}
if (arg == "-blackboxes") {
blackboxes = true;
continue;
@ -1705,7 +1892,7 @@ struct VerilogBackend : public Backend {
*f << stringf("/* Generated by %s */\n", yosys_version_str);
for (auto it = design->modules_.begin(); it != design->modules_.end(); ++it) {
if (it->second->get_bool_attribute("\\blackbox") != blackboxes)
if (it->second->get_blackbox_attribute() != blackboxes)
continue;
if (selected && !design->selected_whole_module(it->first)) {
if (design->selected_module(it->first))
@ -1716,6 +1903,8 @@ struct VerilogBackend : public Backend {
dump_module(*f, "", it->second);
}
auto_name_map.clear();
reg_wires.clear();
reg_ct.clear();
}
} VerilogBackend;

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

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

View File

@ -0,0 +1,12 @@
LED Blink project for Anlogic Lichee Tang board.
Follow the install instructions for the Tang Dynasty IDE from given link below.
https://tang.sipeed.com/en/getting-started/installing-td-ide/linux/
set TD_HOME env variable to the full path to the TD <TD Install Directory> as follow.
export TD_HOME=<TD Install Directory>
then run "bash build.sh" in this directory.

View File

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

View File

@ -0,0 +1,11 @@
import_device eagle_s20.db -package BG256
read_verilog full.v -top demo
read_adc demo.adc
optimize_rtl
map_macro
map
pack
place
route
report_area -io_info -file demo_phy.area
bitgen -bit demo.bit -version 0X0000 -svf demo.svf -svf_comment_on -g ucode:00000000000000000000000000000000

View File

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

View File

@ -0,0 +1,18 @@
module demo (
input wire CLK_IN,
output wire R_LED
);
parameter time1 = 30'd12_000_000;
reg led_state;
reg [29:0] count;
always @(posedge CLK_IN)begin
if(count == time1)begin
count<= 30'd0;
led_state <= ~led_state;
end
else
count <= count + 1'b1;
end
assign R_LED = led_state;
endmodule

View File

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

View File

@ -1,3 +1,4 @@
/netlist.edn
/netlist.v
/work
/netlist.vm
/example.stp
/proj

View File

@ -0,0 +1,20 @@
# Add placement constraints here
set_io clk -pinname H16 -fixed yes -DIRECTION INPUT
set_io SW1 -pinname H12 -fixed yes -DIRECTION INPUT
set_io SW2 -pinname H13 -fixed yes -DIRECTION INPUT
set_io LED1 -pinname J16 -fixed yes -DIRECTION OUTPUT
set_io LED2 -pinname M16 -fixed yes -DIRECTION OUTPUT
set_io LED3 -pinname K16 -fixed yes -DIRECTION OUTPUT
set_io LED4 -pinname N16 -fixed yes -DIRECTION OUTPUT
set_io AA -pinname L12 -fixed yes -DIRECTION OUTPUT
set_io AB -pinname L13 -fixed yes -DIRECTION OUTPUT
set_io AC -pinname M13 -fixed yes -DIRECTION OUTPUT
set_io AD -pinname N15 -fixed yes -DIRECTION OUTPUT
set_io AE -pinname L11 -fixed yes -DIRECTION OUTPUT
set_io AF -pinname L14 -fixed yes -DIRECTION OUTPUT
set_io AG -pinname N14 -fixed yes -DIRECTION OUTPUT
set_io CA -pinname M15 -fixed yes -DIRECTION OUTPUT

View File

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

View File

@ -1,22 +1,64 @@
module top (
module example (
input clk,
input SW1,
input SW2,
output LED1,
output LED2,
output LED3,
output LED4,
output LED5
output AA, AB, AC, AD,
output AE, AF, AG, CA
);
localparam BITS = 5;
localparam BITS = 8;
localparam LOG2DELAY = 22;
reg [BITS+LOG2DELAY-1:0] counter = 0;
reg [BITS-1:0] outcnt;
always @(posedge clk) begin
counter <= counter + 1;
counter <= counter + SW1 + SW2 + 1;
outcnt <= counter >> LOG2DELAY;
end
assign {LED1, LED2, LED3, LED4, LED5} = outcnt ^ (outcnt >> 1);
assign {LED1, LED2, LED3, LED4} = outcnt ^ (outcnt >> 1);
// assign CA = counter[10];
// seg7enc seg7encinst (
// .seg({AA, AB, AC, AD, AE, AF, AG}),
// .dat(CA ? outcnt[3:0] : outcnt[7:4])
// );
assign {AA, AB, AC, AD, AE, AF, AG} = ~(7'b 100_0000 >> outcnt[6:4]);
assign CA = outcnt[7];
endmodule
module seg7enc (
input [3:0] dat,
output [6:0] seg
);
reg [6:0] seg_inv;
always @* begin
seg_inv = 0;
case (dat)
4'h0: seg_inv = 7'b 0111111;
4'h1: seg_inv = 7'b 0000110;
4'h2: seg_inv = 7'b 1011011;
4'h3: seg_inv = 7'b 1001111;
4'h4: seg_inv = 7'b 1100110;
4'h5: seg_inv = 7'b 1101101;
4'h6: seg_inv = 7'b 1111101;
4'h7: seg_inv = 7'b 0000111;
4'h8: seg_inv = 7'b 1111111;
4'h9: seg_inv = 7'b 1101111;
4'hA: seg_inv = 7'b 1110111;
4'hB: seg_inv = 7'b 1111100;
4'hC: seg_inv = 7'b 0111001;
4'hD: seg_inv = 7'b 1011110;
4'hE: seg_inv = 7'b 1111001;
4'hF: seg_inv = 7'b 1110001;
endcase
end
assign seg = ~seg_inv;
endmodule

View File

@ -1,3 +0,0 @@
read_verilog example.v
synth_sf2 -top top -edif netlist.edn
write_verilog netlist.v

View File

@ -1,35 +1,57 @@
# Run with "libero SCRIPT:libero.tcl"
file delete -force proj
new_project \
-name top \
-location work \
-name example \
-location proj \
-block_mode 0 \
-hdl "VERILOG" \
-family IGLOO2 \
-die PA4MGL500 \
-package tq144 \
-speed -1 \
-hdl VERILOG
-die PA4MGL2500 \
-package vf256 \
-speed -1
# import_files -edif "[pwd]/netlist.edn"
import_files -hdl_source {netlist.vm}
import_files -sdc {example.sdc}
import_files -io_pdc {example.pdc}
build_design_hierarchy
set_option -synth 0
import_files -hdl_source "[pwd]/netlist.v"
set_root top
organize_tool_files -tool PLACEROUTE \
-file {proj/constraint/example.sdc} \
-file {proj/constraint/io/example.pdc} \
-input_type constraint
save_project
organize_tool_files -tool VERIFYTIMING \
-file {proj/constraint/example.sdc} \
-input_type constraint
puts "**> SYNTHESIZE"
run_tool -name {SYNTHESIZE}
puts "<** SYNTHESIZE"
configure_tool -name PLACEROUTE \
-params TDPR:true \
-params PDPR:false \
-params EFFORT_LEVEL:false \
-params REPAIR_MIN_DELAY:false
puts ""
puts "**> COMPILE"
run_tool -name {COMPILE}
puts "<** COMPILE"
puts ""
puts "**> PLACEROUTE"
run_tool -name {PLACEROUTE}
puts "<** PLACEROUTE"
# puts "**> export_bitstream"
# export_bitstream_file -trusted_facility_file 1 -trusted_facility_file_components {FABRIC}
# puts "<** export_bitstream"
puts ""
puts "**> VERIFYTIMING"
run_tool -name {VERIFYTIMING}
puts "<** VERIFYTIMING"
puts ""
puts "**> BITSTREAM"
export_bitstream_file -trusted_facility_file 1 -trusted_facility_file_components {FABRIC}
puts "<** BITSTREAM"
puts ""
exit 0

View File

@ -1,5 +1,6 @@
#!/bin/bash
set -ex
rm -rf work
yosys example.ys
LM_LICENSE_FILE=1702@`hostname` /opt/microsemi/Libero_SoC_v11.9/Libero/bin/libero SCRIPT:libero.tcl
yosys -p 'synth_sf2 -top example -edif netlist.edn -vlog netlist.vm' example.v
export LM_LICENSE_FILE=${LM_LICENSE_FILE:-1702@localhost}
/opt/microsemi/Libero_SoC_v12.0/Libero/bin/libero SCRIPT:libero.tcl
cp proj/designer/example/export/example.stp .

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

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

View File

@ -0,0 +1,32 @@
#!/usr/bin/python3
from pyosys import libyosys as ys
import matplotlib.pyplot as plt
import numpy as np
class CellStatsPass(ys.Pass):
def __init__(self):
super().__init__("cell_stats", "Shows cell stats as plot")
def py_help(self):
ys.log("This pass uses the matplotlib library to display cell stats\n")
def py_execute(self, args, design):
ys.log_header(design, "Plotting cell stats\n")
cell_stats = {}
for module in design.selected_whole_modules_warn():
for cell in module.selected_cells():
if cell.type.str() in cell_stats:
cell_stats[cell.type.str()] += 1
else:
cell_stats[cell.type.str()] = 1
plt.bar(range(len(cell_stats)), height = list(cell_stats.values()),align='center')
plt.xticks(range(len(cell_stats)), list(cell_stats.keys()))
plt.show()
def py_clear_flags(self):
ys.log("Clear Flags - CellStatsPass\n")
p = CellStatsPass()

View File

@ -0,0 +1,22 @@
#!/usr/bin/python3
from pyosys import libyosys as ys
import matplotlib.pyplot as plt
import numpy as np
design = ys.Design()
ys.run_pass("read_verilog ../../tests/simple/fiedler-cooley.v", design);
ys.run_pass("prep", design)
ys.run_pass("opt -full", design)
cell_stats = {}
for module in design.selected_whole_modules_warn():
for cell in module.selected_cells():
if cell.type.str() in cell_stats:
cell_stats[cell.type.str()] += 1
else:
cell_stats[cell.type.str()] = 1
plt.bar(range(len(cell_stats)), height = list(cell_stats.values()),align='center')
plt.xticks(range(len(cell_stats)), list(cell_stats.keys()))
plt.show()

View File

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

View File

@ -0,0 +1,416 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
* Eddie Hung <eddie@fpgeh.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
// [[CITE]] The AIGER And-Inverter Graph (AIG) Format Version 20071012
// Armin Biere. The AIGER And-Inverter Graph (AIG) Format Version 20071012. Technical Report 07/1, October 2011, FMV Reports Series, Institute for Formal Models and Verification, Johannes Kepler University, Altenbergerstr. 69, 4040 Linz, Austria.
// http://fmv.jku.at/papers/Biere-FMV-TR-07-1.pdf
#ifndef _WIN32
#include <libgen.h>
#endif
#include <array>
#include "kernel/yosys.h"
#include "kernel/sigtools.h"
#include "aigerparse.h"
YOSYS_NAMESPACE_BEGIN
AigerReader::AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name)
: design(design), f(f), clk_name(clk_name)
{
module = new RTLIL::Module;
module->name = module_name;
if (design->module(module->name))
log_error("Duplicate definition of module %s!\n", log_id(module->name));
}
void AigerReader::parse_aiger()
{
std::string header;
f >> header;
if (header != "aag" && header != "aig")
log_error("Unsupported AIGER file!\n");
// Parse rest of header
if (!(f >> M >> I >> L >> O >> A))
log_error("Invalid AIGER header\n");
// Optional values
B = C = J = F = 0;
if (f.peek() != ' ') goto end_of_header;
if (!(f >> B)) log_error("Invalid AIGER header\n");
if (f.peek() != ' ') goto end_of_header;
if (!(f >> C)) log_error("Invalid AIGER header\n");
if (f.peek() != ' ') goto end_of_header;
if (!(f >> J)) log_error("Invalid AIGER header\n");
if (f.peek() != ' ') goto end_of_header;
if (!(f >> F)) log_error("Invalid AIGER header\n");
end_of_header:
std::string line;
std::getline(f, line); // Ignore up to start of next line, as standard
// says anything that follows could be used for
// optional sections
log_debug("M=%u I=%u L=%u O=%u A=%u B=%u C=%u J=%u F=%u\n", M, I, L, O, A, B, C, J, F);
line_count = 1;
if (header == "aag")
parse_aiger_ascii();
else if (header == "aig")
parse_aiger_binary();
else
log_abort();
// Parse footer (symbol table, comments, etc.)
unsigned l1;
std::string s;
for (int c = f.peek(); c != EOF; c = f.peek(), ++line_count) {
if (c == 'i' || c == 'l' || c == 'o') {
f.ignore(1);
if (!(f >> l1 >> s))
log_error("Line %u cannot be interpreted as a symbol entry!\n", line_count);
if ((c == 'i' && l1 > inputs.size()) || (c == 'l' && l1 > latches.size()) || (c == 'o' && l1 > outputs.size()))
log_error("Line %u has invalid symbol position!\n", line_count);
RTLIL::Wire* wire;
if (c == 'i') wire = inputs[l1];
else if (c == 'l') wire = latches[l1];
else if (c == 'o') wire = outputs[l1];
else log_abort();
module->rename(wire, stringf("\\%s", s.c_str()));
}
else if (c == 'b' || c == 'j' || c == 'f') {
// TODO
}
else if (c == 'c') {
f.ignore(1);
if (f.peek() == '\n')
break;
// Else constraint (TODO)
}
else
log_error("Line %u: cannot interpret first character '%c'!\n", line_count, c);
std::getline(f, line); // Ignore up to start of next line
}
module->fixup_ports();
design->add(module);
}
static RTLIL::Wire* createWireIfNotExists(RTLIL::Module *module, unsigned literal)
{
const unsigned variable = literal >> 1;
const bool invert = literal & 1;
RTLIL::IdString wire_name(stringf("\\n%d%s", variable, invert ? "_inv" : "")); // FIXME: is "_inv" the right suffix?
RTLIL::Wire *wire = module->wire(wire_name);
if (wire) return wire;
log_debug("Creating %s\n", wire_name.c_str());
wire = module->addWire(wire_name);
if (!invert) return wire;
RTLIL::IdString wire_inv_name(stringf("\\n%d", variable));
RTLIL::Wire *wire_inv = module->wire(wire_inv_name);
if (wire_inv) {
if (module->cell(wire_inv_name)) return wire;
}
else {
log_debug("Creating %s\n", wire_inv_name.c_str());
wire_inv = module->addWire(wire_inv_name);
}
log_debug("Creating %s = ~%s\n", wire_name.c_str(), wire_inv_name.c_str());
module->addNotGate(stringf("\\n%d_not", variable), wire_inv, wire); // FIXME: is "_not" the right suffix?
return wire;
}
void AigerReader::parse_aiger_ascii()
{
std::string line;
std::stringstream ss;
unsigned l1, l2, l3;
// Parse inputs
for (unsigned i = 0; i < I; ++i, ++line_count) {
if (!(f >> l1))
log_error("Line %u cannot be interpreted as an input!\n", line_count);
log_debug("%d is an input\n", l1);
log_assert(!(l1 & 1)); // TODO: Inputs can't be inverted?
RTLIL::Wire *wire = createWireIfNotExists(module, l1);
wire->port_input = true;
inputs.push_back(wire);
}
// Parse latches
RTLIL::Wire *clk_wire = nullptr;
if (L > 0) {
clk_wire = module->wire(clk_name);
log_assert(!clk_wire);
log_debug("Creating %s\n", clk_name.c_str());
clk_wire = module->addWire(clk_name);
clk_wire->port_input = true;
}
for (unsigned i = 0; i < L; ++i, ++line_count) {
if (!(f >> l1 >> l2))
log_error("Line %u cannot be interpreted as a latch!\n", line_count);
log_debug("%d %d is a latch\n", l1, l2);
log_assert(!(l1 & 1)); // TODO: Latch outputs can't be inverted?
RTLIL::Wire *q_wire = createWireIfNotExists(module, l1);
RTLIL::Wire *d_wire = createWireIfNotExists(module, l2);
module->addDffGate(NEW_ID, clk_wire, d_wire, q_wire);
// Reset logic is optional in AIGER 1.9
if (f.peek() == ' ') {
if (!(f >> l3))
log_error("Line %u cannot be interpreted as a latch!\n", line_count);
if (l3 == 0 || l3 == 1)
q_wire->attributes["\\init"] = RTLIL::Const(l3);
else if (l3 == l1) {
//q_wire->attributes["\\init"] = RTLIL::Const(RTLIL::State::Sx);
}
else
log_error("Line %u has invalid reset literal for latch!\n", line_count);
}
else {
// AIGER latches are assumed to be initialized to zero
q_wire->attributes["\\init"] = RTLIL::Const(0);
}
latches.push_back(q_wire);
}
// Parse outputs
for (unsigned i = 0; i < O; ++i, ++line_count) {
if (!(f >> l1))
log_error("Line %u cannot be interpreted as an output!\n", line_count);
log_debug("%d is an output\n", l1);
RTLIL::Wire *wire = createWireIfNotExists(module, l1);
wire->port_output = true;
outputs.push_back(wire);
}
std::getline(f, line); // Ignore up to start of next line
// TODO: Parse bad state properties
for (unsigned i = 0; i < B; ++i, ++line_count)
std::getline(f, line); // Ignore up to start of next line
// TODO: Parse invariant constraints
for (unsigned i = 0; i < C; ++i, ++line_count)
std::getline(f, line); // Ignore up to start of next line
// TODO: Parse justice properties
for (unsigned i = 0; i < J; ++i, ++line_count)
std::getline(f, line); // Ignore up to start of next line
// TODO: Parse fairness constraints
for (unsigned i = 0; i < F; ++i, ++line_count)
std::getline(f, line); // Ignore up to start of next line
// Parse AND
for (unsigned i = 0; i < A; ++i) {
if (!(f >> l1 >> l2 >> l3))
log_error("Line %u cannot be interpreted as an AND!\n", line_count);
log_debug("%d %d %d is an AND\n", l1, l2, l3);
log_assert(!(l1 & 1)); // TODO: Output of ANDs can't be inverted?
RTLIL::Wire *o_wire = createWireIfNotExists(module, l1);
RTLIL::Wire *i1_wire = createWireIfNotExists(module, l2);
RTLIL::Wire *i2_wire = createWireIfNotExists(module, l3);
module->addAndGate(NEW_ID, i1_wire, i2_wire, o_wire);
}
std::getline(f, line); // Ignore up to start of next line
}
static unsigned parse_next_delta_literal(std::istream &f, unsigned ref)
{
unsigned x = 0, i = 0;
unsigned char ch;
while ((ch = f.get()) & 0x80)
x |= (ch & 0x7f) << (7 * i++);
return ref - (x | (ch << (7 * i)));
}
void AigerReader::parse_aiger_binary()
{
unsigned l1, l2, l3;
std::string line;
// Parse inputs
for (unsigned i = 1; i <= I; ++i) {
RTLIL::Wire *wire = createWireIfNotExists(module, i << 1);
wire->port_input = true;
inputs.push_back(wire);
}
// Parse latches
RTLIL::Wire *clk_wire = nullptr;
if (L > 0) {
clk_wire = module->wire(clk_name);
log_assert(!clk_wire);
log_debug("Creating %s\n", clk_name.c_str());
clk_wire = module->addWire(clk_name);
clk_wire->port_input = true;
}
l1 = (I+1) * 2;
for (unsigned i = 0; i < L; ++i, ++line_count, l1 += 2) {
if (!(f >> l2))
log_error("Line %u cannot be interpreted as a latch!\n", line_count);
log_debug("%d %d is a latch\n", l1, l2);
RTLIL::Wire *q_wire = createWireIfNotExists(module, l1);
RTLIL::Wire *d_wire = createWireIfNotExists(module, l2);
module->addDff(NEW_ID, clk_wire, d_wire, q_wire);
// Reset logic is optional in AIGER 1.9
if (f.peek() == ' ') {
if (!(f >> l3))
log_error("Line %u cannot be interpreted as a latch!\n", line_count);
if (l3 == 0 || l3 == 1)
q_wire->attributes["\\init"] = RTLIL::Const(l3);
else if (l3 == l1) {
//q_wire->attributes["\\init"] = RTLIL::Const(RTLIL::State::Sx);
}
else
log_error("Line %u has invalid reset literal for latch!\n", line_count);
}
else {
// AIGER latches are assumed to be initialized to zero
q_wire->attributes["\\init"] = RTLIL::Const(0);
}
latches.push_back(q_wire);
}
// Parse outputs
for (unsigned i = 0; i < O; ++i, ++line_count) {
if (!(f >> l1))
log_error("Line %u cannot be interpreted as an output!\n", line_count);
log_debug("%d is an output\n", l1);
RTLIL::Wire *wire = createWireIfNotExists(module, l1);
wire->port_output = true;
outputs.push_back(wire);
}
std::getline(f, line); // Ignore up to start of next line
// TODO: Parse bad state properties
for (unsigned i = 0; i < B; ++i, ++line_count)
std::getline(f, line); // Ignore up to start of next line
// TODO: Parse invariant constraints
for (unsigned i = 0; i < C; ++i, ++line_count)
std::getline(f, line); // Ignore up to start of next line
// TODO: Parse justice properties
for (unsigned i = 0; i < J; ++i, ++line_count)
std::getline(f, line); // Ignore up to start of next line
// TODO: Parse fairness constraints
for (unsigned i = 0; i < F; ++i, ++line_count)
std::getline(f, line); // Ignore up to start of next line
// Parse AND
l1 = (I+L+1) << 1;
for (unsigned i = 0; i < A; ++i, ++line_count, l1 += 2) {
l2 = parse_next_delta_literal(f, l1);
l3 = parse_next_delta_literal(f, l2);
log_debug("%d %d %d is an AND\n", l1, l2, l3);
log_assert(!(l1 & 1)); // TODO: Output of ANDs can't be inverted?
RTLIL::Wire *o_wire = createWireIfNotExists(module, l1);
RTLIL::Wire *i1_wire = createWireIfNotExists(module, l2);
RTLIL::Wire *i2_wire = createWireIfNotExists(module, l3);
RTLIL::Cell *and_cell = module->addCell(NEW_ID, "$_AND_");
and_cell->setPort("\\A", i1_wire);
and_cell->setPort("\\B", i2_wire);
and_cell->setPort("\\Y", o_wire);
}
}
struct AigerFrontend : public Frontend {
AigerFrontend() : Frontend("aiger", "read AIGER file") { }
void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" read_aiger [options] [filename]\n");
log("\n");
log("Load module from an AIGER file into the current design.\n");
log("\n");
log(" -module_name <module_name>\n");
log(" Name of module to be created (default: <filename>)"
#ifdef _WIN32
"top" // FIXME
#else
"<filename>"
#endif
")\n");
log("\n");
log(" -clk_name <wire_name>\n");
log(" AIGER latches to be transformed into posedge DFFs clocked by wire of");
log(" this name (default: clk)\n");
log("\n");
}
void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing AIGER frontend.\n");
RTLIL::IdString clk_name = "\\clk";
RTLIL::IdString module_name;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
std::string arg = args[argidx];
if (arg == "-module_name" && argidx+1 < args.size()) {
module_name = RTLIL::escape_id(args[++argidx]);
continue;
}
if (arg == "-clk_name" && argidx+1 < args.size()) {
clk_name = RTLIL::escape_id(args[++argidx]);
continue;
}
break;
}
extra_args(f, filename, args, argidx);
if (module_name.empty()) {
#ifdef _WIN32
module_name = "top"; // FIXME: basename equivalent on Win32?
#else
char* bn = strdup(filename.c_str());
module_name = RTLIL::escape_id(bn);
free(bn);
#endif
}
AigerReader reader(design, *f, module_name, clk_name);
reader.parse_aiger();
}
} AigerFrontend;
YOSYS_NAMESPACE_END

View File

@ -0,0 +1,51 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
* Eddie Hung <eddie@fpgeh.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#ifndef ABC_AIGERPARSE
#define ABC_AIGERPARSE
#include "kernel/yosys.h"
YOSYS_NAMESPACE_BEGIN
struct AigerReader
{
RTLIL::Design *design;
std::istream &f;
RTLIL::IdString clk_name;
RTLIL::Module *module;
unsigned M, I, L, O, A;
unsigned B, C, J, F; // Optional in AIGER 1.9
unsigned line_count;
std::vector<RTLIL::Wire*> inputs;
std::vector<RTLIL::Wire*> latches;
std::vector<RTLIL::Wire*> outputs;
AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name);
void parse_aiger();
void parse_aiger_ascii();
void parse_aiger_binary();
};
YOSYS_NAMESPACE_END
#endif

View File

@ -45,8 +45,8 @@ namespace AST {
// instantiate global variables (private API)
namespace AST_INTERNAL {
bool flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog, flag_dump_rtlil, flag_nolatches, flag_nomeminit;
bool flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire;
bool flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches, flag_nomeminit;
bool flag_nomem2reg, flag_mem2reg, flag_noblackbox, flag_lib, flag_nowb, flag_noopt, flag_icells, flag_autowire;
AstNode *current_ast, *current_ast_mod;
std::map<std::string, AstNode*> current_scope;
const dict<RTLIL::SigBit, RTLIL::SigBit> *genRTLIL_subst_ptr = NULL;
@ -431,9 +431,12 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
break;
case AST_RANGE:
if (range_valid)
fprintf(f, "[%d:%d]", range_left, range_right);
else {
if (range_valid) {
if (range_swapped)
fprintf(f, "[%d:%d]", range_right, range_left);
else
fprintf(f, "[%d:%d]", range_left, range_right);
} else {
for (auto child : children) {
fprintf(f, "%c", first ? '[' : ':');
child->dumpVlog(f, "");
@ -562,7 +565,8 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const
case AST_CONCAT:
fprintf(f, "{");
for (auto child : children) {
for (int i = GetSize(children)-1; i >= 0; i--) {
auto child = children[i];
if (!first)
fprintf(f, ", ");
child->dumpVlog(f, "");
@ -926,28 +930,106 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast
ast_before_simplify = ast->clone();
if (flag_dump_ast1) {
log("Dumping Verilog AST before simplification:\n");
log("Dumping AST before simplification:\n");
ast->dumpAst(NULL, " ");
log("--- END OF AST DUMP ---\n");
}
if (flag_dump_vlog1) {
log("Dumping Verilog AST before simplification:\n");
ast->dumpVlog(NULL, " ");
log("--- END OF AST DUMP ---\n");
}
if (!defer)
{
bool blackbox_module = flag_lib;
if (!blackbox_module && !flag_noblackbox) {
blackbox_module = true;
for (auto child : ast->children) {
if (child->type == AST_WIRE && (child->is_input || child->is_output))
continue;
if (child->type == AST_PARAMETER || child->type == AST_LOCALPARAM)
continue;
if (child->type == AST_CELL && child->children.size() > 0 && child->children[0]->type == AST_CELLTYPE &&
(child->children[0]->str == "$specify2" || child->children[0]->str == "$specify3" || child->children[0]->str == "$specrule"))
continue;
blackbox_module = false;
break;
}
}
while (ast->simplify(!flag_noopt, false, false, 0, -1, false, false)) { }
if (flag_dump_ast2) {
log("Dumping Verilog AST after simplification:\n");
log("Dumping AST after simplification:\n");
ast->dumpAst(NULL, " ");
log("--- END OF AST DUMP ---\n");
}
if (flag_dump_vlog) {
log("Dumping Verilog AST (as requested by dump_vlog option):\n");
if (flag_dump_vlog2) {
log("Dumping Verilog AST after simplification:\n");
ast->dumpVlog(NULL, " ");
log("--- END OF AST DUMP ---\n");
}
if (flag_lib) {
if (flag_nowb && ast->attributes.count("\\whitebox")) {
delete ast->attributes.at("\\whitebox");
ast->attributes.erase("\\whitebox");
}
if (ast->attributes.count("\\lib_whitebox")) {
if (!flag_lib || flag_nowb) {
delete ast->attributes.at("\\lib_whitebox");
ast->attributes.erase("\\lib_whitebox");
} else {
if (ast->attributes.count("\\whitebox")) {
delete ast->attributes.at("\\whitebox");
ast->attributes.erase("\\whitebox");
}
AstNode *n = ast->attributes.at("\\lib_whitebox");
ast->attributes["\\whitebox"] = n;
ast->attributes.erase("\\lib_whitebox");
}
}
if (!blackbox_module && ast->attributes.count("\\blackbox")) {
AstNode *n = ast->attributes.at("\\blackbox");
if (n->type != AST_CONSTANT)
log_file_error(ast->filename, ast->linenum, "Got blackbox attribute with non-constant value!\n");
blackbox_module = n->asBool();
}
if (blackbox_module && ast->attributes.count("\\whitebox")) {
AstNode *n = ast->attributes.at("\\whitebox");
if (n->type != AST_CONSTANT)
log_file_error(ast->filename, ast->linenum, "Got whitebox attribute with non-constant value!\n");
blackbox_module = !n->asBool();
}
if (ast->attributes.count("\\noblackbox")) {
if (blackbox_module) {
AstNode *n = ast->attributes.at("\\noblackbox");
if (n->type != AST_CONSTANT)
log_file_error(ast->filename, ast->linenum, "Got noblackbox attribute with non-constant value!\n");
blackbox_module = !n->asBool();
}
delete ast->attributes.at("\\noblackbox");
ast->attributes.erase("\\noblackbox");
}
if (blackbox_module)
{
if (ast->attributes.count("\\whitebox")) {
delete ast->attributes.at("\\whitebox");
ast->attributes.erase("\\whitebox");
}
if (ast->attributes.count("\\lib_whitebox")) {
delete ast->attributes.at("\\lib_whitebox");
ast->attributes.erase("\\lib_whitebox");
}
std::vector<AstNode*> new_children;
for (auto child : ast->children) {
if (child->type == AST_WIRE && (child->is_input || child->is_output)) {
@ -956,12 +1038,19 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast
child->delete_children();
child->children.push_back(AstNode::mkconst_int(0, false, 0));
new_children.push_back(child);
} else if (child->type == AST_CELL && child->children.size() > 0 && child->children[0]->type == AST_CELLTYPE &&
(child->children[0]->str == "$specify2" || child->children[0]->str == "$specify3" || child->children[0]->str == "$specrule")) {
new_children.push_back(child);
} else {
delete child;
}
}
ast->children.swap(new_children);
ast->attributes["\\blackbox"] = AstNode::mkconst_int(1, false);
if (ast->attributes.count("\\blackbox") == 0) {
ast->attributes["\\blackbox"] = AstNode::mkconst_int(1, false);
}
}
ignoreThisSignalsInInitial = RTLIL::SigSpec();
@ -1000,7 +1089,9 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast
current_module->nomeminit = flag_nomeminit;
current_module->nomem2reg = flag_nomem2reg;
current_module->mem2reg = flag_mem2reg;
current_module->noblackbox = flag_noblackbox;
current_module->lib = flag_lib;
current_module->nowb = flag_nowb;
current_module->noopt = flag_noopt;
current_module->icells = flag_icells;
current_module->autowire = flag_autowire;
@ -1016,20 +1107,23 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast
}
// 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 no_dump_ptr, bool dump_vlog, bool dump_rtlil,
bool nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool nooverwrite, bool overwrite, bool defer, bool autowire)
void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool no_dump_ptr, bool dump_vlog1, bool dump_vlog2, bool dump_rtlil,
bool nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool noblackbox, bool lib, bool nowb, bool noopt, bool icells, bool nooverwrite, bool overwrite, bool defer, bool autowire)
{
current_ast = ast;
flag_dump_ast1 = dump_ast1;
flag_dump_ast2 = dump_ast2;
flag_no_dump_ptr = no_dump_ptr;
flag_dump_vlog = dump_vlog;
flag_dump_vlog1 = dump_vlog1;
flag_dump_vlog2 = dump_vlog2;
flag_dump_rtlil = dump_rtlil;
flag_nolatches = nolatches;
flag_nomeminit = nomeminit;
flag_nomem2reg = nomem2reg;
flag_mem2reg = mem2reg;
flag_noblackbox = noblackbox;
flag_lib = lib;
flag_nowb = nowb;
flag_noopt = noopt;
flag_icells = icells;
flag_autowire = autowire;
@ -1357,12 +1451,15 @@ std::string AstModule::derive_common(RTLIL::Design *design, dict<RTLIL::IdString
current_ast = NULL;
flag_dump_ast1 = false;
flag_dump_ast2 = false;
flag_dump_vlog = false;
flag_dump_vlog1 = false;
flag_dump_vlog2 = false;
flag_nolatches = nolatches;
flag_nomeminit = nomeminit;
flag_nomem2reg = nomem2reg;
flag_mem2reg = mem2reg;
flag_noblackbox = noblackbox;
flag_lib = lib;
flag_nowb = nowb;
flag_noopt = noopt;
flag_icells = icells;
flag_autowire = autowire;

View File

@ -214,6 +214,8 @@ namespace AST
MEM2REG_FL_SET_ASYNC = 0x00000800,
MEM2REG_FL_EQ2 = 0x00001000,
MEM2REG_FL_CMPLX_LHS = 0x00002000,
MEM2REG_FL_CONST_LHS = 0x00004000,
MEM2REG_FL_VAR_LHS = 0x00008000,
/* proc flags */
MEM2REG_FL_EQ1 = 0x01000000,
@ -237,6 +239,7 @@ namespace AST
bool has_const_only_constructs(bool &recommend_const_eval);
void replace_variables(std::map<std::string, varinfo_t> &variables, AstNode *fcall);
AstNode *eval_const_function(AstNode *fcall);
bool is_simple_const_expr();
// create a human-readable text representation of the AST (for debugging)
void dumpAst(FILE *f, std::string indent) const;
@ -279,14 +282,14 @@ 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 no_dump_ptr, bool dump_vlog, bool dump_rtlil, bool nolatches, bool nomeminit,
bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool nooverwrite, bool overwrite, bool defer, bool autowire);
void process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool no_dump_ptr, bool dump_vlog1, bool dump_vlog2, bool dump_rtlil, bool nolatches, bool nomeminit,
bool nomem2reg, bool mem2reg, bool noblackbox, bool lib, bool nowb, bool noopt, bool icells, bool nooverwrite, bool overwrite, bool defer, bool autowire);
// parametric modules are supported directly by the AST library
// therefore we need our own derivate of RTLIL::Module with overloaded virtual functions
struct AstModule : RTLIL::Module {
AstNode *ast;
bool nolatches, nomeminit, nomem2reg, mem2reg, lib, noopt, icells, autowire;
bool nolatches, nomeminit, nomem2reg, mem2reg, noblackbox, lib, nowb, noopt, icells, autowire;
~AstModule() YS_OVERRIDE;
RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, bool mayfail) YS_OVERRIDE;
RTLIL::IdString derive(RTLIL::Design *design, dict<RTLIL::IdString, RTLIL::Const> parameters, dict<RTLIL::IdString, RTLIL::Module*> interfaces, dict<RTLIL::IdString, RTLIL::IdString> modports, bool mayfail) YS_OVERRIDE;

View File

@ -525,7 +525,16 @@ struct AST_INTERNAL::ProcessGenerator
}
if (last_generated_case != NULL && ast->get_bool_attribute("\\full_case") && default_case == NULL) {
#if 0
// this is a valid transformation, but as optimization it is premature.
// better: add a default case that assigns 'x' to everything, and let later
// optimizations take care of the rest
last_generated_case->compare.clear();
#else
default_case = new RTLIL::CaseRule;
addChunkActions(default_case->actions, this_case_eq_ltemp, SigSpec(State::Sx, GetSize(this_case_eq_rvalue)));
sw->cases.push_back(default_case);
#endif
} else {
if (default_case == NULL) {
default_case = new RTLIL::CaseRule;
@ -544,7 +553,11 @@ struct AST_INTERNAL::ProcessGenerator
break;
case AST_WIRE:
log_file_error(ast->filename, ast->linenum, "Found wire declaration in block without label!\n");
log_file_error(ast->filename, ast->linenum, "Found reg declaration in block without label!\n");
break;
case AST_ASSIGN:
log_file_error(ast->filename, ast->linenum, "Found continous assignment in always/initial block!\n");
break;
case AST_PARAMETER:
@ -632,6 +645,8 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
if (!id_ast->children[0]->range_valid)
log_file_error(filename, linenum, "Failed to detect width of memory access `%s'!\n", str.c_str());
this_width = id_ast->children[0]->range_left - id_ast->children[0]->range_right + 1;
if (children.size() > 1)
range = children[1];
} else
log_file_error(filename, linenum, "Failed to detect width for identifier %s!\n", str.c_str());
if (range) {
@ -644,7 +659,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
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_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;
this_width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1;
delete left_at_zero_ast;
delete right_at_zero_ast;
} else
@ -792,7 +807,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun
// everything should have been handled above -> print error if not.
default:
for (auto f : log_files)
current_ast->dumpAst(f, "verilog-ast> ");
current_ast_mod->dumpAst(f, "verilog-ast> ");
log_file_error(filename, linenum, "Don't know how to detect sign and width for %s node!\n", type2str(type).c_str());
}
@ -942,16 +957,15 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
// simply return the corresponding RTLIL::SigSpec for an AST_CONSTANT node
case AST_CONSTANT:
case AST_REALVALUE:
{
if (width_hint < 0)
detectSignWidth(width_hint, sign_hint);
is_signed = sign_hint;
return RTLIL::SigSpec(bitsAsConst());
}
case AST_REALVALUE:
{
if (type == AST_CONSTANT)
return RTLIL::SigSpec(bitsAsConst());
RTLIL::SigSpec sig = realAsConst(width_hint);
log_file_warning(filename, linenum, "converting real value %e to binary %s.\n", realvalue, log_signal(sig));
return sig;
@ -1035,7 +1049,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
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_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;
int width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1;
AstNode *fake_ast = new AstNode(AST_NONE, clone(), children[0]->children.size() >= 2 ?
children[0]->children[1]->clone() : children[0]->children[0]->clone());
fake_ast->children[0]->delete_children();
@ -1410,10 +1424,16 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
if (GetSize(en) != 1)
en = current_module->ReduceBool(NEW_ID, en);
std::stringstream sstr;
sstr << celltype << "$" << filename << ":" << linenum << "$" << (autoidx++);
IdString cellname;
if (str.empty()) {
std::stringstream sstr;
sstr << celltype << "$" << filename << ":" << linenum << "$" << (autoidx++);
cellname = sstr.str();
} else {
cellname = str;
}
RTLIL::Cell *cell = current_module->addCell(sstr.str(), celltype);
RTLIL::Cell *cell = current_module->addCell(cellname, celltype);
cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
for (auto &attr : attributes) {
@ -1472,10 +1492,12 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
continue;
}
if (child->type == AST_PARASET) {
int extra_const_flags = 0;
IdString paraname = child->str.empty() ? stringf("$%d", ++para_counter) : child->str;
if (child->children[0]->type == AST_REALVALUE) {
log_file_warning(filename, linenum, "Replacing floating point parameter %s.%s = %f with string.\n",
log_id(cell), log_id(paraname), child->children[0]->realvalue);
extra_const_flags = RTLIL::CONST_FLAG_REAL;
auto strnode = AstNode::mkconst_str(stringf("%f", child->children[0]->realvalue));
strnode->cloneInto(child->children[0]);
delete strnode;
@ -1484,6 +1506,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
log_file_error(filename, linenum, "Parameter %s.%s with non-constant value!\n",
log_id(cell), log_id(paraname));
cell->parameters[paraname] = child->children[0]->asParaConst();
cell->parameters[paraname].flags |= extra_const_flags;
continue;
}
if (child->type == AST_ARGUMENT) {
@ -1503,9 +1526,29 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
}
for (auto &attr : attributes) {
if (attr.second->type != AST_CONSTANT)
log_file_error(filename, linenum, "Attribute `%s' with non-constant value!\n", attr.first.c_str());
log_file_error(filename, linenum, "Attribute `%s' with non-constant value.\n", attr.first.c_str());
cell->attributes[attr.first] = attr.second->asAttrConst();
}
if (cell->type.in("$specify2", "$specify3")) {
int src_width = GetSize(cell->getPort("\\SRC"));
int dst_width = GetSize(cell->getPort("\\DST"));
bool full = cell->getParam("\\FULL").as_bool();
if (!full && src_width != dst_width)
log_file_error(filename, linenum, "Parallel specify SRC width does not match DST width.\n");
if (cell->type == "$specify3") {
int dat_width = GetSize(cell->getPort("\\DAT"));
if (dat_width != dst_width)
log_file_error(filename, linenum, "Specify DAT width does not match DST width.\n");
}
cell->setParam("\\SRC_WIDTH", Const(src_width));
cell->setParam("\\DST_WIDTH", Const(dst_width));
}
if (cell->type == "$specrule") {
int src_width = GetSize(cell->getPort("\\SRC"));
int dst_width = GetSize(cell->getPort("\\DST"));
cell->setParam("\\SRC_WIDTH", Const(src_width));
cell->setParam("\\DST_WIDTH", Const(dst_width));
}
}
break;
@ -1566,7 +1609,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
// everything should have been handled above -> print error if not.
default:
for (auto f : log_files)
current_ast->dumpAst(f, "verilog-ast> ");
current_ast_mod->dumpAst(f, "verilog-ast> ");
type_name = type2str(type);
log_file_error(filename, linenum, "Don't know how to generate RTLIL code for %s node!\n", type_name.c_str());
}

View File

@ -50,7 +50,6 @@ using namespace AST_INTERNAL;
bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, int width_hint, bool sign_hint, bool in_param)
{
static int recursion_counter = 0;
static pair<string, int> last_blocking_assignment_warn;
static bool deep_recursion_warning = false;
if (recursion_counter++ == 1000 && deep_recursion_warning) {
@ -72,7 +71,6 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (stage == 0)
{
log_assert(type == AST_MODULE || type == AST_INTERFACE);
last_blocking_assignment_warn = pair<string, int>();
deep_recursion_warning = true;
while (simplify(const_fold, at_zero, in_lvalue, 1, width_hint, sign_hint, in_param)) { }
@ -113,6 +111,9 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
if (memflags & AstNode::MEM2REG_FL_CMPLX_LHS)
goto verbose_activate;
if ((memflags & AstNode::MEM2REG_FL_CONST_LHS) && !(memflags & AstNode::MEM2REG_FL_VAR_LHS))
goto verbose_activate;
// log("Note: Not replacing memory %s with list of registers (flags=0x%08lx).\n", mem->str.c_str(), long(memflags));
continue;
@ -137,9 +138,15 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
int mem_width, mem_size, addr_bits;
node->meminfo(mem_width, mem_size, addr_bits);
int data_range_left = node->children[0]->range_left;
int data_range_right = node->children[0]->range_right;
if (node->children[0]->range_swapped)
std::swap(data_range_left, data_range_right);
for (int i = 0; i < mem_size; i++) {
AstNode *reg = new AstNode(AST_WIRE, new AstNode(AST_RANGE,
mkconst_int(mem_width-1, true), mkconst_int(0, true)));
mkconst_int(data_range_left, true), mkconst_int(data_range_right, true)));
reg->str = stringf("%s[%d]", node->str.c_str(), i);
reg->is_reg = true;
reg->is_signed = node->is_signed;
@ -325,6 +332,15 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
for (size_t i = 0; i < children.size(); i++) {
AstNode *node = children[i];
if (node->type == AST_WIRE) {
if (node->children.size() == 1 && node->children[0]->type == AST_RANGE) {
for (auto c : node->children[0]->children) {
if (!c->is_simple_const_expr()) {
if (attributes.count("\\dynports"))
delete attributes.at("\\dynports");
attributes["\\dynports"] = AstNode::mkconst_int(1, true);
}
}
}
if (this_wire_scope.count(node->str) > 0) {
AstNode *first_node = this_wire_scope[node->str];
if (first_node->is_input && node->is_reg)
@ -642,6 +658,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
// (iterate by index as e.g. auto wires can add new children in the process)
for (size_t i = 0; i < children.size(); i++) {
bool did_something_here = true;
bool backup_flag_autowire = flag_autowire;
if ((type == AST_GENFOR || type == AST_FOR) && i >= 3)
break;
if ((type == AST_GENIF || type == AST_GENCASE) && i >= 1)
@ -652,6 +669,8 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
break;
if (type == AST_PREFIX && i >= 1)
break;
if (type == AST_DEFPARAM && i == 0)
flag_autowire = true;
while (did_something_here && i < children.size()) {
bool const_fold_here = const_fold, in_lvalue_here = in_lvalue;
int width_hint_here = width_hint;
@ -686,6 +705,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
children.erase(children.begin() + (i--));
did_something = true;
}
flag_autowire = backup_flag_autowire;
}
for (auto &attr : attributes) {
while (attr.second->simplify(true, false, false, stage, -1, false, true))
@ -934,12 +954,15 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
}
}
if (current_scope.count(str) == 0) {
// log_warning("Creating auto-wire `%s' in module `%s'.\n", str.c_str(), current_ast_mod->str.c_str());
AstNode *auto_wire = new AstNode(AST_AUTOWIRE);
auto_wire->str = str;
current_ast_mod->children.push_back(auto_wire);
current_scope[str] = auto_wire;
did_something = true;
if (flag_autowire || str == "\\$global_clock") {
AstNode *auto_wire = new AstNode(AST_AUTOWIRE);
auto_wire->str = str;
current_ast_mod->children.push_back(auto_wire);
current_scope[str] = auto_wire;
did_something = true;
} else {
log_file_error(filename, linenum, "Identifier `%s' is implicitly declared and `default_nettype is set to none.\n", str.c_str());
}
}
if (id2ast != current_scope[str]) {
id2ast = current_scope[str];
@ -959,6 +982,9 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
int data_range_left = id2ast->children[0]->range_left;
int data_range_right = id2ast->children[0]->range_right;
if (id2ast->children[0]->range_swapped)
std::swap(data_range_left, data_range_right);
std::stringstream sstr;
sstr << "$mem2bits$" << str << "$" << filename << ":" << linenum << "$" << (autoidx++);
std::string wire_id = sstr.str();
@ -1004,7 +1030,26 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
log_file_error(filename, linenum, "While loops are only allowed in constant functions!\n");
if (type == AST_REPEAT)
log_file_error(filename, linenum, "Repeat loops are only allowed in constant functions!\n");
{
AstNode *count = children[0];
AstNode *body = children[1];
// eval count expression
while (count->simplify(true, false, false, stage, 32, true, false)) { }
if (count->type != AST_CONSTANT)
log_file_error(filename, linenum, "Repeat loops outside must have constant repeat counts!\n");
// convert to a block with the body repeated n times
type = AST_BLOCK;
children.clear();
for (int i = 0; i < count->bitsAsConst().as_int(); i++)
children.insert(children.begin(), body->clone());
delete count;
delete body;
did_something = true;
}
// unroll for loops and generate-for blocks
if ((type == AST_GENFOR || type == AST_FOR) && children.size() != 0)
@ -1040,7 +1085,12 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
// eval 1st expression
AstNode *varbuf = init_ast->children[1]->clone();
while (varbuf->simplify(true, false, false, stage, 32, true, false)) { }
{
int expr_width_hint = -1;
bool expr_sign_hint = true;
varbuf->detectSignWidth(expr_width_hint, expr_sign_hint);
while (varbuf->simplify(true, false, false, stage, 32, true, false)) { }
}
if (varbuf->type != AST_CONSTANT)
log_file_error(filename, linenum, "Right hand side of 1st expression of generate for-loop is not constant!\n");
@ -1062,7 +1112,12 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
{
// eval 2nd expression
AstNode *buf = while_ast->clone();
while (buf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { }
{
int expr_width_hint = -1;
bool expr_sign_hint = true;
buf->detectSignWidth(expr_width_hint, expr_sign_hint);
while (buf->simplify(true, false, false, stage, expr_width_hint, expr_sign_hint, false)) { }
}
if (buf->type != AST_CONSTANT)
log_file_error(filename, linenum, "2nd expression of generate for-loop is not constant!\n");
@ -1103,7 +1158,12 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
// eval 3rd expression
buf = next_ast->children[1]->clone();
while (buf->simplify(true, false, false, stage, 32, true, false)) { }
{
int expr_width_hint = -1;
bool expr_sign_hint = true;
buf->detectSignWidth(expr_width_hint, expr_sign_hint);
while (buf->simplify(true, false, false, stage, expr_width_hint, expr_sign_hint, true)) { }
}
if (buf->type != AST_CONSTANT)
log_file_error(filename, linenum, "Right hand side of 3rd expression of generate for-loop is not constant!\n");
@ -1112,6 +1172,13 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
varbuf->children[0] = buf;
}
if (type == AST_FOR) {
AstNode *buf = next_ast->clone();
delete buf->children[1];
buf->children[1] = varbuf->children[0]->clone();
current_block->children.insert(current_block->children.begin() + current_block_idx++, buf);
}
current_scope[varbuf->str] = backup_scope_varbuf;
delete varbuf;
delete_children();
@ -1492,6 +1559,7 @@ skip_dynamic_range_lvalue_expansion:;
newNode->children.push_back(assign_en);
AstNode *assertnode = new AstNode(type);
assertnode->str = str;
assertnode->children.push_back(new AstNode(AST_IDENTIFIER));
assertnode->children.push_back(new AstNode(AST_IDENTIFIER));
assertnode->children[0]->str = id_check;
@ -1537,6 +1605,7 @@ skip_dynamic_range_lvalue_expansion:;
current_scope[wire_tmp->str] = wire_tmp;
wire_tmp->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
while (wire_tmp->simplify(true, false, false, 1, -1, false, false)) { }
wire_tmp->is_logic = true;
AstNode *wire_tmp_id = new AstNode(AST_IDENTIFIER);
wire_tmp_id->str = wire_tmp->str;
@ -1572,14 +1641,6 @@ skip_dynamic_range_lvalue_expansion:;
sstr << "$memwr$" << children[0]->str << "$" << filename << ":" << linenum << "$" << (autoidx++);
std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA", id_en = sstr.str() + "_EN";
if (type == AST_ASSIGN_EQ) {
pair<string, int> this_blocking_assignment_warn(filename, linenum);
if (this_blocking_assignment_warn != last_blocking_assignment_warn)
log_warning("Blocking assignment to memory in line %s:%d is handled like a non-blocking assignment.\n",
filename.c_str(), linenum);
last_blocking_assignment_warn = this_blocking_assignment_warn;
}
int mem_width, mem_size, addr_bits;
bool mem_signed = children[0]->id2ast->is_signed;
children[0]->id2ast->meminfo(mem_width, mem_size, addr_bits);
@ -1689,7 +1750,7 @@ skip_dynamic_range_lvalue_expansion:;
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_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;
int width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1;
assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER),
new AstNode(AST_SHIFT_LEFT, children[1]->clone(), offset_ast->clone()));
@ -1778,7 +1839,7 @@ skip_dynamic_range_lvalue_expansion:;
if (str == "\\$past")
{
if (width_hint <= 0)
if (width_hint < 0)
goto replace_fcall_later;
int num_steps = 1;
@ -2162,6 +2223,8 @@ skip_dynamic_range_lvalue_expansion:;
}
newNode = readmem(str == "\\$readmemh", node_filename->bitsAsConst().decode_string(), node_memory->id2ast, start_addr, finish_addr, unconditional_init);
delete node_filename;
delete node_memory;
goto apply_newNode;
}
@ -2203,6 +2266,8 @@ skip_dynamic_range_lvalue_expansion:;
std::map<std::string, std::string> replace_rules;
vector<AstNode*> added_mod_children;
dict<std::string, AstNode*> wire_cache;
vector<AstNode*> new_stmts;
vector<AstNode*> output_assignments;
if (current_block == NULL)
{
@ -2327,8 +2392,8 @@ skip_dynamic_range_lvalue_expansion:;
wire->port_id = 0;
wire->is_input = false;
wire->is_output = false;
if (!child->is_output)
wire->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
wire->is_reg = true;
wire->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
wire_cache[child->str] = wire;
current_ast_mod->children.push_back(wire);
@ -2350,13 +2415,10 @@ skip_dynamic_range_lvalue_expansion:;
new AstNode(AST_ASSIGN_EQ, wire_id, arg) :
new AstNode(AST_ASSIGN_EQ, arg, wire_id);
assign->children[0]->was_checked = true;
for (auto it = current_block->children.begin(); it != current_block->children.end(); it++) {
if (*it != current_block_child)
continue;
current_block->children.insert(it, assign);
break;
}
if (child->is_input)
new_stmts.push_back(assign);
else
output_assignments.push_back(assign);
}
}
@ -2370,15 +2432,19 @@ skip_dynamic_range_lvalue_expansion:;
{
AstNode *stmt = child->clone();
stmt->replace_ids(prefix, replace_rules);
for (auto it = current_block->children.begin(); it != current_block->children.end(); it++) {
if (*it != current_block_child)
continue;
current_block->children.insert(it, stmt);
break;
}
new_stmts.push_back(stmt);
}
new_stmts.insert(new_stmts.end(), output_assignments.begin(), output_assignments.end());
for (auto it = current_block->children.begin(); ; it++) {
log_assert(it != current_block->children.end());
if (*it == current_block_child) {
current_block->children.insert(it, new_stmts.begin(), new_stmts.end());
break;
}
}
replace_fcall_with_id:
if (type == AST_FCALL) {
delete_children();
@ -2848,7 +2914,11 @@ void AstNode::expand_genblock(std::string index_var, std::string prefix, std::ma
for (size_t i = 0; i < children.size(); i++) {
AstNode *child = children[i];
if (child->type != AST_FUNCTION && child->type != AST_TASK && child->type != AST_PREFIX)
// AST_PREFIX member names should not be prefixed; a nested AST_PREFIX
// still needs to recursed-into
if (type == AST_PREFIX && i == 1 && child->type == AST_IDENTIFIER)
continue;
if (child->type != AST_FUNCTION && child->type != AST_TASK)
child->expand_genblock(index_var, prefix, name_map);
}
@ -2903,7 +2973,7 @@ void AstNode::mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg
dict<AstNode*, uint32_t> &mem2reg_candidates, dict<AstNode*, uint32_t> &proc_flags, uint32_t &flags)
{
uint32_t children_flags = 0;
int ignore_children_counter = 0;
int lhs_children_counter = 0;
if (type == AST_ASSIGN || type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ)
{
@ -2929,6 +2999,16 @@ void AstNode::mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg
proc_flags[mem] |= AstNode::MEM2REG_FL_EQ1;
}
// for proper (non-init) writes: remember if this is a constant index or not
if ((flags & MEM2REG_FL_INIT) == 0) {
if (children[0]->children.size() && children[0]->children[0]->type == AST_RANGE && children[0]->children[0]->children.size()) {
if (children[0]->children[0]->children[0]->type == AST_CONSTANT)
mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_CONST_LHS;
else
mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_VAR_LHS;
}
}
// remember where this is
if (flags & MEM2REG_FL_INIT) {
if (!(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_SET_INIT))
@ -2941,7 +3021,7 @@ void AstNode::mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg
}
}
ignore_children_counter = 1;
lhs_children_counter = 1;
}
if (type == AST_IDENTIFIER && id2ast && id2ast->type == AST_MEMORY)
@ -2984,12 +3064,23 @@ void AstNode::mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg
log_assert((flags & ~0x000000ff) == 0);
for (auto child : children)
if (ignore_children_counter > 0)
ignore_children_counter--;
else if (proc_flags_p)
{
if (lhs_children_counter > 0) {
lhs_children_counter--;
if (child->children.size() && child->children[0]->type == AST_RANGE && child->children[0]->children.size()) {
for (auto c : child->children[0]->children) {
if (proc_flags_p)
c->mem2reg_as_needed_pass1(mem2reg_places, mem2reg_candidates, *proc_flags_p, flags);
else
c->mem2reg_as_needed_pass1(mem2reg_places, mem2reg_candidates, proc_flags, flags);
}
}
} else
if (proc_flags_p)
child->mem2reg_as_needed_pass1(mem2reg_places, mem2reg_candidates, *proc_flags_p, flags);
else
child->mem2reg_as_needed_pass1(mem2reg_places, mem2reg_candidates, proc_flags, flags);
}
flags &= ~children_flags | backup_flags;
@ -3041,6 +3132,39 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod,
if (type == AST_FUNCTION || type == AST_TASK)
return false;
if (type == AST_MEMINIT && id2ast && mem2reg_set.count(id2ast))
{
log_assert(children[0]->type == AST_CONSTANT);
log_assert(children[1]->type == AST_CONSTANT);
log_assert(children[2]->type == AST_CONSTANT);
int cursor = children[0]->asInt(false);
Const data = children[1]->bitsAsConst();
int length = children[2]->asInt(false);
if (length != 0)
{
AstNode *block = new AstNode(AST_INITIAL, new AstNode(AST_BLOCK));
mod->children.push_back(block);
block = block->children[0];
int wordsz = GetSize(data) / length;
for (int i = 0; i < length; i++) {
block->children.push_back(new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER, new AstNode(AST_RANGE, AstNode::mkconst_int(cursor+i, false))), mkconst_bits(data.extract(i*wordsz, wordsz).bits, false)));
block->children.back()->children[0]->str = str;
block->children.back()->children[0]->id2ast = id2ast;
block->children.back()->children[0]->was_checked = true;
}
}
AstNode *newNode = new AstNode(AST_NONE);
newNode->cloneInto(this);
delete newNode;
did_something = true;
}
if (type == AST_ASSIGN && block == NULL && children[0]->mem2reg_check(mem2reg_set))
{
if (async_block == NULL) {
@ -3270,6 +3394,16 @@ bool AstNode::has_const_only_constructs(bool &recommend_const_eval)
return false;
}
bool AstNode::is_simple_const_expr()
{
if (type == AST_IDENTIFIER)
return false;
for (auto child : children)
if (!child->is_simple_const_expr())
return false;
return true;
}
// helper function for AstNode::eval_const_function()
void AstNode::replace_variables(std::map<std::string, AstNode::varinfo_t> &variables, AstNode *fcall)
{

View File

@ -584,7 +584,7 @@ struct BlifFrontend : public Frontend {
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" read_blif [filename]\n");
log(" read_blif [options] [filename]\n");
log("\n");
log("Load modules from a BLIF file into the current design.\n");
log("\n");

View File

@ -47,16 +47,20 @@ struct IlangFrontend : public Frontend {
log(" -nooverwrite\n");
log(" ignore re-definitions of modules. (the default behavior is to\n");
log(" create an error message if the existing module is not a blackbox\n");
log(" module, and overwrite the existing module if it is a blackbox module.)\n");
log(" module, and overwrite the existing module if it is a blackbox module.)\n");
log("\n");
log(" -overwrite\n");
log(" overwrite existing modules with the same name\n");
log("\n");
log(" -lib\n");
log(" only create empty blackbox modules\n");
log("\n");
}
void execute(std::istream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
ILANG_FRONTEND::flag_nooverwrite = false;
ILANG_FRONTEND::flag_overwrite = false;
ILANG_FRONTEND::flag_lib = false;
log_header(design, "Executing ILANG frontend.\n");
@ -73,6 +77,10 @@ struct IlangFrontend : public Frontend {
ILANG_FRONTEND::flag_overwrite = true;
continue;
}
if (arg == "-lib") {
ILANG_FRONTEND::flag_lib = true;
continue;
}
break;
}
extra_args(f, filename, args, argidx);

View File

@ -34,6 +34,7 @@ namespace ILANG_FRONTEND {
extern RTLIL::Design *current_design;
extern bool flag_nooverwrite;
extern bool flag_overwrite;
extern bool flag_lib;
}
YOSYS_NAMESPACE_END

View File

@ -53,6 +53,7 @@ USING_YOSYS_NAMESPACE
"attribute" { return TOK_ATTRIBUTE; }
"parameter" { return TOK_PARAMETER; }
"signed" { return TOK_SIGNED; }
"real" { return TOK_REAL; }
"wire" { return TOK_WIRE; }
"memory" { return TOK_MEMORY; }
"width" { return TOK_WIDTH; }

View File

@ -37,7 +37,7 @@ namespace ILANG_FRONTEND {
std::vector<std::vector<RTLIL::SwitchRule*>*> switch_stack;
std::vector<RTLIL::CaseRule*> case_stack;
dict<RTLIL::IdString, RTLIL::Const> attrbuf;
bool flag_nooverwrite, flag_overwrite;
bool flag_nooverwrite, flag_overwrite, flag_lib;
bool delete_current_module;
}
using namespace ILANG_FRONTEND;
@ -45,7 +45,16 @@ YOSYS_NAMESPACE_END
USING_YOSYS_NAMESPACE
%}
%name-prefix "rtlil_frontend_ilang_yy"
%define api.prefix {rtlil_frontend_ilang_yy}
/* The union is defined in the header, so we need to provide all the
* includes it requires
*/
%code requires {
#include <string>
#include <vector>
#include "frontends/ilang/ilang_frontend.h"
}
%union {
char *string;
@ -61,7 +70,7 @@ USING_YOSYS_NAMESPACE
%token TOK_CELL TOK_CONNECT TOK_SWITCH TOK_CASE TOK_ASSIGN TOK_SYNC
%token TOK_LOW TOK_HIGH TOK_POSEDGE TOK_NEGEDGE TOK_EDGE TOK_ALWAYS TOK_GLOBAL TOK_INIT
%token TOK_UPDATE TOK_PROCESS TOK_END TOK_INVALID TOK_EOL TOK_OFFSET
%token TOK_PARAMETER TOK_ATTRIBUTE TOK_MEMORY TOK_SIZE TOK_SIGNED TOK_UPTO
%token TOK_PARAMETER TOK_ATTRIBUTE TOK_MEMORY TOK_SIZE TOK_SIGNED TOK_REAL TOK_UPTO
%type <rsigspec> sigspec_list_reversed
%type <sigspec> sigspec sigspec_list
@ -98,7 +107,7 @@ module:
delete_current_module = false;
if (current_design->has($2)) {
RTLIL::Module *existing_mod = current_design->module($2);
if (!flag_overwrite && attrbuf.count("\\blackbox") && attrbuf.at("\\blackbox").as_bool()) {
if (!flag_overwrite && (flag_lib || (attrbuf.count("\\blackbox") && attrbuf.at("\\blackbox").as_bool()))) {
log("Ignoring blackbox re-definition of module %s.\n", $2);
delete_current_module = true;
} else if (!flag_nooverwrite && !flag_overwrite && !existing_mod->get_bool_attribute("\\blackbox")) {
@ -124,6 +133,8 @@ module:
current_module->fixup_ports();
if (delete_current_module)
delete current_module;
else if (flag_lib)
current_module->makeblackbox();
current_module = nullptr;
} EOL;
@ -239,6 +250,12 @@ cell_body:
free($4);
delete $5;
} |
cell_body TOK_PARAMETER TOK_REAL TOK_ID constant EOL {
current_cell->parameters[$4] = *$5;
current_cell->parameters[$4].flags |= RTLIL::CONST_FLAG_REAL;
free($4);
delete $5;
} |
cell_body TOK_CONNECT TOK_ID sigspec EOL {
if (current_cell->hasPort($3))
rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of cell port %s.", $3).c_str());
@ -443,4 +460,3 @@ conn_stmt:
delete $2;
delete $3;
};

View File

@ -21,7 +21,7 @@ Then run in the following command in this directory:
sby -f example.sby
This will generate approximately one page of text outpout. The last lines
This will generate approximately one page of text output. The last lines
should be something like this:
SBY [example] summary: Elapsed clock time [H:MM:SS (secs)]: 0:00:00 (0)

View File

@ -46,7 +46,7 @@ USING_YOSYS_NAMESPACE
#include "VeriModule.h"
#include "VeriWrite.h"
#include "VhdlUnits.h"
#include "Message.h"
#include "VeriLibrary.h"
#ifdef __clang__
#pragma clang diagnostic pop
@ -776,13 +776,14 @@ void VerificImporter::merge_past_ffs(pool<RTLIL::Cell*> &candidates)
void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::set<Netlist*> &nl_todo)
{
std::string module_name = nl->IsOperator() ? std::string("$verific$") + nl->Owner()->Name() : RTLIL::escape_id(nl->Owner()->Name());
std::string netlist_name = nl->GetAtt(" \\top") ? nl->CellBaseName() : nl->Owner()->Name();
std::string module_name = nl->IsOperator() ? "$verific$" + netlist_name : RTLIL::escape_id(netlist_name);
netlist = nl;
if (design->has(module_name)) {
if (!nl->IsOperator() && !is_blackbox(nl))
log_cmd_error("Re-definition of module `%s'.\n", nl->Owner()->Name());
log_cmd_error("Re-definition of module `%s'.\n", netlist_name.c_str());
return;
}
@ -1619,30 +1620,35 @@ struct VerificExtNets
int portname_cnt = 0;
// a map from Net to the same Net one level up in the design hierarchy
std::map<Net*, Net*> net_level_up;
std::map<Net*, Net*> net_level_up_drive_up;
std::map<Net*, Net*> net_level_up_drive_down;
Net *get_net_level_up(Net *net)
Net *route_up(Net *net, bool drive_up, Net *final_net = nullptr)
{
auto &net_level_up = drive_up ? net_level_up_drive_up : net_level_up_drive_down;
if (net_level_up.count(net) == 0)
{
Netlist *nl = net->Owner();
// Simply return if Netlist is not unique
if (nl->NumOfRefs() != 1)
return net;
log_assert(nl->NumOfRefs() == 1);
Instance *up_inst = (Instance*)nl->GetReferences()->GetLast();
Netlist *up_nl = up_inst->Owner();
// create new Port
string name = stringf("___extnets_%d", portname_cnt++);
Port *new_port = new Port(name.c_str(), DIR_OUT);
Port *new_port = new Port(name.c_str(), drive_up ? DIR_OUT : DIR_IN);
nl->Add(new_port);
net->Connect(new_port);
// create new Net in up Netlist
Net *new_net = new Net(name.c_str());
up_nl->Add(new_net);
Net *new_net = final_net;
if (new_net == nullptr || new_net->Owner() != up_nl) {
new_net = new Net(name.c_str());
up_nl->Add(new_net);
}
up_inst->Connect(new_port, new_net);
net_level_up[net] = new_net;
@ -1651,6 +1657,39 @@ struct VerificExtNets
return net_level_up.at(net);
}
Net *route_up(Net *net, bool drive_up, Netlist *dest, Net *final_net = nullptr)
{
while (net->Owner() != dest)
net = route_up(net, drive_up, final_net);
if (final_net != nullptr)
log_assert(net == final_net);
return net;
}
Netlist *find_common_ancestor(Netlist *A, Netlist *B)
{
std::set<Netlist*> ancestors_of_A;
Netlist *cursor = A;
while (1) {
ancestors_of_A.insert(cursor);
if (cursor->NumOfRefs() != 1)
break;
cursor = ((Instance*)cursor->GetReferences()->GetLast())->Owner();
}
cursor = B;
while (1) {
if (ancestors_of_A.count(cursor))
return cursor;
if (cursor->NumOfRefs() != 1)
break;
cursor = ((Instance*)cursor->GetReferences()->GetLast())->Owner();
}
log_error("No common ancestor found between %s and %s.\n", get_full_netlist_name(A).c_str(), get_full_netlist_name(B).c_str());
}
void run(Netlist *nl)
{
MapIter mi, mi2;
@ -1674,19 +1713,37 @@ struct VerificExtNets
if (verific_verbose)
log("Fixing external net reference on port %s.%s.%s:\n", get_full_netlist_name(nl).c_str(), inst->Name(), port->Name());
while (net->IsExternalTo(nl))
{
Net *newnet = get_net_level_up(net);
if (newnet == net) break;
Netlist *ext_nl = net->Owner();
if (verific_verbose)
log(" external net owner: %s\n", get_full_netlist_name(ext_nl).c_str());
Netlist *ca_nl = find_common_ancestor(nl, ext_nl);
if (verific_verbose)
log(" common ancestor: %s\n", get_full_netlist_name(ca_nl).c_str());
Net *ca_net = route_up(net, !port->IsOutput(), ca_nl);
Net *new_net = ca_net;
if (ca_nl != nl)
{
if (verific_verbose)
log(" external net: %s.%s\n", get_full_netlist_name(net->Owner()).c_str(), net->Name());
net = newnet;
log(" net in common ancestor: %s\n", ca_net->Name());
string name = stringf("___extnets_%d", portname_cnt++);
new_net = new Net(name.c_str());
nl->Add(new_net);
Net *n = route_up(new_net, port->IsOutput(), ca_nl, ca_net);
log_assert(n == ca_net);
}
if (verific_verbose)
log(" final net: %s.%s%s\n", get_full_netlist_name(net->Owner()).c_str(), net->Name(), net->IsExternalTo(nl) ? " (external)" : "");
todo_connect.push_back(tuple<Instance*, Port*, Net*>(inst, port, net));
log(" new local net: %s\n", new_net->Name());
log_assert(!new_net->IsExternalTo(nl));
todo_connect.push_back(tuple<Instance*, Port*, Net*>(inst, port, new_net));
}
for (auto it : todo_connect) {
@ -1696,32 +1753,64 @@ struct VerificExtNets
}
};
void verific_import(Design *design, std::string top)
void verific_import(Design *design, const std::map<std::string,std::string> &parameters, std::string top)
{
verific_sva_fsm_limit = 16;
std::set<Netlist*> nl_todo, nl_done;
{
VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary("work", 1);
VeriLibrary *veri_lib = veri_file::GetLibrary("work", 1);
VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary("work", 1);
VeriLibrary *veri_lib = veri_file::GetLibrary("work", 1);
Array *netlists = NULL;
Array veri_libs, vhdl_libs;
if (vhdl_lib) vhdl_libs.InsertLast(vhdl_lib);
if (veri_lib) veri_libs.InsertLast(veri_lib);
Array veri_libs, vhdl_libs;
if (vhdl_lib) vhdl_libs.InsertLast(vhdl_lib);
if (veri_lib) veri_libs.InsertLast(veri_lib);
Map verific_params(STRING_HASH);
for (const auto &i : parameters)
verific_params.Insert(i.first.c_str(), i.second.c_str());
Array *netlists = hier_tree::ElaborateAll(&veri_libs, &vhdl_libs);
Netlist *nl;
int i;
if (top.empty()) {
netlists = hier_tree::ElaborateAll(&veri_libs, &vhdl_libs, &verific_params);
}
else {
Array veri_modules, vhdl_units;
FOREACH_ARRAY_ITEM(netlists, i, nl) {
if (top.empty() || nl->Owner()->Name() == top)
nl_todo.insert(nl);
if (veri_lib) {
VeriModule *veri_module = veri_lib->GetModule(top.c_str(), 1);
if (veri_module) {
veri_modules.InsertLast(veri_module);
}
// Also elaborate all root modules since they may contain bind statements
MapIter mi;
FOREACH_VERILOG_MODULE_IN_LIBRARY(veri_lib, mi, veri_module) {
if (!veri_module->IsRootModule()) continue;
veri_modules.InsertLast(veri_module);
}
}
delete netlists;
if (vhdl_lib) {
VhdlDesignUnit *vhdl_unit = vhdl_lib->GetPrimUnit(top.c_str());
if (vhdl_unit)
vhdl_units.InsertLast(vhdl_unit);
}
netlists = hier_tree::Elaborate(&veri_modules, &vhdl_units, &verific_params);
}
Netlist *nl;
int i;
FOREACH_ARRAY_ITEM(netlists, i, nl) {
if (top.empty() && nl->CellBaseName() != top)
continue;
nl->AddAtt(new Att(" \\top", NULL));
nl_todo.insert(nl);
}
delete netlists;
if (!verific_error_msg.empty())
log_error("%s\n", verific_error_msg.c_str());
@ -1855,6 +1944,13 @@ struct VerificPass : public Pass {
log(" -autocover\n");
log(" Generate automatic cover statements for all asserts\n");
log("\n");
log(" -chparam name value \n");
log(" Elaborate the specified top modules (all modules when -all given) using\n");
log(" this parameter value. Modules on which this parameter does not exist will\n");
log(" cause Verific to produce a VERI-1928 or VHDL-1676 message. This option\n");
log(" can be specified multiple times to override multiple parameters.\n");
log(" String values must be passed in double quotes (\").\n");
log("\n");
log(" -v, -vv\n");
log(" Verbose log messages. (-vv is even more verbose than -v.)\n");
log("\n");
@ -1920,6 +2016,10 @@ struct VerificPass : public Pass {
// WARNING: instantiating unknown module 'XYZ' (VERI-1063)
Message::SetMessageType("VERI-1063", VERIFIC_ERROR);
#ifndef DB_PRESERVE_INITIAL_VALUE
# warning Verific was built without DB_PRESERVE_INITIAL_VALUE.
#endif
set_verific_global_flags = false;
}
@ -2105,6 +2205,7 @@ struct VerificPass : public Pass {
bool mode_autocover = false;
bool flatten = false, extnets = false;
string dumpfile;
Map parameters(STRING_HASH);
for (argidx++; argidx < GetSize(args); argidx++) {
if (args[argidx] == "-all") {
@ -2143,6 +2244,15 @@ struct VerificPass : public Pass {
mode_autocover = true;
continue;
}
if (args[argidx] == "-chparam" && argidx+2 < GetSize(args)) {
const std::string &key = args[++argidx];
const std::string &value = args[++argidx];
unsigned new_insertion = parameters.Insert(key.c_str(), value.c_str(),
1 /* force_overwrite */);
if (!new_insertion)
log_warning_noprefix("-chparam %s already specified: overwriting.\n", key.c_str());
continue;
}
if (args[argidx] == "-V") {
mode_verific = true;
continue;
@ -2176,7 +2286,7 @@ struct VerificPass : public Pass {
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);
Array *netlists = hier_tree::ElaborateAll(&veri_libs, &vhdl_libs, &parameters);
Netlist *nl;
int i;
@ -2193,12 +2303,22 @@ struct VerificPass : public Pass {
for (; argidx < GetSize(args); argidx++)
{
const char *name = args[argidx].c_str();
VeriLibrary* veri_lib = veri_file::GetLibrary(work.c_str(), 1);
VeriModule *veri_module = veri_file::GetModule(name);
if (veri_module) {
log("Adding Verilog module '%s' to elaboration queue.\n", name);
veri_modules.InsertLast(veri_module);
continue;
if (veri_lib) {
VeriModule *veri_module = veri_lib->GetModule(name, 1);
if (veri_module) {
log("Adding Verilog module '%s' to elaboration queue.\n", name);
veri_modules.InsertLast(veri_module);
continue;
}
// Also elaborate all root modules since they may contain bind statements
MapIter mi;
FOREACH_VERILOG_MODULE_IN_LIBRARY(veri_lib, mi, veri_module) {
if (!veri_module->IsRootModule()) continue;
veri_modules.InsertLast(veri_module);
}
}
VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary(work.c_str(), 1);
@ -2213,12 +2333,14 @@ struct VerificPass : public Pass {
}
log("Running hier_tree::Elaborate().\n");
Array *netlists = hier_tree::Elaborate(&veri_modules, &vhdl_units);
Array *netlists = hier_tree::Elaborate(&veri_modules, &vhdl_units, &parameters);
Netlist *nl;
int i;
FOREACH_ARRAY_ITEM(netlists, i, nl)
FOREACH_ARRAY_ITEM(netlists, i, nl) {
nl->AddAtt(new Att(" \\top", NULL));
nl_todo.insert(nl);
}
delete netlists;
}
@ -2309,21 +2431,43 @@ struct ReadPass : public Pass {
log("\n");
log("Add directory to global Verilog/SystemVerilog include directories.\n");
log("\n");
log("\n");
log(" read -verific\n");
log(" read -noverific\n");
log("\n");
log("Subsequent calls to 'read' will either use or not use Verific. Calling 'read'\n");
log("with -verific will result in an error on Yosys binaries that are built without\n");
log("Verific support. The default is to use Verific if it is available.\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
if (args.size() < 2)
#ifdef YOSYS_ENABLE_VERIFIC
static bool verific_available = !check_noverific_env();
#else
static bool verific_available = false;
#endif
static bool use_verific = verific_available;
if (args.size() < 2 || args[1][0] != '-')
log_cmd_error("Missing mode parameter.\n");
if (args[1] == "-verific" || args[1] == "-noverific") {
if (args.size() != 2)
log_cmd_error("Additional arguments to -verific/-noverific.\n");
if (args[1] == "-verific") {
if (!verific_available)
log_cmd_error("This version of Yosys is built without Verific support.\n");
use_verific = true;
} else {
use_verific = false;
}
return;
}
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";

View File

@ -26,7 +26,7 @@ YOSYS_NAMESPACE_BEGIN
extern int verific_verbose;
extern bool verific_import_pending;
extern void verific_import(Design *design, std::string top = std::string());
extern void verific_import(Design *design, const std::map<std::string,std::string> &parameters, std::string top = std::string());
extern pool<int> verific_sva_prims;

View File

@ -1666,7 +1666,20 @@ struct VerificSvaImporter
log(" importing SVA property at root cell %s (%s) at %s:%d.\n", root->Name(), root->View()->Owner()->Name(),
LineFile::GetFileName(root->Linefile()), LineFile::GetLineNo(root->Linefile()));
RTLIL::IdString root_name = module->uniquify(importer->mode_names || root->IsUserDeclared() ? RTLIL::escape_id(root->Name()) : NEW_ID);
bool is_user_declared = root->IsUserDeclared();
// FIXME
if (!is_user_declared) {
const char *name = root->Name();
for (int i = 0; name[i]; i++) {
if (i ? (name[i] < '0' || name[i] > '9') : (name[i] != 'i')) {
is_user_declared = true;
break;
}
}
}
RTLIL::IdString root_name = module->uniquify(importer->mode_names || is_user_declared ? RTLIL::escape_id(root->Name()) : NEW_ID);
// parse SVA sequence into trigger signal

View File

@ -14,6 +14,8 @@ frontends/verilog/verilog_lexer.cc: frontends/verilog/verilog_lexer.l
$(Q) mkdir -p $(dir $@)
$(P) flex -o frontends/verilog/verilog_lexer.cc $<
frontends/verilog/verilog_parser.tab.o: CXXFLAGS += -DYYMAXDEPTH=10000000
OBJS += frontends/verilog/verilog_parser.tab.o
OBJS += frontends/verilog/verilog_lexer.o
OBJS += frontends/verilog/preproc.o

View File

@ -81,6 +81,9 @@ struct VerilogFrontend : public Frontend {
log(" -assert-assumes\n");
log(" treat all assume() statements like assert() statements\n");
log("\n");
log(" -debug\n");
log(" alias for -dump_ast1 -dump_ast2 -dump_vlog1 -dump_vlog2 -yydebug\n");
log("\n");
log(" -dump_ast1\n");
log(" dump abstract syntax tree (before simplification)\n");
log("\n");
@ -90,7 +93,10 @@ struct VerilogFrontend : public Frontend {
log(" -no_dump_ptr\n");
log(" do not include hex memory addresses in dump (easier to diff dumps)\n");
log("\n");
log(" -dump_vlog\n");
log(" -dump_vlog1\n");
log(" dump ast as Verilog code (before simplification)\n");
log("\n");
log(" -dump_vlog2\n");
log(" dump ast as Verilog code (after simplification)\n");
log("\n");
log(" -dump_rtlil\n");
@ -139,8 +145,21 @@ struct VerilogFrontend : public Frontend {
log(" -nodpi\n");
log(" disable DPI-C support\n");
log("\n");
log(" -noblackbox\n");
log(" do not automatically add a (* blackbox *) attribute to an\n");
log(" empty module.\n");
log("\n");
log(" -lib\n");
log(" only create empty blackbox modules. This implies -DBLACKBOX.\n");
log(" modules with the (* whitebox *) attribute will be preserved.\n");
log(" (* lib_whitebox *) will be treated like (* whitebox *).\n");
log("\n");
log(" -nowb\n");
log(" delete (* whitebox *) and (* lib_whitebox *) attributes from\n");
log(" all modules.\n");
log("\n");
log(" -specify\n");
log(" parse and import specify blocks\n");
log("\n");
log(" -noopt\n");
log(" don't perform basic optimizations (such as const folding) in the\n");
@ -197,7 +216,8 @@ struct VerilogFrontend : public Frontend {
bool flag_dump_ast1 = false;
bool flag_dump_ast2 = false;
bool flag_no_dump_ptr = false;
bool flag_dump_vlog = false;
bool flag_dump_vlog1 = false;
bool flag_dump_vlog2 = false;
bool flag_dump_rtlil = false;
bool flag_nolatches = false;
bool flag_nomeminit = false;
@ -211,6 +231,8 @@ struct VerilogFrontend : public Frontend {
bool flag_nooverwrite = false;
bool flag_overwrite = false;
bool flag_defer = false;
bool flag_noblackbox = false;
bool flag_nowb = false;
std::map<std::string, std::string> defines_map;
std::list<std::string> include_dirs;
std::list<std::string> attributes;
@ -221,10 +243,9 @@ struct VerilogFrontend : public Frontend {
norestrict_mode = false;
assume_asserts_mode = false;
lib_mode = false;
specify_mode = false;
default_nettype_wire = true;
log_header(design, "Executing Verilog-2005 frontend.\n");
args.insert(args.begin()+1, verilog_defaults.begin(), verilog_defaults.end());
size_t argidx;
@ -258,6 +279,14 @@ struct VerilogFrontend : public Frontend {
assert_assumes_mode = true;
continue;
}
if (arg == "-debug") {
flag_dump_ast1 = true;
flag_dump_ast2 = true;
flag_dump_vlog1 = true;
flag_dump_vlog2 = true;
frontend_verilog_yydebug = true;
continue;
}
if (arg == "-dump_ast1") {
flag_dump_ast1 = true;
continue;
@ -270,8 +299,12 @@ struct VerilogFrontend : public Frontend {
flag_no_dump_ptr = true;
continue;
}
if (arg == "-dump_vlog") {
flag_dump_vlog = true;
if (arg == "-dump_vlog1") {
flag_dump_vlog1 = true;
continue;
}
if (arg == "-dump_vlog2") {
flag_dump_vlog2 = true;
continue;
}
if (arg == "-dump_rtlil") {
@ -310,11 +343,23 @@ struct VerilogFrontend : public Frontend {
flag_nodpi = true;
continue;
}
if (arg == "-noblackbox") {
flag_noblackbox = true;
continue;
}
if (arg == "-lib") {
lib_mode = true;
defines_map["BLACKBOX"] = string();
continue;
}
if (arg == "-nowb") {
flag_nowb = true;
continue;
}
if (arg == "-specify") {
specify_mode = true;
continue;
}
if (arg == "-noopt") {
flag_noopt = true;
continue;
@ -376,6 +421,8 @@ struct VerilogFrontend : public Frontend {
}
extra_args(f, filename, args, argidx);
log_header(design, "Executing Verilog-2005 frontend: %s\n", filename.c_str());
log("Parsing %s%s input from `%s' to AST representation.\n",
formal_mode ? "formal " : "", sv_mode ? "SystemVerilog" : "Verilog", filename.c_str());
@ -410,7 +457,8 @@ struct VerilogFrontend : public Frontend {
if (flag_nodpi)
error_on_dpi_function(current_ast);
AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog, flag_dump_rtlil, flag_nolatches, flag_nomeminit, flag_nomem2reg, flag_mem2reg, lib_mode, flag_noopt, flag_icells, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire);
AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches,
flag_nomeminit, flag_nomem2reg, flag_mem2reg, flag_noblackbox, lib_mode, flag_nowb, flag_noopt, flag_icells, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire);
if (!flag_nopp)
delete lexin;

View File

@ -72,6 +72,9 @@ namespace VERILOG_FRONTEND
// running in -lib mode
extern bool lib_mode;
// running in -specify mode
extern bool specify_mode;
// lexer input stream
extern std::istream *lexin;
}

View File

@ -148,7 +148,7 @@ YOSYS_NAMESPACE_END
"endfunction" { return TOK_ENDFUNCTION; }
"task" { return TOK_TASK; }
"endtask" { return TOK_ENDTASK; }
"specify" { return TOK_SPECIFY; }
"specify" { return specify_mode ? TOK_SPECIFY : TOK_IGNORED_SPECIFY; }
"endspecify" { return TOK_ENDSPECIFY; }
"specparam" { return TOK_SPECPARAM; }
"package" { SV_KEYWORD(TOK_PACKAGE); }
@ -189,6 +189,14 @@ YOSYS_NAMESPACE_END
"always_ff" { SV_KEYWORD(TOK_ALWAYS); }
"always_latch" { SV_KEYWORD(TOK_ALWAYS); }
/* use special token for labels on assert, assume, cover, and restrict because it's insanley complex
to fix parsing of cells otherwise. (the current cell parser forces a reduce very early to update some
global state.. its a mess) */
[a-zA-Z_$][a-zA-Z0-9_$]*/[ \t\r\n]*:[ \t\r\n]*(assert|assume|cover|restrict)[^a-zA-Z0-9_$\.] {
frontend_verilog_yylval.string = new std::string(std::string("\\") + yytext);
return TOK_SVA_LABEL;
}
"assert" { if (formal_mode) return TOK_ASSERT; SV_KEYWORD(TOK_ASSERT); }
"assume" { if (formal_mode) return TOK_ASSUME; SV_KEYWORD(TOK_ASSUME); }
"cover" { if (formal_mode) return TOK_COVER; SV_KEYWORD(TOK_COVER); }
@ -198,7 +206,9 @@ YOSYS_NAMESPACE_END
"const" { if (formal_mode) return TOK_CONST; SV_KEYWORD(TOK_CONST); }
"checker" { if (formal_mode) return TOK_CHECKER; SV_KEYWORD(TOK_CHECKER); }
"endchecker" { if (formal_mode) return TOK_ENDCHECKER; SV_KEYWORD(TOK_ENDCHECKER); }
"final" { SV_KEYWORD(TOK_FINAL); }
"logic" { SV_KEYWORD(TOK_LOGIC); }
"var" { SV_KEYWORD(TOK_VAR); }
"bit" { SV_KEYWORD(TOK_REG); }
"eventually" { if (formal_mode) return TOK_EVENTUALLY; SV_KEYWORD(TOK_EVENTUALLY); }
@ -293,6 +303,12 @@ supply1 { return TOK_SUPPLY1; }
return TOK_ID;
}
"$"(setup|hold|setuphold|removal|recovery|recrem|skew|timeskew|fullskew|nochange) {
if (!specify_mode) REJECT;
frontend_verilog_yylval.string = new std::string(yytext);
return TOK_ID;
}
"$signed" { return TOK_TO_SIGNED; }
"$unsigned" { return TOK_TO_UNSIGNED; }
@ -303,7 +319,7 @@ supply1 { return TOK_SUPPLY1; }
[a-zA-Z_$][a-zA-Z0-9_$\.]* {
frontend_verilog_yylval.string = new std::string(std::string("\\") + yytext);
return TOK_ID;
return TOK_ID;
}
"/*"[ \t]*(synopsys|synthesis)[ \t]*translate_off[ \t]*"*/" {
@ -403,6 +419,17 @@ import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ {
"+:" { return TOK_POS_INDEXED; }
"-:" { return TOK_NEG_INDEXED; }
[-+]?[=*]> {
if (!specify_mode) REJECT;
frontend_verilog_yylval.string = new std::string(yytext);
return TOK_SPECIFY_OPER;
}
"&&&" {
if (!specify_mode) REJECT;
return TOK_SPECIFY_AND;
}
"/*" { BEGIN(COMMENT); }
<COMMENT>. /* ignore comment body */
<COMMENT>\n /* ignore comment body */

View File

@ -59,7 +59,7 @@ namespace VERILOG_FRONTEND {
std::vector<char> case_type_stack;
bool do_not_require_port_stubs;
bool default_nettype_wire;
bool sv_mode, formal_mode, lib_mode;
bool sv_mode, formal_mode, lib_mode, specify_mode;
bool noassert_mode, noassume_mode, norestrict_mode;
bool assume_asserts_mode, assert_assumes_mode;
bool current_wire_rand, current_wire_const;
@ -94,42 +94,77 @@ static void free_attr(std::map<std::string, AstNode*> *al)
delete al;
}
struct specify_target {
char polarity_op;
AstNode *dst, *dat;
};
struct specify_triple {
AstNode *t_min, *t_avg, *t_max;
};
struct specify_rise_fall {
specify_triple rise;
specify_triple fall;
};
%}
%name-prefix "frontend_verilog_yy"
%define api.prefix {frontend_verilog_yy}
/* The union is defined in the header, so we need to provide all the
* includes it requires
*/
%code requires {
#include <map>
#include <string>
#include "frontends/verilog/verilog_frontend.h"
}
%union {
std::string *string;
struct YOSYS_NAMESPACE_PREFIX AST::AstNode *ast;
std::map<std::string, YOSYS_NAMESPACE_PREFIX AST::AstNode*> *al;
struct specify_target *specify_target_ptr;
struct specify_triple *specify_triple_ptr;
struct specify_rise_fall *specify_rise_fall_ptr;
bool boolean;
char ch;
}
%token <string> TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE
%token <string> TOK_SVA_LABEL TOK_SPECIFY_OPER
%token TOK_ASSERT TOK_ASSUME TOK_RESTRICT TOK_COVER TOK_FINAL
%token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END
%token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM
%token TOK_PACKAGE TOK_ENDPACKAGE TOK_PACKAGESEP
%token TOK_INTERFACE TOK_ENDINTERFACE TOK_MODPORT
%token TOK_INTERFACE TOK_ENDINTERFACE TOK_MODPORT TOK_VAR
%token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_REG TOK_LOGIC
%token TOK_INTEGER TOK_SIGNED TOK_ASSIGN TOK_ALWAYS TOK_INITIAL
%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 TOK_SPECIFY TOK_ENDSPECIFY TOK_SPECPARAM
%token TOK_FUNCTION TOK_ENDFUNCTION TOK_TASK TOK_ENDTASK TOK_SPECIFY
%token TOK_IGNORED_SPECIFY TOK_ENDSPECIFY TOK_SPECPARAM TOK_SPECIFY_AND
%token TOK_GENERATE TOK_ENDGENERATE TOK_GENVAR TOK_REAL
%token TOK_SYNOPSYS_FULL_CASE TOK_SYNOPSYS_PARALLEL_CASE
%token TOK_SUPPLY0 TOK_SUPPLY1 TOK_TO_SIGNED TOK_TO_UNSIGNED
%token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_ASSERT TOK_ASSUME
%token TOK_RESTRICT TOK_COVER TOK_PROPERTY TOK_ENUM TOK_TYPEDEF
%token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_PROPERTY TOK_ENUM TOK_TYPEDEF
%token TOK_RAND TOK_CONST TOK_CHECKER TOK_ENDCHECKER TOK_EVENTUALLY
%token TOK_INCREMENT TOK_DECREMENT TOK_UNIQUE TOK_PRIORITY
%type <ast> range range_or_multirange non_opt_range non_opt_multirange range_or_signed_int
%type <ast> wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list
%type <string> opt_label tok_prim_wrapper hierarchical_id
%type <string> opt_label opt_sva_label tok_prim_wrapper hierarchical_id
%type <boolean> opt_signed opt_property unique_case_attr
%type <al> attr case_attr
%type <specify_target_ptr> specify_target
%type <specify_triple_ptr> specify_triple
%type <specify_rise_fall_ptr> specify_rise_fall
%type <ast> specify_if specify_condition specify_opt_arg
%type <ch> specify_edge
// operator precedence from low to high
%left OP_LOR
%left OP_LAND
@ -456,6 +491,9 @@ wire_type_token:
TOK_LOGIC {
astbuf3->is_logic = true;
} |
TOK_VAR {
astbuf3->is_logic = true;
} |
TOK_INTEGER {
astbuf3->is_reg = true;
astbuf3->range_left = 31;
@ -539,7 +577,7 @@ module_body:
module_body_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;
always_stmt | TOK_GENERATE module_gen_body TOK_ENDGENERATE | defattr | assert_property | checker_decl | ignored_specify_block;
checker_decl:
TOK_CHECKER TOK_ID ';' {
@ -697,15 +735,254 @@ task_func_body:
task_func_body behavioral_stmt |
/* empty */;
specify_block:
TOK_SPECIFY specify_item_opt TOK_ENDSPECIFY |
TOK_SPECIFY TOK_ENDSPECIFY ;
/*************************** specify parser ***************************/
specify_item_opt:
specify_item_opt specify_item |
specify_item ;
specify_block:
TOK_SPECIFY specify_item_list TOK_ENDSPECIFY;
specify_item_list:
specify_item specify_item_list |
/* empty */;
specify_item:
specify_if '(' specify_edge expr TOK_SPECIFY_OPER specify_target ')' '=' specify_rise_fall ';' {
AstNode *en_expr = $1;
char specify_edge = $3;
AstNode *src_expr = $4;
string *oper = $5;
specify_target *target = $6;
specify_rise_fall *timing = $9;
if (specify_edge != 0 && target->dat == nullptr)
frontend_verilog_yyerror("Found specify edge but no data spec.\n");
AstNode *cell = new AstNode(AST_CELL);
ast_stack.back()->children.push_back(cell);
cell->str = stringf("$specify$%d", autoidx++);
cell->children.push_back(new AstNode(AST_CELLTYPE));
cell->children.back()->str = target->dat ? "$specify3" : "$specify2";
char oper_polarity = 0;
char oper_type = oper->at(0);
if (oper->size() == 3) {
oper_polarity = oper->at(0);
oper_type = oper->at(1);
}
cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(oper_type == '*', false, 1)));
cell->children.back()->str = "\\FULL";
cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(oper_polarity != 0, false, 1)));
cell->children.back()->str = "\\SRC_DST_PEN";
cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(oper_polarity == '+', false, 1)));
cell->children.back()->str = "\\SRC_DST_POL";
cell->children.push_back(new AstNode(AST_PARASET, timing->rise.t_min));
cell->children.back()->str = "\\T_RISE_MIN";
cell->children.push_back(new AstNode(AST_PARASET, timing->rise.t_avg));
cell->children.back()->str = "\\T_RISE_TYP";
cell->children.push_back(new AstNode(AST_PARASET, timing->rise.t_max));
cell->children.back()->str = "\\T_RISE_MAX";
cell->children.push_back(new AstNode(AST_PARASET, timing->fall.t_min));
cell->children.back()->str = "\\T_FALL_MIN";
cell->children.push_back(new AstNode(AST_PARASET, timing->fall.t_avg));
cell->children.back()->str = "\\T_FALL_TYP";
cell->children.push_back(new AstNode(AST_PARASET, timing->fall.t_max));
cell->children.back()->str = "\\T_FALL_MAX";
cell->children.push_back(new AstNode(AST_ARGUMENT, en_expr ? en_expr : AstNode::mkconst_int(1, false, 1)));
cell->children.back()->str = "\\EN";
cell->children.push_back(new AstNode(AST_ARGUMENT, src_expr));
cell->children.back()->str = "\\SRC";
cell->children.push_back(new AstNode(AST_ARGUMENT, target->dst));
cell->children.back()->str = "\\DST";
if (target->dat)
{
cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(specify_edge != 0, false, 1)));
cell->children.back()->str = "\\EDGE_EN";
cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(specify_edge == 'p', false, 1)));
cell->children.back()->str = "\\EDGE_POL";
cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(target->polarity_op != 0, false, 1)));
cell->children.back()->str = "\\DAT_DST_PEN";
cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_int(target->polarity_op == '+', false, 1)));
cell->children.back()->str = "\\DAT_DST_POL";
cell->children.push_back(new AstNode(AST_ARGUMENT, target->dat));
cell->children.back()->str = "\\DAT";
}
delete oper;
delete target;
delete timing;
} |
TOK_ID '(' specify_edge expr specify_condition ',' specify_edge expr specify_condition ',' expr specify_opt_arg ')' ';' {
if (*$1 != "$setup" && *$1 != "$hold" && *$1 != "$setuphold" && *$1 != "$removal" && *$1 != "$recovery" &&
*$1 != "$recrem" && *$1 != "$skew" && *$1 != "$timeskew" && *$1 != "$fullskew" && *$1 != "$nochange")
frontend_verilog_yyerror("Unsupported specify rule type: %s\n", $1->c_str());
AstNode *src_pen = AstNode::mkconst_int($3 != 0, false, 1);
AstNode *src_pol = AstNode::mkconst_int($3 == 'p', false, 1);
AstNode *src_expr = $4, *src_en = $5 ? $5 : AstNode::mkconst_int(1, false, 1);
AstNode *dst_pen = AstNode::mkconst_int($7 != 0, false, 1);
AstNode *dst_pol = AstNode::mkconst_int($7 == 'p', false, 1);
AstNode *dst_expr = $8, *dst_en = $9 ? $9 : AstNode::mkconst_int(1, false, 1);
AstNode *limit = $11;
AstNode *limit2 = $12;
AstNode *cell = new AstNode(AST_CELL);
ast_stack.back()->children.push_back(cell);
cell->str = stringf("$specify$%d", autoidx++);
cell->children.push_back(new AstNode(AST_CELLTYPE));
cell->children.back()->str = "$specrule";
cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_str(*$1)));
cell->children.back()->str = "\\TYPE";
cell->children.push_back(new AstNode(AST_PARASET, limit));
cell->children.back()->str = "\\T_LIMIT";
cell->children.push_back(new AstNode(AST_PARASET, limit2 ? limit2 : AstNode::mkconst_int(0, true)));
cell->children.back()->str = "\\T_LIMIT2";
cell->children.push_back(new AstNode(AST_PARASET, src_pen));
cell->children.back()->str = "\\SRC_PEN";
cell->children.push_back(new AstNode(AST_PARASET, src_pol));
cell->children.back()->str = "\\SRC_POL";
cell->children.push_back(new AstNode(AST_PARASET, dst_pen));
cell->children.back()->str = "\\DST_PEN";
cell->children.push_back(new AstNode(AST_PARASET, dst_pol));
cell->children.back()->str = "\\DST_POL";
cell->children.push_back(new AstNode(AST_ARGUMENT, src_en));
cell->children.back()->str = "\\SRC_EN";
cell->children.push_back(new AstNode(AST_ARGUMENT, src_expr));
cell->children.back()->str = "\\SRC";
cell->children.push_back(new AstNode(AST_ARGUMENT, dst_en));
cell->children.back()->str = "\\DST_EN";
cell->children.push_back(new AstNode(AST_ARGUMENT, dst_expr));
cell->children.back()->str = "\\DST";
delete $1;
};
specify_opt_arg:
',' expr {
$$ = $2;
} |
/* empty */ {
$$ = nullptr;
};
specify_if:
TOK_IF '(' expr ')' {
$$ = $3;
} |
/* empty */ {
$$ = nullptr;
};
specify_condition:
TOK_SPECIFY_AND expr {
$$ = $2;
} |
/* empty */ {
$$ = nullptr;
};
specify_target:
expr {
$$ = new specify_target;
$$->polarity_op = 0;
$$->dst = $1;
$$->dat = nullptr;
} |
'(' expr ':' expr ')'{
$$ = new specify_target;
$$->polarity_op = 0;
$$->dst = $2;
$$->dat = $4;
} |
'(' expr TOK_NEG_INDEXED expr ')'{
$$ = new specify_target;
$$->polarity_op = '-';
$$->dst = $2;
$$->dat = $4;
} |
'(' expr TOK_POS_INDEXED expr ')'{
$$ = new specify_target;
$$->polarity_op = '+';
$$->dst = $2;
$$->dat = $4;
};
specify_edge:
TOK_POSEDGE { $$ = 'p'; } |
TOK_NEGEDGE { $$ = 'n'; } |
{ $$ = 0; };
specify_rise_fall:
specify_triple {
$$ = new specify_rise_fall;
$$->rise = *$1;
$$->fall.t_min = $1->t_min->clone();
$$->fall.t_avg = $1->t_avg->clone();
$$->fall.t_max = $1->t_max->clone();
delete $1;
} |
'(' specify_triple ',' specify_triple ')' {
$$ = new specify_rise_fall;
$$->rise = *$2;
$$->fall = *$4;
delete $2;
delete $4;
};
specify_triple:
expr {
$$ = new specify_triple;
$$->t_min = $1;
$$->t_avg = $1->clone();
$$->t_max = $1->clone();
} |
expr ':' expr ':' expr {
$$ = new specify_triple;
$$->t_min = $1;
$$->t_avg = $3;
$$->t_max = $5;
};
/******************** ignored specify parser **************************/
ignored_specify_block:
TOK_IGNORED_SPECIFY ignored_specify_item_opt TOK_ENDSPECIFY |
TOK_IGNORED_SPECIFY TOK_ENDSPECIFY ;
ignored_specify_item_opt:
ignored_specify_item_opt ignored_specify_item |
ignored_specify_item ;
ignored_specify_item:
specparam_declaration
// | pulsestyle_declaration
// | showcancelled_declaration
@ -721,13 +998,13 @@ specparam_declaration:
// 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 ']' ;
'[' ignspec_constant_expression ':' ignspec_constant_expression ']' ;
list_of_specparam_assignments:
specparam_assignment | list_of_specparam_assignments ',' specparam_assignment;
specparam_assignment:
TOK_ID '=' constant_mintypmax_expression ;
ignspec_id '=' constant_mintypmax_expression ;
/*
pulsestyle_declaration :
@ -802,19 +1079,19 @@ opt_polarity_operator :
// Good enough for the time being
specify_input_terminal_descriptor :
TOK_ID ;
ignspec_id ;
// Good enough for the time being
specify_output_terminal_descriptor :
TOK_ID ;
ignspec_id ;
system_timing_declaration :
TOK_ID '(' system_timing_args ')' ';' ;
ignspec_id '(' system_timing_args ')' ';' ;
system_timing_arg :
TOK_POSEDGE TOK_ID |
TOK_NEGEDGE TOK_ID |
expr ;
TOK_POSEDGE ignspec_id |
TOK_NEGEDGE ignspec_id |
ignspec_expr ;
system_timing_args :
system_timing_arg |
@ -871,19 +1148,27 @@ tzx_path_delay_expression :
*/
path_delay_expression :
constant_expression;
ignspec_constant_expression;
constant_mintypmax_expression :
constant_expression
| constant_expression ':' constant_expression ':' constant_expression
ignspec_constant_expression
| ignspec_constant_expression ':' ignspec_constant_expression ':' ignspec_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 adding runtime checks for constant-ness
constant_expression:
expr ;
ignspec_constant_expression:
expr { delete $1; };
ignspec_expr:
expr { delete $1; };
ignspec_id:
TOK_ID { delete $1; };
/**********************************************************************/
param_signed:
TOK_SIGNED {
@ -917,7 +1202,7 @@ param_range:
};
param_decl:
TOK_PARAMETER {
attr TOK_PARAMETER {
astbuf1 = new AstNode(AST_PARAMETER);
astbuf1->children.push_back(AstNode::mkconst_int(0, true));
} param_signed param_integer param_real param_range param_decl_list ';' {
@ -925,7 +1210,7 @@ param_decl:
};
localparam_decl:
TOK_LOCALPARAM {
attr TOK_LOCALPARAM {
astbuf1 = new AstNode(AST_LOCALPARAM);
astbuf1->children.push_back(AstNode::mkconst_int(0, true));
} param_signed param_integer param_real param_range param_decl_list ';' {
@ -1329,17 +1614,25 @@ opt_label:
$$ = NULL;
};
opt_sva_label:
TOK_SVA_LABEL ':' {
$$ = $1;
} |
/* empty */ {
$$ = NULL;
};
opt_property:
TOK_PROPERTY {
$$ = true;
} |
TOK_FINAL {
$$ = false;
} |
/* empty */ {
$$ = false;
};
opt_stmt_label:
TOK_ID ':' | /* empty */;
modport_stmt:
TOK_MODPORT TOK_ID {
AstNode *modport = new AstNode(AST_MODPORT);
@ -1376,83 +1669,164 @@ modport_type_token:
TOK_INPUT {current_modport_input = 1; current_modport_output = 0;} | TOK_OUTPUT {current_modport_input = 0; current_modport_output = 1;}
assert:
opt_stmt_label TOK_ASSERT opt_property '(' expr ')' ';' {
if (noassert_mode)
opt_sva_label TOK_ASSERT opt_property '(' expr ')' ';' {
if (noassert_mode) {
delete $5;
else
ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $5));
} else {
AstNode *node = new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $5);
if ($1 != nullptr)
node->str = *$1;
ast_stack.back()->children.push_back(node);
}
if ($1 != nullptr)
delete $1;
} |
opt_stmt_label TOK_ASSUME opt_property '(' expr ')' ';' {
if (noassume_mode)
opt_sva_label TOK_ASSUME opt_property '(' expr ')' ';' {
if (noassume_mode) {
delete $5;
else
ast_stack.back()->children.push_back(new AstNode(assert_assumes_mode ? AST_ASSERT : AST_ASSUME, $5));
} else {
AstNode *node = new AstNode(assert_assumes_mode ? AST_ASSERT : AST_ASSUME, $5);
if ($1 != nullptr)
node->str = *$1;
ast_stack.back()->children.push_back(node);
}
if ($1 != nullptr)
delete $1;
} |
opt_stmt_label TOK_ASSERT opt_property '(' TOK_EVENTUALLY expr ')' ';' {
if (noassert_mode)
opt_sva_label TOK_ASSERT opt_property '(' TOK_EVENTUALLY expr ')' ';' {
if (noassert_mode) {
delete $6;
else
ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $6));
} else {
AstNode *node = new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $6);
if ($1 != nullptr)
node->str = *$1;
ast_stack.back()->children.push_back(node);
}
if ($1 != nullptr)
delete $1;
} |
opt_stmt_label TOK_ASSUME opt_property '(' TOK_EVENTUALLY expr ')' ';' {
if (noassume_mode)
opt_sva_label TOK_ASSUME opt_property '(' TOK_EVENTUALLY expr ')' ';' {
if (noassume_mode) {
delete $6;
else
ast_stack.back()->children.push_back(new AstNode(assert_assumes_mode ? AST_LIVE : AST_FAIR, $6));
} else {
AstNode *node = new AstNode(assert_assumes_mode ? AST_LIVE : AST_FAIR, $6);
if ($1 != nullptr)
node->str = *$1;
ast_stack.back()->children.push_back(node);
}
if ($1 != nullptr)
delete $1;
} |
opt_stmt_label TOK_COVER opt_property '(' expr ')' ';' {
ast_stack.back()->children.push_back(new AstNode(AST_COVER, $5));
opt_sva_label TOK_COVER opt_property '(' expr ')' ';' {
AstNode *node = new AstNode(AST_COVER, $5);
if ($1 != nullptr) {
node->str = *$1;
delete $1;
}
ast_stack.back()->children.push_back(node);
} |
opt_stmt_label TOK_COVER opt_property '(' ')' ';' {
ast_stack.back()->children.push_back(new AstNode(AST_COVER, AstNode::mkconst_int(1, false)));
opt_sva_label TOK_COVER opt_property '(' ')' ';' {
AstNode *node = new AstNode(AST_COVER, AstNode::mkconst_int(1, false));
if ($1 != nullptr) {
node->str = *$1;
delete $1;
}
ast_stack.back()->children.push_back(node);
} |
opt_stmt_label TOK_COVER ';' {
ast_stack.back()->children.push_back(new AstNode(AST_COVER, AstNode::mkconst_int(1, false)));
opt_sva_label TOK_COVER ';' {
AstNode *node = new AstNode(AST_COVER, AstNode::mkconst_int(1, false));
if ($1 != nullptr) {
node->str = *$1;
delete $1;
}
ast_stack.back()->children.push_back(node);
} |
opt_stmt_label TOK_RESTRICT opt_property '(' expr ')' ';' {
if (norestrict_mode)
opt_sva_label TOK_RESTRICT opt_property '(' expr ')' ';' {
if (norestrict_mode) {
delete $5;
else
ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $5));
} else {
AstNode *node = new AstNode(AST_ASSUME, $5);
if ($1 != nullptr)
node->str = *$1;
ast_stack.back()->children.push_back(node);
}
if (!$3)
log_file_warning(current_filename, get_line_num(), "SystemVerilog does not allow \"restrict\" without \"property\".\n");
if ($1 != nullptr)
delete $1;
} |
opt_stmt_label TOK_RESTRICT opt_property '(' TOK_EVENTUALLY expr ')' ';' {
if (norestrict_mode)
opt_sva_label TOK_RESTRICT opt_property '(' TOK_EVENTUALLY expr ')' ';' {
if (norestrict_mode) {
delete $6;
else
ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $6));
} else {
AstNode *node = new AstNode(AST_FAIR, $6);
if ($1 != nullptr)
node->str = *$1;
ast_stack.back()->children.push_back(node);
}
if (!$3)
log_file_warning(current_filename, get_line_num(), "SystemVerilog does not allow \"restrict\" without \"property\".\n");
if ($1 != nullptr)
delete $1;
};
assert_property:
TOK_ASSERT TOK_PROPERTY '(' expr ')' ';' {
ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $4));
opt_sva_label TOK_ASSERT TOK_PROPERTY '(' expr ')' ';' {
ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $5));
if ($1 != nullptr) {
ast_stack.back()->children.back()->str = *$1;
delete $1;
}
} |
TOK_ASSUME TOK_PROPERTY '(' expr ')' ';' {
ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $4));
opt_sva_label TOK_ASSUME TOK_PROPERTY '(' expr ')' ';' {
ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $5));
if ($1 != nullptr) {
ast_stack.back()->children.back()->str = *$1;
delete $1;
}
} |
TOK_ASSERT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' {
ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $5));
opt_sva_label TOK_ASSERT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' {
ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $6));
if ($1 != nullptr) {
ast_stack.back()->children.back()->str = *$1;
delete $1;
}
} |
TOK_ASSUME TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' {
ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $5));
opt_sva_label TOK_ASSUME TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' {
ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $6));
if ($1 != nullptr) {
ast_stack.back()->children.back()->str = *$1;
delete $1;
}
} |
TOK_COVER TOK_PROPERTY '(' expr ')' ';' {
ast_stack.back()->children.push_back(new AstNode(AST_COVER, $4));
opt_sva_label TOK_COVER TOK_PROPERTY '(' expr ')' ';' {
ast_stack.back()->children.push_back(new AstNode(AST_COVER, $5));
if ($1 != nullptr) {
ast_stack.back()->children.back()->str = *$1;
delete $1;
}
} |
TOK_RESTRICT TOK_PROPERTY '(' expr ')' ';' {
if (norestrict_mode)
delete $4;
else
ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $4));
} |
TOK_RESTRICT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' {
if (norestrict_mode)
opt_sva_label TOK_RESTRICT TOK_PROPERTY '(' expr ')' ';' {
if (norestrict_mode) {
delete $5;
else
ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $5));
} else {
ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $5));
if ($1 != nullptr) {
ast_stack.back()->children.back()->str = *$1;
delete $1;
}
}
} |
opt_sva_label TOK_RESTRICT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' {
if (norestrict_mode) {
delete $6;
} else {
ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $6));
if ($1 != nullptr) {
ast_stack.back()->children.back()->str = *$1;
delete $1;
}
}
};
simple_behavioral_stmt:
@ -1670,6 +2044,11 @@ case_expr_list:
TOK_DEFAULT {
ast_stack.back()->children.push_back(new AstNode(AST_DEFAULT));
} |
TOK_SVA_LABEL {
ast_stack.back()->children.push_back(new AstNode(AST_IDENTIFIER));
ast_stack.back()->children.back()->str = *$1;
delete $1;
} |
expr {
ast_stack.back()->children.push_back($1);
} |
@ -2048,4 +2427,3 @@ concat_list:
$$ = $3;
$$->children.push_back($1);
};

View File

@ -453,7 +453,7 @@ Aig::Aig(Cell *cell)
int B = mk.inport("\\B");
int C = mk.inport("\\C");
int D = mk.inport("\\D");
int Y = mk.nand_gate(mk.nor_gate(A, B), mk.nor_gate(C, D));
int Y = mk.nand_gate(mk.or_gate(A, B), mk.or_gate(C, D));
mk.outport(Y, "\\Y");
goto optimize;
}

View File

@ -81,6 +81,32 @@ struct CellTypes
}
void setup_internals()
{
setup_internals_eval();
IdString A = "\\A", B = "\\B", EN = "\\EN", Y = "\\Y";
IdString SRC = "\\SRC", DST = "\\DST", DAT = "\\DAT";
IdString EN_SRC = "\\EN_SRC", EN_DST = "\\EN_DST";
setup_type("$tribuf", {A, EN}, {Y}, true);
setup_type("$assert", {A, EN}, pool<RTLIL::IdString>(), true);
setup_type("$assume", {A, EN}, pool<RTLIL::IdString>(), true);
setup_type("$live", {A, EN}, pool<RTLIL::IdString>(), true);
setup_type("$fair", {A, EN}, pool<RTLIL::IdString>(), true);
setup_type("$cover", {A, EN}, pool<RTLIL::IdString>(), true);
setup_type("$initstate", pool<RTLIL::IdString>(), {Y}, true);
setup_type("$anyconst", pool<RTLIL::IdString>(), {Y}, true);
setup_type("$anyseq", pool<RTLIL::IdString>(), {Y}, true);
setup_type("$allconst", pool<RTLIL::IdString>(), {Y}, true);
setup_type("$allseq", pool<RTLIL::IdString>(), {Y}, true);
setup_type("$equiv", {A, B}, {Y}, true);
setup_type("$specify2", {EN, SRC, DST}, pool<RTLIL::IdString>(), true);
setup_type("$specify3", {EN, SRC, DST, DAT}, pool<RTLIL::IdString>(), true);
setup_type("$specrule", {EN_SRC, EN_DST, SRC, DST}, pool<RTLIL::IdString>(), true);
}
void setup_internals_eval()
{
std::vector<RTLIL::IdString> unary_ops = {
"$not", "$pos", "$neg",
@ -111,20 +137,6 @@ struct CellTypes
setup_type("$lcu", {P, G, CI}, {CO}, true);
setup_type("$alu", {A, B, CI, BI}, {X, Y, CO}, true);
setup_type("$fa", {A, B, C}, {X, Y}, true);
setup_type("$tribuf", {A, EN}, {Y}, true);
setup_type("$assert", {A, EN}, pool<RTLIL::IdString>(), true);
setup_type("$assume", {A, EN}, pool<RTLIL::IdString>(), true);
setup_type("$live", {A, EN}, pool<RTLIL::IdString>(), true);
setup_type("$fair", {A, EN}, pool<RTLIL::IdString>(), true);
setup_type("$cover", {A, EN}, pool<RTLIL::IdString>(), true);
setup_type("$initstate", pool<RTLIL::IdString>(), {Y}, true);
setup_type("$anyconst", pool<RTLIL::IdString>(), {Y}, true);
setup_type("$anyseq", pool<RTLIL::IdString>(), {Y}, true);
setup_type("$allconst", pool<RTLIL::IdString>(), {Y}, true);
setup_type("$allseq", pool<RTLIL::IdString>(), {Y}, true);
setup_type("$equiv", {A, B}, {Y}, true);
}
void setup_internals_mem()
@ -153,6 +165,15 @@ struct CellTypes
}
void setup_stdcells()
{
setup_stdcells_eval();
IdString A = "\\A", E = "\\E", Y = "\\Y";
setup_type("$_TBUF_", {A, E}, {Y}, true);
}
void setup_stdcells_eval()
{
IdString A = "\\A", B = "\\B", C = "\\C", D = "\\D";
IdString E = "\\E", F = "\\F", G = "\\G", H = "\\H";
@ -179,7 +200,6 @@ struct CellTypes
setup_type("$_OAI3_", {A, B, C}, {Y}, true);
setup_type("$_AOI4_", {A, B, C, D}, {Y}, true);
setup_type("$_OAI4_", {A, B, C, D}, {Y}, true);
setup_type("$_TBUF_", {A, E}, {Y}, true);
}
void setup_stdcells_mem()
@ -449,7 +469,7 @@ struct CellTypes
if (cell->type == "$_AOI4_")
return eval_not(const_or(const_and(arg1, arg2, false, false, 1), const_and(arg3, arg4, false, false, 1), false, false, 1));
if (cell->type == "$_OAI4_")
return eval_not(const_and(const_or(arg1, arg2, false, false, 1), const_and(arg3, arg4, false, false, 1), false, false, 1));
return eval_not(const_and(const_or(arg1, arg2, false, false, 1), const_or(arg3, arg4, false, false, 1), false, false, 1));
log_assert(arg4.bits.size() == 0);
return eval(cell, arg1, arg2, arg3, errp);

View File

@ -26,7 +26,7 @@ YOSYS_NAMESPACE_BEGIN
int get_cell_cost(RTLIL::Cell *cell, dict<RTLIL::IdString, int> *mod_cost_cache = nullptr);
int get_cell_cost(RTLIL::IdString type, const dict<RTLIL::IdString, RTLIL::Const> &parameters = dict<RTLIL::IdString, RTLIL::Const>(),
inline int get_cell_cost(RTLIL::IdString type, const dict<RTLIL::IdString, RTLIL::Const> &parameters = dict<RTLIL::IdString, RTLIL::Const>(),
RTLIL::Design *design = nullptr, dict<RTLIL::IdString, int> *mod_cost_cache = nullptr)
{
static dict<RTLIL::IdString, int> gate_cost = {
@ -76,7 +76,7 @@ int get_cell_cost(RTLIL::IdString type, const dict<RTLIL::IdString, RTLIL::Const
return 1;
}
int get_cell_cost(RTLIL::Cell *cell, dict<RTLIL::IdString, int> *mod_cost_cache)
inline int get_cell_cost(RTLIL::Cell *cell, dict<RTLIL::IdString, int> *mod_cost_cache)
{
return get_cell_cost(cell->type, cell->parameters, cell->module->design, mod_cost_cache);
}

View File

@ -110,6 +110,10 @@ int main(int argc, char **argv)
log_error_stderr = true;
yosys_banner();
yosys_setup();
#ifdef WITH_PYTHON
PyRun_SimpleString(("sys.path.append(\""+proc_self_dirname()+"\")").c_str());
PyRun_SimpleString(("sys.path.append(\""+proc_share_dirname()+"plugins\")").c_str());
#endif
if (argc == 2)
{
@ -179,6 +183,7 @@ int main(int argc, char **argv)
{
std::string frontend_command = "auto";
std::string backend_command = "auto";
std::vector<std::string> vlog_defines;
std::vector<std::string> passes_commands;
std::vector<std::string> plugin_filenames;
std::string output_filename = "";
@ -268,7 +273,10 @@ int main(int argc, char **argv)
printf(" -A\n");
printf(" will call abort() at the end of the script. for debugging\n");
printf("\n");
printf(" -D <header_id>[:<filename>]\n");
printf(" -D <macro>[=<value>]\n");
printf(" set the specified Verilog define (via \"read -define\")\n");
printf("\n");
printf(" -P <header_id>[:<filename>]\n");
printf(" dump the design when printing the specified log header to a file.\n");
printf(" yosys_dump_<header_id>.il is used as filename if none is specified.\n");
printf(" Use 'ALL' as <header_id> to dump at every header.\n");
@ -287,6 +295,9 @@ int main(int argc, char **argv)
printf(" -E <depsfile>\n");
printf(" write a Makefile dependencies file with in- and output file names\n");
printf("\n");
printf(" -g\n");
printf(" globally enable debug log messages\n");
printf("\n");
printf(" -V\n");
printf(" print version information and exit\n");
printf("\n");
@ -307,7 +318,7 @@ int main(int argc, char **argv)
}
int opt;
while ((opt = getopt(argc, argv, "MXAQTVSm:f:Hh:b:o:p:l:L:qv:tds:c:W:w:e:D:E:")) != -1)
while ((opt = getopt(argc, argv, "MXAQTVSgm:f:Hh:b:o:p:l:L:qv:tds:c:W:w:e:D:P:E:")) != -1)
{
switch (opt)
{
@ -332,6 +343,9 @@ int main(int argc, char **argv)
case 'S':
passes_commands.push_back("synth");
break;
case 'g':
log_force_debug++;
break;
case 'm':
plugin_filenames.push_back(optarg);
break;
@ -408,6 +422,9 @@ int main(int argc, char **argv)
std::regex_constants::egrep));
break;
case 'D':
vlog_defines.push_back(optarg);
break;
case 'P':
{
auto args = split_tokens(optarg, ":");
if (!args.empty() && args[0] == "ALL") {
@ -462,6 +479,10 @@ int main(int argc, char **argv)
#endif
yosys_setup();
#ifdef WITH_PYTHON
PyRun_SimpleString(("sys.path.append(\""+proc_self_dirname()+"\")").c_str());
PyRun_SimpleString(("sys.path.append(\""+proc_share_dirname()+"plugins\")").c_str());
#endif
log_error_atexit = yosys_atexit;
for (auto &fn : plugin_filenames)
@ -473,6 +494,13 @@ int main(int argc, char **argv)
shell(yosys_design);
}
if (!vlog_defines.empty()) {
std::string vdef_cmd = "read -define";
for (auto vdef : vlog_defines)
vdef_cmd += " " + vdef;
run_pass(vdef_cmd);
}
while (optind < argc)
run_frontend(argv[optind++], frontend_command, output_filename == "-" ? &backend_command : NULL);
@ -501,13 +529,13 @@ int main(int argc, char **argv)
log_error("Can't open dependencies file for writing: %s\n", strerror(errno));
bool first = true;
for (auto fn : yosys_output_files) {
fprintf(f, "%s%s", first ? "" : " ", fn.c_str());
fprintf(f, "%s%s", first ? "" : " ", escape_filename_spaces(fn).c_str());
first = false;
}
fprintf(f, ":");
for (auto fn : yosys_input_files) {
if (yosys_output_files.count(fn) == 0)
fprintf(f, " %s", fn.c_str());
fprintf(f, " %s", escape_filename_spaces(fn).c_str());
}
fprintf(f, "\n");
}

View File

@ -557,9 +557,11 @@ public:
void clear() { hashtable.clear(); entries.clear(); }
iterator begin() { return iterator(this, int(entries.size())-1); }
iterator element(int n) { return iterator(this, int(entries.size())-1-n); }
iterator end() { return iterator(nullptr, -1); }
const_iterator begin() const { return const_iterator(this, int(entries.size())-1); }
const_iterator element(int n) const { return const_iterator(this, int(entries.size())-1-n); }
const_iterator end() const { return const_iterator(nullptr, -1); }
};
@ -881,9 +883,11 @@ public:
void clear() { hashtable.clear(); entries.clear(); }
iterator begin() { return iterator(this, int(entries.size())-1); }
iterator element(int n) { return iterator(this, int(entries.size())-1-n); }
iterator end() { return iterator(nullptr, -1); }
const_iterator begin() const { return const_iterator(this, int(entries.size())-1); }
const_iterator element(int n) const { return const_iterator(this, int(entries.size())-1-n); }
const_iterator end() const { return const_iterator(nullptr, -1); }
};
@ -952,6 +956,7 @@ public:
void clear() { database.clear(); }
const_iterator begin() const { return database.begin(); }
const_iterator element(int n) const { return database.element(n); }
const_iterator end() const { return database.end(); }
};
@ -1051,6 +1056,7 @@ public:
void clear() { database.clear(); parents.clear(); }
const_iterator begin() const { return database.begin(); }
const_iterator element(int n) const { return database.element(n); }
const_iterator end() const { return database.end(); }
};

View File

@ -56,6 +56,10 @@ int log_verbose_level;
string log_last_error;
void (*log_error_atexit)() = NULL;
int log_make_debug = 0;
int log_force_debug = 0;
int log_debug_suppressed = 0;
vector<int> header_count;
pool<RTLIL::IdString> log_id_cache;
vector<shared_str> string_buf;
@ -92,6 +96,9 @@ void logv(const char *format, va_list ap)
format++;
}
if (log_make_debug && !ys_debug(1))
return;
std::string str = vstringf(format, ap);
if (str.empty())
@ -196,7 +203,11 @@ void logv_header(RTLIL::Design *design, const char *format, va_list ap)
if (log_hdump.count(header_id) && design != nullptr)
for (auto &filename : log_hdump.at(header_id)) {
log("Dumping current design to '%s'.\n", filename.c_str());
if (yosys_xtrace)
IdString::xtrace_db_dump();
Pass::call(design, {"dump", "-o", filename});
if (yosys_xtrace)
log("#X# -- end of dump --\n");
}
if (pop_errfile)

View File

@ -64,6 +64,10 @@ extern int log_verbose_level;
extern string log_last_error;
extern void (*log_error_atexit)();
extern int log_make_debug;
extern int log_force_debug;
extern int log_debug_suppressed;
void logv(const char *format, va_list ap);
void logv_header(RTLIL::Design *design, const char *format, va_list ap);
void logv_warning(const char *format, va_list ap);
@ -82,6 +86,45 @@ YS_NORETURN void log_error(const char *format, ...) YS_ATTRIBUTE(format(printf,
void log_file_error(const string &filename, int lineno, const char *format, ...) YS_ATTRIBUTE(format(printf, 3, 4), noreturn);
YS_NORETURN void log_cmd_error(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2), noreturn);
#ifndef NDEBUG
static inline bool ys_debug(int n = 0) { if (log_force_debug) return true; log_debug_suppressed += n; return false; }
# define log_debug(...) do { if (ys_debug(1)) log(__VA_ARGS__); } while (0)
#else
static inline bool ys_debug(int n = 0) { return false; }
# define log_debug(_fmt, ...) do { } while (0)
#endif
static inline void log_suppressed() {
if (log_debug_suppressed && !log_make_debug) {
log("<suppressed ~%d debug messages>\n", log_debug_suppressed);
log_debug_suppressed = 0;
}
}
struct LogMakeDebugHdl {
bool status = false;
LogMakeDebugHdl(bool start_on = false) {
if (start_on)
on();
}
~LogMakeDebugHdl() {
off();
}
void on() {
if (status) return;
status=true;
log_make_debug++;
}
void off_silent() {
if (!status) return;
status=false;
log_make_debug--;
}
void off() {
off_silent();
}
};
void log_spacer();
void log_push();
void log_pop();
@ -94,7 +137,9 @@ const char *log_signal(const RTLIL::SigSpec &sig, bool autoint = true);
const char *log_const(const RTLIL::Const &value, bool autoint = true);
const char *log_id(RTLIL::IdString id);
template<typename T> static inline const char *log_id(T *obj) {
template<typename T> static inline const char *log_id(T *obj, const char *nullstr = nullptr) {
if (nullstr && obj == nullptr)
return nullstr;
return log_id(obj->name);
}

View File

@ -86,6 +86,9 @@ Pass::pre_post_exec_state_t Pass::pre_execute()
void Pass::post_execute(Pass::pre_post_exec_state_t state)
{
IdString::checkpoint();
log_suppressed();
int64_t time_ns = PerformanceTimer::query() - state.begin_ns;
runtime_ns += time_ns;
current_pass = state.parent_pass;

View File

@ -33,6 +33,8 @@ std::vector<int> RTLIL::IdString::global_refcount_storage_;
std::vector<char*> RTLIL::IdString::global_id_storage_;
dict<char*, int, hash_cstr_ops> RTLIL::IdString::global_id_index_;
std::vector<int> RTLIL::IdString::global_free_idx_list_;
int RTLIL::IdString::last_created_idx_[8];
int RTLIL::IdString::last_created_idx_ptr_;
RTLIL::Const::Const()
{
@ -74,6 +76,13 @@ RTLIL::Const::Const(const std::vector<bool> &bits)
this->bits.push_back(b ? RTLIL::S1 : RTLIL::S0);
}
RTLIL::Const::Const(const RTLIL::Const &c)
{
flags = c.flags;
for (auto b : c.bits)
this->bits.push_back(b);
}
bool RTLIL::Const::operator <(const RTLIL::Const &other) const
{
if (bits.size() != other.bits.size())
@ -205,16 +214,23 @@ bool RTLIL::Const::is_fully_undef() const
return true;
}
void RTLIL::AttrObject::set_bool_attribute(RTLIL::IdString id)
void RTLIL::AttrObject::set_bool_attribute(RTLIL::IdString id, bool value)
{
attributes[id] = RTLIL::Const(1);
if (value)
attributes[id] = RTLIL::Const(1);
else {
const auto it = attributes.find(id);
if (it != attributes.end())
attributes.erase(it);
}
}
bool RTLIL::AttrObject::get_bool_attribute(RTLIL::IdString id) const
{
if (attributes.count(id) == 0)
const auto it = attributes.find(id);
if (it == attributes.end())
return false;
return attributes.at(id).as_bool();
return it->second.as_bool();
}
void RTLIL::AttrObject::set_strpool_attribute(RTLIL::IdString id, const pool<string> &data)
@ -358,6 +374,10 @@ RTLIL::Design::Design()
refcount_modules_ = 0;
selection_stack.push_back(RTLIL::Selection());
#ifdef WITH_PYTHON
RTLIL::Design::get_all_designs()->insert(std::pair<unsigned int, RTLIL::Design*>(hashidx_, this));
#endif
}
RTLIL::Design::~Design()
@ -368,8 +388,19 @@ RTLIL::Design::~Design()
delete n;
for (auto n : verilog_globals)
delete n;
#ifdef WITH_PYTHON
RTLIL::Design::get_all_designs()->erase(hashidx_);
#endif
}
#ifdef WITH_PYTHON
static std::map<unsigned int, RTLIL::Design*> all_designs;
std::map<unsigned int, RTLIL::Design*> *RTLIL::Design::get_all_designs(void)
{
return &all_designs;
}
#endif
RTLIL::ObjRange<RTLIL::Module*> RTLIL::Design::modules()
{
return RTLIL::ObjRange<RTLIL::Module*>(&modules_, &refcount_modules_);
@ -587,7 +618,7 @@ std::vector<RTLIL::Module*> RTLIL::Design::selected_modules() const
std::vector<RTLIL::Module*> result;
result.reserve(modules_.size());
for (auto &it : modules_)
if (selected_module(it.first) && !it.second->get_bool_attribute("\\blackbox"))
if (selected_module(it.first) && !it.second->get_blackbox_attribute())
result.push_back(it.second);
return result;
}
@ -597,7 +628,7 @@ std::vector<RTLIL::Module*> RTLIL::Design::selected_whole_modules() const
std::vector<RTLIL::Module*> result;
result.reserve(modules_.size());
for (auto &it : modules_)
if (selected_whole_module(it.first) && !it.second->get_bool_attribute("\\blackbox"))
if (selected_whole_module(it.first) && !it.second->get_blackbox_attribute())
result.push_back(it.second);
return result;
}
@ -607,7 +638,7 @@ std::vector<RTLIL::Module*> RTLIL::Design::selected_whole_modules_warn() const
std::vector<RTLIL::Module*> result;
result.reserve(modules_.size());
for (auto &it : modules_)
if (it.second->get_bool_attribute("\\blackbox"))
if (it.second->get_blackbox_attribute())
continue;
else if (selected_whole_module(it.first))
result.push_back(it.second);
@ -625,6 +656,10 @@ RTLIL::Module::Module()
design = nullptr;
refcount_wires_ = 0;
refcount_cells_ = 0;
#ifdef WITH_PYTHON
RTLIL::Module::get_all_modules()->insert(std::pair<unsigned int, RTLIL::Module*>(hashidx_, this));
#endif
}
RTLIL::Module::~Module()
@ -637,6 +672,41 @@ RTLIL::Module::~Module()
delete it->second;
for (auto it = processes.begin(); it != processes.end(); ++it)
delete it->second;
#ifdef WITH_PYTHON
RTLIL::Module::get_all_modules()->erase(hashidx_);
#endif
}
#ifdef WITH_PYTHON
static std::map<unsigned int, RTLIL::Module*> all_modules;
std::map<unsigned int, RTLIL::Module*> *RTLIL::Module::get_all_modules(void)
{
return &all_modules;
}
#endif
void RTLIL::Module::makeblackbox()
{
pool<RTLIL::Wire*> delwires;
for (auto it = wires_.begin(); it != wires_.end(); ++it)
if (!it->second->port_input && !it->second->port_output)
delwires.insert(it->second);
for (auto it = memories.begin(); it != memories.end(); ++it)
delete it->second;
memories.clear();
for (auto it = cells_.begin(); it != cells_.end(); ++it)
delete it->second;
cells_.clear();
for (auto it = processes.begin(); it != processes.end(); ++it)
delete it->second;
processes.clear();
remove(delwires);
set_bool_attribute("\\blackbox");
}
void RTLIL::Module::reprocess_module(RTLIL::Design *, dict<RTLIL::IdString, RTLIL::Module *>)
@ -758,7 +828,7 @@ namespace {
void check()
{
if (cell->type.substr(0, 1) != "$" || cell->type.substr(0, 3) == "$__" || cell->type.substr(0, 8) == "$paramod" ||
if (cell->type.substr(0, 1) != "$" || cell->type.substr(0, 3) == "$__" || cell->type.substr(0, 8) == "$paramod" || cell->type.substr(0,10) == "$fmcombine" ||
cell->type.substr(0, 9) == "$verific$" || cell->type.substr(0, 7) == "$array:" || cell->type.substr(0, 8) == "$extern:")
return;
@ -1128,6 +1198,46 @@ namespace {
return;
}
if (cell->type.in("$specify2", "$specify3")) {
param_bool("\\FULL");
param_bool("\\SRC_DST_PEN");
param_bool("\\SRC_DST_POL");
param("\\T_RISE_MIN");
param("\\T_RISE_TYP");
param("\\T_RISE_MAX");
param("\\T_FALL_MIN");
param("\\T_FALL_TYP");
param("\\T_FALL_MAX");
port("\\EN", 1);
port("\\SRC", param("\\SRC_WIDTH"));
port("\\DST", param("\\DST_WIDTH"));
if (cell->type == "$specify3") {
param_bool("\\EDGE_EN");
param_bool("\\EDGE_POL");
param_bool("\\DAT_DST_PEN");
param_bool("\\DAT_DST_POL");
port("\\DAT", param("\\DST_WIDTH"));
}
check_expected();
return;
}
if (cell->type == "$specrule") {
param("\\TYPE");
param_bool("\\SRC_PEN");
param_bool("\\SRC_POL");
param_bool("\\DST_PEN");
param_bool("\\DST_POL");
param("\\T_LIMIT");
param("\\T_LIMIT2");
port("\\SRC_EN", 1);
port("\\DST_EN", 1);
port("\\SRC", param("\\SRC_WIDTH"));
port("\\DST", param("\\DST_WIDTH"));
check_expected();
return;
}
if (cell->type == "$_BUF_") { check_gate("AY"); return; }
if (cell->type == "$_NOT_") { check_gate("AY"); return; }
if (cell->type == "$_AND_") { check_gate("ABY"); return; }
@ -1404,7 +1514,10 @@ void RTLIL::Module::add(RTLIL::Cell *cell)
cell->module = this;
}
namespace {
void RTLIL::Module::remove(const pool<RTLIL::Wire*> &wires)
{
log_assert(refcount_wires_ == 0);
struct DeleteWireWorker
{
RTLIL::Module *module;
@ -1419,17 +1532,29 @@ namespace {
}
sig = chunks;
}
};
}
void RTLIL::Module::remove(const pool<RTLIL::Wire*> &wires)
{
log_assert(refcount_wires_ == 0);
void operator()(RTLIL::SigSpec &lhs, RTLIL::SigSpec &rhs) {
log_assert(GetSize(lhs) == GetSize(rhs));
RTLIL::SigSpec new_lhs, new_rhs;
for (int i = 0; i < GetSize(lhs); i++) {
RTLIL::SigBit lhs_bit = lhs[i];
if (lhs_bit.wire != nullptr && wires_p->count(lhs_bit.wire))
continue;
RTLIL::SigBit rhs_bit = rhs[i];
if (rhs_bit.wire != nullptr && wires_p->count(rhs_bit.wire))
continue;
new_lhs.append(lhs_bit);
new_rhs.append(rhs_bit);
}
lhs = new_lhs;
rhs = new_rhs;
}
};
DeleteWireWorker delete_wire_worker;
delete_wire_worker.module = this;
delete_wire_worker.wires_p = &wires;
rewrite_sigspecs(delete_wire_worker);
rewrite_sigspecs2(delete_wire_worker);
for (auto &it : wires) {
log_assert(wires_.count(it->name) != 0);
@ -2200,8 +2325,27 @@ RTLIL::Wire::Wire()
port_input = false;
port_output = false;
upto = false;
#ifdef WITH_PYTHON
RTLIL::Wire::get_all_wires()->insert(std::pair<unsigned int, RTLIL::Wire*>(hashidx_, this));
#endif
}
RTLIL::Wire::~Wire()
{
#ifdef WITH_PYTHON
RTLIL::Wire::get_all_wires()->erase(hashidx_);
#endif
}
#ifdef WITH_PYTHON
static std::map<unsigned int, RTLIL::Wire*> all_wires;
std::map<unsigned int, RTLIL::Wire*> *RTLIL::Wire::get_all_wires(void)
{
return &all_wires;
}
#endif
RTLIL::Memory::Memory()
{
static unsigned int hashidx_count = 123456789;
@ -2211,6 +2355,9 @@ RTLIL::Memory::Memory()
width = 1;
start_offset = 0;
size = 0;
#ifdef WITH_PYTHON
RTLIL::Memory::get_all_memorys()->insert(std::pair<unsigned int, RTLIL::Memory*>(hashidx_, this));
#endif
}
RTLIL::Cell::Cell() : module(nullptr)
@ -2221,8 +2368,27 @@ RTLIL::Cell::Cell() : module(nullptr)
// log("#memtrace# %p\n", this);
memhasher();
#ifdef WITH_PYTHON
RTLIL::Cell::get_all_cells()->insert(std::pair<unsigned int, RTLIL::Cell*>(hashidx_, this));
#endif
}
RTLIL::Cell::~Cell()
{
#ifdef WITH_PYTHON
RTLIL::Cell::get_all_cells()->erase(hashidx_);
#endif
}
#ifdef WITH_PYTHON
static std::map<unsigned int, RTLIL::Cell*> all_cells;
std::map<unsigned int, RTLIL::Cell*> *RTLIL::Cell::get_all_cells(void)
{
return &all_cells;
}
#endif
bool RTLIL::Cell::hasPort(RTLIL::IdString portname) const
{
return connections_.count(portname) != 0;
@ -2358,7 +2524,7 @@ void RTLIL::Cell::check()
void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed)
{
if (type.substr(0, 1) != "$" || type.substr(0, 2) == "$_" || type.substr(0, 8) == "$paramod" ||
if (type.substr(0, 1) != "$" || type.substr(0, 2) == "$_" || type.substr(0, 8) == "$paramod" || type.substr(0,10) == "$fmcombine" ||
type.substr(0, 9) == "$verific$" || type.substr(0, 7) == "$array:" || type.substr(0, 8) == "$extern:")
return;
@ -2410,6 +2576,9 @@ void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed)
if (connections_.count("\\Y"))
parameters["\\Y_WIDTH"] = GetSize(connections_["\\Y"]);
if (connections_.count("\\Q"))
parameters["\\WIDTH"] = GetSize(connections_["\\Q"]);
check();
}
@ -2479,6 +2648,14 @@ RTLIL::SigChunk::SigChunk(RTLIL::SigBit bit)
width = 1;
}
RTLIL::SigChunk::SigChunk(const RTLIL::SigChunk &sigchunk) : data(sigchunk.data)
{
wire = sigchunk.wire;
data = sigchunk.data;
width = sigchunk.width;
offset = sigchunk.offset;
}
RTLIL::SigChunk RTLIL::SigChunk::extract(int offset, int length) const
{
RTLIL::SigChunk ret;
@ -3232,7 +3409,7 @@ void RTLIL::SigSpec::extend_u0(int width, bool is_signed)
remove(width, width_ - width);
if (width_ < width) {
RTLIL::SigBit padding = width_ > 0 ? (*this)[width_ - 1] : RTLIL::State::S0;
RTLIL::SigBit padding = width_ > 0 ? (*this)[width_ - 1] : RTLIL::State::Sx;
if (!is_signed)
padding = RTLIL::State::S0;
while (width_ < width)
@ -3338,7 +3515,7 @@ bool RTLIL::SigSpec::operator ==(const RTLIL::SigSpec &other) const
pack();
other.pack();
if (chunks_.size() != chunks_.size())
if (chunks_.size() != other.chunks_.size())
return false;
updhash();
@ -3863,5 +4040,15 @@ RTLIL::Process *RTLIL::Process::clone() const
return new_proc;
}
#ifdef WITH_PYTHON
RTLIL::Memory::~Memory()
{
RTLIL::Memory::get_all_memorys()->erase(hashidx_);
}
static std::map<unsigned int, RTLIL::Memory*> all_memorys;
std::map<unsigned int, RTLIL::Memory*> *RTLIL::Memory::get_all_memorys(void)
{
return &all_memorys;
}
#endif
YOSYS_NAMESPACE_END

View File

@ -50,7 +50,7 @@ namespace RTLIL
CONST_FLAG_NONE = 0,
CONST_FLAG_STRING = 1,
CONST_FLAG_SIGNED = 2, // only used for parameters
CONST_FLAG_REAL = 4 // unused -- to be used for parameters
CONST_FLAG_REAL = 4 // only used for parameters
};
struct Const;
@ -76,6 +76,9 @@ namespace RTLIL
struct IdString
{
#undef YOSYS_XTRACE_GET_PUT
#undef YOSYS_SORT_ID_FREE_LIST
// the global id string cache
static struct destruct_guard_t {
@ -89,9 +92,43 @@ namespace RTLIL
static dict<char*, int, hash_cstr_ops> global_id_index_;
static std::vector<int> global_free_idx_list_;
static int last_created_idx_ptr_;
static int last_created_idx_[8];
static inline void xtrace_db_dump()
{
#ifdef YOSYS_XTRACE_GET_PUT
for (int idx = 0; idx < GetSize(global_id_storage_); idx++)
{
if (global_id_storage_.at(idx) == nullptr)
log("#X# DB-DUMP index %d: FREE\n", idx);
else
log("#X# DB-DUMP index %d: '%s' (ref %d)\n", idx, global_id_storage_.at(idx), global_refcount_storage_.at(idx));
}
#endif
}
static inline void checkpoint()
{
last_created_idx_ptr_ = 0;
for (int i = 0; i < 8; i++) {
if (last_created_idx_[i])
put_reference(last_created_idx_[i]);
last_created_idx_[i] = 0;
}
#ifdef YOSYS_SORT_ID_FREE_LIST
std::sort(global_free_idx_list_.begin(), global_free_idx_list_.end(), std::greater<int>());
#endif
}
static inline int get_reference(int idx)
{
global_refcount_storage_.at(idx)++;
#ifdef YOSYS_XTRACE_GET_PUT
if (yosys_xtrace) {
log("#X# GET-BY-INDEX '%s' (index %d, refcount %d)\n", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx));
}
#endif
return idx;
}
@ -107,6 +144,11 @@ namespace RTLIL
auto it = global_id_index_.find((char*)p);
if (it != global_id_index_.end()) {
global_refcount_storage_.at(it->second)++;
#ifdef YOSYS_XTRACE_GET_PUT
if (yosys_xtrace) {
log("#X# GET-BY-NAME '%s' (index %d, refcount %d)\n", global_id_storage_.at(it->second), it->second, global_refcount_storage_.at(it->second));
}
#endif
return it->second;
}
@ -124,16 +166,22 @@ namespace RTLIL
global_refcount_storage_.at(idx)++;
// Avoid Create->Delete->Create pattern
static IdString last_created_id;
put_reference(last_created_id.index_);
last_created_id.index_ = idx;
get_reference(last_created_id.index_);
if (last_created_idx_[last_created_idx_ptr_])
put_reference(last_created_idx_[last_created_idx_ptr_]);
last_created_idx_[last_created_idx_ptr_] = idx;
get_reference(last_created_idx_[last_created_idx_ptr_]);
last_created_idx_ptr_ = (last_created_idx_ptr_ + 1) & 7;
if (yosys_xtrace) {
log("#X# New IdString '%s' with index %d.\n", p, idx);
log_backtrace("-X- ", yosys_xtrace-1);
}
#ifdef YOSYS_XTRACE_GET_PUT
if (yosys_xtrace) {
log("#X# GET-BY-NAME '%s' (index %d, refcount %d)\n", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx));
}
#endif
return idx;
}
@ -144,6 +192,12 @@ namespace RTLIL
if (!destruct_guard.ok)
return;
#ifdef YOSYS_XTRACE_GET_PUT
if (yosys_xtrace) {
log("#X# PUT '%s' (index %d, refcount %d)\n", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx));
}
#endif
log_assert(global_refcount_storage_.at(idx) > 0);
if (--global_refcount_storage_.at(idx) != 0)
@ -463,6 +517,8 @@ struct RTLIL::Const
Const(RTLIL::State bit, int width = 1);
Const(const std::vector<RTLIL::State> &bits) : bits(bits) { flags = CONST_FLAG_NONE; }
Const(const std::vector<bool> &bits);
Const(const RTLIL::Const &c);
RTLIL::Const &operator =(const RTLIL::Const &other) = default;
bool operator <(const RTLIL::Const &other) const;
bool operator ==(const RTLIL::Const &other) const;
@ -492,6 +548,14 @@ struct RTLIL::Const
return ret;
}
void extu(int width) {
bits.resize(width, RTLIL::State::S0);
}
void exts(int width) {
bits.resize(width, bits.empty() ? RTLIL::State::Sx : bits.back());
}
inline unsigned int hash() const {
unsigned int h = mkhash_init;
for (auto b : bits)
@ -504,9 +568,13 @@ struct RTLIL::AttrObject
{
dict<RTLIL::IdString, RTLIL::Const> attributes;
void set_bool_attribute(RTLIL::IdString id);
void set_bool_attribute(RTLIL::IdString id, bool value=true);
bool get_bool_attribute(RTLIL::IdString id) const;
bool get_blackbox_attribute(bool ignore_wb=false) const {
return get_bool_attribute("\\blackbox") || (!ignore_wb && get_bool_attribute("\\whitebox"));
}
void set_strpool_attribute(RTLIL::IdString id, const pool<string> &data);
void add_strpool_attribute(RTLIL::IdString id, const pool<string> &data);
pool<string> get_strpool_attribute(RTLIL::IdString id) const;
@ -529,6 +597,8 @@ struct RTLIL::SigChunk
SigChunk(int val, int width = 32);
SigChunk(RTLIL::State bit, int width = 1);
SigChunk(RTLIL::SigBit bit);
SigChunk(const RTLIL::SigChunk &sigchunk);
RTLIL::SigChunk &operator =(const RTLIL::SigChunk &other) = default;
RTLIL::SigChunk extract(int offset, int length) const;
@ -553,6 +623,8 @@ struct RTLIL::SigBit
SigBit(const RTLIL::SigChunk &chunk);
SigBit(const RTLIL::SigChunk &chunk, int index);
SigBit(const RTLIL::SigSpec &sig);
SigBit(const RTLIL::SigBit &sigbit);
RTLIL::SigBit &operator =(const RTLIL::SigBit &other) = default;
bool operator <(const RTLIL::SigBit &other) const;
bool operator ==(const RTLIL::SigBit &other) const;
@ -874,9 +946,13 @@ struct RTLIL::Design
}
}
std::vector<RTLIL::Module*> selected_modules() const;
std::vector<RTLIL::Module*> selected_whole_modules() const;
std::vector<RTLIL::Module*> selected_whole_modules_warn() const;
#ifdef WITH_PYTHON
static std::map<unsigned int, RTLIL::Design*> *get_all_designs(void);
#endif
};
struct RTLIL::Module : public RTLIL::AttrObject
@ -914,6 +990,7 @@ public:
virtual void sort();
virtual void check();
virtual void optimize();
virtual void makeblackbox();
void connect(const RTLIL::SigSig &conn);
void connect(const RTLIL::SigSpec &lhs, const RTLIL::SigSpec &rhs);
@ -924,6 +1001,7 @@ public:
void fixup_ports();
template<typename T> void rewrite_sigspecs(T &functor);
template<typename T> void rewrite_sigspecs2(T &functor);
void cloneInto(RTLIL::Module *new_mod) const;
virtual RTLIL::Module *clone() const;
@ -1132,6 +1210,10 @@ public:
RTLIL::SigSpec Allconst (RTLIL::IdString name, int width = 1, const std::string &src = "");
RTLIL::SigSpec Allseq (RTLIL::IdString name, int width = 1, const std::string &src = "");
RTLIL::SigSpec Initstate (RTLIL::IdString name, const std::string &src = "");
#ifdef WITH_PYTHON
static std::map<unsigned int, RTLIL::Module*> *get_all_modules(void);
#endif
};
struct RTLIL::Wire : public RTLIL::AttrObject
@ -1143,7 +1225,7 @@ protected:
// use module->addWire() and module->remove() to create or destroy wires
friend struct RTLIL::Module;
Wire();
~Wire() { };
~Wire();
public:
// do not simply copy wires
@ -1154,6 +1236,10 @@ public:
RTLIL::IdString name;
int width, start_offset, port_id;
bool port_input, port_output, upto;
#ifdef WITH_PYTHON
static std::map<unsigned int, RTLIL::Wire*> *get_all_wires(void);
#endif
};
struct RTLIL::Memory : public RTLIL::AttrObject
@ -1165,6 +1251,10 @@ struct RTLIL::Memory : public RTLIL::AttrObject
RTLIL::IdString name;
int width, start_offset, size;
#ifdef WITH_PYTHON
~Memory();
static std::map<unsigned int, RTLIL::Memory*> *get_all_memorys(void);
#endif
};
struct RTLIL::Cell : public RTLIL::AttrObject
@ -1176,6 +1266,7 @@ protected:
// use module->addCell() and module->remove() to create or destroy cells
friend struct RTLIL::Module;
Cell();
~Cell();
public:
// do not simply copy cells
@ -1216,6 +1307,11 @@ public:
}
template<typename T> void rewrite_sigspecs(T &functor);
template<typename T> void rewrite_sigspecs2(T &functor);
#ifdef WITH_PYTHON
static std::map<unsigned int, RTLIL::Cell*> *get_all_cells(void);
#endif
};
struct RTLIL::CaseRule
@ -1230,6 +1326,7 @@ struct RTLIL::CaseRule
bool empty() const;
template<typename T> void rewrite_sigspecs(T &functor);
template<typename T> void rewrite_sigspecs2(T &functor);
RTLIL::CaseRule *clone() const;
};
@ -1243,6 +1340,7 @@ struct RTLIL::SwitchRule : public RTLIL::AttrObject
bool empty() const;
template<typename T> void rewrite_sigspecs(T &functor);
template<typename T> void rewrite_sigspecs2(T &functor);
RTLIL::SwitchRule *clone() const;
};
@ -1253,6 +1351,7 @@ struct RTLIL::SyncRule
std::vector<RTLIL::SigSig> actions;
template<typename T> void rewrite_sigspecs(T &functor);
template<typename T> void rewrite_sigspecs2(T &functor);
RTLIL::SyncRule *clone() const;
};
@ -1265,6 +1364,7 @@ struct RTLIL::Process : public RTLIL::AttrObject
~Process();
template<typename T> void rewrite_sigspecs(T &functor);
template<typename T> void rewrite_sigspecs2(T &functor);
RTLIL::Process *clone() const;
};
@ -1276,13 +1376,14 @@ inline RTLIL::SigBit::SigBit(RTLIL::Wire *wire) : wire(wire), offset(0) { log_as
inline RTLIL::SigBit::SigBit(RTLIL::Wire *wire, int offset) : wire(wire), offset(offset) { log_assert(wire != nullptr); }
inline RTLIL::SigBit::SigBit(const RTLIL::SigChunk &chunk) : wire(chunk.wire) { log_assert(chunk.width == 1); if (wire) offset = chunk.offset; else data = chunk.data[0]; }
inline RTLIL::SigBit::SigBit(const RTLIL::SigChunk &chunk, int index) : wire(chunk.wire) { if (wire) offset = chunk.offset + index; else data = chunk.data[index]; }
inline RTLIL::SigBit::SigBit(const RTLIL::SigBit &sigbit) : wire(sigbit.wire), data(sigbit.data){if(wire) offset = sigbit.offset;}
inline bool RTLIL::SigBit::operator<(const RTLIL::SigBit &other) const {
if (wire == other.wire)
return wire ? (offset < other.offset) : (data < other.data);
if (wire != nullptr && other.wire != nullptr)
return wire->name < other.wire->name;
return wire < other.wire;
return (wire != nullptr) < (other.wire != nullptr);
}
inline bool RTLIL::SigBit::operator==(const RTLIL::SigBit &other) const {
@ -1325,12 +1426,30 @@ void RTLIL::Module::rewrite_sigspecs(T &functor)
}
}
template<typename T>
void RTLIL::Module::rewrite_sigspecs2(T &functor)
{
for (auto &it : cells_)
it.second->rewrite_sigspecs2(functor);
for (auto &it : processes)
it.second->rewrite_sigspecs2(functor);
for (auto &it : connections_) {
functor(it.first, it.second);
}
}
template<typename T>
void RTLIL::Cell::rewrite_sigspecs(T &functor) {
for (auto &it : connections_)
functor(it.second);
}
template<typename T>
void RTLIL::Cell::rewrite_sigspecs2(T &functor) {
for (auto &it : connections_)
functor(it.second);
}
template<typename T>
void RTLIL::CaseRule::rewrite_sigspecs(T &functor) {
for (auto &it : compare)
@ -1343,6 +1462,17 @@ void RTLIL::CaseRule::rewrite_sigspecs(T &functor) {
it->rewrite_sigspecs(functor);
}
template<typename T>
void RTLIL::CaseRule::rewrite_sigspecs2(T &functor) {
for (auto &it : compare)
functor(it);
for (auto &it : actions) {
functor(it.first, it.second);
}
for (auto it : switches)
it->rewrite_sigspecs2(functor);
}
template<typename T>
void RTLIL::SwitchRule::rewrite_sigspecs(T &functor)
{
@ -1351,6 +1481,14 @@ void RTLIL::SwitchRule::rewrite_sigspecs(T &functor)
it->rewrite_sigspecs(functor);
}
template<typename T>
void RTLIL::SwitchRule::rewrite_sigspecs2(T &functor)
{
functor(signal);
for (auto it : cases)
it->rewrite_sigspecs2(functor);
}
template<typename T>
void RTLIL::SyncRule::rewrite_sigspecs(T &functor)
{
@ -1361,6 +1499,15 @@ void RTLIL::SyncRule::rewrite_sigspecs(T &functor)
}
}
template<typename T>
void RTLIL::SyncRule::rewrite_sigspecs2(T &functor)
{
functor(signal);
for (auto &it : actions) {
functor(it.first, it.second);
}
}
template<typename T>
void RTLIL::Process::rewrite_sigspecs(T &functor)
{
@ -1369,6 +1516,14 @@ void RTLIL::Process::rewrite_sigspecs(T &functor)
it->rewrite_sigspecs(functor);
}
template<typename T>
void RTLIL::Process::rewrite_sigspecs2(T &functor)
{
root_case.rewrite_sigspecs2(functor);
for (auto it : syncs)
it->rewrite_sigspecs2(functor);
}
YOSYS_NAMESPACE_END
#endif

View File

@ -33,7 +33,7 @@
# include <dlfcn.h>
#endif
#ifdef _WIN32
#if defined(_WIN32)
# include <windows.h>
# include <io.h>
#elif defined(__APPLE__)
@ -41,13 +41,15 @@
# include <unistd.h>
# include <dirent.h>
# include <sys/stat.h>
# include <glob.h>
#else
# include <unistd.h>
# include <dirent.h>
# include <sys/types.h>
# include <sys/wait.h>
# include <sys/stat.h>
#endif
#if !defined(_WIN32) && defined(YOSYS_ENABLE_GLOB)
# include <glob.h>
#endif
@ -55,6 +57,16 @@
# include <sys/sysctl.h>
#endif
#ifdef WITH_PYTHON
#if PY_MAJOR_VERSION >= 3
# define INIT_MODULE PyInit_libyosys
extern "C" PyObject* INIT_MODULE();
#else
# define INIT_MODULE initlibyosys
extern "C" void INIT_MODULE();
#endif
#endif
#include <limits.h>
#include <errno.h>
@ -139,14 +151,16 @@ void yosys_banner()
int ceil_log2(int x)
{
#if defined(__GNUC__)
return x > 1 ? (8*sizeof(int)) - __builtin_clz(x-1) : 0;
#else
if (x <= 0)
return 0;
for (int i = 0; i < 32; i++)
if (((x-1) >> i) == 0)
return i;
log_abort();
#endif
}
std::string stringf(const char *fmt, ...)
@ -216,12 +230,18 @@ std::string next_token(std::string &text, const char *sep, bool long_strings)
if (long_strings && pos_begin != text.size() && text[pos_begin] == '"') {
string sep_string = sep;
for (size_t i = pos_begin+1; i < text.size(); i++)
for (size_t i = pos_begin+1; i < text.size(); i++) {
if (text[i] == '"' && (i+1 == text.size() || sep_string.find(text[i+1]) != std::string::npos)) {
std::string token = text.substr(pos_begin, i-pos_begin+1);
text = text.substr(i+1);
return token;
}
if (i+1 < text.size() && text[i] == '"' && text[i+1] == ';' && (i+2 == text.size() || sep_string.find(text[i+2]) != std::string::npos)) {
std::string token = text.substr(pos_begin, i-pos_begin+1);
text = text.substr(i+2);
return token + ";";
}
}
}
size_t pos_end = text.find_first_of(sep, pos_begin);
@ -464,26 +484,61 @@ void remove_directory(std::string dirname)
#endif
}
std::string escape_filename_spaces(const std::string& filename)
{
std::string out;
out.reserve(filename.size());
for (auto c : filename)
{
if (c == ' ')
out += "\\ ";
else
out.push_back(c);
}
return out;
}
int GetSize(RTLIL::Wire *wire)
{
return wire->width;
}
bool already_setup = false;
void yosys_setup()
{
if(already_setup)
return;
already_setup = true;
// if there are already IdString objects then we have a global initialization order bug
IdString empty_id;
log_assert(empty_id.index_ == 0);
IdString::get_reference(empty_id.index_);
#ifdef WITH_PYTHON
PyImport_AppendInittab((char*)"libyosys", INIT_MODULE);
Py_Initialize();
PyRun_SimpleString("import sys");
#endif
Pass::init_register();
yosys_design = new RTLIL::Design;
yosys_celltypes.setup();
log_push();
}
bool yosys_already_setup()
{
return already_setup;
}
bool already_shutdown = false;
void yosys_shutdown()
{
if(already_shutdown)
return;
already_shutdown = true;
log_pop();
delete yosys_design;
@ -511,9 +566,16 @@ void yosys_shutdown()
dlclose(it.second);
loaded_plugins.clear();
#ifdef WITH_PYTHON
loaded_python_plugins.clear();
#endif
loaded_plugin_aliases.clear();
#endif
#ifdef WITH_PYTHON
Py_Finalize();
#endif
IdString empty_id;
IdString::put_reference(empty_id.index_);
}
@ -564,7 +626,7 @@ std::vector<std::string> glob_filename(const std::string &filename_pattern)
{
std::vector<std::string> results;
#ifdef _WIN32
#if defined(_WIN32) || !defined(YOSYS_ENABLE_GLOB)
results.push_back(filename_pattern);
#else
glob_t globbuf;

View File

@ -66,6 +66,10 @@
#include <stdio.h>
#include <limits.h>
#ifdef WITH_PYTHON
#include <Python.h>
#endif
#ifndef _YOSYS_
# error It looks like you are trying to build Yosys without the config defines set. \
When building Yosys with a custom make system, make sure you set all the \
@ -115,6 +119,7 @@ extern const char *Tcl_GetStringResult(Tcl_Interp *interp);
# define PATH_MAX 4096
#endif
#define YOSYS_NAMESPACE Yosys
#define PRIVATE_NAMESPACE_BEGIN namespace {
#define PRIVATE_NAMESPACE_END }
#define YOSYS_NAMESPACE_BEGIN namespace Yosys {
@ -239,7 +244,7 @@ extern bool memhasher_active;
inline void memhasher() { if (memhasher_active) memhasher_do(); }
void yosys_banner();
int ceil_log2(int x);
int ceil_log2(int x) YS_ATTRIBUTE(const);
std::string stringf(const char *fmt, ...) YS_ATTRIBUTE(format(printf, 1, 2));
std::string vstringf(const char *fmt, va_list ap);
int readsome(std::istream &f, char *s, int n);
@ -252,6 +257,7 @@ std::string make_temp_dir(std::string template_str = "/tmp/yosys_XXXXXX");
bool check_file_exists(std::string filename, bool is_exec = false);
bool is_absolute_path(std::string filename);
void remove_directory(std::string dirname);
std::string escape_filename_spaces(const std::string& filename);
template<typename T> int GetSize(const T &obj) { return obj.size(); }
int GetSize(RTLIL::Wire *wire);
@ -276,6 +282,11 @@ namespace hashlib {
}
void yosys_setup();
#ifdef WITH_PYTHON
bool yosys_already_setup();
#endif
void yosys_shutdown();
#ifdef YOSYS_ENABLE_TCL
@ -317,6 +328,9 @@ extern std::vector<RTLIL::Design*> pushed_designs;
// from passes/cmds/pluginc.cc
extern std::map<std::string, void*> loaded_plugins;
#ifdef WITH_PYTHON
extern std::map<std::string, void*> loaded_python_plugins;
#endif
extern std::map<std::string, std::string> loaded_plugin_aliases;
void load_plugin(std::string filename, std::vector<std::string> aliases);

View File

@ -320,12 +320,10 @@ class SubCircuit::SolverWorker
static int numberOfPermutations(const std::vector<std::string> &list)
{
int numPermutations = 1;
for (int i = 0; i < int(list.size()); i++) {
assert(numPermutations < maxPermutationsLimit);
numPermutations *= i+1;
}
return numPermutations;
constexpr size_t mappedPermutationsSize = 10;
constexpr int mappedPermutations[mappedPermutationsSize] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880};
assert(list.size() < mappedPermutationsSize);
return mappedPermutations[list.size()];
}
static void permutateVectorToMap(std::map<std::string, std::string> &map, const std::vector<std::string> &list, int idx)

View File

@ -119,6 +119,12 @@ than one bit from \B{S} is set the output is undefined. Cells of this type are u
``parallel cases'' (defined by using the {\tt parallel\_case} attribute or detected by
an optimization).
The {\tt \$tribuf} cell is used to implement tristate logic. Cells of this type have a \B{WIDTH}
parameter and inputs \B{A} and \B{EN} and an output \B{Y}. The \B{A} input and \B{Y} output are
\B{WIDTH} bits wide, and the \B{EN} input is one bit wide. When \B{EN} is 0, the output \B{Y}
is not driven. When \B{EN} is 1, the value from \B{A} input is sent to the \B{Y} output. Therefore,
the {\tt \$tribuf} cell implements the function \lstinline[language=Verilog]; Y = EN ? A : 'bz;.
Behavioural code with cascaded {\tt if-then-else}- and {\tt case}-statements
usually results in trees of multiplexer cells. Many passes (from various
optimizations to FSM extraction) heavily depend on these multiplexer trees to
@ -398,9 +404,15 @@ Verilog & Cell Type \\
\hline
\lstinline[language=Verilog]; Y = ~A; & {\tt \$\_NOT\_} \\
\lstinline[language=Verilog]; Y = A & B; & {\tt \$\_AND\_} \\
\lstinline[language=Verilog]; Y = ~(A & B); & {\tt \$\_NAND\_} \\
\lstinline[language=Verilog]; Y = A & ~B; & {\tt \$\_ANDNOT\_} \\
\lstinline[language=Verilog]; Y = A | B; & {\tt \$\_OR\_} \\
\lstinline[language=Verilog]; Y = ~(A | B); & {\tt \$\_NOR\_} \\
\lstinline[language=Verilog]; Y = A | ~B; & {\tt \$\_ORNOT\_} \\
\lstinline[language=Verilog]; Y = A ^ B; & {\tt \$\_XOR\_} \\
\lstinline[language=Verilog]; Y = ~(A ^ B); & {\tt \$\_XNOR\_} \\
\lstinline[language=Verilog]; Y = S ? B : A; & {\tt \$\_MUX\_} \\
\lstinline[language=Verilog]; Y = EN ? A : 'bz; & {\tt \$\_TBUF\_} \\
\hline
\lstinline[language=Verilog]; always @(negedge C) Q <= D; & {\tt \$\_DFF\_N\_} \\
\lstinline[language=Verilog]; always @(posedge C) Q <= D; & {\tt \$\_DFF\_P\_} \\
@ -423,9 +435,10 @@ $ClkEdge$ & $RstLvl$ & $RstVal$ & Cell Type \\
\end{table}
Table~\ref{tab:CellLib_gates} lists all cell types used for gate level logic. The cell types
{\tt \$\_NOT\_}, {\tt \$\_AND\_}, {\tt \$\_OR\_}, {\tt \$\_XOR\_} and {\tt \$\_MUX\_}
are used to model combinatorial logic. The cell types {\tt \$\_DFF\_N\_} and {\tt \$\_DFF\_P\_}
represent d-type flip-flops.
{\tt \$\_NOT\_}, {\tt \$\_AND\_}, {\tt \$\_NAND\_}, {\tt \$\_ANDNOT\_}, {\tt \$\_OR\_}, {\tt \$\_NOR\_},
{\tt \$\_ORNOT\_}, {\tt \$\_XOR\_}, {\tt \$\_XNOR\_} and {\tt \$\_MUX\_} are used to model combinatorial logic.
The cell type {\tt \$\_TBUF\_} is used to model tristate logic.
The cell types {\tt \$\_DFF\_N\_} and {\tt \$\_DFF\_P\_} represent d-type flip-flops.
The cell types {\tt \$\_DFF\_NN0\_}, {\tt \$\_DFF\_NN1\_}, {\tt \$\_DFF\_NP0\_}, {\tt \$\_DFF\_NP1\_},
{\tt \$\_DFF\_PN0\_}, {\tt \$\_DFF\_PN1\_}, {\tt \$\_DFF\_PP0\_} and {\tt \$\_DFF\_PP1\_} implement
@ -452,6 +465,10 @@ Add information about {\tt \$assert}, {\tt \$assume}, {\tt \$live}, {\tt \$fair}
{\tt \$initstate}, {\tt \$anyconst}, {\tt \$anyseq}, {\tt \$allconst}, {\tt \$allseq} cells.
\end{fixme}
\begin{fixme}
Add information about {\tt \$specify2}, {\tt \$specify3}, and {\tt \$specrule} cells.
\end{fixme}
\begin{fixme}
Add information about {\tt \$slice} and {\tt \$concat} cells.
\end{fixme}
@ -477,7 +494,6 @@ Add information about {\tt \$\_DFFE\_??\_}, {\tt \$\_DFFSR\_???\_}, {\tt \$\_DLA
\end{fixme}
\begin{fixme}
Add information about {\tt \$\_NAND\_}, {\tt \$\_NOR\_}, {\tt \$\_XNOR\_}, {\tt \$\_ANDNOT\_}, {\tt \$\_ORNOT\_},
{\tt \$\_AOI3\_}, {\tt \$\_OAI3\_}, {\tt \$\_AOI4\_}, and {\tt \$\_OAI4\_} cells.
Add information about {\tt \$\_AOI3\_}, {\tt \$\_OAI3\_}, {\tt \$\_AOI4\_}, and {\tt \$\_OAI4\_} cells.
\end{fixme}

5
yosys/misc/__init__.py Normal file
View File

@ -0,0 +1,5 @@
import os
import sys
sys.setdlopenflags(os.RTLD_NOW | os.RTLD_GLOBAL)
__all__ = ["libyosys"]

358
yosys/misc/launcher.c Normal file
View File

@ -0,0 +1,358 @@
/* This file comes from the PyPA Setuptools repository, commit 16e452a:
https://github.com/pypa/setuptools
Modifications include this comment and inline inclusion of the LICENSE text. */
/* Copyright (C) 2016 Jason R Coombs <jaraco@jaraco.com>
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. */
/* Setuptools Script Launcher for Windows
This is a stub executable for Windows that functions somewhat like
Effbot's "exemaker", in that it runs a script with the same name but
a .py extension, using information from a #! line. It differs in that
it spawns the actual Python executable, rather than attempting to
hook into the Python DLL. This means that the script will run with
sys.executable set to the Python executable, where exemaker ends up with
sys.executable pointing to itself. (Which means it won't work if you try
to run another Python process using sys.executable.)
To build/rebuild with mingw32, do this in the setuptools project directory:
gcc -DGUI=0 -mno-cygwin -O -s -o setuptools/cli.exe launcher.c
gcc -DGUI=1 -mwindows -mno-cygwin -O -s -o setuptools/gui.exe launcher.c
To build for Windows RT, install both Visual Studio Express for Windows 8
and for Windows Desktop (both freeware), create "win32" application using
"Windows Desktop" version, create new "ARM" target via
"Configuration Manager" menu and modify ".vcxproj" file by adding
"<WindowsSDKDesktopARMSupport>true</WindowsSDKDesktopARMSupport>" tag
as child of "PropertyGroup" tags that has "Debug|ARM" and "Release|ARM"
properties.
It links to msvcrt.dll, but this shouldn't be a problem since it doesn't
actually run Python in the same process. Note that using 'exec' instead
of 'spawn' doesn't work, because on Windows this leads to the Python
executable running in the *background*, attached to the same console
window, meaning you get a command prompt back *before* Python even finishes
starting. So, we have to use spawnv() and wait for Python to exit before
continuing. :(
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <windows.h>
#include <tchar.h>
#include <fcntl.h>
int child_pid=0;
int fail(char *format, char *data) {
/* Print error message to stderr and return 2 */
fprintf(stderr, format, data);
return 2;
}
char *quoted(char *data) {
int i, ln = strlen(data), nb;
/* We allocate twice as much space as needed to deal with worse-case
of having to escape everything. */
char *result = calloc(ln*2+3, sizeof(char));
char *presult = result;
*presult++ = '"';
for (nb=0, i=0; i < ln; i++)
{
if (data[i] == '\\')
nb += 1;
else if (data[i] == '"')
{
for (; nb > 0; nb--)
*presult++ = '\\';
*presult++ = '\\';
}
else
nb = 0;
*presult++ = data[i];
}
for (; nb > 0; nb--) /* Deal w trailing slashes */
*presult++ = '\\';
*presult++ = '"';
*presult++ = 0;
return result;
}
char *loadable_exe(char *exename) {
/* HINSTANCE hPython; DLL handle for python executable */
char *result;
/* hPython = LoadLibraryEx(exename, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
if (!hPython) return NULL; */
/* Return the absolute filename for spawnv */
result = calloc(MAX_PATH, sizeof(char));
strncpy(result, exename, MAX_PATH);
/*if (result) GetModuleFileNameA(hPython, result, MAX_PATH);
FreeLibrary(hPython); */
return result;
}
char *find_exe(char *exename, char *script) {
char drive[_MAX_DRIVE], dir[_MAX_DIR], fname[_MAX_FNAME], ext[_MAX_EXT];
char path[_MAX_PATH], c, *result;
/* convert slashes to backslashes for uniform search below */
result = exename;
while (c = *result++) if (c=='/') result[-1] = '\\';
_splitpath(exename, drive, dir, fname, ext);
if (drive[0] || dir[0]=='\\') {
return loadable_exe(exename); /* absolute path, use directly */
}
/* Use the script's parent directory, which should be the Python home
(This should only be used for bdist_wininst-installed scripts, because
easy_install-ed scripts use the absolute path to python[w].exe
*/
_splitpath(script, drive, dir, fname, ext);
result = dir + strlen(dir) -1;
if (*result == '\\') result--;
while (*result != '\\' && result>=dir) *result-- = 0;
_makepath(path, drive, dir, exename, NULL);
return loadable_exe(path);
}
char **parse_argv(char *cmdline, int *argc)
{
/* Parse a command line in-place using MS C rules */
char **result = calloc(strlen(cmdline), sizeof(char *));
char *output = cmdline;
char c;
int nb = 0;
int iq = 0;
*argc = 0;
result[0] = output;
while (isspace(*cmdline)) cmdline++; /* skip leading spaces */
do {
c = *cmdline++;
if (!c || (isspace(c) && !iq)) {
while (nb) {*output++ = '\\'; nb--; }
*output++ = 0;
result[++*argc] = output;
if (!c) return result;
while (isspace(*cmdline)) cmdline++; /* skip leading spaces */
if (!*cmdline) return result; /* avoid empty arg if trailing ws */
continue;
}
if (c == '\\')
++nb; /* count \'s */
else {
if (c == '"') {
if (!(nb & 1)) { iq = !iq; c = 0; } /* skip " unless odd # of \ */
nb = nb >> 1; /* cut \'s in half */
}
while (nb) {*output++ = '\\'; nb--; }
if (c) *output++ = c;
}
} while (1);
}
void pass_control_to_child(DWORD control_type) {
/*
* distribute-issue207
* passes the control event to child process (Python)
*/
if (!child_pid) {
return;
}
GenerateConsoleCtrlEvent(child_pid,0);
}
BOOL control_handler(DWORD control_type) {
/*
* distribute-issue207
* control event handler callback function
*/
switch (control_type) {
case CTRL_C_EVENT:
pass_control_to_child(0);
break;
}
return TRUE;
}
int create_and_wait_for_subprocess(char* command) {
/*
* distribute-issue207
* launches child process (Python)
*/
DWORD return_value = 0;
LPSTR commandline = command;
STARTUPINFOA s_info;
PROCESS_INFORMATION p_info;
ZeroMemory(&p_info, sizeof(p_info));
ZeroMemory(&s_info, sizeof(s_info));
s_info.cb = sizeof(STARTUPINFO);
// set-up control handler callback funciotn
SetConsoleCtrlHandler((PHANDLER_ROUTINE) control_handler, TRUE);
if (!CreateProcessA(NULL, commandline, NULL, NULL, TRUE, 0, NULL, NULL, &s_info, &p_info)) {
fprintf(stderr, "failed to create process.\n");
return 0;
}
child_pid = p_info.dwProcessId;
// wait for Python to exit
WaitForSingleObject(p_info.hProcess, INFINITE);
if (!GetExitCodeProcess(p_info.hProcess, &return_value)) {
fprintf(stderr, "failed to get exit code from process.\n");
return 0;
}
return return_value;
}
char* join_executable_and_args(char *executable, char **args, int argc)
{
/*
* distribute-issue207
* CreateProcess needs a long string of the executable and command-line arguments,
* so we need to convert it from the args that was built
*/
int len,counter;
char* cmdline;
len=strlen(executable)+2;
for (counter=1; counter<argc; counter++) {
len+=strlen(args[counter])+1;
}
cmdline = (char*)calloc(len, sizeof(char));
sprintf(cmdline, "%s", executable);
len=strlen(executable);
for (counter=1; counter<argc; counter++) {
sprintf(cmdline+len, " %s", args[counter]);
len+=strlen(args[counter])+1;
}
return cmdline;
}
int run(int argc, char **argv, int is_gui) {
char python[256]; /* python executable's filename*/
char *pyopt; /* Python option */
char script[256]; /* the script's filename */
int scriptf; /* file descriptor for script file */
char **newargs, **newargsp, **parsedargs; /* argument array for exec */
char *ptr, *end; /* working pointers for string manipulation */
char *cmdline;
int i, parsedargc; /* loop counter */
/* compute script name from our .exe name*/
GetModuleFileNameA(NULL, script, sizeof(script));
end = script + strlen(script);
while( end>script && *end != '.')
*end-- = '\0';
*end-- = '\0';
strcat(script, (GUI ? "-script.pyw" : "-script.py"));
/* figure out the target python executable */
scriptf = open(script, O_RDONLY);
if (scriptf == -1) {
return fail("Cannot open %s\n", script);
}
end = python + read(scriptf, python, sizeof(python));
close(scriptf);
ptr = python-1;
while(++ptr < end && *ptr && *ptr!='\n' && *ptr!='\r') {;}
*ptr-- = '\0';
if (strncmp(python, "#!", 2)) {
/* default to python.exe if no #! header */
strcpy(python, "#!python.exe");
}
parsedargs = parse_argv(python+2, &parsedargc);
/* Using spawnv() can fail strangely if you e.g. find the Cygwin
Python, so we'll make sure Windows can find and load it */
ptr = find_exe(parsedargs[0], script);
if (!ptr) {
return fail("Cannot find Python executable %s\n", parsedargs[0]);
}
/* printf("Python executable: %s\n", ptr); */
/* Argument array needs to be
parsedargc + argc, plus 1 for null sentinel */
newargs = (char **)calloc(parsedargc + argc + 1, sizeof(char *));
newargsp = newargs;
*newargsp++ = quoted(ptr);
for (i = 1; i<parsedargc; i++) *newargsp++ = quoted(parsedargs[i]);
*newargsp++ = quoted(script);
for (i = 1; i < argc; i++) *newargsp++ = quoted(argv[i]);
*newargsp++ = NULL;
/* printf("args 0: %s\nargs 1: %s\n", newargs[0], newargs[1]); */
if (is_gui) {
/* Use exec, we don't need to wait for the GUI to finish */
execv(ptr, (const char * const *)(newargs));
return fail("Could not exec %s", ptr); /* shouldn't get here! */
}
/*
* distribute-issue207: using CreateProcessA instead of spawnv
*/
cmdline = join_executable_and_args(ptr, newargs, parsedargc + argc);
return create_and_wait_for_subprocess(cmdline);
}
int WINAPI WinMain(HINSTANCE hI, HINSTANCE hP, LPSTR lpCmd, int nShow) {
return run(__argc, __argv, GUI);
}
int main(int argc, char** argv) {
return run(argc, argv, GUI);
}

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +1,12 @@
//
// 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
@ -73,7 +73,7 @@ message Module {
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
@ -129,7 +129,7 @@ message Model {
TYPE_FALSE = 6;
};
Type type = 1;
message Port {
// Name of port.
string portname = 1;
@ -148,7 +148,7 @@ message Model {
// Set for AND, NAND.
Gate gate = 3;
}
// Set when the node drives given output port(s).
message OutPort {
// Name of port.

View File

@ -71,7 +71,7 @@ static void add_wire(RTLIL::Design *design, RTLIL::Module *module, std::string n
RTLIL::Module *mod = design->modules_.at(it.second->type);
if (!design->selected_whole_module(mod->name))
continue;
if (mod->get_bool_attribute("\\blackbox"))
if (mod->get_blackbox_attribute())
continue;
if (it.second->hasPort(name))
continue;

View File

@ -128,7 +128,7 @@ struct BugpointPass : public Pass {
{
for (auto &it : design_copy->modules_)
{
if (it.second->get_bool_attribute("\\blackbox"))
if (it.second->get_blackbox_attribute())
continue;
if (index++ == seed)
@ -143,7 +143,7 @@ struct BugpointPass : public Pass {
{
for (auto mod : design_copy->modules())
{
if (mod->get_bool_attribute("\\blackbox"))
if (mod->get_blackbox_attribute())
continue;
for (auto wire : mod->wires())
@ -168,7 +168,7 @@ struct BugpointPass : public Pass {
{
for (auto mod : design_copy->modules())
{
if (mod->get_bool_attribute("\\blackbox"))
if (mod->get_blackbox_attribute())
continue;
for (auto &it : mod->cells_)
@ -186,7 +186,7 @@ struct BugpointPass : public Pass {
{
for (auto mod : design_copy->modules())
{
if (mod->get_bool_attribute("\\blackbox"))
if (mod->get_blackbox_attribute())
continue;
for (auto cell : mod->cells())
@ -281,6 +281,9 @@ struct BugpointPass : public Pass {
}
extra_args(args, argidx, design);
if (script.empty())
log_cmd_error("Missing -script option.\n");
if (!has_part)
{
modules = true;
@ -298,7 +301,7 @@ struct BugpointPass : public Pass {
if (!check_logfile(grep))
log_cmd_error("The provided grep string is not found in the log file!\n");
int seed = 0, crashing_seed = seed;
int seed = 0;
bool found_something = false, stage2 = false;
while (true)
{
@ -324,7 +327,6 @@ struct BugpointPass : public Pass {
if (crashing_design != design)
delete crashing_design;
crashing_design = simplified;
crashing_seed = seed;
found_something = true;
}
else

View File

@ -98,21 +98,23 @@ struct CoverPass : public Pass {
}
if ((args[argidx] == "-o" || args[argidx] == "-a" || args[argidx] == "-d") && argidx+1 < args.size()) {
const char *open_mode = args[argidx] == "-a" ? "a+" : "w";
std::string filename = args[++argidx];
const std::string &filename = args[++argidx];
FILE *f = nullptr;
if (args[argidx-1] == "-d") {
#ifdef _WIN32
log_cmd_error("The 'cover -d' option is not supported on win32.\n");
#else
char filename_buffer[4096];
snprintf(filename_buffer, 4096, "%s/yosys_cover_%d_XXXXXX.txt", filename.c_str(), getpid());
filename = mkstemps(filename_buffer, 4);
f = fdopen(mkstemps(filename_buffer, 4), "w");
#endif
} else {
f = fopen(filename.c_str(), open_mode);
}
FILE *f = fopen(filename.c_str(), open_mode);
if (f == NULL) {
for (auto f : out_files)
fclose(f);
log_cmd_error("Can't create file %s.\n", args[argidx].c_str());
log_cmd_error("Can't create file %s%s.\n", args[argidx-1] == "-d" ? "in directory " : "", args[argidx].c_str());
}
out_files.push_back(f);
continue;

View File

@ -23,9 +23,18 @@
# include <dlfcn.h>
#endif
#ifdef WITH_PYTHON
# include <boost/algorithm/string/predicate.hpp>
# include <Python.h>
# include <boost/filesystem.hpp>
#endif
YOSYS_NAMESPACE_BEGIN
std::map<std::string, void*> loaded_plugins;
#ifdef WITH_PYTHON
std::map<std::string, void*> loaded_python_plugins;
#endif
std::map<std::string, std::string> loaded_plugin_aliases;
#ifdef YOSYS_ENABLE_PLUGINS
@ -36,7 +45,35 @@ void load_plugin(std::string filename, std::vector<std::string> aliases)
if (filename.find('/') == std::string::npos)
filename = "./" + filename;
#ifdef WITH_PYTHON
if (!loaded_plugins.count(filename) && !loaded_python_plugins.count(filename)) {
#else
if (!loaded_plugins.count(filename)) {
#endif
#ifdef WITH_PYTHON
boost::filesystem::path full_path(filename);
if(strcmp(full_path.extension().c_str(), ".py") == 0)
{
std::string path(full_path.parent_path().c_str());
filename = full_path.filename().c_str();
filename = filename.substr(0,filename.size()-3);
PyRun_SimpleString(("sys.path.insert(0,\""+path+"\")").c_str());
PyErr_Print();
PyObject *module_p = PyImport_ImportModule(filename.c_str());
if(module_p == NULL)
{
PyErr_Print();
log_cmd_error("Can't load python module `%s'\n", full_path.filename().c_str());
return;
}
loaded_python_plugins[orig_filename] = module_p;
Pass::init_register();
} else {
#endif
void *hdl = dlopen(filename.c_str(), RTLD_LAZY|RTLD_LOCAL);
if (hdl == NULL && orig_filename.find('/') == std::string::npos)
hdl = dlopen((proc_share_dirname() + "plugins/" + orig_filename + ".so").c_str(), RTLD_LAZY|RTLD_LOCAL);
@ -44,6 +81,10 @@ void load_plugin(std::string filename, std::vector<std::string> aliases)
log_cmd_error("Can't load module `%s': %s\n", filename.c_str(), dlerror());
loaded_plugins[orig_filename] = hdl;
Pass::init_register();
#ifdef WITH_PYTHON
}
#endif
}
for (auto &alias : aliases)
@ -107,7 +148,11 @@ struct PluginPass : public Pass {
if (list_mode)
{
log("\n");
#ifdef WITH_PYTHON
if (loaded_plugins.empty() and loaded_python_plugins.empty())
#else
if (loaded_plugins.empty())
#endif
log("No plugins loaded.\n");
else
log("Loaded plugins:\n");
@ -115,6 +160,11 @@ struct PluginPass : public Pass {
for (auto &it : loaded_plugins)
log(" %s\n", it.first.c_str());
#ifdef WITH_PYTHON
for (auto &it : loaded_python_plugins)
log(" %s\n", it.first.c_str());
#endif
if (!loaded_plugin_aliases.empty()) {
log("\n");
int max_alias_len = 1;

View File

@ -291,7 +291,7 @@ struct QwpWorker
// gaussian elimination
for (int i = 0; i < N; i++)
{
if (config.verbose && ((i+1) % (N/15)) == 0)
if (config.verbose && N > 15 && ((i+1) % (N/15)) == 0)
log("> Solved %d%%: %d/%d\n", (100*(i+1))/N, i+1, N);
// find best row

View File

@ -24,7 +24,7 @@
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
static void rename_in_module(RTLIL::Module *module, std::string from_name, std::string to_name)
static void rename_in_module(RTLIL::Module *module, std::string from_name, std::string to_name, bool flag_output)
{
from_name = RTLIL::escape_id(from_name);
to_name = RTLIL::escape_id(to_name);
@ -37,13 +37,18 @@ static void rename_in_module(RTLIL::Module *module, std::string from_name, std::
Wire *w = it.second;
log("Renaming wire %s to %s in module %s.\n", log_id(w), log_id(to_name), log_id(module));
module->rename(w, to_name);
if (w->port_id)
if (w->port_id || flag_output) {
if (flag_output)
w->port_output = true;
module->fixup_ports();
}
return;
}
for (auto &it : module->cells_)
if (it.first == from_name) {
if (flag_output)
log_cmd_error("Called with -output but the specified object is a cell.\n");
log("Renaming cell %s to %s in module %s.\n", log_id(it.second), log_id(to_name), log_id(module));
module->rename(it.second, to_name);
return;
@ -108,15 +113,26 @@ struct RenamePass : public Pass {
log("Rename the specified object. Note that selection patterns are not supported\n");
log("by this command.\n");
log("\n");
log("\n");
log("\n");
log(" rename -output old_name new_name\n");
log("\n");
log("Like above, but also make the wire an output. This will fail if the object is\n");
log("not a wire.\n");
log("\n");
log("\n");
log(" rename -src [selection]\n");
log("\n");
log("Assign names auto-generated from the src attribute to all selected wires and\n");
log("cells with private names.\n");
log("\n");
log("\n");
log(" rename -wire [selection]\n");
log("\n");
log("Assign auto-generated names based on the wires they drive to all selected\n");
log("cells with private names. Ignores cells driving privatly named wires.\n");
log("\n");
log("\n");
log(" rename -enumerate [-pattern <pattern>] [selection]\n");
log("\n");
log("Assign short auto-generated names to all selected wires and cells with private\n");
@ -124,11 +140,13 @@ struct RenamePass : public Pass {
log("The character %% in the pattern is replaced with a integer number. The default\n");
log("pattern is '_%%_'.\n");
log("\n");
log("\n");
log(" rename -hide [selection]\n");
log("\n");
log("Assign private names (the ones with $-prefix) to all selected wires and cells\n");
log("with public names. This ignores all selected ports.\n");
log("\n");
log("\n");
log(" rename -top new_name\n");
log("\n");
log("Rename top module.\n");
@ -142,6 +160,7 @@ struct RenamePass : public Pass {
bool flag_enumerate = false;
bool flag_hide = false;
bool flag_top = false;
bool flag_output = false;
bool got_mode = false;
size_t argidx;
@ -153,6 +172,11 @@ struct RenamePass : public Pass {
got_mode = true;
continue;
}
if (arg == "-output" && !got_mode) {
flag_output = true;
got_mode = true;
continue;
}
if (arg == "-wire" && !got_mode) {
flag_wire = true;
got_mode = true;
@ -322,10 +346,12 @@ struct RenamePass : public Pass {
if (!design->selected_active_module.empty())
{
if (design->modules_.count(design->selected_active_module) > 0)
rename_in_module(design->modules_.at(design->selected_active_module), from_name, to_name);
rename_in_module(design->modules_.at(design->selected_active_module), from_name, to_name, flag_output);
}
else
{
if (flag_output)
log_cmd_error("Mode -output requires that there is an active module selected.\n");
for (auto &mod : design->modules_) {
if (mod.first == from_name || RTLIL::unescape_id(mod.first) == from_name) {
to_name = RTLIL::escape_id(to_name);

View File

@ -128,6 +128,45 @@ struct SetattrPass : public Pass {
}
} SetattrPass;
struct WbflipPass : public Pass {
WbflipPass() : Pass("wbflip", "flip the whitebox attribute") { }
void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" wbflip [selection]\n");
log("\n");
log("Flip the whitebox attribute on selected cells. I.e. if it's set, unset it, and\n");
log("vice-versa. Blackbox cells are not effected by this command.\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
std::string arg = args[argidx];
// if (arg == "-mod") {
// flag_mod = true;
// continue;
// }
break;
}
extra_args(args, argidx, design);
for (Module *module : design->modules())
{
if (!design->selected(module))
continue;
if (module->get_bool_attribute("\\blackbox"))
continue;
module->set_bool_attribute("\\whitebox", !module->get_bool_attribute("\\whitebox"));
}
}
} WbflipPass;
struct SetparamPass : public Pass {
SetparamPass() : Pass("setparam", "set/unset parameters on objects") { }
void help() YS_OVERRIDE

View File

@ -143,6 +143,9 @@ struct SetundefPass : public Pass {
log(" -init\n");
log(" also create/update init values for flip-flops\n");
log("\n");
log(" -params\n");
log(" replace undef in cell parameters\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
@ -150,6 +153,7 @@ struct SetundefPass : public Pass {
bool undriven_mode = false;
bool expose_mode = false;
bool init_mode = false;
bool params_mode = false;
SetundefWorker worker;
log_header(design, "Executing SETUNDEF pass (replace undef values with defined constants).\n");
@ -199,6 +203,10 @@ struct SetundefPass : public Pass {
init_mode = true;
continue;
}
if (args[argidx] == "-params") {
params_mode = true;
continue;
}
if (args[argidx] == "-random" && !got_value && argidx+1 < args.size()) {
got_value = true;
worker.next_bit_mode = MODE_RANDOM;
@ -228,6 +236,18 @@ struct SetundefPass : public Pass {
for (auto module : design->selected_modules())
{
if (params_mode)
{
for (auto *cell : module->selected_cells()) {
for (auto &parameter : cell->parameters) {
for (auto &bit : parameter.second.bits) {
if (bit > RTLIL::State::S1)
bit = worker.next_bit();
}
}
}
}
if (undriven_mode)
{
if (!module->processes.empty())

View File

@ -237,15 +237,34 @@ struct ShowWorker
int idx = single_idx_count++;
for (int rep, i = int(sig.chunks().size())-1; i >= 0; i -= rep) {
const RTLIL::SigChunk &c = sig.chunks().at(i);
net = gen_signode_simple(c, false);
log_assert(!net.empty());
if (!driver && c.wire == nullptr) {
RTLIL::State s1 = c.data.front();
for (auto s2 : c.data)
if (s1 != s2)
goto not_const_stream;
net.clear();
} else {
not_const_stream:
net = gen_signode_simple(c, false);
log_assert(!net.empty());
}
for (rep = 1; i-rep >= 0 && c == sig.chunks().at(i-rep); rep++) {}
std::string repinfo = rep > 1 ? stringf("%dx ", rep) : "";
if (driver) {
log_assert(!net.empty());
label_string += stringf("<s%d> %d:%d - %s%d:%d |", i, pos, pos-c.width+1, repinfo.c_str(), c.offset+c.width-1, c.offset);
net_conn_map[net].in.insert(stringf("x%d:s%d", idx, i));
net_conn_map[net].bits = rep*c.width;
net_conn_map[net].color = nextColor(c, net_conn_map[net].color);
} else
if (net.empty()) {
log_assert(rep == 1);
label_string += stringf("%c -&gt; %d:%d |",
c.data.front() == State::S0 ? '0' :
c.data.front() == State::S1 ? '1' :
c.data.front() == State::Sx ? 'X' :
c.data.front() == State::Sz ? 'Z' : '?',
pos, pos-rep*c.width+1);
} else {
label_string += stringf("<s%d> %s%d:%d - %d:%d |", i, repinfo.c_str(), c.offset+c.width-1, c.offset, pos, pos-rep*c.width+1);
net_conn_map[net].out.insert(stringf("x%d:s%d", idx, i));
@ -555,7 +574,7 @@ struct ShowWorker
if (!design->selected_module(module->name))
continue;
if (design->selected_whole_module(module->name)) {
if (module->get_bool_attribute("\\blackbox")) {
if (module->get_blackbox_attribute()) {
// log("Skipping blackbox module %s.\n", id2cstr(module->name));
continue;
} else
@ -771,7 +790,7 @@ struct ShowPass : public Pass {
if (format != "ps" && format != "dot") {
int modcount = 0;
for (auto &mod_it : design->modules_) {
if (mod_it.second->get_bool_attribute("\\blackbox"))
if (mod_it.second->get_blackbox_attribute())
continue;
if (mod_it.second->cells_.empty() && mod_it.second->connections().empty())
continue;

View File

@ -37,7 +37,9 @@ struct statdata_t
STAT_INT_MEMBERS
#undef X
double area;
string tech;
std::map<RTLIL::IdString, int> techinfo;
std::map<RTLIL::IdString, int, RTLIL::sort_by_id_str> num_cells_by_type;
std::set<RTLIL::IdString> unknown_cell_area;
@ -70,8 +72,10 @@ struct statdata_t
#undef X
}
statdata_t(RTLIL::Design *design, RTLIL::Module *mod, bool width_mode, const dict<IdString, double> &cell_area)
statdata_t(RTLIL::Design *design, RTLIL::Module *mod, bool width_mode, const dict<IdString, double> &cell_area, string techname)
{
tech = techname;
#define X(_name) _name = 0;
STAT_NUMERIC_MEMBERS
#undef X
@ -153,7 +157,8 @@ struct statdata_t
log(" Number of processes: %6d\n", num_processes);
log(" Number of cells: %6d\n", num_cells);
for (auto &it : num_cells_by_type)
log(" %-26s %6d\n", RTLIL::id2cstr(it.first), it.second);
if (it.second)
log(" %-26s %6d\n", RTLIL::id2cstr(it.first), it.second);
if (!unknown_cell_area.empty()) {
log("\n");
@ -165,6 +170,59 @@ struct statdata_t
log("\n");
log(" Chip area for %smodule '%s': %f\n", (top_mod) ? "top " : "", mod_name.c_str(), area);
}
if (tech == "xilinx")
{
int lut6_cnt = num_cells_by_type["\\LUT6"];
int lut5_cnt = num_cells_by_type["\\LUT5"];
int lut4_cnt = num_cells_by_type["\\LUT4"];
int lut3_cnt = num_cells_by_type["\\LUT3"];
int lut2_cnt = num_cells_by_type["\\LUT2"];
int lut1_cnt = num_cells_by_type["\\LUT1"];
int lc_cnt = 0;
lc_cnt += lut6_cnt;
lc_cnt += lut5_cnt;
if (lut1_cnt) {
int cnt = std::min(lut5_cnt, lut1_cnt);
lut5_cnt -= cnt;
lut1_cnt -= cnt;
}
lc_cnt += lut4_cnt;
if (lut1_cnt) {
int cnt = std::min(lut4_cnt, lut1_cnt);
lut4_cnt -= cnt;
lut1_cnt -= cnt;
}
if (lut2_cnt) {
int cnt = std::min(lut4_cnt, lut2_cnt);
lut4_cnt -= cnt;
lut2_cnt -= cnt;
}
lc_cnt += lut3_cnt;
if (lut1_cnt) {
int cnt = std::min(lut3_cnt, lut1_cnt);
lut3_cnt -= cnt;
lut1_cnt -= cnt;
}
if (lut2_cnt) {
int cnt = std::min(lut3_cnt, lut2_cnt);
lut3_cnt -= cnt;
lut2_cnt -= cnt;
}
if (lut3_cnt) {
int cnt = (lut3_cnt + 1) / 2;
lut3_cnt -= cnt;
}
lc_cnt += (lut2_cnt + lut1_cnt + 1) / 2;
log("\n");
log(" Estimated number of LCs: %10d\n", lc_cnt);
}
}
};
@ -226,6 +284,10 @@ struct StatPass : public Pass {
log(" -liberty <liberty_file>\n");
log(" use cell area information from the provided liberty file\n");
log("\n");
log(" -tech <technology>\n");
log(" print area estemate for the specified technology. Corrently supported\n");
log(" calues for <technology>: xilinx\n");
log("\n");
log(" -width\n");
log(" annotate internal cell types with their word width.\n");
log(" e.g. $add_8 for an 8 bit wide $add cell.\n");
@ -239,6 +301,7 @@ struct StatPass : public Pass {
RTLIL::Module *top_mod = NULL;
std::map<RTLIL::IdString, statdata_t> mod_stat;
dict<IdString, double> cell_area;
string techname;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
@ -253,6 +316,10 @@ struct StatPass : public Pass {
read_liberty_cellarea(cell_area, liberty_file);
continue;
}
if (args[argidx] == "-tech" && argidx+1 < args.size()) {
techname = args[++argidx];
continue;
}
if (args[argidx] == "-top" && argidx+1 < args.size()) {
if (design->modules_.count(RTLIL::escape_id(args[argidx+1])) == 0)
log_cmd_error("Can't find module %s.\n", args[argidx+1].c_str());
@ -263,13 +330,16 @@ struct StatPass : public Pass {
}
extra_args(args, argidx, design);
if (techname != "" && techname != "xilinx")
log_cmd_error("Unsupported technology: '%s'\n", techname.c_str());
for (auto mod : design->selected_modules())
{
if (!top_mod && design->full_selection())
if (mod->get_bool_attribute("\\top"))
top_mod = mod;
statdata_t data(design, mod, width_mode, cell_area);
statdata_t data(design, mod, width_mode, cell_area, techname);
mod_stat[mod->name] = data;
log("\n");

View File

@ -94,4 +94,38 @@ struct TracePass : public Pass {
}
} TracePass;
struct DebugPass : public Pass {
DebugPass() : Pass("debug", "run command with debug log messages enabled") { }
void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" debug cmd\n");
log("\n");
log("Execute the specified command with debug log messages enabled\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
// .. parse options ..
break;
}
log_force_debug++;
try {
std::vector<std::string> new_args(args.begin() + argidx, args.end());
Pass::call(design, new_args);
} catch (...) {
log_force_debug--;
throw;
}
log_force_debug--;
}
} DebugPass;
PRIVATE_NAMESPACE_END

View File

@ -44,7 +44,10 @@ struct EquivOptPass:public ScriptPass
log(" useful for handling architecture-specific primitives.\n");
log("\n");
log(" -assert\n");
log(" produce an error if the circuits are not equivalent\n");
log(" produce an error if the circuits are not equivalent.\n");
log("\n");
log(" -undef\n");
log(" enable modelling of undef states during equiv_induct.\n");
log("\n");
log("The following commands are executed by this verification command:\n");
help_script();
@ -52,13 +55,14 @@ struct EquivOptPass:public ScriptPass
}
std::string command, techmap_opts;
bool assert;
bool assert, undef;
void clear_flags() YS_OVERRIDE
{
command = "";
techmap_opts = "";
assert = false;
undef = false;
}
void execute(std::vector < std::string > args, RTLIL::Design * design) YS_OVERRIDE
@ -84,6 +88,10 @@ struct EquivOptPass:public ScriptPass
assert = true;
continue;
}
if (args[argidx] == "-undef") {
undef = true;
continue;
}
break;
}
@ -134,12 +142,17 @@ struct EquivOptPass:public ScriptPass
opts = " -map <filename> ...";
else
opts = techmap_opts;
run("techmap -D EQUIV -autoproc" + opts);
run("techmap -wb -D EQUIV -autoproc" + opts);
}
if (check_label("prove")) {
run("equiv_make gold gate equiv");
run("equiv_induct equiv");
if (help_mode)
run("equiv_induct [-undef] equiv");
else if (undef)
run("equiv_induct -undef equiv");
else
run("equiv_induct equiv");
if (help_mode)
run("equiv_status [-assert] equiv");
else if (assert)

View File

@ -72,7 +72,8 @@ struct FsmOpt
new_transition_table.swap(fsm_data.transition_table);
new_state_table.swap(fsm_data.state_table);
fsm_data.reset_state = old_to_new_state.at(fsm_data.reset_state);
if (fsm_data.reset_state != -1)
fsm_data.reset_state = old_to_new_state.at(fsm_data.reset_state);
}
}

View File

@ -140,6 +140,23 @@ void generate(RTLIL::Design *design, const std::vector<std::string> &celltypes,
}
}
// Return the "basic" type for an array item.
std::string basic_cell_type(const std::string celltype, int pos[3] = nullptr) {
std::string basicType = celltype;
if (celltype.substr(0, 7) == "$array:") {
int pos_idx = celltype.find_first_of(':');
int pos_num = celltype.find_first_of(':', pos_idx + 1);
int pos_type = celltype.find_first_of(':', pos_num + 1);
basicType = celltype.substr(pos_type + 1);
if (pos != nullptr) {
pos[0] = pos_idx;
pos[1] = pos_num;
pos[2] = pos_type;
}
}
return basicType;
}
bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check, bool flag_simcheck, std::vector<std::string> &libdirs)
{
bool did_something = false;
@ -178,9 +195,11 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check
std::vector<RTLIL::SigSpec> connections_to_add_signal;
if (cell->type.substr(0, 7) == "$array:") {
int pos_idx = cell->type.str().find_first_of(':');
int pos_num = cell->type.str().find_first_of(':', pos_idx + 1);
int pos_type = cell->type.str().find_first_of(':', pos_num + 1);
int pos[3];
basic_cell_type(cell->type.str(), pos);
int pos_idx = pos[0];
int pos_num = pos[1];
int pos_type = pos[2];
int idx = atoi(cell->type.str().substr(pos_idx + 1, pos_num).c_str());
int num = atoi(cell->type.str().substr(pos_num + 1, pos_type).c_str());
array_cells[cell] = std::pair<int, int>(idx, num);
@ -327,9 +346,9 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check
}
RTLIL::Module *mod = design->modules_[cell->type];
if (design->modules_.at(cell->type)->get_bool_attribute("\\blackbox")) {
if (design->modules_.at(cell->type)->get_blackbox_attribute()) {
if (flag_simcheck)
log_error("Module `%s' referenced in module `%s' in cell `%s' is a blackbox module.\n",
log_error("Module `%s' referenced in module `%s' in cell `%s' is a blackbox/whitebox module.\n",
cell->type.c_str(), module->name.c_str(), cell->name.c_str());
continue;
}
@ -432,17 +451,14 @@ void hierarchy_worker(RTLIL::Design *design, std::set<RTLIL::Module*, IdString::
if (indent == 0)
log("Top module: %s\n", mod->name.c_str());
else if (!mod->get_bool_attribute("\\blackbox"))
else if (!mod->get_blackbox_attribute())
log("Used module: %*s%s\n", indent, "", mod->name.c_str());
used.insert(mod);
for (auto cell : mod->cells()) {
std::string celltype = cell->type.str();
if (celltype.substr(0, 7) == "$array:") {
int pos_idx = celltype.find_first_of(':');
int pos_num = celltype.find_first_of(':', pos_idx + 1);
int pos_type = celltype.find_first_of(':', pos_num + 1);
celltype = celltype.substr(pos_type + 1);
celltype = basic_cell_type(celltype);
}
if (design->module(celltype))
hierarchy_worker(design, used, design->module(celltype), indent+4);
@ -475,7 +491,7 @@ void hierarchy_clean(RTLIL::Design *design, RTLIL::Module *top, bool purge_lib)
int del_counter = 0;
for (auto mod : del_modules) {
if (!purge_lib && mod->get_bool_attribute("\\blackbox"))
if (!purge_lib && mod->get_blackbox_attribute())
continue;
log("Removing unused module `%s'.\n", mod->name.c_str());
design->modules_.erase(mod->name);
@ -502,9 +518,19 @@ int find_top_mod_score(Design *design, Module *module, dict<Module*, int> &db)
if (db.count(module) == 0) {
int score = 0;
db[module] = 0;
for (auto cell : module->cells())
if (design->module(cell->type))
score = max(score, find_top_mod_score(design, design->module(cell->type), db) + 1);
for (auto cell : module->cells()) {
std::string celltype = cell->type.str();
// Is this an array instance
if (celltype.substr(0, 7) == "$array:") {
celltype = basic_cell_type(celltype);
}
// Is this cell a module instance?
auto instModule = design->module(celltype);
// If there is no instance for this, issue a warning.
if (instModule != nullptr) {
score = max(score, find_top_mod_score(design, instModule, db) + 1);
}
}
db[module] = score;
}
return db.at(module);
@ -544,7 +570,7 @@ struct HierarchyPass : public Pass {
log("\n");
log(" -simcheck\n");
log(" like -check, but also throw an error if blackbox modules are\n");
log(" instantiated, and throw an error if the design has no top module\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");
@ -557,20 +583,20 @@ struct HierarchyPass : public Pass {
log("\n");
log(" -keep_positionals\n");
log(" per default this pass also converts positional arguments in cells\n");
log(" to arguments using port names. this option disables this behavior.\n");
log(" to arguments using port names. This option disables this behavior.\n");
log("\n");
log(" -keep_portwidths\n");
log(" per default this pass adjusts the port width on cells that are\n");
log(" module instances when the width does not match the module port. this\n");
log(" module instances when the width does not match the module port. This\n");
log(" option disables this behavior.\n");
log("\n");
log(" -nokeep_asserts\n");
log(" per default this pass sets the \"keep\" attribute on all modules\n");
log(" that directly or indirectly contain one or more $assert cells. this\n");
log(" option disables this behavior.\n");
log(" that directly or indirectly contain one or more formal properties.\n");
log(" This option disables this behavior.\n");
log("\n");
log(" -top <module>\n");
log(" use the specified top module to built a design hierarchy. modules\n");
log(" use the specified top module to build the design hierarchy. Modules\n");
log(" outside this tree (unused modules) are removed.\n");
log("\n");
log(" when the -top option is used, the 'top' attribute will be set on the\n");
@ -580,6 +606,12 @@ struct HierarchyPass : public Pass {
log(" -auto-top\n");
log(" automatically determine the top of the design hierarchy and mark it.\n");
log("\n");
log(" -chparam name value \n");
log(" elaborate the top module using this parameter value. Modules on which\n");
log(" this parameter does not exist may cause a warning message to be output.\n");
log(" This option can be specified multiple times to override multiple\n");
log(" parameters. String values must be passed in double quotes (\").\n");
log("\n");
log("In -generate mode this pass generates blackbox modules for the given cell\n");
log("types (wildcards supported). For this the design is searched for cells that\n");
log("match the given types and then the given port declarations are used to\n");
@ -615,6 +647,7 @@ struct HierarchyPass : public Pass {
bool nokeep_asserts = false;
std::vector<std::string> generate_cells;
std::vector<generate_port_decl_t> generate_ports;
std::map<std::string, std::string> parameters;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
@ -689,28 +722,61 @@ struct HierarchyPass : public Pass {
if (args[argidx] == "-top") {
if (++argidx >= args.size())
log_cmd_error("Option -top requires an additional argument!\n");
top_mod = design->modules_.count(RTLIL::escape_id(args[argidx])) ? design->modules_.at(RTLIL::escape_id(args[argidx])) : NULL;
if (top_mod == NULL && design->modules_.count("$abstract" + RTLIL::escape_id(args[argidx]))) {
dict<RTLIL::IdString, RTLIL::Const> empty_parameters;
design->modules_.at("$abstract" + RTLIL::escape_id(args[argidx]))->derive(design, empty_parameters);
top_mod = design->modules_.count(RTLIL::escape_id(args[argidx])) ? design->modules_.at(RTLIL::escape_id(args[argidx])) : NULL;
}
if (top_mod == NULL)
load_top_mod = args[argidx];
load_top_mod = args[argidx];
continue;
}
if (args[argidx] == "-auto-top") {
auto_top_mode = true;
continue;
}
if (args[argidx] == "-chparam" && argidx+2 < args.size()) {
const std::string &key = args[++argidx];
const std::string &value = args[++argidx];
auto r = parameters.emplace(key, value);
if (!r.second) {
log_warning("-chparam %s already specified: overwriting.\n", key.c_str());
r.first->second = value;
}
continue;
}
break;
}
extra_args(args, argidx, design, false);
if (!load_top_mod.empty()) {
if (!load_top_mod.empty())
{
IdString top_name = RTLIL::escape_id(load_top_mod);
IdString abstract_id = "$abstract" + RTLIL::escape_id(load_top_mod);
top_mod = design->module(top_name);
dict<RTLIL::IdString, RTLIL::Const> top_parameters;
for (auto &para : parameters) {
SigSpec sig_value;
if (!RTLIL::SigSpec::parse(sig_value, NULL, para.second))
log_cmd_error("Can't decode value '%s'!\n", para.second.c_str());
top_parameters[RTLIL::escape_id(para.first)] = sig_value.as_const();
}
if (top_mod == nullptr && design->module(abstract_id))
top_mod = design->module(design->module(abstract_id)->derive(design, top_parameters));
else if (top_mod != nullptr && !top_parameters.empty())
top_mod = design->module(top_mod->derive(design, top_parameters));
if (top_mod != nullptr && top_mod->name != top_name) {
Module *m = top_mod->clone();
m->name = top_name;
Module *old_mod = design->module(top_name);
if (old_mod)
design->remove(old_mod);
design->add(m);
top_mod = m;
}
}
if (top_mod == nullptr && !load_top_mod.empty()) {
#ifdef YOSYS_ENABLE_VERIFIC
if (verific_import_pending) {
verific_import(design, load_top_mod);
verific_import(design, parameters, load_top_mod);
top_mod = design->module(RTLIL::escape_id(load_top_mod));
}
#endif
@ -719,7 +785,7 @@ struct HierarchyPass : public Pass {
} else {
#ifdef YOSYS_ENABLE_VERIFIC
if (verific_import_pending)
verific_import(design);
verific_import(design, parameters);
#endif
}
@ -820,7 +886,7 @@ struct HierarchyPass : public Pass {
std::map<RTLIL::Module*, bool> cache;
for (auto mod : design->modules())
if (set_keep_assert(cache, mod)) {
log("Module %s directly or indirectly contains $assert cells -> setting \"keep\" attribute.\n", log_id(mod));
log("Module %s directly or indirectly contains formal properties -> setting \"keep\" attribute.\n", log_id(mod));
mod->set_bool_attribute("\\keep");
}
}
@ -884,7 +950,7 @@ struct HierarchyPass : public Pass {
if (m == nullptr)
continue;
if (m->get_bool_attribute("\\blackbox") && !cell->parameters.empty()) {
if (m->get_blackbox_attribute() && !cell->parameters.empty() && m->get_bool_attribute("\\dynports")) {
IdString new_m_name = m->derive(design, cell->parameters, true);
if (new_m_name.empty())
continue;

View File

@ -75,7 +75,7 @@ struct UniquifyPass : public Pass {
if (tmod == nullptr)
continue;
if (tmod->get_bool_attribute("\\blackbox"))
if (tmod->get_blackbox_attribute())
continue;
if (tmod->get_bool_attribute("\\unique") && newname == tmod->name)
@ -87,6 +87,8 @@ struct UniquifyPass : public Pass {
smod->name = newname;
cell->type = newname;
smod->set_bool_attribute("\\unique");
if (smod->attributes.count("\\hdlname") == 0)
smod->attributes["\\hdlname"] = string(log_id(tmod->name));
design->add(smod);
did_something = true;

View File

@ -542,7 +542,7 @@ bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram,
}
// assign write ports
pair<SigBit, bool> wr_clkdom;
for (int cell_port_i = 0, bram_port_i = 0; cell_port_i < wr_ports; cell_port_i++)
{
bool clken = wr_clken[cell_port_i] == State::S1;
@ -552,7 +552,7 @@ bool replace_cell(Cell *cell, const rules_t &rules, const rules_t::bram_t &bram,
pair<SigBit, bool> clkdom(clksig, clkpol);
if (!clken)
clkdom = pair<SigBit, bool>(State::S1, false);
wr_clkdom = clkdom;
log(" Write port #%d is in clock domain %s%s.\n",
cell_port_i, clkdom.second ? "" : "!",
clken ? log_signal(clkdom.first) : "~async~");
@ -641,6 +641,7 @@ grow_read_ports:;
pi.sig_data = SigSpec();
pi.sig_en = SigSpec();
pi.make_outreg = false;
pi.make_transp = false;
}
new_portinfos.push_back(pi);
if (pi.dupidx == dup_count-1) {
@ -718,7 +719,13 @@ grow_read_ports:;
if (read_transp.count(pi.transp) && read_transp.at(pi.transp) != transp) {
if (match.make_transp && wr_ports <= 1) {
pi.make_transp = true;
enable_make_transp = true;
if (pi.clocks != 0) {
if (wr_ports == 1 && wr_clkdom != clkdom) {
log(" Bram port %c%d.%d cannot have soft transparency logic added as read and write clock domains differ.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);
goto skip_bram_rport;
}
enable_make_transp = true;
}
} else {
log(" Bram port %c%d.%d has incompatible read transparency.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);
goto skip_bram_rport;
@ -737,7 +744,8 @@ grow_read_ports:;
if (clken) {
clock_domains[pi.clocks] = clkdom;
clock_polarities[pi.clkpol] = clkdom.second;
read_transp[pi.transp] = transp;
if (!pi.make_transp)
read_transp[pi.transp] = transp;
pi.sig_clock = clkdom.first;
pi.sig_en = rd_en[cell_port_i];
pi.effective_clkpol = clkdom.second;
@ -913,17 +921,18 @@ grow_read_ports:;
} else {
SigSpec bram_dout = module->addWire(NEW_ID, bram.dbits);
c->setPort(stringf("\\%sDATA", pf), bram_dout);
if (pi.make_outreg) {
if (pi.make_outreg && pi.make_transp) {
log(" Moving output register to address for transparent port %c%d.%d.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);
SigSpec sig_addr_q = module->addWire(NEW_ID, bram.abits);
module->addDff(NEW_ID, pi.sig_clock, sig_addr, sig_addr_q, pi.effective_clkpol);
c->setPort(stringf("\\%sADDR", pf), sig_addr_q);
} else if (pi.make_outreg) {
SigSpec bram_dout_q = module->addWire(NEW_ID, bram.dbits);
if (!pi.sig_en.empty())
bram_dout = module->Mux(NEW_ID, bram_dout_q, bram_dout, pi.sig_en);
module->addDff(NEW_ID, pi.sig_clock, bram_dout, bram_dout_q, pi.effective_clkpol);
bram_dout = bram_dout_q;
}
if (pi.make_transp)
{
} else if (pi.make_transp) {
log(" Adding extra logic for transparent port %c%d.%d.\n", pi.group + 'A', pi.index + 1, pi.dupidx + 1);
SigSpec transp_en_d = module->Mux(NEW_ID, SigSpec(0, make_transp_enbits),
@ -949,6 +958,8 @@ grow_read_ports:;
SigSpec addr_ok_q = addr_ok;
if ((pi.clocks || pi.make_outreg) && !addr_ok.empty()) {
addr_ok_q = module->addWire(NEW_ID);
if (!pi.sig_en.empty())
addr_ok = module->Mux(NEW_ID, addr_ok_q, addr_ok, pi.sig_en);
module->addDff(NEW_ID, pi.sig_clock, addr_ok, addr_ok_q, pi.effective_clkpol);
}

View File

@ -13,5 +13,6 @@ OBJS += passes/opt/wreduce.o
OBJS += passes/opt/opt_demorgan.o
OBJS += passes/opt/rmports.o
OBJS += passes/opt/opt_lut.o
OBJS += passes/opt/pmux2shiftx.o
endif

View File

@ -64,7 +64,7 @@ struct keep_cache_t
bool query(Cell *cell)
{
if (cell->type.in("$memwr", "$meminit", "$assert", "$assume", "$live", "$fair", "$cover"))
if (cell->type.in("$memwr", "$meminit", "$assert", "$assume", "$live", "$fair", "$cover", "$specify2", "$specify3", "$specrule"))
return true;
if (cell->has_keep_attr())
@ -85,22 +85,34 @@ void rmunused_module_cells(Module *module, bool verbose)
{
SigMap sigmap(module);
pool<Cell*> queue, unused;
pool<SigBit> used_raw_bits;
dict<SigBit, pool<Cell*>> wire2driver;
dict<SigBit, vector<string>> driver_driver_logs;
SigMap raw_sigmap;
for (auto &it : module->connections_) {
for (int i = 0; i < GetSize(it.second); i++) {
if (it.second[i].wire != nullptr)
raw_sigmap.add(it.first[i], it.second[i]);
}
}
for (auto &it : module->cells_) {
Cell *cell = it.second;
for (auto &it2 : cell->connections()) {
if (!ct_all.cell_known(cell->type) || ct_all.cell_output(cell->type, it2.first))
for (auto raw_bit : it2.second) {
if (raw_bit.wire == nullptr)
continue;
auto bit = sigmap(raw_bit);
if (bit.wire == nullptr)
log_warning("Driver-driver conflict for %s between cell %s.%s and constant %s in %s: Resolved using constant.\n",
log_signal(raw_bit), log_id(cell), log_id(it2.first), log_signal(bit), log_id(module));
if (bit.wire != nullptr)
wire2driver[bit].insert(cell);
}
if (ct_all.cell_known(cell->type) && !ct_all.cell_output(cell->type, it2.first))
continue;
for (auto raw_bit : it2.second) {
if (raw_bit.wire == nullptr)
continue;
auto bit = sigmap(raw_bit);
if (bit.wire == nullptr)
driver_driver_logs[raw_sigmap(raw_bit)].push_back(stringf("Driver-driver conflict "
"for %s between cell %s.%s and constant %s in %s: Resolved using constant.",
log_signal(raw_bit), log_id(cell), log_id(it2.first), log_signal(bit), log_id(module)));
if (bit.wire != nullptr)
wire2driver[bit].insert(cell);
}
}
if (keep_cache.query(cell))
queue.insert(cell);
@ -114,6 +126,8 @@ void rmunused_module_cells(Module *module, bool verbose)
for (auto bit : sigmap(wire))
for (auto c : wire2driver[bit])
queue.insert(c), unused.erase(c);
for (auto raw_bit : SigSpec(wire))
used_raw_bits.insert(raw_sigmap(raw_bit));
}
}
@ -137,11 +151,27 @@ void rmunused_module_cells(Module *module, bool verbose)
for (auto cell : unused) {
if (verbose)
log(" removing unused `%s' cell `%s'.\n", cell->type.c_str(), cell->name.c_str());
log_debug(" removing unused `%s' cell `%s'.\n", cell->type.c_str(), cell->name.c_str());
module->design->scratchpad_set_bool("opt.did_something", true);
module->remove(cell);
count_rm_cells++;
}
for (auto &it : module->cells_) {
Cell *cell = it.second;
for (auto &it2 : cell->connections()) {
if (ct_all.cell_known(cell->type) && !ct_all.cell_input(cell->type, it2.first))
continue;
for (auto raw_bit : raw_sigmap(it2.second))
used_raw_bits.insert(raw_bit);
}
}
for (auto it : driver_driver_logs) {
if (used_raw_bits.count(it.first))
for (auto msg : it.second)
log_warning("%s\n", msg.c_str());
}
}
int count_nontrivial_wire_attrs(RTLIL::Wire *w)
@ -202,7 +232,7 @@ bool check_public_name(RTLIL::IdString id)
return true;
}
void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbose)
bool rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbose)
{
SigPool register_signals;
SigPool connected_signals;
@ -245,11 +275,13 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
module->connections_.clear();
SigPool used_signals;
SigPool raw_used_signals;
SigPool used_signals_nodrivers;
for (auto &it : module->cells_) {
RTLIL::Cell *cell = it.second;
for (auto &it2 : cell->connections_) {
assign_map.apply(it2.second);
raw_used_signals.add(it2.second);
used_signals.add(it2.second);
if (!ct_all.cell_output(cell->type, it2.first))
used_signals_nodrivers.add(it2.second);
@ -259,6 +291,7 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
RTLIL::Wire *wire = it.second;
if (wire->port_id > 0) {
RTLIL::SigSpec sig = RTLIL::SigSpec(wire);
raw_used_signals.add(sig);
assign_map.apply(sig);
used_signals.add(sig);
if (!wire->port_input)
@ -271,72 +304,102 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
}
}
std::vector<RTLIL::Wire*> maybe_del_wires;
pool<RTLIL::Wire*> del_wires_queue;
for (auto wire : module->wires())
{
if ((!purge_mode && check_public_name(wire->name)) || wire->port_id != 0 || wire->get_bool_attribute("\\keep") || wire->attributes.count("\\init")) {
RTLIL::SigSpec s1 = RTLIL::SigSpec(wire), s2 = s1;
assign_map.apply(s2);
if (!used_signals.check_any(s2) && wire->port_id == 0 && !wire->get_bool_attribute("\\keep")) {
maybe_del_wires.push_back(wire);
} else {
log_assert(GetSize(s1) == GetSize(s2));
RTLIL::SigSig new_conn;
for (int i = 0; i < GetSize(s1); i++)
if (s1[i] != s2[i]) {
new_conn.first.append_bit(s1[i]);
new_conn.second.append_bit(s2[i]);
}
if (new_conn.first.size() > 0) {
used_signals.add(new_conn.first);
used_signals.add(new_conn.second);
module->connect(new_conn);
}
}
} else {
if (!used_signals.check_any(RTLIL::SigSpec(wire)))
maybe_del_wires.push_back(wire);
SigSpec s1 = SigSpec(wire), s2 = assign_map(s1);
log_assert(GetSize(s1) == GetSize(s2));
Const initval;
if (wire->attributes.count("\\init"))
initval = wire->attributes.at("\\init");
if (GetSize(initval) != GetSize(wire))
initval.bits.resize(GetSize(wire), State::Sx);
if (initval.is_fully_undef())
wire->attributes.erase("\\init");
if (GetSize(wire) == 0) {
// delete zero-width wires
goto delete_this_wire;
} else
if (wire->port_id != 0 || wire->get_bool_attribute("\\keep") || !initval.is_fully_undef()) {
// do not delete anything with "keep" or module ports or initialized wires
} else
if (!purge_mode && check_public_name(wire->name)) {
// do not get rid of public names unless in purge mode
} else
if (!raw_used_signals.check_any(s1)) {
// delete wires that aren't used by anything directly
goto delete_this_wire;
} else
if (!used_signals.check_any(s2)) {
// delete wires that aren't used by anything indirectly, even though other wires may alias it
goto delete_this_wire;
}
RTLIL::SigSpec sig = assign_map(RTLIL::SigSpec(wire));
if (!used_signals_nodrivers.check_any(sig)) {
std::string unused_bits;
for (int i = 0; i < GetSize(sig); i++) {
if (sig[i].wire == NULL)
continue;
if (!used_signals_nodrivers.check(sig[i])) {
if (!unused_bits.empty())
unused_bits += " ";
unused_bits += stringf("%d", i);
if (0)
{
delete_this_wire:
del_wires_queue.insert(wire);
}
else
{
RTLIL::SigSig new_conn;
for (int i = 0; i < GetSize(s1); i++)
if (s1[i] != s2[i]) {
if (s2[i] == State::Sx && (initval[i] == State::S0 || initval[i] == State::S1)) {
s2[i] = initval[i];
initval[i] = State::Sx;
}
new_conn.first.append_bit(s1[i]);
new_conn.second.append_bit(s2[i]);
}
if (new_conn.first.size() > 0) {
if (initval.is_fully_undef())
wire->attributes.erase("\\init");
else
wire->attributes.at("\\init") = initval;
used_signals.add(new_conn.first);
used_signals.add(new_conn.second);
module->connect(new_conn);
}
if (unused_bits.empty() || wire->port_id != 0)
if (!used_signals_nodrivers.check_all(s2)) {
std::string unused_bits;
for (int i = 0; i < GetSize(s2); i++) {
if (s2[i].wire == NULL)
continue;
if (!used_signals_nodrivers.check(s2[i])) {
if (!unused_bits.empty())
unused_bits += " ";
unused_bits += stringf("%d", i);
}
}
if (unused_bits.empty() || wire->port_id != 0)
wire->attributes.erase("\\unused_bits");
else
wire->attributes["\\unused_bits"] = RTLIL::Const(unused_bits);
} else {
wire->attributes.erase("\\unused_bits");
else
wire->attributes["\\unused_bits"] = RTLIL::Const(unused_bits);
} else {
wire->attributes.erase("\\unused_bits");
}
}
}
int del_temp_wires_count = 0;
for (auto wire : del_wires_queue) {
if (ys_debug() || (check_public_name(wire->name) && verbose))
log_debug(" removing unused non-port wire %s.\n", wire->name.c_str());
else
del_temp_wires_count++;
}
pool<RTLIL::Wire*> del_wires;
module->remove(del_wires_queue);
count_rm_wires += GetSize(del_wires_queue);
int del_wires_count = 0;
for (auto wire : maybe_del_wires)
if (!used_signals.check_any(RTLIL::SigSpec(wire))) {
if (check_public_name(wire->name) && verbose) {
log(" removing unused non-port wire %s.\n", wire->name.c_str());
}
del_wires.insert(wire);
del_wires_count++;
}
if (verbose && del_temp_wires_count)
log_debug(" removed %d unused temporary wires.\n", del_temp_wires_count);
module->remove(del_wires);
count_rm_wires += del_wires.size();
if (verbose && del_wires_count > 0)
log(" removed %d unused temporary wires.\n", del_wires_count);
return !del_wires_queue.empty();
}
bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose)
@ -399,7 +462,7 @@ bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose)
}
if (verbose)
log(" removing redundant init attribute on %s.\n", log_id(wire));
log_debug(" removing redundant init attribute on %s.\n", log_id(wire));
wire->attributes.erase("\\init");
did_something = true;
@ -426,7 +489,7 @@ void rmunused_module(RTLIL::Module *module, bool purge_mode, bool verbose, bool
}
for (auto cell : delcells) {
if (verbose)
log(" removing buffer cell `%s': %s = %s\n", cell->name.c_str(),
log_debug(" removing buffer cell `%s': %s = %s\n", cell->name.c_str(),
log_signal(cell->getPort("\\Y")), log_signal(cell->getPort("\\A")));
module->remove(cell);
}
@ -434,10 +497,10 @@ void rmunused_module(RTLIL::Module *module, bool purge_mode, bool verbose, bool
module->design->scratchpad_set_bool("opt.did_something", true);
rmunused_module_cells(module, verbose);
rmunused_module_signals(module, purge_mode, verbose);
while (rmunused_module_signals(module, purge_mode, verbose)) { }
if (rminit && rmunused_module_init(module, purge_mode, verbose))
rmunused_module_signals(module, purge_mode, verbose);
while (rmunused_module_signals(module, purge_mode, verbose)) { }
}
struct OptCleanPass : public Pass {
@ -483,6 +546,9 @@ struct OptCleanPass : public Pass {
ct_all.setup(design);
count_rm_cells = 0;
count_rm_wires = 0;
for (auto module : design->selected_whole_modules_warn()) {
if (module->has_processes_warn())
continue;
@ -548,9 +614,10 @@ struct CleanPass : public Pass {
for (auto module : design->selected_whole_modules()) {
if (module->has_processes())
continue;
rmunused_module(module, purge_mode, false, false);
rmunused_module(module, purge_mode, ys_debug(), false);
}
log_suppressed();
if (count_rm_cells > 0 || count_rm_wires > 0)
log("Removed %d unused cells and %d unused wires.\n", count_rm_cells, count_rm_wires);

View File

@ -39,6 +39,9 @@ void replace_undriven(RTLIL::Design *design, RTLIL::Module *module)
SigPool used_signals;
SigPool all_signals;
dict<SigBit, pair<Wire*, State>> initbits;
pool<Wire*> revisit_initwires;
for (auto cell : module->cells())
for (auto &conn : cell->connections()) {
if (!ct.cell_known(cell->type) || ct.cell_output(cell->type, conn.first))
@ -48,9 +51,17 @@ void replace_undriven(RTLIL::Design *design, RTLIL::Module *module)
}
for (auto wire : module->wires()) {
if (wire->attributes.count("\\init")) {
SigSpec sig = sigmap(wire);
Const initval = wire->attributes.at("\\init");
for (int i = 0; i < GetSize(initval) && i < GetSize(wire); i++) {
if (initval[i] == State::S0 || initval[i] == State::S1)
initbits[sig[i]] = make_pair(wire, initval[i]);
}
}
if (wire->port_input)
driven_signals.add(sigmap(wire));
if (wire->port_output)
if (wire->port_output || wire->get_bool_attribute("\\keep"))
used_signals.add(sigmap(wire));
all_signals.add(sigmap(wire));
}
@ -67,10 +78,43 @@ void replace_undriven(RTLIL::Design *design, RTLIL::Module *module)
if (sig.size() == 0)
continue;
log("Setting undriven signal in %s to undef: %s\n", RTLIL::id2cstr(module->name), log_signal(c));
module->connect(RTLIL::SigSig(c, RTLIL::SigSpec(RTLIL::State::Sx, c.width)));
Const val(RTLIL::State::Sx, GetSize(sig));
for (int i = 0; i < GetSize(sig); i++) {
SigBit bit = sigmap(sig[i]);
auto cursor = initbits.find(bit);
if (cursor != initbits.end()) {
revisit_initwires.insert(cursor->second.first);
val[i] = cursor->second.second;
}
}
log_debug("Setting undriven signal in %s to constant: %s = %s\n", log_id(module), log_signal(sig), log_signal(val));
module->connect(sig, val);
did_something = true;
}
if (!revisit_initwires.empty())
{
SigMap sm2(module);
for (auto wire : revisit_initwires) {
SigSpec sig = sm2(wire);
Const initval = wire->attributes.at("\\init");
for (int i = 0; i < GetSize(initval) && i < GetSize(wire); i++) {
if (SigBit(initval[i]) == sig[i])
initval[i] = State::Sx;
}
if (initval.is_fully_undef()) {
log_debug("Removing init attribute from %s/%s.\n", log_id(module), log_id(wire));
wire->attributes.erase("\\init");
did_something = true;
} else if (initval != wire->attributes.at("\\init")) {
log_debug("Updating init attribute on %s/%s: %s\n", log_id(module), log_id(wire), log_signal(initval));
wire->attributes["\\init"] = initval;
did_something = true;
}
}
}
}
void replace_cell(SigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell, std::string info, std::string out_port, RTLIL::SigSpec out_val)
@ -78,7 +122,7 @@ void replace_cell(SigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell,
RTLIL::SigSpec Y = cell->getPort(out_port);
out_val.extend_u0(Y.size(), false);
log("Replacing %s cell `%s' (%s) in module `%s' with constant driver `%s = %s'.\n",
log_debug("Replacing %s cell `%s' (%s) in module `%s' with constant driver `%s = %s'.\n",
cell->type.c_str(), cell->name.c_str(), info.c_str(),
module->name.c_str(), log_signal(Y), log_signal(out_val));
// log_cell(cell);
@ -134,7 +178,7 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ
if (GetSize(grouped_bits[i]) == GetSize(bits_y))
return false;
log("Replacing %s cell `%s' in module `%s' with cells using grouped bits:\n",
log_debug("Replacing %s cell `%s' in module `%s' with cells using grouped bits:\n",
log_id(cell->type), log_id(cell), log_id(module));
for (int i = 0; i < GRP_N; i++)
@ -155,6 +199,13 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ
new_b.append_bit(it.first.second);
}
if (cell->type.in("$and", "$or") && i == GRP_CONST_A) {
log_debug(" Direct Connection: %s (%s with %s)\n", log_signal(new_b), log_id(cell->type), log_signal(new_a));
module->connect(new_y, new_b);
module->connect(new_conn);
continue;
}
RTLIL::Cell *c = module->addCell(NEW_ID, cell->type);
c->setPort("\\A", new_a);
@ -173,10 +224,10 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ
module->connect(new_conn);
log(" New cell `%s': A=%s", log_id(c), log_signal(new_a));
log_debug(" New cell `%s': A=%s", log_id(c), log_signal(new_a));
if (b_name == "\\B")
log(", B=%s", log_signal(new_b));
log("\n");
log_debug(", B=%s", log_signal(new_b));
log_debug("\n");
}
cover_list("opt.opt_expr.fine.group", "$not", "$pos", "$and", "$or", "$xor", "$xnor", cell->type.str());
@ -190,7 +241,7 @@ void handle_polarity_inv(Cell *cell, IdString port, IdString param, const SigMap
{
SigSpec sig = assign_map(cell->getPort(port));
if (invert_map.count(sig)) {
log("Inverting %s of %s cell `%s' in module `%s': %s -> %s\n",
log_debug("Inverting %s of %s cell `%s' in module `%s': %s -> %s\n",
log_id(port), log_id(cell->type), log_id(cell), log_id(cell->module),
log_signal(sig), log_signal(invert_map.at(sig)));
cell->setPort(port, (invert_map.at(sig)));
@ -219,7 +270,7 @@ void handle_clkpol_celltype_swap(Cell *cell, string type1, string type2, IdStrin
if (cell->type.in(type1, type2)) {
SigSpec sig = assign_map(cell->getPort(port));
if (invert_map.count(sig)) {
log("Inverting %s of %s cell `%s' in module `%s': %s -> %s\n",
log_debug("Inverting %s of %s cell `%s' in module `%s': %s -> %s\n",
log_id(port), log_id(cell->type), log_id(cell), log_id(cell->module),
log_signal(sig), log_signal(invert_map.at(sig)));
cell->setPort(port, (invert_map.at(sig)));
@ -448,9 +499,10 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
{
if (cell->type == "$reduce_xnor") {
cover("opt.opt_expr.reduce_xnor_not");
log("Replacing %s cell `%s' in module `%s' with $not cell.\n",
log_debug("Replacing %s cell `%s' in module `%s' with $not cell.\n",
log_id(cell->type), log_id(cell->name), log_id(module));
cell->type = "$not";
did_something = true;
} else {
cover("opt.opt_expr.unary_buffer");
replace_cell(assign_map, module, cell, "unary_buffer", "\\Y", cell->getPort("\\A"));
@ -481,7 +533,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (GetSize(new_sig_a) < GetSize(sig_a)) {
cover_list("opt.opt_expr.fine.neutral_A", "$logic_not", "$logic_and", "$logic_or", "$reduce_or", "$reduce_and", "$reduce_bool", cell->type.str());
log("Replacing port A of %s cell `%s' in module `%s' with shorter expression: %s -> %s\n",
log_debug("Replacing port A of %s cell `%s' in module `%s' with shorter expression: %s -> %s\n",
cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_sig_a));
cell->setPort("\\A", new_sig_a);
cell->parameters.at("\\A_WIDTH") = GetSize(new_sig_a);
@ -504,7 +556,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (GetSize(new_sig_b) < GetSize(sig_b)) {
cover_list("opt.opt_expr.fine.neutral_B", "$logic_and", "$logic_or", cell->type.str());
log("Replacing port B of %s cell `%s' in module `%s' with shorter expression: %s -> %s\n",
log_debug("Replacing port B of %s cell `%s' in module `%s' with shorter expression: %s -> %s\n",
cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_b), log_signal(new_sig_b));
cell->setPort("\\B", new_sig_b);
cell->parameters.at("\\B_WIDTH") = GetSize(new_sig_b);
@ -530,7 +582,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (new_a != RTLIL::State::Sm && RTLIL::SigSpec(new_a) != sig_a) {
cover("opt.opt_expr.fine.$reduce_and");
log("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n",
log_debug("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n",
cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_a));
cell->setPort("\\A", sig_a = new_a);
cell->parameters.at("\\A_WIDTH") = 1;
@ -556,7 +608,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (new_a != RTLIL::State::Sm && RTLIL::SigSpec(new_a) != sig_a) {
cover_list("opt.opt_expr.fine.A", "$logic_not", "$logic_and", "$logic_or", "$reduce_or", "$reduce_bool", cell->type.str());
log("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n",
log_debug("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n",
cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_a));
cell->setPort("\\A", sig_a = new_a);
cell->parameters.at("\\A_WIDTH") = 1;
@ -582,7 +634,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (new_b != RTLIL::State::Sm && RTLIL::SigSpec(new_b) != sig_b) {
cover_list("opt.opt_expr.fine.B", "$logic_and", "$logic_or", cell->type.str());
log("Replacing port B of %s cell `%s' in module `%s' with constant driver: %s -> %s\n",
log_debug("Replacing port B of %s cell `%s' in module `%s' with constant driver: %s -> %s\n",
cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_b), log_signal(new_b));
cell->setPort("\\B", sig_b = new_b);
cell->parameters.at("\\B_WIDTH") = 1;
@ -633,7 +685,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if ((cell->type == "$_MUX_" || cell->type == "$mux") && invert_map.count(assign_map(cell->getPort("\\S"))) != 0) {
cover_list("opt.opt_expr.invert.muxsel", "$_MUX_", "$mux", cell->type.str());
log("Optimizing away select inverter for %s cell `%s' in module `%s'.\n", log_id(cell->type), log_id(cell), log_id(module));
log_debug("Optimizing away select inverter for %s cell `%s' in module `%s'.\n", log_id(cell->type), log_id(cell), log_id(module));
RTLIL::SigSpec tmp = cell->getPort("\\A");
cell->setPort("\\A", cell->getPort("\\B"));
cell->setPort("\\B", tmp);
@ -743,7 +795,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
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",
log_debug("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;
@ -815,7 +867,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
ACTION_DO("\\Y", cell->getPort("\\A"));
} else {
cover_list("opt.opt_expr.eqneq.isnot", "$eq", "$ne", cell->type.str());
log("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell->type), log_id(cell), log_id(module));
log_debug("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell->type), log_id(cell), log_id(module));
cell->type = "$not";
cell->parameters.erase("\\B_WIDTH");
cell->parameters.erase("\\B_SIGNED");
@ -830,7 +882,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
(assign_map(cell->getPort("\\A")).is_fully_zero() || assign_map(cell->getPort("\\B")).is_fully_zero()))
{
cover_list("opt.opt_expr.eqneq.cmpzero", "$eq", "$ne", cell->type.str());
log("Replacing %s cell `%s' in module `%s' with %s.\n", log_id(cell->type), log_id(cell),
log_debug("Replacing %s cell `%s' in module `%s' with %s.\n", log_id(cell->type), log_id(cell),
log_id(module), "$eq" ? "$logic_not" : "$reduce_bool");
cell->type = cell->type == "$eq" ? "$logic_not" : "$reduce_bool";
if (assign_map(cell->getPort("\\A")).is_fully_zero()) {
@ -869,7 +921,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
cover_list("opt.opt_expr.constshift", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", cell->type.str());
log("Replacing %s cell `%s' (B=%s, SHR=%d) in module `%s' with fixed wiring: %s\n",
log_debug("Replacing %s cell `%s' (B=%s, SHR=%d) in module `%s' with fixed wiring: %s\n",
log_id(cell->type), log_id(cell), log_signal(assign_map(cell->getPort("\\B"))), shift_bits, log_id(module), log_signal(sig_y));
module->connect(cell->getPort("\\Y"), sig_y);
@ -932,7 +984,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (identity_wrt_b)
cover_list("opt.opt_expr.identwrt.b", "$add", "$sub", "$or", "$xor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", "$mul", "$div", cell->type.str());
log("Replacing %s cell `%s' in module `%s' with identity for port %c.\n",
log_debug("Replacing %s cell `%s' in module `%s' with identity for port %c.\n",
cell->type.c_str(), cell->name.c_str(), module->name.c_str(), identity_wrt_a ? 'A' : 'B');
if (!identity_wrt_a) {
@ -962,7 +1014,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") &&
cell->getPort("\\A") == RTLIL::SigSpec(1, 1) && cell->getPort("\\B") == RTLIL::SigSpec(0, 1)) {
cover_list("opt.opt_expr.mux_invert", "$mux", "$_MUX_", cell->type.str());
log("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell->type), log_id(cell), log_id(module));
log_debug("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell->type), log_id(cell), log_id(module));
cell->setPort("\\A", cell->getPort("\\S"));
cell->unsetPort("\\B");
cell->unsetPort("\\S");
@ -981,7 +1033,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (consume_x && mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") && cell->getPort("\\A") == RTLIL::SigSpec(0, 1)) {
cover_list("opt.opt_expr.mux_and", "$mux", "$_MUX_", cell->type.str());
log("Replacing %s cell `%s' in module `%s' with and-gate.\n", log_id(cell->type), log_id(cell), log_id(module));
log_debug("Replacing %s cell `%s' in module `%s' with and-gate.\n", log_id(cell->type), log_id(cell), log_id(module));
cell->setPort("\\A", cell->getPort("\\S"));
cell->unsetPort("\\S");
if (cell->type == "$mux") {
@ -1001,7 +1053,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (consume_x && mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") && cell->getPort("\\B") == RTLIL::SigSpec(1, 1)) {
cover_list("opt.opt_expr.mux_or", "$mux", "$_MUX_", cell->type.str());
log("Replacing %s cell `%s' in module `%s' with or-gate.\n", log_id(cell->type), log_id(cell), log_id(module));
log_debug("Replacing %s cell `%s' in module `%s' with or-gate.\n", log_id(cell->type), log_id(cell), log_id(module));
cell->setPort("\\B", cell->getPort("\\S"));
cell->unsetPort("\\S");
if (cell->type == "$mux") {
@ -1054,7 +1106,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
}
if (cell->getPort("\\S").size() != new_s.size()) {
cover_list("opt.opt_expr.mux_reduce", "$mux", "$pmux", cell->type.str());
log("Optimized away %d select inputs of %s cell `%s' in module `%s'.\n",
log_debug("Optimized away %d select inputs of %s cell `%s' in module `%s'.\n",
GetSize(cell->getPort("\\S")) - GetSize(new_s), log_id(cell->type), log_id(cell), log_id(module));
cell->setPort("\\A", new_a);
cell->setPort("\\B", new_b);
@ -1172,7 +1224,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
{
cover("opt.opt_expr.mul_shift.zero");
log("Replacing multiply-by-zero cell `%s' in module `%s' with zero-driver.\n",
log_debug("Replacing multiply-by-zero cell `%s' in module `%s' with zero-driver.\n",
cell->name.c_str(), module->name.c_str());
module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size())));
@ -1190,7 +1242,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
else
cover("opt.opt_expr.mul_shift.unswapped");
log("Replacing multiply-by-%d cell `%s' in module `%s' with shift-by-%d.\n",
log_debug("Replacing multiply-by-%d cell `%s' in module `%s' with shift-by-%d.\n",
a_val, cell->name.c_str(), module->name.c_str(), i);
if (!swapped_ab) {
@ -1230,7 +1282,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
{
cover("opt.opt_expr.divmod_zero");
log("Replacing divide-by-zero cell `%s' in module `%s' with undef-driver.\n",
log_debug("Replacing divide-by-zero cell `%s' in module `%s' with undef-driver.\n",
cell->name.c_str(), module->name.c_str());
module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(State::Sx, sig_y.size())));
@ -1247,7 +1299,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
{
cover("opt.opt_expr.div_shift");
log("Replacing divide-by-%d cell `%s' in module `%s' with shift-by-%d.\n",
log_debug("Replacing divide-by-%d cell `%s' in module `%s' with shift-by-%d.\n",
b_val, cell->name.c_str(), module->name.c_str(), i);
std::vector<RTLIL::SigBit> new_b = RTLIL::SigSpec(i, 6);
@ -1265,7 +1317,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
{
cover("opt.opt_expr.mod_mask");
log("Replacing modulo-by-%d cell `%s' in module `%s' with bitmask.\n",
log_debug("Replacing modulo-by-%d cell `%s' in module `%s' with bitmask.\n",
b_val, cell->name.c_str(), module->name.c_str());
std::vector<RTLIL::SigBit> new_b = RTLIL::SigSpec(State::S1, i);
@ -1335,7 +1387,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
SigSpec y_sig = cell->getPort("\\Y");
Const y_value(cell->type.in("$eq", "$eqx") ? 0 : 1, GetSize(y_sig));
log("Replacing cell `%s' in module `%s' with constant driver %s.\n",
log_debug("Replacing cell `%s' in module `%s' with constant driver %s.\n",
log_id(cell), log_id(module), log_signal(y_value));
module->connect(y_sig, y_value);
@ -1347,7 +1399,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (redundant_bits)
{
log("Removed %d redundant input bits from %s cell `%s' in module `%s'.\n",
log_debug("Removed %d redundant input bits from %s cell `%s' in module `%s'.\n",
redundant_bits, log_id(cell->type), log_id(cell), log_id(module));
cell->setPort("\\A", sig_a);
@ -1486,7 +1538,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (replace || remove)
{
log("Replacing %s cell `%s' (implementing %s) with %s.\n",
log_debug("Replacing %s cell `%s' (implementing %s) with %s.\n",
log_id(cell->type), log_id(cell), condition.c_str(), replacement.c_str());
if (replace)
module->connect(cell->getPort("\\Y"), replace_sig);
@ -1592,8 +1644,14 @@ struct OptExprPass : public Pass {
for (auto module : design->selected_modules())
{
if (undriven)
log("Optimizing module %s.\n", log_id(module));
if (undriven) {
did_something = false;
replace_undriven(design, module);
if (did_something)
design->scratchpad_set_bool("opt.did_something", true);
}
do {
do {
@ -1603,7 +1661,11 @@ struct OptExprPass : public Pass {
design->scratchpad_set_bool("opt.did_something", true);
} while (did_something);
replace_const_cells(design, module, true, mux_undef, mux_bool, do_fine, keepdc, clkinv);
if (did_something)
design->scratchpad_set_bool("opt.did_something", true);
} while (did_something);
log_suppressed();
}
log_pop();

View File

@ -315,17 +315,17 @@ struct OptMergeWorker
{
if (sharemap.count(cell) > 0) {
did_something = true;
log(" Cell `%s' is identical to cell `%s'.\n", cell->name.c_str(), sharemap[cell]->name.c_str());
log_debug(" Cell `%s' is identical to cell `%s'.\n", cell->name.c_str(), sharemap[cell]->name.c_str());
for (auto &it : cell->connections()) {
if (cell->output(it.first)) {
RTLIL::SigSpec other_sig = sharemap[cell]->getPort(it.first);
log(" Redirecting output %s: %s = %s\n", it.first.c_str(),
log_debug(" Redirecting output %s: %s = %s\n", it.first.c_str(),
log_signal(it.second), log_signal(other_sig));
module->connect(RTLIL::SigSig(it.second, other_sig));
assign_map.add(it.second, other_sig);
}
}
log(" Removing %s cell `%s' from module `%s'.\n", cell->type.c_str(), cell->name.c_str(), module->name.c_str());
log_debug(" Removing %s cell `%s' from module `%s'.\n", cell->type.c_str(), cell->name.c_str(), module->name.c_str());
#ifdef USE_CELL_HASH_CACHE
cell_hash_cache.erase(cell);
#endif
@ -336,6 +336,8 @@ struct OptMergeWorker
}
}
}
log_suppressed();
}
};

View File

@ -181,20 +181,29 @@ struct OptMuxtreeWorker
for (int mux_idx = 0; mux_idx < GetSize(root_muxes); mux_idx++)
if (root_muxes.at(mux_idx)) {
log(" Root of a mux tree: %s%s\n", log_id(mux2info[mux_idx].cell), root_enable_muxes.at(mux_idx) ? " (pure)" : "");
log_debug(" Root of a mux tree: %s%s\n", log_id(mux2info[mux_idx].cell), root_enable_muxes.at(mux_idx) ? " (pure)" : "");
root_mux_rerun.erase(mux_idx);
eval_root_mux(mux_idx);
if (glob_abort_cnt == 0) {
log(" Giving up (too many iterations)\n");
return;
}
}
while (!root_mux_rerun.empty()) {
int mux_idx = *root_mux_rerun.begin();
log(" Root of a mux tree: %s (rerun as non-pure)\n", log_id(mux2info[mux_idx].cell));
log_debug(" Root of a mux tree: %s (rerun as non-pure)\n", log_id(mux2info[mux_idx].cell));
log_assert(root_enable_muxes.at(mux_idx));
root_mux_rerun.erase(mux_idx);
eval_root_mux(mux_idx);
if (glob_abort_cnt == 0) {
log(" Giving up (too many iterations)\n");
return;
}
}
log(" Analyzing evaluation results.\n");
log_assert(glob_abort_cnt > 0);
for (auto &mi : mux2info)
{
@ -326,7 +335,7 @@ struct OptMuxtreeWorker
if (abort_count == 0) {
root_mux_rerun.insert(m);
root_enable_muxes.at(m) = true;
log(" Removing pure flag from root mux %s.\n", log_id(mux2info[m].cell));
log_debug(" Removing pure flag from root mux %s.\n", log_id(mux2info[m].cell));
} else
eval_mux(knowledge, m, false, do_enable_ports, abort_count - 1);
} else
@ -397,10 +406,8 @@ struct OptMuxtreeWorker
void eval_mux(knowledge_t &knowledge, int mux_idx, bool do_replace_known, bool do_enable_ports, int abort_count)
{
if (glob_abort_cnt == 0) {
log(" Giving up (too many iterations)\n");
if (glob_abort_cnt == 0)
return;
}
glob_abort_cnt--;
muxinfo_t &muxinfo = mux2info[mux_idx];
@ -454,6 +461,7 @@ struct OptMuxtreeWorker
void eval_root_mux(int mux_idx)
{
log_assert(glob_abort_cnt > 0);
knowledge_t knowledge;
knowledge.known_inactive.resize(GetSize(bit2info));
knowledge.known_active.resize(GetSize(bit2info));

View File

@ -174,8 +174,6 @@ bool handle_dffsr(RTLIL::Module *mod, RTLIL::Cell *cell)
cell->unsetParam("\\CLR_POLARITY");
cell->unsetPort("\\SET");
cell->unsetPort("\\CLR");
return true;
}
else
{
@ -186,11 +184,12 @@ bool handle_dffsr(RTLIL::Module *mod, RTLIL::Cell *cell)
cell->unsetParam("\\CLR_POLARITY");
cell->unsetPort("\\SET");
cell->unsetPort("\\CLR");
return true;
}
return true;
}
else
if (!hasreset)
{
IdString new_type;
@ -207,8 +206,10 @@ bool handle_dffsr(RTLIL::Module *mod, RTLIL::Cell *cell)
cell->unsetPort("\\S");
cell->unsetPort("\\R");
return did_something;
return true;
}
return did_something;
}
bool handle_dlatch(RTLIL::Module *mod, RTLIL::Cell *dlatch)

View File

@ -0,0 +1,852 @@
/*
* 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 OnehotDatabase
{
Module *module;
const SigMap &sigmap;
bool verbose = false;
bool initialized = false;
pool<SigBit> init_ones;
dict<SigSpec, pool<SigSpec>> sig_sources_db;
dict<SigSpec, bool> sig_onehot_cache;
pool<SigSpec> recursion_guard;
OnehotDatabase(Module *module, const SigMap &sigmap) : module(module), sigmap(sigmap)
{
}
void initialize()
{
log_assert(!initialized);
initialized = true;
for (auto wire : module->wires())
{
auto it = wire->attributes.find("\\init");
if (it == wire->attributes.end())
continue;
auto &val = it->second;
int width = std::max(GetSize(wire), GetSize(val));
for (int i = 0; i < width; i++)
if (val[i] == State::S1)
init_ones.insert(sigmap(SigBit(wire, i)));
}
for (auto cell : module->cells())
{
vector<SigSpec> inputs;
SigSpec output;
if (cell->type.in("$adff", "$dff", "$dffe", "$dlatch", "$ff"))
{
output = cell->getPort("\\Q");
if (cell->type == "$adff")
inputs.push_back(cell->getParam("\\ARST_VALUE"));
inputs.push_back(cell->getPort("\\D"));
}
if (cell->type.in("$mux", "$pmux"))
{
output = cell->getPort("\\Y");
inputs.push_back(cell->getPort("\\A"));
SigSpec B = cell->getPort("\\B");
for (int i = 0; i < GetSize(B); i += GetSize(output))
inputs.push_back(B.extract(i, GetSize(output)));
}
if (!output.empty())
{
output = sigmap(output);
auto &srcs = sig_sources_db[output];
for (auto src : inputs) {
while (!src.empty() && src[GetSize(src)-1] == State::S0)
src.remove(GetSize(src)-1);
srcs.insert(sigmap(src));
}
}
}
}
void query_worker(const SigSpec &sig, bool &retval, bool &cache, int indent)
{
if (verbose)
log("%*s %s\n", indent, "", log_signal(sig));
log_assert(retval);
if (recursion_guard.count(sig)) {
if (verbose)
log("%*s - recursion\n", indent, "");
cache = false;
return;
}
auto it = sig_onehot_cache.find(sig);
if (it != sig_onehot_cache.end()) {
if (verbose)
log("%*s - cached (%s)\n", indent, "", it->second ? "true" : "false");
if (!it->second)
retval = false;
return;
}
bool found_init_ones = false;
for (auto bit : sig) {
if (init_ones.count(bit)) {
if (found_init_ones) {
if (verbose)
log("%*s - non-onehot init value\n", indent, "");
retval = false;
break;
}
found_init_ones = true;
}
}
if (retval)
{
if (sig.is_fully_const())
{
bool found_ones = false;
for (auto bit : sig) {
if (bit == State::S1) {
if (found_ones) {
if (verbose)
log("%*s - non-onehot constant\n", indent, "");
retval = false;
break;
}
found_ones = true;
}
}
}
else
{
auto srcs = sig_sources_db.find(sig);
if (srcs == sig_sources_db.end()) {
if (verbose)
log("%*s - no sources for non-const signal\n", indent, "");
retval = false;
} else {
for (auto &src : srcs->second) {
bool child_cache = true;
recursion_guard.insert(sig);
query_worker(src, retval, child_cache, indent+4);
recursion_guard.erase(sig);
if (!child_cache)
cache = false;
if (!retval)
break;
}
}
}
}
// it is always safe to cache a negative result
if (cache || !retval)
sig_onehot_cache[sig] = retval;
}
bool query(const SigSpec &sig)
{
bool retval = true;
bool cache = true;
if (verbose)
log("** ONEHOT QUERY START (%s)\n", log_signal(sig));
if (!initialized)
initialize();
query_worker(sig, retval, cache, 3);
if (verbose)
log("** ONEHOT QUERY RESULT = %s\n", retval ? "true" : "false");
// it is always safe to cache the root result of a query
if (!cache)
sig_onehot_cache[sig] = retval;
return retval;
}
};
struct Pmux2ShiftxPass : public Pass {
Pmux2ShiftxPass() : Pass("pmux2shiftx", "transform $pmux cells to $shiftx cells") { }
void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" pmux2shiftx [options] [selection]\n");
log("\n");
log("This pass transforms $pmux cells to $shiftx cells.\n");
log("\n");
log(" -v, -vv\n");
log(" verbose output\n");
log("\n");
log(" -min_density <percentage>\n");
log(" specifies the minimum density for the shifter\n");
log(" default: 50\n");
log("\n");
log(" -min_choices <int>\n");
log(" specified the minimum number of choices for a control signal\n");
log(" default: 3\n");
log("\n");
log(" -onehot ignore|pmux|shiftx\n");
log(" select strategy for one-hot encoded control signals\n");
log(" default: pmux\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
int min_density = 50;
int min_choices = 3;
bool allow_onehot = false;
bool optimize_onehot = true;
bool verbose = false;
bool verbose_onehot = false;
log_header(design, "Executing PMUX2SHIFTX pass.\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
if (args[argidx] == "-min_density" && argidx+1 < args.size()) {
min_density = atoi(args[++argidx].c_str());
continue;
}
if (args[argidx] == "-min_choices" && argidx+1 < args.size()) {
min_choices = atoi(args[++argidx].c_str());
continue;
}
if (args[argidx] == "-onehot" && argidx+1 < args.size() && args[argidx+1] == "ignore") {
argidx++;
allow_onehot = false;
optimize_onehot = false;
continue;
}
if (args[argidx] == "-onehot" && argidx+1 < args.size() && args[argidx+1] == "pmux") {
argidx++;
allow_onehot = false;
optimize_onehot = true;
continue;
}
if (args[argidx] == "-onehot" && argidx+1 < args.size() && args[argidx+1] == "shiftx") {
argidx++;
allow_onehot = true;
optimize_onehot = false;
continue;
}
if (args[argidx] == "-v") {
verbose = true;
continue;
}
if (args[argidx] == "-vv") {
verbose = true;
verbose_onehot = true;
continue;
}
break;
}
extra_args(args, argidx, design);
for (auto module : design->selected_modules())
{
SigMap sigmap(module);
OnehotDatabase onehot_db(module, sigmap);
onehot_db.verbose = verbose_onehot;
dict<SigBit, pair<SigSpec, Const>> eqdb;
for (auto cell : module->cells())
{
if (cell->type == "$eq")
{
dict<SigBit, State> bits;
SigSpec A = sigmap(cell->getPort("\\A"));
SigSpec B = sigmap(cell->getPort("\\B"));
int a_width = cell->getParam("\\A_WIDTH").as_int();
int b_width = cell->getParam("\\B_WIDTH").as_int();
if (a_width < b_width) {
bool a_signed = cell->getParam("\\A_SIGNED").as_int();
A.extend_u0(b_width, a_signed);
}
if (b_width < a_width) {
bool b_signed = cell->getParam("\\B_SIGNED").as_int();
B.extend_u0(a_width, b_signed);
}
for (int i = 0; i < GetSize(A); i++) {
SigBit a_bit = A[i], b_bit = B[i];
if (b_bit.wire && !a_bit.wire) {
std::swap(a_bit, b_bit);
}
if (!a_bit.wire || b_bit.wire)
goto next_cell;
if (bits.count(a_bit))
goto next_cell;
bits[a_bit] = b_bit.data;
}
if (GetSize(bits) > 20)
goto next_cell;
bits.sort();
pair<SigSpec, Const> entry;
for (auto it : bits) {
entry.first.append_bit(it.first);
entry.second.bits.push_back(it.second);
}
eqdb[sigmap(cell->getPort("\\Y")[0])] = entry;
goto next_cell;
}
if (cell->type == "$logic_not")
{
dict<SigBit, State> bits;
SigSpec A = sigmap(cell->getPort("\\A"));
for (int i = 0; i < GetSize(A); i++)
bits[A[i]] = State::S0;
bits.sort();
pair<SigSpec, Const> entry;
for (auto it : bits) {
entry.first.append_bit(it.first);
entry.second.bits.push_back(it.second);
}
eqdb[sigmap(cell->getPort("\\Y")[0])] = entry;
goto next_cell;
}
next_cell:;
}
for (auto cell : module->selected_cells())
{
if (cell->type != "$pmux")
continue;
string src = cell->get_src_attribute();
int width = cell->getParam("\\WIDTH").as_int();
int width_bits = ceil_log2(width);
int extwidth = width;
while (extwidth & (extwidth-1))
extwidth++;
dict<SigSpec, pool<int>> seldb;
SigSpec A = cell->getPort("\\A");
SigSpec B = cell->getPort("\\B");
SigSpec S = sigmap(cell->getPort("\\S"));
for (int i = 0; i < GetSize(S); i++)
{
if (!eqdb.count(S[i]))
continue;
auto &entry = eqdb.at(S[i]);
seldb[entry.first].insert(i);
}
if (seldb.empty())
continue;
bool printed_pmux_header = false;
if (verbose) {
printed_pmux_header = true;
log("Inspecting $pmux cell %s/%s.\n", log_id(module), log_id(cell));
log(" data width: %d (next power-of-2 = %d, log2 = %d)\n", width, extwidth, width_bits);
}
SigSpec updated_S = cell->getPort("\\S");
SigSpec updated_B = cell->getPort("\\B");
while (!seldb.empty())
{
// pick the largest entry in seldb
SigSpec sig = seldb.begin()->first;
for (auto &it : seldb) {
if (GetSize(sig) < GetSize(it.first))
sig = it.first;
else if (GetSize(seldb.at(sig)) < GetSize(it.second))
sig = it.first;
}
// find the relevant choices
bool is_onehot = GetSize(sig) > 2;
dict<Const, int> choices;
for (int i : seldb.at(sig)) {
Const val = eqdb.at(S[i]).second;
int onebits = 0;
for (auto b : val.bits)
if (b == State::S1)
onebits++;
if (onebits > 1)
is_onehot = false;
choices[val] = i;
}
bool full_pmux = GetSize(choices) == GetSize(S);
// TBD: also find choices that are using signals that are subsets of the bits in "sig"
if (!verbose)
{
if (is_onehot && !allow_onehot && !optimize_onehot) {
seldb.erase(sig);
continue;
}
if (GetSize(choices) < min_choices) {
seldb.erase(sig);
continue;
}
}
if (!printed_pmux_header) {
printed_pmux_header = true;
log("Inspecting $pmux cell %s/%s.\n", log_id(module), log_id(cell));
log(" data width: %d (next power-of-2 = %d, log2 = %d)\n", width, extwidth, width_bits);
}
log(" checking ctrl signal %s\n", log_signal(sig));
auto print_choices = [&]() {
log(" table of choices:\n");
for (auto &it : choices)
log(" %3d: %s: %s\n", it.second, log_signal(it.first),
log_signal(B.extract(it.second*width, width)));
};
if (verbose)
{
if (is_onehot && !allow_onehot && !optimize_onehot) {
print_choices();
log(" ignoring one-hot encoding.\n");
seldb.erase(sig);
continue;
}
if (GetSize(choices) < min_choices) {
print_choices();
log(" insufficient choices.\n");
seldb.erase(sig);
continue;
}
}
if (is_onehot && optimize_onehot)
{
print_choices();
if (!onehot_db.query(sig))
{
log(" failed to detect onehot driver. do not optimize.\n");
}
else
{
log(" optimizing one-hot encoding.\n");
for (auto &it : choices)
{
const Const &val = it.first;
int index = -1;
for (int i = 0; i < GetSize(val); i++)
if (val[i] == State::S1) {
log_assert(index < 0);
index = i;
}
if (index < 0) {
log(" %3d: zero encoding.\n", it.second);
continue;
}
SigBit new_ctrl = sig[index];
log(" %3d: new crtl signal is %s.\n", it.second, log_signal(new_ctrl));
updated_S[it.second] = new_ctrl;
}
}
seldb.erase(sig);
continue;
}
// find the best permutation
vector<int> perm_new_from_old(GetSize(sig));
Const perm_xormask(State::S0, GetSize(sig));
{
vector<int> values(GetSize(choices));
vector<bool> used_src_columns(GetSize(sig));
vector<vector<bool>> columns(GetSize(sig), vector<bool>(GetSize(values)));
for (int i = 0; i < GetSize(choices); i++) {
Const val = choices.element(i)->first;
for (int k = 0; k < GetSize(val); k++)
if (val[k] == State::S1)
columns[k][i] = true;
}
for (int dst_col = GetSize(sig)-1; dst_col >= 0; dst_col--)
{
int best_src_col = -1;
bool best_inv = false;
int best_maxval = 0;
int best_delta = 0;
// find best src column for this dst column
for (int src_col = 0; src_col < GetSize(sig); src_col++)
{
if (used_src_columns[src_col])
continue;
int this_maxval = 0;
int this_minval = 1 << 30;
int this_inv_maxval = 0;
int this_inv_minval = 1 << 30;
for (int i = 0; i < GetSize(values); i++)
{
int val = values[i];
int inv_val = val;
if (columns[src_col][i])
val |= 1 << dst_col;
else
inv_val |= 1 << dst_col;
this_maxval = std::max(this_maxval, val);
this_minval = std::min(this_minval, val);
this_inv_maxval = std::max(this_inv_maxval, inv_val);
this_inv_minval = std::min(this_inv_minval, inv_val);
}
int this_delta = this_maxval - this_minval;
int this_inv_delta = this_maxval - this_minval;
bool this_inv = false;
if (this_delta != this_inv_delta)
this_inv = this_inv_delta < this_delta;
else if (this_maxval != this_inv_maxval)
this_inv = this_inv_maxval < this_maxval;
if (this_inv) {
this_delta = this_inv_delta;
this_maxval = this_inv_maxval;
this_minval = this_inv_minval;
}
bool this_is_better = false;
if (best_src_col < 0)
this_is_better = true;
else if (this_delta != best_delta)
this_is_better = this_delta < best_delta;
else if (this_maxval != best_maxval)
this_is_better = this_maxval < best_maxval;
else
this_is_better = sig[best_src_col] < sig[src_col];
if (this_is_better) {
best_src_col = src_col;
best_inv = this_inv;
best_maxval = this_maxval;
best_delta = this_delta;
}
}
used_src_columns[best_src_col] = true;
perm_new_from_old[dst_col] = best_src_col;
perm_xormask[dst_col] = best_inv ? State::S1 : State::S0;
}
}
// permutated sig
SigSpec perm_sig(State::S0, GetSize(sig));
for (int i = 0; i < GetSize(sig); i++)
perm_sig[i] = sig[perm_new_from_old[i]];
log(" best permutation: %s\n", log_signal(perm_sig));
log(" best xor mask: %s\n", log_signal(perm_xormask));
// permutated choices
int min_choice = 1 << 30;
int max_choice = -1;
dict<Const, int> perm_choices;
for (auto &it : choices)
{
Const &old_c = it.first;
Const new_c(State::S0, GetSize(old_c));
for (int i = 0; i < GetSize(old_c); i++)
new_c[i] = old_c[perm_new_from_old[i]];
Const new_c_before_xor = new_c;
new_c = const_xor(new_c, perm_xormask, false, false, GetSize(new_c));
perm_choices[new_c] = it.second;
min_choice = std::min(min_choice, new_c.as_int());
max_choice = std::max(max_choice, new_c.as_int());
log(" %3d: %s -> %s -> %s: %s\n", it.second, log_signal(old_c), log_signal(new_c_before_xor),
log_signal(new_c), log_signal(B.extract(it.second*width, width)));
}
int range_density = 100*GetSize(choices) / (max_choice-min_choice+1);
int absolute_density = 100*GetSize(choices) / (max_choice+1);
log(" choices: %d\n", GetSize(choices));
log(" min choice: %d\n", min_choice);
log(" max choice: %d\n", max_choice);
log(" range density: %d%%\n", range_density);
log(" absolute density: %d%%\n", absolute_density);
if (full_pmux) {
int full_density = 100*GetSize(choices) / (1 << GetSize(sig));
log(" full density: %d%%\n", full_density);
if (full_density < min_density) {
full_pmux = false;
} else {
min_choice = 0;
max_choice = (1 << GetSize(sig))-1;
log(" update to full case.\n");
log(" new min choice: %d\n", min_choice);
log(" new max choice: %d\n", max_choice);
}
}
bool full_case = (min_choice == 0) && (max_choice == (1 << GetSize(sig))-1) && (full_pmux || max_choice+1 == GetSize(choices));
log(" full case: %s\n", full_case ? "true" : "false");
// check density percentages
Const offset(State::S0, GetSize(sig));
if (absolute_density < min_density && range_density >= min_density)
{
offset = Const(min_choice, GetSize(sig));
log(" offset: %s\n", log_signal(offset));
min_choice -= offset.as_int();
max_choice -= offset.as_int();
dict<Const, int> new_perm_choices;
for (auto &it : perm_choices)
new_perm_choices[const_sub(it.first, offset, false, false, GetSize(sig))] = it.second;
perm_choices.swap(new_perm_choices);
} else
if (absolute_density < min_density) {
log(" insufficient density.\n");
seldb.erase(sig);
continue;
}
// creat cmp signal
SigSpec cmp = perm_sig;
if (perm_xormask.as_bool())
cmp = module->Xor(NEW_ID, cmp, perm_xormask, false, src);
if (offset.as_bool())
cmp = module->Sub(NEW_ID, cmp, offset, false, src);
// create enable signal
SigBit en = State::S1;
if (!full_case) {
Const enable_mask(State::S0, max_choice+1);
for (auto &it : perm_choices)
enable_mask[it.first.as_int()] = State::S1;
en = module->addWire(NEW_ID);
module->addShift(NEW_ID, enable_mask, cmp, en, false, src);
}
// create data signal
SigSpec data(State::Sx, (max_choice+1)*extwidth);
if (full_pmux) {
for (int i = 0; i <= max_choice; i++)
data.replace(i*extwidth, A);
}
for (auto &it : perm_choices) {
int position = it.first.as_int()*extwidth;
int data_index = it.second;
data.replace(position, B.extract(data_index*width, width));
updated_S[data_index] = State::S0;
updated_B.replace(data_index*width, SigSpec(State::Sx, width));
}
// create shiftx cell
SigSpec shifted_cmp = {cmp, SigSpec(State::S0, width_bits)};
SigSpec outsig = module->addWire(NEW_ID, width);
Cell *c = module->addShiftx(NEW_ID, data, shifted_cmp, outsig, false, src);
updated_S.append(en);
updated_B.append(outsig);
log(" created $shiftx cell %s.\n", log_id(c));
// remove this sig and continue with the next block
seldb.erase(sig);
}
// update $pmux cell
cell->setPort("\\S", updated_S);
cell->setPort("\\B", updated_B);
cell->setParam("\\S_WIDTH", GetSize(updated_S));
}
}
}
} Pmux2ShiftxPass;
struct OnehotPass : public Pass {
OnehotPass() : Pass("onehot", "optimize $eq cells for onehot signals") { }
void help() YS_OVERRIDE
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" onehot [options] [selection]\n");
log("\n");
log("This pass optimizes $eq cells that compare one-hot signals against constants\n");
log("\n");
log(" -v, -vv\n");
log(" verbose output\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
bool verbose = false;
bool verbose_onehot = false;
log_header(design, "Executing ONEHOT pass.\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
if (args[argidx] == "-v") {
verbose = true;
continue;
}
if (args[argidx] == "-vv") {
verbose = true;
verbose_onehot = true;
continue;
}
break;
}
extra_args(args, argidx, design);
for (auto module : design->selected_modules())
{
SigMap sigmap(module);
OnehotDatabase onehot_db(module, sigmap);
onehot_db.verbose = verbose_onehot;
for (auto cell : module->selected_cells())
{
if (cell->type != "$eq")
continue;
SigSpec A = sigmap(cell->getPort("\\A"));
SigSpec B = sigmap(cell->getPort("\\B"));
int a_width = cell->getParam("\\A_WIDTH").as_int();
int b_width = cell->getParam("\\B_WIDTH").as_int();
if (a_width < b_width) {
bool a_signed = cell->getParam("\\A_SIGNED").as_int();
A.extend_u0(b_width, a_signed);
}
if (b_width < a_width) {
bool b_signed = cell->getParam("\\B_SIGNED").as_int();
B.extend_u0(a_width, b_signed);
}
if (A.is_fully_const())
std::swap(A, B);
if (!B.is_fully_const())
continue;
if (verbose)
log("Checking $eq(%s, %s) cell %s/%s.\n", log_signal(A), log_signal(B), log_id(module), log_id(cell));
if (!onehot_db.query(A)) {
if (verbose)
log(" onehot driver test on %s failed.\n", log_signal(A));
continue;
}
int index = -1;
bool not_onehot = false;
for (int i = 0; i < GetSize(B); i++) {
if (B[i] != State::S1)
continue;
if (index >= 0)
not_onehot = true;
index = i;
}
if (index < 0) {
if (verbose)
log(" not optimizing the zero pattern.\n");
continue;
}
SigSpec Y = cell->getPort("\\Y");
if (not_onehot)
{
if (verbose)
log(" replacing with constant 0 driver.\n");
else
log("Replacing one-hot $eq(%s, %s) cell %s/%s with constant 0 driver.\n", log_signal(A), log_signal(B), log_id(module), log_id(cell));
module->connect(Y, SigSpec(1, GetSize(Y)));
}
else
{
SigSpec sig = A[index];
if (verbose)
log(" replacing with signal %s.\n", log_signal(sig));
else
log("Replacing one-hot $eq(%s, %s) cell %s/%s with signal %s.\n",log_signal(A), log_signal(B), log_id(module), log_id(cell), log_signal(sig));
sig.extend_u0(GetSize(Y));
module->connect(Y, sig);
}
module->remove(cell);
}
}
}
} OnehotPass;
PRIVATE_NAMESPACE_END

View File

@ -29,6 +29,7 @@ PRIVATE_NAMESPACE_BEGIN
struct WreduceConfig
{
pool<IdString> supported_cell_types;
bool keepdc = false;
WreduceConfig()
{
@ -38,7 +39,8 @@ struct WreduceConfig
"$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx",
"$lt", "$le", "$eq", "$ne", "$eqx", "$nex", "$ge", "$gt",
"$add", "$sub", "$mul", // "$div", "$mod", "$pow",
"$mux", "$pmux"
"$mux", "$pmux",
"$dff", "$adff"
});
}
};
@ -52,6 +54,8 @@ struct WreduceWorker
std::set<Cell*, IdString::compare_ptr_by_name<Cell>> work_queue_cells;
std::set<SigBit> work_queue_bits;
pool<SigBit> keep_bits;
dict<SigBit, State> init_bits;
pool<SigBit> remove_init_bits;
WreduceWorker(WreduceConfig *config, Module *module) :
config(config), module(module), mi(module) { }
@ -79,7 +83,7 @@ struct WreduceWorker
SigBit ref = sig_a[i];
for (int k = 0; k < GetSize(sig_s); k++) {
if (ref != Sx && sig_b[k*GetSize(sig_a) + i] != Sx && ref != sig_b[k*GetSize(sig_a) + i])
if ((config->keepdc || (ref != Sx && sig_b[k*GetSize(sig_a) + i] != Sx)) && ref != sig_b[k*GetSize(sig_a) + i])
goto no_match_ab;
if (sig_b[k*GetSize(sig_a) + i] != Sx)
ref = sig_b[k*GetSize(sig_a) + i];
@ -134,6 +138,93 @@ struct WreduceWorker
module->connect(sig_y.extract(n_kept, n_removed), sig_removed);
}
void run_cell_dff(Cell *cell)
{
// Reduce size of FF if inputs are just sign/zero extended or output bit is not used
SigSpec sig_d = mi.sigmap(cell->getPort("\\D"));
SigSpec sig_q = mi.sigmap(cell->getPort("\\Q"));
Const initval;
int width_before = GetSize(sig_q);
if (width_before == 0)
return;
bool zero_ext = sig_d[GetSize(sig_d)-1] == State::S0;
bool sign_ext = !zero_ext;
for (int i = 0; i < GetSize(sig_q); i++) {
SigBit bit = sig_q[i];
if (init_bits.count(bit))
initval.bits.push_back(init_bits.at(bit));
else
initval.bits.push_back(State::Sx);
}
for (int i = GetSize(sig_q)-1; i >= 0; i--)
{
if (zero_ext && sig_d[i] == State::S0 && (initval[i] == State::S0 || initval[i] == State::Sx)) {
module->connect(sig_q[i], State::S0);
remove_init_bits.insert(sig_q[i]);
sig_d.remove(i);
sig_q.remove(i);
continue;
}
if (sign_ext && i > 0 && sig_d[i] == sig_d[i-1] && initval[i] == initval[i-1]) {
module->connect(sig_q[i], sig_q[i-1]);
remove_init_bits.insert(sig_q[i]);
sig_d.remove(i);
sig_q.remove(i);
continue;
}
auto info = mi.query(sig_q[i]);
if (info == nullptr)
return;
if (!info->is_output && GetSize(info->ports) == 1 && !keep_bits.count(mi.sigmap(sig_q[i]))) {
remove_init_bits.insert(sig_q[i]);
sig_d.remove(i);
sig_q.remove(i);
zero_ext = false;
sign_ext = false;
continue;
}
break;
}
if (width_before == GetSize(sig_q))
return;
if (GetSize(sig_q) == 0) {
log("Removed cell %s.%s (%s).\n", log_id(module), log_id(cell), log_id(cell->type));
module->remove(cell);
return;
}
log("Removed top %d bits (of %d) from FF cell %s.%s (%s).\n", width_before - GetSize(sig_q), width_before,
log_id(module), log_id(cell), log_id(cell->type));
for (auto bit : sig_d)
work_queue_bits.insert(bit);
for (auto bit : sig_q)
work_queue_bits.insert(bit);
// Narrow ARST_VALUE parameter to new size.
if (cell->parameters.count("\\ARST_VALUE")) {
Const arst_value = cell->getParam("\\ARST_VALUE");
arst_value.bits.resize(GetSize(sig_q));
cell->setParam("\\ARST_VALUE", arst_value);
}
cell->setPort("\\D", sig_d);
cell->setPort("\\Q", sig_q);
cell->fixup_parameters();
}
void run_reduce_inport(Cell *cell, char port, int max_port_size, bool &port_signed, bool &did_something)
{
port_signed = cell->getParam(stringf("\\%c_SIGNED", port)).as_bool();
@ -176,6 +267,9 @@ struct WreduceWorker
if (cell->type.in("$mux", "$pmux"))
return run_cell_mux(cell);
if (cell->type.in("$dff", "$adff"))
return run_cell_dff(cell);
SigSpec sig = mi.sigmap(cell->getPort("\\Y"));
if (sig.has_const())
@ -300,10 +394,21 @@ struct WreduceWorker
void run()
{
for (auto w : module->wires())
// create a copy as mi.sigmap will be updated as we process the module
SigMap init_attr_sigmap = mi.sigmap;
for (auto w : module->wires()) {
if (w->get_bool_attribute("\\keep"))
for (auto bit : mi.sigmap(w))
keep_bits.insert(bit);
if (w->attributes.count("\\init")) {
Const initval = w->attributes.at("\\init");
SigSpec initsig = init_attr_sigmap(w);
int width = std::min(GetSize(initval), GetSize(initsig));
for (int i = 0; i < width; i++)
init_bits[initsig[i]] = initval[i];
}
}
for (auto c : module->selected_cells())
work_queue_cells.insert(c);
@ -351,6 +456,22 @@ struct WreduceWorker
module->connect(nw, SigSpec(w).extract(0, GetSize(nw)));
module->swap_names(w, nw);
}
if (!remove_init_bits.empty()) {
for (auto w : module->wires()) {
if (w->attributes.count("\\init")) {
Const initval = w->attributes.at("\\init");
Const new_initval(State::Sx, GetSize(w));
SigSpec initsig = init_attr_sigmap(w);
int width = std::min(GetSize(initval), GetSize(initsig));
for (int i = 0; i < width; i++) {
if (!remove_init_bits.count(initsig[i]))
new_initval[i] = initval[i];
}
w->attributes.at("\\init") = new_initval;
}
}
}
}
};
@ -375,6 +496,9 @@ struct WreducePass : public Pass {
log(" Do not change the width of memory address ports. Use this options in\n");
log(" flows that use the 'memory_memx' pass.\n");
log("\n");
log(" -keepdc\n");
log(" Do not optimize explicit don't-care values.\n");
log("\n");
}
void execute(std::vector<std::string> args, Design *design) YS_OVERRIDE
{
@ -389,6 +513,10 @@ struct WreducePass : public Pass {
opt_memx = true;
continue;
}
if (args[argidx] == "-keepdc") {
config.keepdc = true;
continue;
}
break;
}
extra_args(args, argidx, design);
@ -411,6 +539,42 @@ struct WreducePass : public Pass {
module->connect(sig, Const(0, GetSize(sig)));
}
}
if (c->type.in("$div", "$mod", "$pow"))
{
SigSpec A = c->getPort("\\A");
int original_a_width = GetSize(A);
if (c->getParam("\\A_SIGNED").as_bool()) {
while (GetSize(A) > 1 && A[GetSize(A)-1] == State::S0 && A[GetSize(A)-2] == State::S0)
A.remove(GetSize(A)-1, 1);
} else {
while (GetSize(A) > 0 && A[GetSize(A)-1] == State::S0)
A.remove(GetSize(A)-1, 1);
}
if (original_a_width != GetSize(A)) {
log("Removed top %d bits (of %d) from port A of cell %s.%s (%s).\n",
original_a_width-GetSize(A), original_a_width, log_id(module), log_id(c), log_id(c->type));
c->setPort("\\A", A);
c->setParam("\\A_WIDTH", GetSize(A));
}
SigSpec B = c->getPort("\\B");
int original_b_width = GetSize(B);
if (c->getParam("\\B_SIGNED").as_bool()) {
while (GetSize(B) > 1 && B[GetSize(B)-1] == State::S0 && B[GetSize(B)-2] == State::S0)
B.remove(GetSize(B)-1, 1);
} else {
while (GetSize(B) > 0 && B[GetSize(B)-1] == State::S0)
B.remove(GetSize(B)-1, 1);
}
if (original_b_width != GetSize(B)) {
log("Removed top %d bits (of %d) from port B of cell %s.%s (%s).\n",
original_b_width-GetSize(B), original_b_width, log_id(module), log_id(c), log_id(c->type));
c->setPort("\\B", B);
c->setParam("\\B_WIDTH", GetSize(B));
}
}
if (!opt_memx && c->type.in("$memrd", "$memwr", "$meminit")) {
IdString memid = c->getParam("\\MEMID").decode_string();
RTLIL::Memory *mem = module->memories.at(memid);

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