Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Jim Lawson 2019-04-30 13:19:27 -07:00
commit 58650ffe87
91 changed files with 5176 additions and 475 deletions

View File

@ -32,6 +32,10 @@ matrix:
- xdot
- pkg-config
- python
- python3
- libboost-system-dev
- libboost-python-dev
- libboost-filesystem-dev
env:
- MATRIX_EVAL="CONFIG=gcc && CC=gcc-4.8 && CXX=g++-4.8"
@ -56,6 +60,10 @@ matrix:
- xdot
- pkg-config
- python
- python3
- libboost-system-dev
- libboost-python-dev
- libboost-filesystem-dev
env:
- MATRIX_EVAL="CONFIG=gcc && CC=gcc-6 && CXX=g++-6"
@ -80,6 +88,10 @@ matrix:
- xdot
- pkg-config
- python
- python3
- libboost-system-dev
- libboost-python-dev
- libboost-filesystem-dev
env:
- MATRIX_EVAL="CONFIG=gcc && CC=gcc-7 && CXX=g++-7"
@ -105,6 +117,10 @@ matrix:
- xdot
- pkg-config
- python
- python3
- libboost-system-dev
- libboost-python-dev
- libboost-filesystem-dev
env:
- MATRIX_EVAL="CONFIG=clang && CC=clang-3.8 && CXX=clang++-3.8"
@ -129,6 +145,10 @@ matrix:
- xdot
- pkg-config
- python
- python3
- libboost-system-dev
- libboost-python-dev
- libboost-filesystem-dev
env:
- MATRIX_EVAL="CONFIG=clang && CC=clang-5.0 && CXX=clang++-5.0"

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

@ -19,6 +19,14 @@ 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_DESTDIR := `$(PYTHON_EXECUTABLE)-config --prefix`/lib/python$(PYTHON_VERSION)/dist-packages
# other configuration flags
ENABLE_GCOV := 0
ENABLE_GPROF := 0
@ -111,7 +119,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 = 2ddc57d
ABCREV = 3709744
ABCPULL = 1
ABCURL ?= https://github.com/berkeley-abc/abc
ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1
@ -261,6 +269,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)
@ -510,6 +546,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) $<
@ -638,6 +682,11 @@ ifeq ($(ENABLE_LIBYOSYS),1)
$(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:
@ -645,6 +694,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)
@ -657,8 +711,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

@ -66,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
@ -310,12 +311,24 @@ 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 ``dynports'' attribute is used by the Verilog front-end to mark modules
- 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
- 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
@ -357,7 +370,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;
@ -444,7 +457,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.
@ -457,7 +470,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());

View File

@ -178,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())
@ -192,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);
@ -302,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);

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

@ -1543,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

@ -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

@ -187,6 +187,10 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o
{
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()) {
@ -340,6 +344,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 {
@ -1770,7 +1778,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))

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

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

32
examples/python-api/pass.py Executable file
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()

22
examples/python-api/script.py Executable file
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

@ -33,8 +33,6 @@
YOSYS_NAMESPACE_BEGIN
#define log_debug log
AigerReader::AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name)
: design(design), f(f), clk_name(clk_name)
{

View File

@ -46,7 +46,7 @@ namespace AST {
// instantiate global variables (private API)
namespace AST_INTERNAL {
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_lib, flag_noopt, flag_icells, flag_autowire;
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;
@ -942,6 +942,20 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast
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;
blackbox_module = false;
break;
}
}
while (ast->simplify(!flag_noopt, false, false, 0, -1, false, false)) { }
if (flag_dump_ast2) {
@ -956,7 +970,63 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast
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)) {
@ -969,8 +1039,12 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast
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();
@ -1009,7 +1083,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;
@ -1026,7 +1102,7 @@ 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_vlog1, bool dump_vlog2, 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)
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;
@ -1039,7 +1115,9 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump
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;
@ -1373,7 +1451,9 @@ std::string AstModule::derive_common(RTLIL::Design *design, dict<RTLIL::IdString
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

@ -283,13 +283,13 @@ 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_vlog1, bool dump_vlog2, 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);
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

@ -1030,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)
@ -1066,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");
@ -1088,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");
@ -1129,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");
@ -1138,6 +1172,15 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
varbuf->children[0] = buf;
}
#if 0
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);
}
#endif
current_scope[varbuf->str] = backup_scope_varbuf;
delete varbuf;
delete_children();

View File

@ -145,8 +145,18 @@ 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(" -noopt\n");
log(" don't perform basic optimizations (such as const folding) in the\n");
@ -227,11 +237,11 @@ struct VerilogFrontend : public Frontend {
formal_mode = false;
norestrict_mode = false;
assume_asserts_mode = false;
noblackbox_mode = false;
lib_mode = false;
nowb_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;
@ -329,11 +339,19 @@ struct VerilogFrontend : public Frontend {
flag_nodpi = true;
continue;
}
if (arg == "-noblackbox") {
noblackbox_mode = true;
continue;
}
if (arg == "-lib") {
lib_mode = true;
defines_map["BLACKBOX"] = string();
continue;
}
if (arg == "-nowb") {
nowb_mode = true;
continue;
}
if (arg == "-noopt") {
flag_noopt = true;
continue;
@ -395,6 +413,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());
@ -429,7 +449,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_vlog1, flag_dump_vlog2, 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, noblackbox_mode, lib_mode, nowb_mode, flag_noopt, flag_icells, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire);
if (!flag_nopp)
delete lexin;

View File

@ -69,9 +69,15 @@ namespace VERILOG_FRONTEND
// running in -assert-assumes mode
extern bool assert_assumes_mode;
// running in -noblackbox mode
extern bool noblackbox_mode;
// running in -lib mode
extern bool lib_mode;
// running in -nowb mode
extern bool nowb_mode;
// lexer input stream
extern std::istream *lexin;
}

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, noblackbox_mode, lib_mode, nowb_mode;
bool noassert_mode, noassume_mode, norestrict_mode;
bool assume_asserts_mode, assert_assumes_mode;
bool current_wire_rand, current_wire_const;

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

@ -464,7 +464,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)
{
@ -291,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");
@ -311,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:P: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)
{
@ -336,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;
@ -469,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)
@ -515,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

@ -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())

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();

View File

@ -87,6 +87,7 @@ 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;

View File

@ -76,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())
@ -207,9 +214,12 @@ 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 if (attributes.count(id))
attributes.erase(id);
}
bool RTLIL::AttrObject::get_bool_attribute(RTLIL::IdString id) const
@ -360,6 +370,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()
@ -370,8 +384,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_);
@ -589,7 +614,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;
}
@ -599,7 +624,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;
}
@ -609,7 +634,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);
@ -627,6 +652,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()
@ -639,8 +668,19 @@ 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;
@ -2226,8 +2266,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;
@ -2237,6 +2296,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)
@ -2247,8 +2309,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;
@ -2508,6 +2589,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;
@ -3367,7 +3456,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();
@ -3892,5 +3981,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

@ -517,6 +517,7 @@ 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);
bool operator <(const RTLIL::Const &other) const;
bool operator ==(const RTLIL::Const &other) const;
@ -566,9 +567,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;
@ -591,6 +596,7 @@ 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 extract(int offset, int length) const;
@ -615,6 +621,7 @@ 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);
bool operator <(const RTLIL::SigBit &other) const;
bool operator ==(const RTLIL::SigBit &other) const;
@ -936,9 +943,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
@ -1195,6 +1206,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
@ -1206,7 +1221,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
@ -1217,6 +1232,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
@ -1228,6 +1247,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
@ -1239,6 +1262,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
@ -1279,6 +1303,10 @@ public:
}
template<typename T> void rewrite_sigspecs(T &functor);
#ifdef WITH_PYTHON
static std::map<unsigned int, RTLIL::Cell*> *get_all_cells(void);
#endif
};
struct RTLIL::CaseRule
@ -1339,6 +1367,7 @@ 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)

View File

@ -57,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>
@ -472,26 +482,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;
@ -519,9 +564,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_);
}

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 {
@ -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);

5
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"]

2096
misc/py_wrap_generator.py Normal file

File diff suppressed because it is too large Load Diff

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())

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

@ -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

@ -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

@ -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

@ -346,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;
}
@ -451,7 +451,7 @@ 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);
@ -491,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);
@ -910,7 +910,7 @@ struct HierarchyPass : public Pass {
if (m == nullptr)
continue;
if (m->get_bool_attribute("\\blackbox") && !cell->parameters.empty() && m->get_bool_attribute("\\dynports")) {
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)

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

@ -137,7 +137,7 @@ 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++;
@ -281,13 +281,26 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
maybe_del_wires.push_back(wire);
} else {
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);
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);
@ -326,7 +339,7 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
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());
log_debug(" removing unused non-port wire %s.\n", wire->name.c_str());
}
del_wires.insert(wire);
del_wires_count++;
@ -336,7 +349,7 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
count_rm_wires += del_wires.size();
if (verbose && del_wires_count > 0)
log(" removed %d unused temporary wires.\n", del_wires_count);
log_debug(" removed %d unused temporary wires.\n", del_wires_count);
}
bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose)
@ -399,7 +412,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 +439,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);
}
@ -551,6 +564,7 @@ struct CleanPass : public Pass {
rmunused_module(module, purge_mode, false, 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,6 +51,14 @@ 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)
@ -67,10 +78,38 @@ 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", RTLIL::id2cstr(module->name), 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())
wire->attributes.erase("\\init");
else
wire->attributes["\\init"] = initval;
}
}
}
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 +117,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 +173,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++)
@ -156,7 +195,7 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ
}
if (cell->type.in("$and", "$or") && i == GRP_CONST_A) {
log(" Direct Connection: %s (%s with %s)\n", log_signal(new_b), log_id(cell->type), log_signal(new_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;
@ -180,10 +219,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());
@ -197,7 +236,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)));
@ -226,7 +265,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)));
@ -455,9 +494,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"));
@ -488,7 +528,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);
@ -511,7 +551,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);
@ -537,7 +577,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;
@ -563,7 +603,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;
@ -589,7 +629,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;
@ -640,7 +680,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);
@ -750,7 +790,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;
@ -822,7 +862,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");
@ -837,7 +877,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()) {
@ -876,7 +916,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);
@ -939,7 +979,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) {
@ -969,7 +1009,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");
@ -988,7 +1028,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") {
@ -1008,7 +1048,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") {
@ -1061,7 +1101,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);
@ -1179,7 +1219,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())));
@ -1197,7 +1237,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) {
@ -1237,7 +1277,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())));
@ -1254,7 +1294,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);
@ -1272,7 +1312,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);
@ -1342,7 +1382,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);
@ -1354,7 +1394,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);
@ -1493,7 +1533,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);
@ -1599,8 +1639,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 {
@ -1610,7 +1656,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,14 +181,14 @@ 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);
}
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);
@ -326,7 +326,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

852
passes/opt/pmux2shiftx.cc Normal file
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

@ -462,12 +462,10 @@ struct WreduceWorker
SigSpec initsig = init_attr_sigmap(w);
int width = std::min(GetSize(initval), GetSize(initsig));
for (int i = 0; i < width; i++) {
log_dump(initsig[i], remove_init_bits.count(initsig[i]));
if (!remove_init_bits.count(initsig[i]))
new_initval[i] = initval[i];
}
w->attributes.at("\\init") = new_initval;
log_dump(w->name, initval, new_initval);
}
}
}

View File

@ -220,5 +220,5 @@ But in some cases it is more natural to utilize the implicit branch statement:
portAB = \B;
endcode
There is an implicit `code..endcode` block at the end of each `.pgm` file
There is an implicit `code..endcode` block at the end of each `.pmg` file
that just accepts everything that gets all the way there.

View File

@ -108,6 +108,7 @@ struct SigSnippets
struct SnippetSwCache
{
dict<RTLIL::SwitchRule*, pool<RTLIL::SigBit>, hash_ptr_ops> full_case_bits_cache;
dict<RTLIL::SwitchRule*, pool<int>, hash_ptr_ops> cache;
const SigSnippets *snippets;
int current_snippet;
@ -268,6 +269,49 @@ void append_pmux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::ve
last_mux_cell->parameters["\\S_WIDTH"] = last_mux_cell->getPort("\\S").size();
}
const pool<SigBit> &get_full_case_bits(SnippetSwCache &swcache, RTLIL::SwitchRule *sw)
{
if (!swcache.full_case_bits_cache.count(sw))
{
pool<SigBit> bits;
if (sw->get_bool_attribute("\\full_case"))
{
bool first_case = true;
for (auto cs : sw->cases)
{
pool<SigBit> case_bits;
for (auto it : cs->actions) {
for (auto bit : it.first)
case_bits.insert(bit);
}
for (auto it : cs->switches) {
for (auto bit : get_full_case_bits(swcache, it))
case_bits.insert(bit);
}
if (first_case) {
first_case = false;
bits = case_bits;
} else {
pool<SigBit> new_bits;
for (auto bit : bits)
if (case_bits.count(bit))
new_bits.insert(bit);
bits.swap(new_bits);
}
}
}
bits.swap(swcache.full_case_bits_cache[sw]);
}
return swcache.full_case_bits_cache.at(sw);
}
RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, dict<RTLIL::SwitchRule*, bool, hash_ptr_ops> &swpara,
RTLIL::CaseRule *cs, const RTLIL::SigSpec &sig, const RTLIL::SigSpec &defval, bool ifxmode)
{
@ -337,10 +381,15 @@ RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, d
}
}
// mask default bits that are irrelevant because the output is driven by a full case
const pool<SigBit> &full_case_bits = get_full_case_bits(swcache, sw);
for (int i = 0; i < GetSize(sig); i++)
if (full_case_bits.count(sig[i]))
result[i] = State::Sx;
// evaluate in reverse order to give the first entry the top priority
RTLIL::SigSpec initial_val = result;
RTLIL::Cell *last_mux_cell = NULL;
bool shiftx = initial_val.is_fully_undef();
for (size_t i = 0; i < sw->cases.size(); i++) {
int case_idx = sw->cases.size() - i - 1;
RTLIL::CaseRule *cs2 = sw->cases[case_idx];
@ -349,33 +398,6 @@ RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, d
append_pmux(mod, sw->signal, cs2->compare, value, last_mux_cell, sw, ifxmode);
else
result = gen_mux(mod, sw->signal, cs2->compare, value, result, last_mux_cell, sw, ifxmode);
// Ignore output values which are entirely don't care
if (shiftx && !value.is_fully_undef()) {
// Keep checking if case condition is the same as the current case index
if (cs2->compare.size() == 1 && cs2->compare.front().is_fully_const())
shiftx = (cs2->compare.front().as_int() == case_idx);
else
shiftx = false;
}
}
// Transform into a $shiftx where possible
if (shiftx && last_mux_cell && last_mux_cell->type == "$pmux") {
// Create bit-blasted $shiftx-es that shifts by the address line used in the case statement
auto pmux_b_port = last_mux_cell->getPort("\\B");
auto pmux_y_port = last_mux_cell->getPort("\\Y");
int width = last_mux_cell->getParam("\\WIDTH").as_int();
for (int i = 0; i < width; ++i) {
RTLIL::SigSpec a_port;
// Because we went in reverse order above, un-reverse $pmux's B port here
for (int j = pmux_b_port.size()/width-1; j >= 0; --j)
a_port.append(pmux_b_port.extract(j*width+i, 1));
// Create a $shiftx that shifts by the address line used in the case statement
mod->addShiftx(NEW_ID, a_port, sw->signal, pmux_y_port.extract(i, 1));
}
// Disconnect $pmux by replacing its output port with a floating wire
last_mux_cell->setPort("\\Y", mod->addWire(NEW_ID, width));
}
}

View File

@ -28,7 +28,7 @@
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
void proc_rmdead(RTLIL::SwitchRule *sw, int &counter)
void proc_rmdead(RTLIL::SwitchRule *sw, int &counter, int &full_case_counter)
{
BitPatternPool pool(sw->signal);
@ -56,11 +56,16 @@ void proc_rmdead(RTLIL::SwitchRule *sw, int &counter)
}
for (auto switch_it : sw->cases[i]->switches)
proc_rmdead(switch_it, counter);
proc_rmdead(switch_it, counter, full_case_counter);
if (is_default)
pool.take_all();
}
if (pool.empty() && !sw->get_bool_attribute("\\full_case")) {
sw->set_bool_attribute("\\full_case");
full_case_counter++;
}
}
struct ProcRmdeadPass : public Pass {
@ -87,12 +92,15 @@ struct ProcRmdeadPass : public Pass {
for (auto &proc_it : mod->processes) {
if (!design->selected(mod, proc_it.second))
continue;
int counter = 0;
int counter = 0, full_case_counter = 0;
for (auto switch_it : proc_it.second->root_case.switches)
proc_rmdead(switch_it, counter);
proc_rmdead(switch_it, counter, full_case_counter);
if (counter > 0)
log("Removed %d dead cases from process %s in module %s.\n", counter,
proc_it.first.c_str(), log_id(mod));
log_id(proc_it.first), log_id(mod));
if (full_case_counter > 0)
log("Marked %d switch rules as full_case in process %s in module %s.\n",
full_case_counter, log_id(proc_it.first), log_id(mod));
total_counter += counter;
}
}

View File

@ -254,7 +254,7 @@ void create_miter_equiv(struct Pass *that, std::vector<std::string> args, RTLIL:
if (flag_flatten) {
log_push();
Pass::call_on_module(design, miter_module, "flatten; opt_expr -keepdc -undriven;;");
Pass::call_on_module(design, miter_module, "flatten -wb; opt_expr -keepdc -undriven;;");
log_pop();
}
}
@ -308,7 +308,7 @@ void create_miter_assert(struct Pass *that, std::vector<std::string> args, RTLIL
if (flag_flatten) {
log_push();
Pass::call_on_module(design, module, "flatten;;");
Pass::call_on_module(design, module, "flatten -wb;;");
log_pop();
}
@ -385,7 +385,7 @@ struct MiterPass : public Pass {
log(" also create an 'assert' cell that checks if trigger is always low.\n");
log("\n");
log(" -flatten\n");
log(" call 'flatten; opt_expr -keepdc -undriven;;' on the miter circuit.\n");
log(" call 'flatten -wb; opt_expr -keepdc -undriven;;' on the miter circuit.\n");
log("\n");
log("\n");
log(" miter -assert [options] module [miter_name]\n");
@ -399,7 +399,7 @@ struct MiterPass : public Pass {
log(" keep module output ports.\n");
log("\n");
log(" -flatten\n");
log(" call 'flatten; opt_expr -keepdc -undriven;;' on the miter circuit.\n");
log(" call 'flatten -wb; opt_expr -keepdc -undriven;;' on the miter circuit.\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE

View File

@ -29,17 +29,17 @@
// Kahn, Arthur B. (1962), "Topological sorting of large networks", Communications of the ACM 5 (11): 558-562, doi:10.1145/368996.369025
// http://en.wikipedia.org/wiki/Topological_sorting
#define ABC_COMMAND_LIB "strash; ifraig; scorr; dc2; dretime; strash; &get -n; &dch -f; &nf {D}; &put"
#define ABC_COMMAND_CTR "strash; ifraig; scorr; dc2; dretime; strash; &get -n; &dch -f; &nf {D}; &put; buffer; upsize {D}; dnsize {D}; stime -p"
#define ABC_COMMAND_LUT "strash; ifraig; scorr; dc2; dretime; strash; dch -f; if; mfs2"
#define ABC_COMMAND_SOP "strash; ifraig; scorr; dc2; dretime; strash; dch -f; cover {I} {P}"
#define ABC_COMMAND_DFL "strash; ifraig; scorr; dc2; dretime; strash; &get -n; &dch -f; &nf {D}; &put"
#define ABC_COMMAND_LIB "strash; ifraig; scorr; dc2; dretime; retime {D}; strash; &get -n; &dch -f; &nf {D}; &put"
#define ABC_COMMAND_CTR "strash; ifraig; scorr; dc2; dretime; retime {D}; strash; &get -n; &dch -f; &nf {D}; &put; buffer; upsize {D}; dnsize {D}; stime -p"
#define ABC_COMMAND_LUT "strash; ifraig; scorr; dc2; dretime; retime {D}; strash; dch -f; if; mfs2"
#define ABC_COMMAND_SOP "strash; ifraig; scorr; dc2; dretime; retime {D}; strash; dch -f; cover {I} {P}"
#define ABC_COMMAND_DFL "strash; ifraig; scorr; dc2; dretime; retime {D}; strash; &get -n; &dch -f; &nf {D}; &put"
#define ABC_FAST_COMMAND_LIB "strash; dretime; map {D}"
#define ABC_FAST_COMMAND_CTR "strash; dretime; map {D}; buffer; upsize {D}; dnsize {D}; stime -p"
#define ABC_FAST_COMMAND_LUT "strash; dretime; if"
#define ABC_FAST_COMMAND_SOP "strash; dretime; cover -I {I} -P {P}"
#define ABC_FAST_COMMAND_DFL "strash; dretime; map"
#define ABC_FAST_COMMAND_LIB "strash; dretime; retime {D}; map {D}"
#define ABC_FAST_COMMAND_CTR "strash; dretime; retime {D}; map {D}; buffer; upsize {D}; dnsize {D}; stime -p"
#define ABC_FAST_COMMAND_LUT "strash; dretime; retime {D}; if"
#define ABC_FAST_COMMAND_SOP "strash; dretime; retime {D}; cover -I {I} -P {P}"
#define ABC_FAST_COMMAND_DFL "strash; dretime; retime {D}; map"
#include "kernel/register.h"
#include "kernel/sigtools.h"
@ -331,19 +331,23 @@ std::string remap_name(RTLIL::IdString abc_name, RTLIL::Wire **orig_wire = nullp
{
std::string abc_sname = abc_name.substr(1);
if (abc_sname.substr(0, 5) == "ys__n") {
int sid = std::stoi(abc_sname.substr(5));
bool inv = abc_sname.back() == 'v';
for (auto sig : signal_list) {
if (sig.id == sid && sig.bit.wire != nullptr) {
std::stringstream sstr;
sstr << "$abc$" << map_autoidx << "$" << sig.bit.wire->name.substr(1);
if (sig.bit.wire->width != 1)
sstr << "[" << sig.bit.offset << "]";
if (inv)
sstr << "_inv";
if (orig_wire != nullptr)
*orig_wire = sig.bit.wire;
return sstr.str();
if (inv) abc_sname.pop_back();
abc_sname.erase(0, 5);
if (abc_sname.find_last_not_of("012345689") == std::string::npos) {
int sid = std::stoi(abc_sname);
for (auto sig : signal_list) {
if (sig.id == sid && sig.bit.wire != nullptr) {
std::stringstream sstr;
sstr << "$abc$" << map_autoidx << "$" << sig.bit.wire->name.substr(1);
if (sig.bit.wire->width != 1)
sstr << "[" << sig.bit.offset << "]";
if (inv)
sstr << "_inv";
if (orig_wire != nullptr)
*orig_wire = sig.bit.wire;
return sstr.str();
}
}
}
}
@ -731,10 +735,6 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
else
abc_script += fast_mode ? ABC_FAST_COMMAND_DFL : ABC_COMMAND_DFL;
if (script_file.empty() && !delay_target.empty())
for (size_t pos = abc_script.find("dretime;"); pos != std::string::npos; pos = abc_script.find("dretime;", pos+1))
abc_script = abc_script.substr(0, pos) + "dretime; retime -o {D};" + abc_script.substr(pos+8);
for (size_t pos = abc_script.find("{D}"); pos != std::string::npos; pos = abc_script.find("{D}", pos))
abc_script = abc_script.substr(0, pos) + delay_target + abc_script.substr(pos+3);
@ -1726,7 +1726,7 @@ struct AbcPass : public Pass {
signal_init[initsig[i]] = State::S0;
break;
case State::S1:
signal_init[initsig[i]] = State::S0;
signal_init[initsig[i]] = State::S1;
break;
default:
break;

View File

@ -111,9 +111,10 @@ struct AttrmapMap : AttrmapAction {
};
struct AttrmapRemove : AttrmapAction {
bool has_value;
string name, value;
bool apply(IdString &id, Const &val) YS_OVERRIDE {
return !(match_name(name, id) && match_value(value, val));
return !(match_name(name, id) && (!has_value || match_value(value, val)));
}
};
@ -235,6 +236,7 @@ struct AttrmapPass : public Pass {
}
auto action = new AttrmapRemove;
action->name = arg1;
action->has_value = (p != string::npos);
action->value = val1;
actions.push_back(std::unique_ptr<AttrmapAction>(action));
continue;

View File

@ -664,7 +664,7 @@ struct DfflibmapPass : public Pass {
logmap_all();
for (auto &it : design->modules_)
if (design->selected(it.second) && !it.second->get_bool_attribute("\\blackbox"))
if (design->selected(it.second) && !it.second->get_blackbox_attribute())
dfflibmap(design, it.second, prepare_mode);
cell_mappings.clear();

View File

@ -71,9 +71,9 @@ struct PmuxtreePass : public Pass {
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" pmuxtree [options] [selection]\n");
log(" pmuxtree [selection]\n");
log("\n");
log("This pass transforms $pmux cells to a trees of $mux cells.\n");
log("This pass transforms $pmux cells to trees of $mux cells.\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE

View File

@ -26,7 +26,9 @@ PRIVATE_NAMESPACE_BEGIN
struct ShregmapTech
{
virtual ~ShregmapTech() { }
virtual bool analyze(vector<int> &taps) = 0;
virtual void init(const Module * /*module*/, const SigMap &/*sigmap*/) {}
virtual void non_chain_user(const SigBit &/*bit*/, const Cell* /*cell*/, IdString /*port*/) {}
virtual bool analyze(vector<int> &taps, const vector<SigBit> &qbits) = 0;
virtual bool fixup(Cell *cell, dict<int, SigBit> &taps) = 0;
};
@ -54,7 +56,7 @@ struct ShregmapOptions
struct ShregmapTechGreenpak4 : ShregmapTech
{
bool analyze(vector<int> &taps)
bool analyze(vector<int> &taps, const vector<SigBit> &/*qbits*/)
{
if (GetSize(taps) > 2 && taps[0] == 0 && taps[2] < 17) {
taps.clear();
@ -91,6 +93,145 @@ struct ShregmapTechGreenpak4 : ShregmapTech
}
};
struct ShregmapTechXilinx7 : ShregmapTech
{
dict<SigBit, std::tuple<Cell*,int,int>> sigbit_to_shiftx_offset;
const ShregmapOptions &opts;
ShregmapTechXilinx7(const ShregmapOptions &opts) : opts(opts) {}
virtual void init(const Module* module, const SigMap &sigmap) override
{
for (const auto &i : module->cells_) {
auto cell = i.second;
if (cell->type == "$shiftx") {
if (cell->getParam("\\Y_WIDTH") != 1) continue;
int j = 0;
for (auto bit : sigmap(cell->getPort("\\A")))
sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, j++, 0);
log_assert(j == cell->getParam("\\A_WIDTH").as_int());
}
else if (cell->type == "$mux") {
int j = 0;
for (auto bit : sigmap(cell->getPort("\\A")))
sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, 0, j++);
j = 0;
for (auto bit : sigmap(cell->getPort("\\B")))
sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, 1, j++);
}
}
}
virtual void non_chain_user(const SigBit &bit, const Cell *cell, IdString port) override
{
auto it = sigbit_to_shiftx_offset.find(bit);
if (it == sigbit_to_shiftx_offset.end())
return;
if (cell) {
if (cell->type == "$shiftx" && port == "\\A")
return;
if (cell->type == "$mux" && (port == "\\A" || port == "\\B"))
return;
}
sigbit_to_shiftx_offset.erase(it);
}
virtual bool analyze(vector<int> &taps, const vector<SigBit> &qbits) override
{
if (GetSize(taps) == 1)
return taps[0] >= opts.minlen-1 && sigbit_to_shiftx_offset.count(qbits[0]);
if (taps.back() < opts.minlen-1)
return false;
Cell *shiftx = nullptr;
int group = 0;
for (int i = 0; i < GetSize(taps); ++i) {
auto it = sigbit_to_shiftx_offset.find(qbits[i]);
if (it == sigbit_to_shiftx_offset.end())
return false;
// Check taps are sequential
if (i != taps[i])
return false;
// Check taps are not connected to a shift register,
// or sequential to the same shift register
if (i == 0) {
int offset;
std::tie(shiftx,offset,group) = it->second;
if (offset != i)
return false;
}
else {
Cell *shiftx_ = std::get<0>(it->second);
if (shiftx_ != shiftx)
return false;
int offset = std::get<1>(it->second);
if (offset != i)
return false;
int group_ = std::get<2>(it->second);
if (group_ != group)
return false;
}
}
log_assert(shiftx);
// Only map if $shiftx exclusively covers the shift register
if (shiftx->type == "$shiftx") {
if (GetSize(taps) != shiftx->getParam("\\A_WIDTH").as_int())
return false;
}
else if (shiftx->type == "$mux") {
if (GetSize(taps) != 2)
return false;
}
else log_abort();
return true;
}
virtual bool fixup(Cell *cell, dict<int, SigBit> &taps) override
{
const auto &tap = *taps.begin();
auto bit = tap.second;
auto it = sigbit_to_shiftx_offset.find(bit);
log_assert(it != sigbit_to_shiftx_offset.end());
auto newcell = cell->module->addCell(NEW_ID, "$__XILINX_SHREG_");
newcell->set_src_attribute(cell->get_src_attribute());
newcell->setParam("\\DEPTH", cell->getParam("\\DEPTH"));
newcell->setParam("\\INIT", cell->getParam("\\INIT"));
newcell->setParam("\\CLKPOL", cell->getParam("\\CLKPOL"));
newcell->setParam("\\ENPOL", cell->getParam("\\ENPOL"));
newcell->setPort("\\C", cell->getPort("\\C"));
newcell->setPort("\\D", cell->getPort("\\D"));
if (cell->hasPort("\\E"))
newcell->setPort("\\E", cell->getPort("\\E"));
Cell* shiftx = std::get<0>(it->second);
RTLIL::SigSpec l_wire, q_wire;
if (shiftx->type == "$shiftx") {
l_wire = shiftx->getPort("\\B");
q_wire = shiftx->getPort("\\Y");
shiftx->setPort("\\Y", cell->module->addWire(NEW_ID));
}
else if (shiftx->type == "$mux") {
l_wire = shiftx->getPort("\\S");
q_wire = shiftx->getPort("\\Y");
shiftx->setPort("\\Y", cell->module->addWire(NEW_ID));
}
else log_abort();
newcell->setPort("\\Q", q_wire);
newcell->setPort("\\L", l_wire);
return false;
}
};
struct ShregmapWorker
{
Module *module;
@ -113,8 +254,10 @@ struct ShregmapWorker
for (auto wire : module->wires())
{
if (wire->port_output || wire->get_bool_attribute("\\keep")) {
for (auto bit : sigmap(wire))
for (auto bit : sigmap(wire)) {
sigbit_with_non_chain_users.insert(bit);
if (opts.tech) opts.tech->non_chain_user(bit, nullptr, {});
}
}
if (wire->attributes.count("\\init")) {
@ -152,8 +295,10 @@ struct ShregmapWorker
for (auto conn : cell->connections())
if (cell->input(conn.first))
for (auto bit : sigmap(conn.second))
for (auto bit : sigmap(conn.second)) {
sigbit_with_non_chain_users.insert(bit);
if (opts.tech) opts.tech->non_chain_user(bit, cell, conn.first);
}
}
}
@ -258,7 +403,7 @@ struct ShregmapWorker
if (taps.empty() || taps.back() < depth-1)
taps.push_back(depth-1);
if (opts.tech->analyze(taps))
if (opts.tech->analyze(taps, qbits))
break;
taps.pop_back();
@ -377,6 +522,9 @@ struct ShregmapWorker
ShregmapWorker(Module *module, const ShregmapOptions &opts) :
module(module), sigmap(module), opts(opts), dff_count(0), shreg_count(0)
{
if (opts.tech)
opts.tech->init(module, sigmap);
make_sigbit_chain_next_prev();
find_chain_start_cells();
@ -501,6 +649,12 @@ struct ShregmapPass : public Pass {
clkpol = "pos";
opts.zinit = true;
opts.tech = new ShregmapTechGreenpak4;
}
else if (tech == "xilinx") {
opts.init = true;
opts.params = true;
enpol = "any_or_none";
opts.tech = new ShregmapTechXilinx7(opts);
} else {
argidx--;
break;

View File

@ -599,7 +599,7 @@ struct SimplemapPass : public Pass {
simplemap_get_mappers(mappers);
for (auto mod : design->modules()) {
if (!design->selected(mod))
if (!design->selected(mod) || mod->get_blackbox_attribute())
continue;
std::vector<RTLIL::Cell*> cells = mod->cells();
for (auto cell : cells) {

View File

@ -72,6 +72,8 @@ struct TechmapWorker
pool<IdString> flatten_done_list;
pool<Cell*> flatten_keep_list;
pool<string> log_msg_cache;
struct TechmapWireData {
RTLIL::Wire *wire;
RTLIL::SigSpec value;
@ -84,6 +86,7 @@ struct TechmapWorker
bool flatten_mode;
bool recursive_mode;
bool autoproc_mode;
bool ignore_wb;
TechmapWorker()
{
@ -92,6 +95,7 @@ struct TechmapWorker
flatten_mode = false;
recursive_mode = false;
autoproc_mode = false;
ignore_wb = false;
}
std::string constmap_tpl_name(SigMap &sigmap, RTLIL::Module *tpl, RTLIL::Cell *cell, bool verbose)
@ -383,11 +387,12 @@ struct TechmapWorker
{
std::string mapmsg_prefix = in_recursion ? "Recursively mapping" : "Mapping";
if (!design->selected(module))
if (!design->selected(module) || module->get_blackbox_attribute(ignore_wb))
return false;
bool log_continue = false;
bool did_something = false;
LogMakeDebugHdl mkdebug;
SigMap sigmap(module);
@ -472,7 +477,7 @@ struct TechmapWorker
RTLIL::Module *tpl = map->modules_[tpl_name];
std::map<RTLIL::IdString, RTLIL::Const> parameters(cell->parameters.begin(), cell->parameters.end());
if (tpl->get_bool_attribute("\\blackbox"))
if (tpl->get_blackbox_attribute(ignore_wb))
continue;
if (!flatten_mode)
@ -545,6 +550,7 @@ struct TechmapWorker
if (extmapper_name == "wrap") {
std::string cmd_string = tpl->attributes.at("\\techmap_wrap").decode_string();
log("Running \"%s\" on wrapper %s.\n", cmd_string.c_str(), log_id(extmapper_module));
mkdebug.on();
Pass::call_on_module(extmapper_design, extmapper_module, cmd_string);
log_continue = true;
}
@ -558,11 +564,21 @@ struct TechmapWorker
goto use_wrapper_tpl;
}
log("%s %s.%s (%s) to %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(cell->type), log_id(extmapper_module));
auto msg = stringf("Using extmapper %s for cells of type %s.", log_id(extmapper_module), log_id(cell->type));
if (!log_msg_cache.count(msg)) {
log_msg_cache.insert(msg);
log("%s\n", msg.c_str());
}
log_debug("%s %s.%s (%s) to %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(cell->type), log_id(extmapper_module));
}
else
{
log("%s %s.%s (%s) with %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(cell->type), extmapper_name.c_str());
auto msg = stringf("Using extmapper %s for cells of type %s.", extmapper_name.c_str(), log_id(cell->type));
if (!log_msg_cache.count(msg)) {
log_msg_cache.insert(msg);
log("%s\n", msg.c_str());
}
log_debug("%s %s.%s (%s) with %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(cell->type), extmapper_name.c_str());
if (extmapper_name == "simplemap") {
if (simplemap_mappers.count(cell->type) == 0)
@ -660,6 +676,7 @@ struct TechmapWorker
tpl = techmap_cache[key];
} else {
if (parameters.size() != 0) {
mkdebug.on();
derived_name = tpl->derive(map, dict<RTLIL::IdString, RTLIL::Const>(parameters.begin(), parameters.end()));
tpl = map->module(derived_name);
log_continue = true;
@ -829,6 +846,7 @@ struct TechmapWorker
if (log_continue) {
log_header(design, "Continuing TECHMAP pass.\n");
log_continue = false;
mkdebug.off();
}
while (techmap_module(map, tpl, map, handled_cells, celltypeMap, true)) { }
}
@ -840,6 +858,7 @@ struct TechmapWorker
if (log_continue) {
log_header(design, "Continuing TECHMAP pass.\n");
log_continue = false;
mkdebug.off();
}
if (extern_mode && !in_recursion)
@ -859,13 +878,18 @@ struct TechmapWorker
module_queue.insert(m);
}
log("%s %s.%s to imported %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(m_name));
log_debug("%s %s.%s to imported %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(m_name));
cell->type = m_name;
cell->parameters.clear();
}
else
{
log("%s %s.%s using %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(tpl));
auto msg = stringf("Using template %s for cells of type %s.", log_id(tpl), log_id(cell->type));
if (!log_msg_cache.count(msg)) {
log_msg_cache.insert(msg);
log("%s\n", msg.c_str());
}
log_debug("%s %s.%s (%s) using %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(cell->type), log_id(tpl));
techmap_module_worker(design, module, cell, tpl);
cell = NULL;
}
@ -883,6 +907,7 @@ struct TechmapWorker
if (log_continue) {
log_header(design, "Continuing TECHMAP pass.\n");
log_continue = false;
mkdebug.off();
}
return did_something;
@ -925,6 +950,9 @@ struct TechmapPass : public Pass {
log(" -autoproc\n");
log(" Automatically call \"proc\" on implementations that contain processes.\n");
log("\n");
log(" -wb\n");
log(" Ignore the 'whitebox' attribute on cell implementations.\n");
log("\n");
log(" -assert\n");
log(" this option will cause techmap to exit with an error if it can't map\n");
log(" a selected cell. only cell types that end on an underscore are accepted\n");
@ -1031,7 +1059,7 @@ struct TechmapPass : public Pass {
simplemap_get_mappers(worker.simplemap_mappers);
std::vector<std::string> map_files;
std::string verilog_frontend = "verilog -nooverwrite";
std::string verilog_frontend = "verilog -nooverwrite -noblackbox";
int max_iter = -1;
size_t argidx;
@ -1068,6 +1096,10 @@ struct TechmapPass : public Pass {
worker.autoproc_mode = true;
continue;
}
if (args[argidx] == "-wb") {
worker.ignore_wb = true;
continue;
}
break;
}
extra_args(args, argidx, design);
@ -1076,7 +1108,7 @@ struct TechmapPass : public Pass {
if (map_files.empty()) {
std::istringstream f(stdcells_code);
Frontend::frontend_call(map, &f, "<techmap.v>", verilog_frontend);
} else
} else {
for (auto &fn : map_files)
if (fn.substr(0, 1) == "%") {
if (!saved_designs.count(fn.substr(1))) {
@ -1095,6 +1127,9 @@ struct TechmapPass : public Pass {
log_cmd_error("Can't open map file `%s'\n", fn.c_str());
Frontend::frontend_call(map, &f, fn, (fn.size() > 3 && fn.substr(fn.size()-3) == ".il") ? "ilang" : verilog_frontend);
}
}
log_header(design, "Continuing TECHMAP pass.\n");
std::map<RTLIL::IdString, std::set<RTLIL::IdString, RTLIL::sort_by_id_str>> celltypeMap;
for (auto &it : map->modules_) {
@ -1145,7 +1180,7 @@ struct FlattenPass : public Pass {
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" flatten [selection]\n");
log(" flatten [options] [selection]\n");
log("\n");
log("This pass flattens the design by replacing cells by their implementation. This\n");
log("pass is very similar to the 'techmap' pass. The only difference is that this\n");
@ -1154,17 +1189,29 @@ struct FlattenPass : public Pass {
log("Cells and/or modules with the 'keep_hierarchy' attribute set will not be\n");
log("flattened by this command.\n");
log("\n");
log(" -wb\n");
log(" Ignore the 'whitebox' attribute on cell implementations.\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing FLATTEN pass (flatten design).\n");
log_push();
extra_args(args, 1, design);
TechmapWorker worker;
worker.flatten_mode = true;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++) {
if (args[argidx] == "-wb") {
worker.ignore_wb = true;
continue;
}
break;
}
extra_args(args, argidx, design);
std::map<RTLIL::IdString, std::set<RTLIL::IdString, RTLIL::sort_by_id_str>> celltypeMap;
for (auto module : design->modules())
celltypeMap[module->name].insert(module->name);
@ -1190,6 +1237,7 @@ struct FlattenPass : public Pass {
}
}
log_suppressed();
log("No more expansions possible.\n");
if (top_mod != NULL)
@ -1209,7 +1257,7 @@ struct FlattenPass : public Pass {
dict<RTLIL::IdString, RTLIL::Module*> new_modules;
for (auto mod : vector<Module*>(design->modules()))
if (used_modules[mod->name] || mod->get_bool_attribute("\\blackbox")) {
if (used_modules[mod->name] || mod->get_blackbox_attribute(worker.ignore_wb)) {
new_modules[mod->name] = mod;
} else {
log("Deleting now unused module %s.\n", log_id(mod));

View File

@ -253,7 +253,7 @@ struct SynthEcp5Pass : public ScriptPass
if (!nodffe)
run("dff2dffe -direct-match $_DFF_* -direct-match $__DFFS_*");
run("techmap -D NO_LUT -map +/ecp5/cells_map.v");
run("opt_expr -mux_undef");
run("opt_expr -undriven -mux_undef");
run("simplemap");
run("ecp5_ffinit");
}

View File

@ -1,7 +1,17 @@
OBJS += techlibs/gowin/synth_gowin.o
OBJS += techlibs/gowin/determine_init.o
$(eval $(call add_share_file,share/gowin,techlibs/gowin/cells_map.v))
$(eval $(call add_share_file,share/gowin,techlibs/gowin/cells_sim.v))
$(eval $(call add_share_file,share/gowin,techlibs/gowin/arith_map.v))
$(eval $(call add_share_file,share/gowin,techlibs/gowin/brams_map.v))
$(eval $(call add_share_file,share/gowin,techlibs/gowin/bram.txt))
$(eval $(call add_share_file,share/gowin,techlibs/gowin/drams_map.v))
$(eval $(call add_share_file,share/gowin,techlibs/gowin/dram.txt))
$(eval $(call add_share_file,share/gowin,techlibs/gowin/brams_init3.vh))

29
techlibs/gowin/bram.txt Normal file
View File

@ -0,0 +1,29 @@
bram $__GW1NR_SDP
# uncomment when done
# init 1
abits 10 @a10d18
dbits 16 @a10d18
abits 11 @a11d9
dbits 8 @a11d9
abits 12 @a12d4
dbits 4 @a12d4
abits 13 @a13d2
dbits 2 @a13d2
abits 14 @a14d1
dbits 1 @a14d1
groups 2
ports 1 1
wrmode 1 0
enable 1 1 @a10d18
enable 1 1 @a11d9 @a12d4 @a13d2 @a14d1
transp 0 0
clocks 2 3
clkpol 2 3
endbram
match $__GW1NR_SDP
min bits 2048
min efficiency 5
shuffle_enable B
make_transp
endmatch

View File

@ -0,0 +1,12 @@
localparam [15:0] INIT_0 = {
INIT[ 60], INIT[ 56], INIT[ 52], INIT[ 48], INIT[ 44], INIT[ 40], INIT[ 36], INIT[ 32], INIT[ 28], INIT[ 24], INIT[ 20], INIT[ 16], INIT[ 12], INIT[ 8], INIT[ 4], INIT[ 0]
};
localparam [15:0] INIT_1 = {
INIT[ 61], INIT[ 57], INIT[ 53], INIT[ 49], INIT[ 45], INIT[ 41], INIT[ 37], INIT[ 33], INIT[ 29], INIT[ 25], INIT[ 21], INIT[ 17], INIT[ 13], INIT[ 9], INIT[ 5], INIT[ 1]
};
localparam [15:0] INIT_2 = {
INIT[ 62], INIT[ 58], INIT[ 54], INIT[ 50], INIT[ 46], INIT[ 42], INIT[ 38], INIT[ 34], INIT[ 30], INIT[ 26], INIT[ 22], INIT[ 18], INIT[ 14], INIT[ 10], INIT[ 6], INIT[ 2]
};
localparam [15:0] INIT_3 = {
INIT[ 63], INIT[ 59], INIT[ 55], INIT[ 51], INIT[ 47], INIT[ 43], INIT[ 39], INIT[ 35], INIT[ 31], INIT[ 27], INIT[ 23], INIT[ 19], INIT[ 15], INIT[ 11], INIT[ 7], INIT[ 3]
};

103
techlibs/gowin/brams_map.v Normal file
View File

@ -0,0 +1,103 @@
/* Semi Dual Port (SDP) memory have the following configurations:
* Memory Config RAM(BIT) Port Mode Memory Depth Data Depth
* ----------------|---------| ----------|--------------|------------|
* B-SRAM_16K_SD1 16K 16Kx1 16,384 1
* B-SRAM_8K_SD2 16K 8Kx2 8,192 2
* B-SRAM_4K_SD4 16K 4Kx2 4,096 4
*/
module \$__GW1NR_SDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
parameter CFG_ABITS = 10;
parameter CFG_DBITS = 16;
parameter CFG_ENABLE_A = 3;
parameter [16383:0] INIT = 16384'hx;
parameter CLKPOL2 = 1;
parameter CLKPOL3 = 1;
input CLK2;
input CLK3;
input [CFG_ABITS-1:0] A1ADDR;
input [CFG_DBITS-1:0] A1DATA;
input [CFG_ENABLE_A-1:0] A1EN;
input [CFG_ABITS-1:0] B1ADDR;
output [CFG_DBITS-1:0] B1DATA;
input B1EN;
generate if (CFG_DBITS == 1) begin
SDP #(
.READ_MODE(0),
.BIT_WIDTH_0(1),
.BIT_WIDTH_1(1),
.BLK_SEL(3'b000),
.RESET_MODE("SYNC")
) _TECHMAP_REPLACE_ (
.CLKA(CLK2), .CLKB(CLK3),
.WREA(A1EN), .OCE(1'b0), .CEA(1'b1),
.WREB(1'b0), .CEB(B1EN),
.RESETA(1'b0), .RESETB(1'b0), .BLKSEL(3'b000),
.DI(A1DATA), .DO(B1DATA), .ADA(A1ADDR), .ADB(B1ADDR)
);
end else if (CFG_DBITS == 2) begin
SDP #(
.READ_MODE(0),
.BIT_WIDTH_0(2),
.BIT_WIDTH_1(2),
.BLK_SEL(3'b000),
.RESET_MODE("SYNC")
) _TECHMAP_REPLACE_ (
.CLKA(CLK2), .CLKB(CLK3),
.WREA(A1EN), .OCE(1'b0), .CEA(1'b1),
.WREB(1'b0), .CEB(B1EN),
.RESETA(1'b0), .RESETB(1'b0), .BLKSEL(3'b000),
.DI(A1DATA), .DO(B1DATA), .ADA(A1ADDR), .ADB(B1ADDR)
);
end else if (CFG_DBITS <= 4) begin
SDP #(
.READ_MODE(0),
.BIT_WIDTH_0(4),
.BIT_WIDTH_1(4),
.BLK_SEL(3'b000),
.RESET_MODE("SYNC")
) _TECHMAP_REPLACE_ (
.CLKA(CLK2), .CLKB(CLK3),
.WREA(A1EN), .OCE(1'b0),
.WREB(1'b0), .CEB(B1EN), .CEA(1'b1),
.RESETA(1'b0), .RESETB(1'b0), .BLKSEL(3'b000),
.DI(A1DATA), .DO(B1DATA), .ADA(A1ADDR), .ADB(B1ADDR)
);
end else if (CFG_DBITS <= 8) begin
SDP #(
.READ_MODE(0),
.BIT_WIDTH_0(8),
.BIT_WIDTH_1(8),
.BLK_SEL(3'b000),
.RESET_MODE("SYNC")
) _TECHMAP_REPLACE_ (
.CLKA(CLK2), .CLKB(CLK3),
.WREA(A1EN), .OCE(1'b0), .CEA(1'b1),
.WREB(1'b0), .CEB(B1EN),
.RESETA(1'b0), .RESETB(1'b0), .BLKSEL(3'b000),
.DI(A1DATA), .DO(B1DATA), .ADA(A1ADDR), .ADB(B1ADDR)
);
end else if (CFG_DBITS <= 16) begin
SDP #(
.READ_MODE(0),
.BIT_WIDTH_0(16),
.BIT_WIDTH_1(16),
.BLK_SEL(3'b000),
.RESET_MODE("SYNC")
) _TECHMAP_REPLACE_ (
.CLKA(CLK2), .CLKB(CLK3),
.WREA(A1EN), .OCE(1'b0),
.WREB(1'b0), .CEB(B1EN), .CEA(1'b1),
.RESETA(1'b0), .RESETB(1'b0), .BLKSEL(3'b000),
.DI(A1DATA), .DO(B1DATA), .ADA(A1ADDR), .ADB(B1ADDR)
);
end else begin
wire TECHMAP_FAIL = 1'b1;
end endgenerate
endmodule

View File

@ -1,5 +1,9 @@
module \$_DFF_N_ (input D, C, output Q); DFFN _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C)); endmodule
module \$_DFF_P_ (input D, C, output Q); DFF _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C)); endmodule
module \$_DFF_P_ #(parameter INIT = 1'b0) (input D, C, output Q); DFF #(.INIT(INIT)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C)); endmodule
module \$__DFFS_PN0_ (input D, C, R, output Q); DFFR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .RESET(!R)); endmodule
module \$__DFFS_PP0_ (input D, C, R, output Q); DFFR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .RESET(R)); endmodule
module \$__DFFS_PP1_ (input D, C, R, output Q); DFFR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .RESET(R)); endmodule
module \$lut (A, Y);
parameter WIDTH = 0;

View File

@ -38,6 +38,17 @@ module DFFN (output reg Q, input CLK, D);
Q <= D;
endmodule
module DFFR (output reg Q, input D, CLK, RESET);
parameter [0:0] INIT = 1'b0;
initial Q = INIT;
always @(posedge CLK) begin
if (RESET)
Q <= 1'b0;
else
Q <= D;
end
endmodule // DFFR (positive clock edge; synchronous reset)
module VCC(output V);
assign V = 1;
endmodule
@ -63,3 +74,126 @@ module ALU (input I0, input I1, input I3, input CIN, output COUT, output SUM);
assign {COUT, SUM} = CIN + I1 + I0;
endmodule // alu
module RAM16S4 (DO, DI, AD, WRE, CLK);
parameter WIDTH = 4;
parameter INIT_0 = 16'h0000;
parameter INIT_1 = 16'h0000;
parameter INIT_2 = 16'h0000;
parameter INIT_3 = 16'h0000;
input [WIDTH-1:0] AD;
input [WIDTH-1:0] DI;
output [WIDTH-1:0] DO;
input CLK;
input WRE;
reg [15:0] mem0, mem1, mem2, mem3;
initial begin
mem0 = INIT_0;
mem1 = INIT_1;
mem2 = INIT_2;
mem3 = INIT_3;
end
assign DO[0] = mem0[AD];
assign DO[1] = mem1[AD];
assign DO[2] = mem2[AD];
assign DO[3] = mem3[AD];
always @(posedge CLK) begin
if (WRE) begin
mem0[AD] <= DI[0];
mem1[AD] <= DI[1];
mem2[AD] <= DI[2];
mem3[AD] <= DI[3];
end
end
endmodule // RAM16S4
(* blackbox *)
module SDP (DO, DI, BLKSEL, ADA, ADB, WREA, WREB, CLKA, CLKB, CEA, CEB, OCE, RESETA, RESETB);
//1'b0: Bypass mode; 1'b1 Pipeline mode
parameter READ_MODE = 1'b0;
parameter BIT_WIDTH_0 = 32; // 1, 2, 4, 8, 16, 32
parameter BIT_WIDTH_1 = 32; // 1, 2, 4, 8, 16, 32
parameter BLK_SEL = 3'b000;
parameter RESET_MODE = "SYNC";
parameter INIT_RAM_00 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_01 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_02 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_03 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_04 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_05 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_06 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_07 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_08 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_09 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_0A = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_0B = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_0C = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_0D = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_0E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_0F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_10 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_11 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_12 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_13 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_14 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_15 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_16 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_17 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_18 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_19 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_1A = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_1B = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_1C = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_1D = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_1E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_1F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_20 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_21 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_22 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_23 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_24 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_25 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_26 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_27 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_28 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_29 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_2A = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_2B = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_2C = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_2D = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_2E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_2F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_30 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_31 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_32 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_33 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_34 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_35 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_36 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_37 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_38 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_39 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_3A = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_3B = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_3C = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_3D = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_3E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
parameter INIT_RAM_3F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
input CLKA, CEA, CLKB, CEB;
input OCE; // clock enable of memory output register
input RESETA, RESETB; // resets output registers, not memory contents
input WREA, WREB; // 1'b0: read enabled; 1'b1: write enabled
input [13:0] ADA, ADB;
input [31:0] DI;
input [2:0] BLKSEL;
output [31:0] DO;
endmodule

View File

@ -0,0 +1,72 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2018 Icenowy Zheng <icenowy@aosc.io>
*
* 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 DetermineInitPass : public Pass {
DetermineInitPass() : Pass("determine_init", "Determine the init value of cells") { }
void help() YS_OVERRIDE
{
log("\n");
log(" determine_init [selection]\n");
log("\n");
log("Determine the init value of cells that doesn't allow unknown init value.\n");
log("\n");
}
Const determine_init(Const init)
{
for (int i = 0; i < GetSize(init); i++) {
if (init[i] != State::S0 && init[i] != State::S1)
init[i] = State::S0;
}
return init;
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
log_header(design, "Executing DETERMINE_INIT pass (determine init value for cells).\n");
extra_args(args, args.size(), design);
size_t cnt = 0;
for (auto module : design->selected_modules())
{
for (auto cell : module->selected_cells())
{
if (cell->type == "\\RAM16S4")
{
cell->setParam("\\INIT_0", determine_init(cell->getParam("\\INIT_0")));
cell->setParam("\\INIT_1", determine_init(cell->getParam("\\INIT_1")));
cell->setParam("\\INIT_2", determine_init(cell->getParam("\\INIT_2")));
cell->setParam("\\INIT_3", determine_init(cell->getParam("\\INIT_3")));
cnt++;
}
}
}
log_header(design, "Updated %lu cells with determined init value.\n", cnt);
}
} DetermineInitPass;
PRIVATE_NAMESPACE_END

17
techlibs/gowin/dram.txt Normal file
View File

@ -0,0 +1,17 @@
bram $__GW1NR_RAM16S4
init 1
abits 4
dbits 4
groups 2
ports 1 1
wrmode 0 1
enable 0 1
transp 0 1
clocks 0 1
clkpol 0 1
endbram
match $__GW1NR_RAM16S4
make_outreg
min wports 1
endmatch

View File

@ -0,0 +1,31 @@
module \$__GW1NR_RAM16S4 (CLK1, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
parameter CFG_ABITS = 4;
parameter CFG_DBITS = 4;
parameter [63:0] INIT = 64'bx;
input CLK1;
input [CFG_ABITS-1:0] A1ADDR;
output [CFG_DBITS-1:0] A1DATA;
input A1EN;
input [CFG_ABITS-1:0] B1ADDR;
input [CFG_DBITS-1:0] B1DATA;
input B1EN;
`include "brams_init3.vh"
RAM16S4
#(.INIT_0(INIT_0),
.INIT_1(INIT_1),
.INIT_2(INIT_2),
.INIT_3(INIT_3))
_TECHMAP_REPLACE_
(.AD(B1ADDR),
.DI(B1DATA),
.DO(A1DATA),
.CLK(CLK1),
.WRE(B1EN));
endmodule

View File

@ -49,9 +49,15 @@ struct SynthGowinPass : public ScriptPass
log(" from label is synonymous to 'begin', and empty to label is\n");
log(" synonymous to the end of the command list.\n");
log("\n");
log(" -nodffe\n");
log(" do not use flipflops with CE in output netlist\n");
log("\n");
log(" -nobram\n");
log(" do not use BRAM cells in output netlist\n");
log("\n");
log(" -nodram\n");
log(" do not use distributed RAM cells in output netlist\n");
log("\n");
log(" -noflatten\n");
log(" do not flatten design before synthesis\n");
log("\n");
@ -65,7 +71,7 @@ struct SynthGowinPass : public ScriptPass
}
string top_opt, vout_file;
bool retime, flatten, nobram;
bool retime, nobram, nodram, flatten, nodffe;
void clear_flags() YS_OVERRIDE
{
@ -73,7 +79,9 @@ struct SynthGowinPass : public ScriptPass
vout_file = "";
retime = false;
flatten = true;
nobram = true;
nobram = false;
nodffe = false;
nodram = false;
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
@ -108,6 +116,14 @@ struct SynthGowinPass : public ScriptPass
nobram = true;
continue;
}
if (args[argidx] == "-nodram") {
nodram = true;
continue;
}
if (args[argidx] == "-nodffe") {
nodffe = true;
continue;
}
if (args[argidx] == "-noflatten") {
flatten = false;
continue;
@ -147,25 +163,43 @@ struct SynthGowinPass : public ScriptPass
{
run("synth -run coarse");
}
if (!nobram && check_label("bram", "(skip if -nobram)"))
if (!nobram && check_label("bram", "(skip if -nobram)"))
{
run("memory_bram -rules +/gowin/bram.txt");
run("techmap -map +/gowin/brams_map.v");
run("techmap -map +/gowin/brams_map.v -map +/gowin/cells_sim.v");
}
if (!nodram && check_label("dram", "(skip if -nodram)"))
{
run("memory_bram -rules +/gowin/dram.txt");
run("techmap -map +/gowin/drams_map.v");
run("determine_init");
}
if (check_label("fine"))
{
run("opt -fast -mux_undef -undriven -fine");
run("memory_map");
run("opt -undriven -fine");
run("techmap -map +/techmap.v -map +/gowin/arith_map.v");
run("opt -fine");
run("clean -purge");
run("splitnets -ports");
run("setundef -undriven -zero");
run("techmap -map +/techmap.v");
if (retime || help_mode)
run("abc -dff", "(only if -retime)");
}
if (check_label("map_ffs"))
{
run("dffsr2dff");
run("dff2dffs");
run("opt_clean");
if (!nodffe)
run("dff2dffe -direct-match $_DFF_* -direct-match $__DFFS_*");
run("techmap -map +/gowin/cells_map.v");
run("opt_expr -mux_undef");
run("simplemap");
}
if (check_label("map_luts"))
{
run("abc -lut 4");
@ -176,8 +210,10 @@ struct SynthGowinPass : public ScriptPass
{
run("techmap -map +/gowin/cells_map.v");
run("hilomap -hicell VCC V -locell GND G");
run("iopadmap -inpad IBUF O:I -outpad OBUF I:O");
run("clean -purge");
run("iopadmap -bits -inpad IBUF O:I -outpad OBUF I:O", "(unless -noiopads)");
run("dffinit -ff DFF Q INIT");
run("clean");
}
if (check_label("check"))

View File

@ -27,18 +27,27 @@ module SB_IO (
reg dout_q_0, dout_q_1;
reg outena_q;
// IO tile generates a constant 1'b1 internally if global_cen is not connected
wire clken_pulled = CLOCK_ENABLE || CLOCK_ENABLE === 1'bz;
reg clken_pulled_ri;
reg clken_pulled_ro;
generate if (!NEG_TRIGGER) begin
always @(posedge INPUT_CLK) if (CLOCK_ENABLE) din_q_0 <= PACKAGE_PIN;
always @(negedge INPUT_CLK) if (CLOCK_ENABLE) din_q_1 <= PACKAGE_PIN;
always @(posedge OUTPUT_CLK) if (CLOCK_ENABLE) dout_q_0 <= D_OUT_0;
always @(negedge OUTPUT_CLK) if (CLOCK_ENABLE) dout_q_1 <= D_OUT_1;
always @(posedge OUTPUT_CLK) if (CLOCK_ENABLE) outena_q <= OUTPUT_ENABLE;
always @(posedge INPUT_CLK) clken_pulled_ri <= clken_pulled;
always @(posedge INPUT_CLK) if (clken_pulled) din_q_0 <= PACKAGE_PIN;
always @(negedge INPUT_CLK) if (clken_pulled_ri) din_q_1 <= PACKAGE_PIN;
always @(posedge OUTPUT_CLK) clken_pulled_ro <= clken_pulled;
always @(posedge OUTPUT_CLK) if (clken_pulled) dout_q_0 <= D_OUT_0;
always @(negedge OUTPUT_CLK) if (clken_pulled_ro) dout_q_1 <= D_OUT_1;
always @(posedge OUTPUT_CLK) if (clken_pulled) outena_q <= OUTPUT_ENABLE;
end else begin
always @(negedge INPUT_CLK) if (CLOCK_ENABLE) din_q_0 <= PACKAGE_PIN;
always @(posedge INPUT_CLK) if (CLOCK_ENABLE) din_q_1 <= PACKAGE_PIN;
always @(negedge OUTPUT_CLK) if (CLOCK_ENABLE) dout_q_0 <= D_OUT_0;
always @(posedge OUTPUT_CLK) if (CLOCK_ENABLE) dout_q_1 <= D_OUT_1;
always @(negedge OUTPUT_CLK) if (CLOCK_ENABLE) outena_q <= OUTPUT_ENABLE;
always @(negedge INPUT_CLK) clken_pulled_ri <= clken_pulled;
always @(negedge INPUT_CLK) if (clken_pulled) din_q_0 <= PACKAGE_PIN;
always @(posedge INPUT_CLK) if (clken_pulled_ri) din_q_1 <= PACKAGE_PIN;
always @(negedge OUTPUT_CLK) clken_pulled_ro <= clken_pulled;
always @(negedge OUTPUT_CLK) if (clken_pulled) dout_q_0 <= D_OUT_0;
always @(posedge OUTPUT_CLK) if (clken_pulled_ro) dout_q_1 <= D_OUT_1;
always @(negedge OUTPUT_CLK) if (clken_pulled) outena_q <= OUTPUT_ENABLE;
end endgenerate
always @* begin

View File

@ -225,11 +225,13 @@ struct SynthIce40Pass : public ScriptPass
run("proc");
}
if (flatten && check_label("flatten", "(unless -noflatten)"))
if (check_label("flatten", "(unless -noflatten)"))
{
run("flatten");
run("tribuf -logic");
run("deminout");
if (flatten) {
run("flatten");
run("tribuf -logic");
run("deminout");
}
}
if (check_label("coarse"))

View File

@ -85,7 +85,7 @@ module cyclonev_lcell_comb
begin
upper_lut_value = lut4(mask[31:16], dataa, datab, datac, datad);
lower_lut_value = lut4(mask[15:0], dataa, datab, datac, datad);
lut5 = (datae) ? upper_mask_value : lower_mask_value;
lut5 = (datae) ? upper_lut_value : lower_lut_value;
end
endfunction // lut5
@ -95,15 +95,16 @@ module cyclonev_lcell_comb
input dataa, datab, datac, datad, datae, dataf;
reg upper_lut_value;
reg lower_lut_value;
reg out_0, out_1, out_2, out_3;
begin
upper_lut_value = lut5(mask[63:32], dataa, datab, datac, datad, datae);
lower_lut_value = lut5(mask[31:0], dataa, datab, datac, datad, datae);
lut6 = (dataf) ? upper_mask_value : lower_mask_value;
lut6 = (dataf) ? upper_lut_value : lower_lut_value;
end
endfunction // lut6
assign {mask_a, mask_b, mask_c, mask_d} = {lut_mask[15:0], lut_mask[31:16], lut_mask[47:32], lut_mask[63:48]};
`ifdef ADVANCED_ALM
always @(*) begin
if(extended_lut == "on")
shared_lut_alm = datag;
@ -115,6 +116,11 @@ module cyclonev_lcell_comb
out_2 = lut4(mask_c, dataa, datab, datac, datad);
out_3 = lut4(mask_d, dataa, datab, shared_lut_alm, datad);
end
`else
`ifdef DEBUG
initial $display("Advanced ALM lut combine is not implemented yet");
`endif
`endif
endmodule // cyclonev_lcell_comb

View File

@ -17,4 +17,130 @@
*
*/
// Empty for now
module \$__SHREG_ (input C, input D, input E, output Q);
parameter DEPTH = 0;
parameter [DEPTH-1:0] INIT = 0;
parameter CLKPOL = 1;
parameter ENPOL = 2;
\$__XILINX_SHREG_ #(.DEPTH(DEPTH), .INIT(INIT), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) _TECHMAP_REPLACE_ (.C(C), .D(D), .L(DEPTH-1), .E(E), .Q(Q));
endmodule
module \$__XILINX_SHREG_ (input C, input D, input [31:0] L, input E, output Q, output SO);
parameter DEPTH = 0;
parameter [DEPTH-1:0] INIT = 0;
parameter CLKPOL = 1;
parameter ENPOL = 2;
// shregmap's INIT parameter shifts out LSB first;
// however Xilinx expects MSB first
function [DEPTH-1:0] brev;
input [DEPTH-1:0] din;
integer i;
begin
for (i = 0; i < DEPTH; i=i+1)
brev[i] = din[DEPTH-1-i];
end
endfunction
localparam [DEPTH-1:0] INIT_R = brev(INIT);
parameter _TECHMAP_CONSTMSK_L_ = 0;
parameter _TECHMAP_CONSTVAL_L_ = 0;
wire CE;
generate
if (ENPOL == 0)
assign CE = ~E;
else if (ENPOL == 1)
assign CE = E;
else
assign CE = 1'b1;
if (DEPTH == 1) begin
if (CLKPOL)
FDRE #(.INIT(INIT_R)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(CE), .R(1'b0));
else
FDRE_1 #(.INIT(INIT_R)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(CE), .R(1'b0));
end else
if (DEPTH <= 16) begin
SRL16E #(.INIT(INIT_R), .IS_CLK_INVERTED(~CLKPOL[0])) _TECHMAP_REPLACE_ (.A0(L[0]), .A1(L[1]), .A2(L[2]), .A3(L[3]), .CE(CE), .CLK(C), .D(D), .Q(Q));
end else
if (DEPTH > 17 && DEPTH <= 32) begin
SRLC32E #(.INIT(INIT_R), .IS_CLK_INVERTED(~CLKPOL[0])) _TECHMAP_REPLACE_ (.A(L[4:0]), .CE(CE), .CLK(C), .D(D), .Q(Q));
end else
if (DEPTH > 33 && DEPTH <= 64) begin
wire T0, T1, T2;
SRLC32E #(.INIT(INIT_R[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(L[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1));
\$__XILINX_SHREG_ #(.DEPTH(DEPTH-32), .INIT(INIT[DEPTH-32-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T1), .L(L), .E(E), .Q(T2));
if (&_TECHMAP_CONSTMSK_L_)
assign Q = T2;
else
MUXF7 fpga_mux_0 (.O(Q), .I0(T0), .I1(T2), .S(L[5]));
end else
if (DEPTH > 65 && DEPTH <= 96) begin
wire T0, T1, T2, T3, T4, T5, T6;
SRLC32E #(.INIT(INIT_R[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(L[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1));
SRLC32E #(.INIT(INIT_R[64-1:32]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_1 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T1), .Q(T2), .Q31(T3));
\$__XILINX_SHREG_ #(.DEPTH(DEPTH-64), .INIT(INIT[DEPTH-64-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_2 (.C(C), .D(T3), .L(L[4:0]), .E(E), .Q(T4));
if (&_TECHMAP_CONSTMSK_L_)
assign Q = T4;
else begin
MUXF7 fpga_mux_0 (.O(T5), .I0(T0), .I1(T2), .S(L[5]));
MUXF7 fpga_mux_1 (.O(T6), .I0(T4), .I1(1'b0 /* unused */), .S(L[5]));
MUXF8 fpga_mux_2 (.O(Q), .I0(T5), .I1(T6), .S(L[6]));
end
end else
if (DEPTH > 97 && DEPTH < 128) begin
wire T0, T1, T2, T3, T4, T5, T6, T7, T8;
SRLC32E #(.INIT(INIT_R[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(L[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1));
SRLC32E #(.INIT(INIT_R[64-1:32]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_1 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T1), .Q(T2), .Q31(T3));
SRLC32E #(.INIT(INIT_R[96-1:64]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_2 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T3), .Q(T4), .Q31(T5));
\$__XILINX_SHREG_ #(.DEPTH(DEPTH-96), .INIT(INIT[DEPTH-96-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_3 (.C(C), .D(T5), .L(L[4:0]), .E(E), .Q(T6));
if (&_TECHMAP_CONSTMSK_L_)
assign Q = T6;
else begin
MUXF7 fpga_mux_0 (.O(T7), .I0(T0), .I1(T2), .S(L[5]));
MUXF7 fpga_mux_1 (.O(T8), .I0(T4), .I1(T6), .S(L[5]));
MUXF8 fpga_mux_2 (.O(Q), .I0(T7), .I1(T8), .S(L[6]));
end
end
else if (DEPTH == 128) begin
wire T0, T1, T2, T3, T4, T5, T6;
SRLC32E #(.INIT(INIT_R[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(L[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1));
SRLC32E #(.INIT(INIT_R[64-1:32]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_1 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T1), .Q(T2), .Q31(T3));
SRLC32E #(.INIT(INIT_R[96-1:64]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_2 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T3), .Q(T4), .Q31(T5));
SRLC32E #(.INIT(INIT_R[128-1:96]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_3 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T5), .Q(T6), .Q31(SO));
if (&_TECHMAP_CONSTMSK_L_)
assign Q = T6;
else begin
wire T7, T8;
MUXF7 fpga_mux_0 (.O(T7), .I0(T0), .I1(T2), .S(L[5]));
MUXF7 fpga_mux_1 (.O(T8), .I0(T4), .I1(T6), .S(L[5]));
MUXF8 fpga_mux_2 (.O(Q), .I0(T7), .I1(T8), .S(L[6]));
end
end
else if (DEPTH <= 129 && ~&_TECHMAP_CONSTMSK_L_) begin
// Handle cases where fixed-length depth is
// just 1 over a convenient value
\$__XILINX_SHREG_ #(.DEPTH(DEPTH+1), .INIT({INIT,1'b0}), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) _TECHMAP_REPLACE_ (.C(C), .D(D), .L(L), .E(E), .Q(Q));
end
else begin
localparam lower_clog2 = $clog2((DEPTH+1)/2);
localparam lower_depth = 2 ** lower_clog2;
wire T0, T1, T2, T3;
if (&_TECHMAP_CONSTMSK_L_) begin
\$__XILINX_SHREG_ #(.DEPTH(lower_depth), .INIT(INIT[DEPTH-1:DEPTH-lower_depth]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .L(lower_depth-1), .E(E), .Q(T0));
\$__XILINX_SHREG_ #(.DEPTH(DEPTH-lower_depth), .INIT(INIT[DEPTH-lower_depth-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T0), .L(DEPTH-lower_depth-1), .E(E), .Q(Q), .SO(T3));
end
else begin
\$__XILINX_SHREG_ #(.DEPTH(lower_depth), .INIT(INIT[DEPTH-1:DEPTH-lower_depth]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .L(L[lower_clog2-1:0]), .E(E), .Q(T0), .SO(T1));
\$__XILINX_SHREG_ #(.DEPTH(DEPTH-lower_depth), .INIT(INIT[DEPTH-lower_depth-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T1), .L(L[lower_clog2-1:0]), .E(E), .Q(T2), .SO(T3));
assign Q = L[lower_clog2] ? T2 : T0;
end
if (DEPTH == 2 * lower_depth)
assign SO = T3;
end
endgenerate
endmodule
`ifndef SRL_ONLY
`endif

View File

@ -30,10 +30,15 @@ module GND(output G);
endmodule
module IBUF(output O, input I);
parameter IOSTANDARD = "default";
parameter IBUF_LOW_PWR = 0;
assign O = I;
endmodule
module OBUF(output O, input I);
parameter IOSTANDARD = "default";
parameter DRIVE = 12;
parameter SLEW = "SLOW";
assign O = I;
endmodule
@ -41,6 +46,42 @@ module BUFG(output O, input I);
assign O = I;
endmodule
module BUFGCTRL(
output O,
input I0, input I1,
input S0, input S1,
input CE0, input CE1,
input IGNORE0, input IGNORE1);
parameter [0:0] INIT_OUT = 1'b0;
parameter PRESELECT_I0 = "FALSE";
parameter PRESELECT_I1 = "FALSE";
parameter [0:0] IS_CE0_INVERTED = 1'b0;
parameter [0:0] IS_CE1_INVERTED = 1'b0;
parameter [0:0] IS_S0_INVERTED = 1'b0;
parameter [0:0] IS_S1_INVERTED = 1'b0;
parameter [0:0] IS_IGNORE0_INVERTED = 1'b0;
parameter [0:0] IS_IGNORE1_INVERTED = 1'b0;
wire I0_internal = ((CE0 ^ IS_CE0_INVERTED) ? I0 : INIT_OUT);
wire I1_internal = ((CE1 ^ IS_CE1_INVERTED) ? I1 : INIT_OUT);
wire S0_true = (S0 ^ IS_S0_INVERTED);
wire S1_true = (S1 ^ IS_S1_INVERTED);
assign O = S0_true ? I0_internal : (S1_true ? I1_internal : INIT_OUT);
endmodule
module BUFHCE(output O, input I, input CE);
parameter [0:0] INIT_OUT = 1'b0;
parameter CE_TYPE = "SYNC";
parameter [0:0] IS_CE_INVERTED = 1'b0;
assign O = ((CE ^ IS_CE_INVERTED) ? I : INIT_OUT);
endmodule
// module OBUFT(output O, input I, T);
// assign O = T ? 1'bz : I;
// endmodule
@ -98,6 +139,22 @@ module LUT6(output O, input I0, I1, I2, I3, I4, I5);
assign O = I0 ? s1[1] : s1[0];
endmodule
module LUT6_2(output O6, output O5, input I0, I1, I2, I3, I4, I5);
parameter [63:0] INIT = 0;
wire [31: 0] s5 = I5 ? INIT[63:32] : INIT[31: 0];
wire [15: 0] s4 = I4 ? s5[31:16] : s5[15: 0];
wire [ 7: 0] s3 = I3 ? s4[15: 8] : s4[ 7: 0];
wire [ 3: 0] s2 = I2 ? s3[ 7: 4] : s3[ 3: 0];
wire [ 1: 0] s1 = I1 ? s2[ 3: 2] : s2[ 1: 0];
assign O6 = I0 ? s1[1] : s1[0];
wire [15: 0] s5_4 = I4 ? INIT[31:16] : INIT[15: 0];
wire [ 7: 0] s5_3 = I3 ? s5_4[15: 8] : s5_4[ 7: 0];
wire [ 3: 0] s5_2 = I2 ? s5_3[ 7: 4] : s5_3[ 3: 0];
wire [ 1: 0] s5_1 = I1 ? s5_2[ 3: 2] : s5_2[ 1: 0];
assign O5 = I0 ? s5_1[1] : s5_1[0];
endmodule
module MUXCY(output O, input CI, DI, S);
assign O = S ? CI : DI;
endmodule
@ -251,3 +308,42 @@ module RAM128X1D (
wire clk = WCLK ^ IS_WCLK_INVERTED;
always @(posedge clk) if (WE) mem[A] <= D;
endmodule
module SRL16E (
output Q,
input A0, A1, A2, A3, CE, CLK, D
);
parameter [15:0] INIT = 16'h0000;
parameter [0:0] IS_CLK_INVERTED = 1'b0;
reg [15:0] r = INIT;
assign Q = r[{A3,A2,A1,A0}];
generate
if (IS_CLK_INVERTED) begin
always @(negedge CLK) if (CE) r <= { r[14:0], D };
end
else
always @(posedge CLK) if (CE) r <= { r[14:0], D };
endgenerate
endmodule
module SRLC32E (
output Q,
output Q31,
input [4:0] A,
input CE, CLK, D
);
parameter [31:0] INIT = 32'h00000000;
parameter [0:0] IS_CLK_INVERTED = 1'b0;
reg [31:0] r = INIT;
assign Q31 = r[31];
assign Q = r[A];
generate
if (IS_CLK_INVERTED) begin
always @(negedge CLK) if (CE) r <= { r[30:0], D };
end
else
always @(posedge CLK) if (CE) r <= { r[30:0], D };
endgenerate
endmodule

View File

@ -28,12 +28,12 @@ function xtract_cell_decl()
# xtract_cell_decl BUFG
xtract_cell_decl BUFGCE
xtract_cell_decl BUFGCE_1
xtract_cell_decl BUFGCTRL
#xtract_cell_decl BUFGCTRL
xtract_cell_decl BUFGMUX
xtract_cell_decl BUFGMUX_1
xtract_cell_decl BUFGMUX_CTRL
xtract_cell_decl BUFH
xtract_cell_decl BUFHCE
#xtract_cell_decl BUFHCE
xtract_cell_decl BUFIO
xtract_cell_decl BUFMR
xtract_cell_decl BUFMRCE
@ -92,7 +92,7 @@ function xtract_cell_decl()
# xtract_cell_decl LUT4
# xtract_cell_decl LUT5
# xtract_cell_decl LUT6
xtract_cell_decl LUT6_2
#xtract_cell_decl LUT6_2
xtract_cell_decl MMCME2_ADV
xtract_cell_decl MMCME2_BASE
# xtract_cell_decl MUXF7
@ -135,8 +135,8 @@ function xtract_cell_decl()
xtract_cell_decl ROM256X1
xtract_cell_decl ROM32X1
xtract_cell_decl ROM64X1
xtract_cell_decl SRL16E
xtract_cell_decl SRLC32E
#xtract_cell_decl SRL16E
#xtract_cell_decl SRLC32E
xtract_cell_decl STARTUPE2 "(* keep *)"
xtract_cell_decl USR_ACCESSE2
xtract_cell_decl XADC

View File

@ -30,29 +30,6 @@ module BUFGCE_1 (...);
input CE, I;
endmodule
module BUFGCTRL (...);
output O;
input CE0;
input CE1;
input I0;
input I1;
input IGNORE0;
input IGNORE1;
input S0;
input S1;
parameter integer INIT_OUT = 0;
parameter PRESELECT_I0 = "FALSE";
parameter PRESELECT_I1 = "FALSE";
parameter [0:0] IS_CE0_INVERTED = 1'b0;
parameter [0:0] IS_CE1_INVERTED = 1'b0;
parameter [0:0] IS_I0_INVERTED = 1'b0;
parameter [0:0] IS_I1_INVERTED = 1'b0;
parameter [0:0] IS_IGNORE0_INVERTED = 1'b0;
parameter [0:0] IS_IGNORE1_INVERTED = 1'b0;
parameter [0:0] IS_S0_INVERTED = 1'b0;
parameter [0:0] IS_S1_INVERTED = 1'b0;
endmodule
module BUFGMUX (...);
parameter CLK_SEL_TYPE = "SYNC";
output O;
@ -77,15 +54,6 @@ module BUFH (...);
input I;
endmodule
module BUFHCE (...);
parameter CE_TYPE = "SYNC";
parameter integer INIT_OUT = 0;
parameter [0:0] IS_CE_INVERTED = 1'b0;
output O;
input CE;
input I;
endmodule
module BUFIO (...);
output O;
input I;
@ -2420,12 +2388,6 @@ module LDPE (...);
input D, G, GE, PRE;
endmodule
module LUT6_2 (...);
parameter [63:0] INIT = 64'h0000000000000000;
input I0, I1, I2, I3, I4, I5;
output O5, O6;
endmodule
module MMCME2_ADV (...);
parameter BANDWIDTH = "OPTIMIZED";
parameter real CLKFBOUT_MULT_F = 5.000;
@ -3847,22 +3809,6 @@ module ROM64X1 (...);
input A0, A1, A2, A3, A4, A5;
endmodule
module SRL16E (...);
parameter [15:0] INIT = 16'h0000;
parameter [0:0] IS_CLK_INVERTED = 1'b0;
output Q;
input A0, A1, A2, A3, CE, CLK, D;
endmodule
module SRLC32E (...);
parameter [31:0] INIT = 32'h00000000;
parameter [0:0] IS_CLK_INVERTED = 1'b0;
output Q;
output Q31;
input [4:0] A;
input CE, CLK, D;
endmodule
(* keep *)
module STARTUPE2 (...);
parameter PROG_USR = "FALSE";

View File

@ -22,21 +22,26 @@
`ifndef _NO_FFS
`ifndef _NO_POS_SR
module \$_DFF_N_ (input D, C, output Q); FDRE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); endmodule
module \$_DFF_P_ (input D, C, output Q); FDRE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); endmodule
module \$_DFFE_NP_ (input D, C, E, output Q); FDRE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); endmodule
module \$_DFFE_PP_ (input D, C, E, output Q); FDRE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); endmodule
module \$_DFF_NN0_ (input D, C, R, output Q); FDCE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(!R)); endmodule
module \$_DFF_NP0_ (input D, C, R, output Q); FDCE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); endmodule
module \$_DFF_PN0_ (input D, C, R, output Q); FDCE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(!R)); endmodule
module \$_DFF_PP0_ (input D, C, R, output Q); FDCE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); endmodule
module \$_DFF_NN1_ (input D, C, R, output Q); FDPE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(!R)); endmodule
module \$_DFF_NP1_ (input D, C, R, output Q); FDPE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); endmodule
module \$_DFF_PN1_ (input D, C, R, output Q); FDPE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(!R)); endmodule
module \$_DFF_PP1_ (input D, C, R, output Q); FDPE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); endmodule
`endif
module \$_DFF_NN0_ (input D, C, R, output Q); \$_DFF_NP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
module \$_DFF_PN0_ (input D, C, R, output Q); \$_DFF_PP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
module \$_DFF_NN1_ (input D, C, R, output Q); \$_DFF_NP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
module \$_DFF_PN1_ (input D, C, R, output Q); \$_DFF_PP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule
`endif
`endif

View File

@ -25,18 +25,9 @@
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
bool check_label(bool &active, std::string run_from, std::string run_to, std::string label)
struct SynthXilinxPass : public ScriptPass
{
if (label == run_from)
active = true;
if (label == run_to)
active = false;
return active;
}
struct SynthXilinxPass : public Pass
{
SynthXilinxPass() : Pass("synth_xilinx", "synthesis for Xilinx FPGAs") { }
SynthXilinxPass() : ScriptPass("synth_xilinx", "synthesis for Xilinx FPGAs") { }
void help() YS_OVERRIDE
{
@ -64,10 +55,13 @@ struct SynthXilinxPass : public Pass
log(" (this feature is experimental and incomplete)\n");
log("\n");
log(" -nobram\n");
log(" disable infering of block rams\n");
log(" disable inference of block rams\n");
log("\n");
log(" -nodram\n");
log(" disable infering of distributed rams\n");
log(" disable inference of distributed rams\n");
log("\n");
log(" -nosrl\n");
log(" disable inference of shift registers\n");
log("\n");
log(" -run <from_label>:<to_label>\n");
log(" only run the commands between the labels (see below). an empty\n");
@ -82,71 +76,30 @@ struct SynthXilinxPass : public Pass
log("\n");
log("\n");
log("The following commands are executed by this synthesis command:\n");
log("\n");
log(" begin:\n");
log(" read_verilog -lib +/xilinx/cells_sim.v\n");
log(" read_verilog -lib +/xilinx/cells_xtra.v\n");
log(" read_verilog -lib +/xilinx/brams_bb.v\n");
log(" hierarchy -check -top <top>\n");
log("\n");
log(" flatten: (only if -flatten)\n");
log(" proc\n");
log(" flatten\n");
log("\n");
log(" coarse:\n");
log(" synth -run coarse\n");
log("\n");
log(" bram: (only executed when '-nobram' is not given)\n");
log(" memory_bram -rules +/xilinx/brams.txt\n");
log(" techmap -map +/xilinx/brams_map.v\n");
log("\n");
log(" dram: (only executed when '-nodram' is not given)\n");
log(" memory_bram -rules +/xilinx/drams.txt\n");
log(" techmap -map +/xilinx/drams_map.v\n");
log("\n");
log(" fine:\n");
log(" opt -fast -full\n");
log(" memory_map\n");
log(" dffsr2dff\n");
log(" dff2dffe\n");
log(" opt -full\n");
log(" techmap -map +/techmap.v -map +/xilinx/arith_map.v -map +/xilinx/ff_map.v\n");
log(" opt -fast\n");
log("\n");
log(" map_luts:\n");
log(" abc -luts 2:2,3,6:5,10,20 [-dff] (without '-vpr' only!)\n");
log(" abc -lut 5 [-dff] (with '-vpr' only!)\n");
log(" clean\n");
log("\n");
log(" map_cells:\n");
log(" techmap -map +/xilinx/cells_map.v\n");
log(" dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT \\\n");
log(" -ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT\n");
log(" clean\n");
log("\n");
log(" check:\n");
log(" hierarchy -check\n");
log(" stat\n");
log(" check -noinit\n");
log("\n");
log(" edif: (only if -edif)\n");
log(" write_edif <file-name>\n");
log("\n");
log(" blif: (only if -blif)\n");
log(" write_blif <file-name>\n");
help_script();
log("\n");
}
std::string top_opt, edif_file, blif_file;
bool flatten, retime, vpr, nobram, nodram, nosrl;
void clear_flags() YS_OVERRIDE
{
top_opt = "-auto-top";
edif_file.clear();
blif_file.clear();
flatten = false;
retime = false;
vpr = false;
nobram = false;
nodram = false;
nosrl = false;
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
{
std::string top_opt = "-auto-top";
std::string edif_file;
std::string blif_file;
std::string run_from, run_to;
bool flatten = false;
bool retime = false;
bool vpr = false;
bool nobram = false;
bool nodram = false;
clear_flags();
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
@ -191,6 +144,10 @@ struct SynthXilinxPass : public Pass
nodram = true;
continue;
}
if (args[argidx] == "-nosrl") {
nosrl = true;
continue;
}
break;
}
extra_args(args, argidx, design);
@ -198,108 +155,129 @@ struct SynthXilinxPass : public Pass
if (!design->full_selection())
log_cmd_error("This command only operates on fully selected designs!\n");
bool active = run_from.empty();
log_header(design, "Executing SYNTH_XILINX pass.\n");
log_push();
if (check_label(active, run_from, run_to, "begin"))
{
if (vpr) {
Pass::call(design, "read_verilog -lib -D_EXPLICIT_CARRY +/xilinx/cells_sim.v");
} else {
Pass::call(design, "read_verilog -lib +/xilinx/cells_sim.v");
}
Pass::call(design, "read_verilog -lib +/xilinx/cells_xtra.v");
if (!nobram) {
Pass::call(design, "read_verilog -lib +/xilinx/brams_bb.v");
}
Pass::call(design, stringf("hierarchy -check %s", top_opt.c_str()));
}
if (flatten && check_label(active, run_from, run_to, "flatten"))
{
Pass::call(design, "proc");
Pass::call(design, "flatten");
}
if (check_label(active, run_from, run_to, "coarse"))
{
Pass::call(design, "synth -run coarse");
}
if (check_label(active, run_from, run_to, "bram"))
{
if (!nobram) {
Pass::call(design, "memory_bram -rules +/xilinx/brams.txt");
Pass::call(design, "techmap -map +/xilinx/brams_map.v");
}
}
if (check_label(active, run_from, run_to, "dram"))
{
if (!nodram) {
Pass::call(design, "memory_bram -rules +/xilinx/drams.txt");
Pass::call(design, "techmap -map +/xilinx/drams_map.v");
}
}
if (check_label(active, run_from, run_to, "fine"))
{
Pass::call(design, "opt -fast -full");
Pass::call(design, "memory_map");
Pass::call(design, "dffsr2dff");
Pass::call(design, "dff2dffe");
Pass::call(design, "opt -full");
if (vpr) {
Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/arith_map.v -map +/xilinx/ff_map.v -D _EXPLICIT_CARRY");
} else {
Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/arith_map.v -map +/xilinx/ff_map.v");
}
Pass::call(design, "hierarchy -check");
Pass::call(design, "opt -fast");
}
if (check_label(active, run_from, run_to, "map_luts"))
{
Pass::call(design, "abc -luts 2:2,3,6:5,10,20" + string(retime ? " -dff" : ""));
Pass::call(design, "clean");
Pass::call(design, "techmap -map +/xilinx/lut_map.v");
}
if (check_label(active, run_from, run_to, "map_cells"))
{
Pass::call(design, "techmap -map +/xilinx/cells_map.v");
Pass::call(design, "dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT "
"-ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT");
Pass::call(design, "clean");
}
if (check_label(active, run_from, run_to, "check"))
{
Pass::call(design, "hierarchy -check");
Pass::call(design, "stat");
Pass::call(design, "check -noinit");
}
if (check_label(active, run_from, run_to, "edif"))
{
if (!edif_file.empty())
Pass::call(design, stringf("write_edif -pvector bra %s", edif_file.c_str()));
}
if (check_label(active, run_from, run_to, "blif"))
{
if (!blif_file.empty())
Pass::call(design, stringf("write_blif %s", edif_file.c_str()));
}
run_script(design, run_from, run_to);
log_pop();
}
void script() YS_OVERRIDE
{
if (check_label("begin")) {
if (vpr)
run("read_verilog -lib -D_EXPLICIT_CARRY +/xilinx/cells_sim.v");
else
run("read_verilog -lib +/xilinx/cells_sim.v");
run("read_verilog -lib +/xilinx/cells_xtra.v");
if (!nobram || help_mode)
run("read_verilog -lib +/xilinx/brams_bb.v", "(skip if '-nobram')");
run(stringf("hierarchy -check %s", top_opt.c_str()));
}
if (check_label("flatten", "(with '-flatten' only)")) {
if (flatten || help_mode) {
run("proc");
run("flatten");
}
}
if (check_label("coarse")) {
run("synth -run coarse");
}
if (check_label("bram", "(skip if '-nobram')")) {
if (!nobram || help_mode) {
run("memory_bram -rules +/xilinx/brams.txt");
run("techmap -map +/xilinx/brams_map.v");
}
}
if (check_label("dram", "(skip if '-nodram')")) {
if (!nodram || help_mode) {
run("memory_bram -rules +/xilinx/drams.txt");
run("techmap -map +/xilinx/drams_map.v");
}
}
if (check_label("fine")) {
run("opt -fast");
run("memory_map");
run("dffsr2dff");
run("dff2dffe");
if (!vpr || help_mode)
run("techmap -map +/xilinx/arith_map.v");
else
run("techmap -map +/xilinx/arith_map.v -D _EXPLICIT_CARRY");
run("hierarchy -check");
run("opt -fast");
}
if (check_label("map_cells"))
{
if (!nosrl || help_mode) {
// shregmap operates on bit-level flops, not word-level,
// so break those down here
run("simplemap t:$dff t:$dffe", "(skip if '-nosrl')");
// shregmap -tech xilinx can cope with $shiftx and $mux
// cells for identifiying variable-length shift registers,
// so attempt to convert $pmux-es to the former
run("pmux2shiftx", "(skip if '-nosrl')");
// pmux2shiftx can leave behind a $pmux with a single entry
// -- need this to clean that up before shregmap
run("opt_expr -mux_undef", "(skip if '-nosrl')");
// shregmap with '-tech xilinx' infers variable length shift regs
run("shregmap -tech xilinx -minlen 3", "(skip if '-nosrl')");
}
run("techmap -map +/xilinx/cells_map.v");
run("clean");
}
if (check_label("map_luts"))
{
run("opt -full");
run("techmap -map +/techmap.v -D _NO_POS_SR -map +/xilinx/ff_map.v");
if (help_mode)
run("abc -luts 2:2,3,6:5,10,20 [-dff]");
else
run("abc -luts 2:2,3,6:5,10,20" + string(retime ? " -dff" : ""));
run("clean");
// This shregmap call infers fixed length shift registers after abc
// has performed any necessary retiming
if (!nosrl || help_mode)
run("shregmap -minlen 3 -init -params -enpol any_or_none", "(skip if '-nosrl')");
run("techmap -map +/xilinx/lut_map.v -map +/xilinx/ff_map.v -map +/xilinx/cells_map.v");
run("dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT "
"-ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT");
run("clean");
}
if (check_label("check"))
{
run("hierarchy -check");
run("stat");
run("check -noinit");
}
if (check_label("edif"))
{
if (!edif_file.empty() || help_mode)
run(stringf("write_edif -pvector bra %s", edif_file.c_str()));
}
if (check_label("blif"))
{
if (!blif_file.empty() || help_mode)
run(stringf("write_blif %s", edif_file.c_str()));
}
}
} SynthXilinxPass;
PRIVATE_NAMESPACE_END

2
tests/aiger/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*.log
*.out

View File

@ -0,0 +1,38 @@
// coverage for repeat loops outside of constant functions
module counter1(clk, rst, ping);
input clk, rst;
output ping;
reg [31:0] count;
always @(posedge clk) begin
if (rst)
count <= 0;
else
count <= count + 1;
end
assign ping = &count;
endmodule
module counter2(clk, rst, ping);
input clk, rst;
output ping;
reg [31:0] count;
integer i;
reg carry;
always @(posedge clk) begin
carry = 1;
i = 0;
repeat (32) begin
count[i] <= !rst & (count[i] ^ carry);
carry = count[i] & carry;
i = i+1;
end
end
assign ping = &count;
endmodule

View File

@ -0,0 +1,10 @@
read_verilog counters-repeat.v
proc; opt
expose -shared counter1 counter2
miter -equiv -make_assert -make_outputs counter1 counter2 miter
cd miter; flatten; opt
sat -verify -prove-asserts -tempinduct -set-at 1 in_rst 1 -seq 1 -show-inputs -show-outputs

6
tests/simple/retime.v Normal file
View File

@ -0,0 +1,6 @@
module retime_test(input clk, input [7:0] a, output z);
reg [7:0] ff = 8'hF5;
always @(posedge clk)
ff <= {ff[6:0], ^a};
assign z = ff[7];
endmodule

View File

@ -7,7 +7,7 @@ use_modelsim=false
verbose=false
keeprunning=false
makejmode=false
frontend="verilog"
frontend="verilog -noblackbox"
backend_opts="-noattr -noexpr -siminit"
autotb_opts=""
include_opts=""
@ -137,7 +137,7 @@ do
egrep -v '^\s*`timescale' ../$fn > ${bn}_ref.${ext}
else
"$toolsdir"/../../yosys -f "$frontend $include_opts" -b "verilog" -o ${bn}_ref.v ../${fn}
frontend="verilog"
frontend="verilog -noblackbox"
fi
if [ ! -f ../${bn}_tb.v ]; then

View File

@ -53,6 +53,7 @@ echo -n " no explicit top - "
module noTop(a, y);
input a;
output [31:0] y;
assign y = a;
endmodule
EOV
hierarchy -auto-top

View File

@ -0,0 +1,34 @@
module pmux2shiftx_test (
input [2:0] S1,
input [5:0] S2,
input [1:0] S3,
input [9:0] A, B, C, D, D, E, F, G, H,
input [9:0] I, J, K, L, M, N, O, P, Q,
output reg [9:0] X
);
always @* begin
case (S1)
3'd 0: X = A;
3'd 1: X = B;
3'd 2: X = C;
3'd 3: X = D;
3'd 4: X = E;
3'd 5: X = F;
3'd 6: X = G;
3'd 7: X = H;
endcase
case (S2)
6'd 45: X = I;
6'd 47: X = J;
6'd 49: X = K;
6'd 55: X = L;
6'd 57: X = M;
6'd 59: X = N;
endcase
case (S3)
2'd 1: X = O;
2'd 2: X = P;
2'd 3: X = Q;
endcase
end
endmodule

View File

@ -0,0 +1,28 @@
read_verilog pmux2shiftx.v
prep
design -save gold
pmux2shiftx -min_density 70
opt
stat
# show -width
select -assert-count 1 t:$sub
select -assert-count 1 t:$mux
select -assert-count 1 t:$shift
select -assert-count 3 t:$shiftx
design -stash gate
design -import gold -as gold
design -import gate -as gate
miter -equiv -flatten -make_assert -make_outputs gold gate miter
sat -verify -prove-asserts -show-ports miter
design -load gold
stat
design -load gate
stat