Compare commits

..

No commits in common. "main" and "v0.59.1" have entirely different histories.

184 changed files with 1569 additions and 4776 deletions

View File

@ -37,7 +37,7 @@ jobs:
persist-credentials: false
- run: sudo apt-get install libfl-dev
- name: Build
run: make vcxsrc YOSYS_COMPILER="Visual Studio" VCX_DIR_NAME=yosys-win32-vcxsrc-latest
run: make vcxsrc YOSYS_VER=latest
- uses: actions/upload-artifact@v4
with:
name: vcxsrc

View File

@ -83,42 +83,3 @@ jobs:
shell: bash
run: |
make -j$procs unit-test ENABLE_LTO=1 ENABLE_LIBYOSYS=1
test-pyosys:
needs: pre-job
if: ${{ needs.pre-job.outputs.should_skip != 'true' && github.repository == 'YosysHQ/Yosys' }}
runs-on: [self-hosted, linux, x64, fast]
steps:
- name: Checkout Yosys
uses: actions/checkout@v4
with:
persist-credentials: false
submodules: true
- name: Install UV
run: |
curl -LsSf https://astral.sh/uv/install.sh | sh
- name: Runtime environment
run: |
echo "procs=$(nproc)" >> $GITHUB_ENV
echo "${{ github.workspace }}/.local/bin" >> $GITHUB_PATH
- name: Build pyosys
run: |
make config-clang
echo "ENABLE_VERIFIC := 1" >> Makefile.conf
echo "ENABLE_VERIFIC_EDIF := 1" >> Makefile.conf
echo "ENABLE_VERIFIC_LIBERTY := 1" >> Makefile.conf
echo "ENABLE_VERIFIC_YOSYSHQ_EXTENSIONS := 1" >> Makefile.conf
echo "ENABLE_CCACHE := 1" >> Makefile.conf
echo "ENABLE_PYOSYS := 1" >> Makefile.conf
echo "PYTHON_DESTDIR := /usr/lib/python3/site-packages" >> Makefile.conf
make -j$procs
- name: Install pyosys
run: |
make install DESTDIR=${GITHUB_WORKSPACE}/.local PREFIX=
- name: Run pyosys tests
run: |
export PYTHONPATH=${GITHUB_WORKSPACE}/.local/usr/lib/python3/site-packages:$PYTHONPATH
python3 tests/pyosys/run_tests.py

View File

@ -2,20 +2,9 @@
List of major changes and improvements between releases
=======================================================
Yosys 0.60 .. Yosys 0.61-dev
Yosys 0.59 .. Yosys 0.60-dev
--------------------------
Yosys 0.59 .. Yosys 0.60
--------------------------
* Various
- read_verilog: suport unsized parameters.
- Added static library compile option.
* New commands and options
- Added "sdc" pass for reading SDC files.
- Added experimental "sdc_expand" and "opensta" for OpenSTA integration.
- Added "icell_liberty" pass for used internal cells.
Yosys 0.58 .. Yosys 0.59
--------------------------
* Various

View File

@ -21,8 +21,8 @@ ENABLE_VERIFIC_HIER_TREE := 1
ENABLE_VERIFIC_YOSYSHQ_EXTENSIONS := 0
ENABLE_VERIFIC_EDIF := 0
ENABLE_VERIFIC_LIBERTY := 0
ENABLE_COVER := 1
ENABLE_LIBYOSYS := 0
ENABLE_LIBYOSYS_STATIC := 0
ENABLE_ZLIB := 1
ENABLE_HELP_SOURCE := 0
@ -161,7 +161,7 @@ ifeq ($(OS), Haiku)
CXXFLAGS += -D_DEFAULT_SOURCE
endif
YOSYS_VER := 0.60+64
YOSYS_VER := 0.59+0
YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1)
YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1)
YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2)
@ -177,16 +177,14 @@ CXXFLAGS += -DYOSYS_VER=\\"$(YOSYS_VER)\\" \
TARBALL_GIT_REV := $(shell cat $(YOSYS_SRC)/.gitcommit)
ifneq ($(findstring Format:,$(TARBALL_GIT_REV)),)
GIT_REV := $(shell GIT_DIR=$(YOSYS_SRC)/.git git rev-parse --short=9 HEAD || echo UNKNOWN)
GIT_DIRTY := $(shell GIT_DIR=$(YOSYS_SRC)/.git git diff --exit-code --quiet 2>/dev/null; if [ $$? -ne 0 ]; then echo "-dirty"; fi)
else
GIT_REV := $(TARBALL_GIT_REV)
GIT_DIRTY := ""
endif
OBJS = kernel/version_$(GIT_REV).o
bumpversion:
sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 5bafeb7.. | wc -l`/;" Makefile
sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 03eb220.. | wc -l`/;" Makefile
ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABC_USE_NAMESPACE=abc VERBOSE=$(Q)
@ -250,6 +248,9 @@ ifneq ($(SANITIZER),)
$(info [Clang Sanitizer] $(SANITIZER))
CXXFLAGS += -g -O1 -fno-omit-frame-pointer -fno-optimize-sibling-calls -fsanitize=$(SANITIZER)
LINKFLAGS += -g -fsanitize=$(SANITIZER)
ifneq ($(findstring address,$(SANITIZER)),)
ENABLE_COVER := 0
endif
ifneq ($(findstring memory,$(SANITIZER)),)
CXXFLAGS += -fPIE -fsanitize-memory-track-origins
LINKFLAGS += -fPIE -fsanitize-memory-track-origins
@ -341,9 +342,6 @@ endif
ifeq ($(ENABLE_LIBYOSYS),1)
TARGETS += libyosys.so
ifeq ($(ENABLE_LIBYOSYS_STATIC),1)
TARGETS += libyosys.a
endif
endif
PY_WRAPPER_FILE = pyosys/wrappers
@ -476,9 +474,6 @@ else
ifeq ($(ABCEXTERNAL),)
TARGETS := $(PROGRAM_PREFIX)yosys-abc$(EXE) $(TARGETS)
endif
ifeq ($(DISABLE_SPAWN),1)
$(error ENABLE_ABC=1 requires either LINK_ABC=1 or DISABLE_SPAWN=0)
endif
endif
endif
@ -546,6 +541,10 @@ LIBS_VERIFIC += -Wl,--whole-archive $(patsubst %,$(VERIFIC_DIR)/%/*-linux.a,$(VE
endif
endif
ifeq ($(ENABLE_COVER),1)
CXXFLAGS += -DYOSYS_ENABLE_COVER
endif
ifeq ($(ENABLE_CCACHE),1)
CXX := ccache $(CXX)
else
@ -723,6 +722,7 @@ OBJS += passes/hierarchy/hierarchy.o
OBJS += passes/cmds/select.o
OBJS += passes/cmds/show.o
OBJS += passes/cmds/stat.o
OBJS += passes/cmds/cover.o
OBJS += passes/cmds/design.o
OBJS += passes/cmds/plugin.o
@ -772,9 +772,6 @@ else
$(P) $(CXX) -o libyosys.so -shared -Wl,-soname,libyosys.so $(LINKFLAGS) $^ $(LIBS) $(LIBS_VERIFIC)
endif
libyosys.a: $(filter-out kernel/driver.o,$(OBJS))
$(P) $(AR) rcs $@ $^
%.o: %.cc
$(Q) mkdir -p $(dir $@)
$(P) $(CXX) -o $@ -c $(CPPFLAGS) $(CXXFLAGS) $<
@ -793,13 +790,12 @@ endif
$(Q) mkdir -p $(dir $@)
$(P) $(CXX) -o $@ -c $(CPPFLAGS) $(CXXFLAGS) $<
YOSYS_GIT_STR := $(GIT_REV)$(GIT_DIRTY)
YOSYS_COMPILER := $(notdir $(CXX)) $(shell $(CXX) --version | tr ' ()' '\n' | grep '^[0-9]' | head -n1) $(filter -f% -m% -O% -DNDEBUG,$(CXXFLAGS))
YOSYS_VER_STR := Yosys $(YOSYS_VER) (git sha1 $(YOSYS_GIT_STR), $(YOSYS_COMPILER))
YOSYS_VER_STR := Yosys $(YOSYS_VER) (git sha1 $(GIT_REV), $(notdir $(CXX)) $(shell \
$(CXX) --version | tr ' ()' '\n' | grep '^[0-9]' | head -n1) $(filter -f% -m% -O% -DNDEBUG,$(CXXFLAGS)))
kernel/version_$(GIT_REV).cc: $(YOSYS_SRC)/Makefile
$(P) rm -f kernel/version_*.o kernel/version_*.d kernel/version_*.cc
$(Q) mkdir -p kernel && echo "namespace Yosys { extern const char *yosys_version_str; const char *yosys_version_str=\"$(YOSYS_VER_STR)\"; const char *yosys_git_hash_str=\"$(YOSYS_GIT_STR)\"; }" > kernel/version_$(GIT_REV).cc
$(Q) mkdir -p kernel && echo "namespace Yosys { extern const char *yosys_version_str; const char *yosys_version_str=\"$(YOSYS_VER_STR)\"; }" > kernel/version_$(GIT_REV).cc
ifeq ($(ENABLE_VERIFIC),1)
CXXFLAGS_NOVERIFIC = $(foreach v,$(CXXFLAGS),$(if $(findstring $(VERIFIC_DIR),$(v)),,$(v)))
@ -906,7 +902,6 @@ MK_TEST_DIRS += tests/arch/xilinx
MK_TEST_DIRS += tests/bugpoint
MK_TEST_DIRS += tests/opt
MK_TEST_DIRS += tests/sat
MK_TEST_DIRS += tests/sdc
MK_TEST_DIRS += tests/sim
MK_TEST_DIRS += tests/svtypes
MK_TEST_DIRS += tests/techmap
@ -1027,7 +1022,7 @@ install-dev: $(PROGRAM_PREFIX)yosys-config share
install: $(TARGETS) $(EXTRA_TARGETS)
$(INSTALL_SUDO) mkdir -p $(DESTDIR)$(BINDIR)
$(INSTALL_SUDO) cp $(filter-out libyosys.so libyosys.a,$(TARGETS)) $(DESTDIR)$(BINDIR)
$(INSTALL_SUDO) cp $(filter-out libyosys.so,$(TARGETS)) $(DESTDIR)$(BINDIR)
ifneq ($(filter $(PROGRAM_PREFIX)yosys,$(TARGETS)),)
if [ -n "$(STRIP)" ]; then $(INSTALL_SUDO) $(STRIP) -S $(DESTDIR)$(BINDIR)/$(PROGRAM_PREFIX)yosys; fi
endif
@ -1043,18 +1038,13 @@ ifeq ($(ENABLE_LIBYOSYS),1)
$(INSTALL_SUDO) mkdir -p $(DESTDIR)$(LIBDIR)
$(INSTALL_SUDO) cp libyosys.so $(DESTDIR)$(LIBDIR)/
if [ -n "$(STRIP)" ]; then $(INSTALL_SUDO) $(STRIP) -S $(DESTDIR)$(LIBDIR)/libyosys.so; fi
ifeq ($(ENABLE_LIBYOSYS_STATIC),1)
$(INSTALL_SUDO) cp libyosys.a $(DESTDIR)$(LIBDIR)/
endif
ifeq ($(ENABLE_PYOSYS),1)
$(INSTALL_SUDO) mkdir -p $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys
$(INSTALL_SUDO) cp $(YOSYS_SRC)/pyosys/__init__.py $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys/__init__.py
$(INSTALL_SUDO) cp pyosys/__init__.py $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys/__init__.py
$(INSTALL_SUDO) cp libyosys.so $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys/libyosys.so
$(INSTALL_SUDO) cp -r share $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys
ifeq ($(ENABLE_ABC),1)
ifeq ($(ABCEXTERNAL),)
$(INSTALL_SUDO) cp $(PROGRAM_PREFIX)yosys-abc$(EXE) $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys/yosys-abc$(EXE)
endif
$(INSTALL_SUDO) cp yosys-abc $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys/yosys-abc
endif
endif
endif
@ -1070,9 +1060,6 @@ uninstall:
$(INSTALL_SUDO) rm -rvf $(DESTDIR)$(DATDIR)
ifeq ($(ENABLE_LIBYOSYS),1)
$(INSTALL_SUDO) rm -vf $(DESTDIR)$(LIBDIR)/libyosys.so
ifeq ($(ENABLE_LIBYOSYS_STATIC),1)
$(INSTALL_SUDO) rm -vf $(DESTDIR)$(LIBDIR)/libyosys.a
endif
ifeq ($(ENABLE_PYOSYS),1)
$(INSTALL_SUDO) rm -vf $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys/libyosys.so
$(INSTALL_SUDO) rm -vf $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys/__init__.py
@ -1171,7 +1158,7 @@ clean-py:
rm -f $(PY_WRAPPER_FILE).inc.cc $(PY_WRAPPER_FILE).cc
rm -f $(PYTHON_OBJECTS)
rm -f *.whl
rm -f libyosys.so libyosys.a
rm -f libyosys.so
rm -rf kernel/*.pyh
clean-abc:
@ -1205,17 +1192,15 @@ qtcreator:
{ echo .; find backends frontends kernel libs passes -type f \( -name '*.h' -o -name '*.hh' \) -printf '%h\n' | sort -u; } > qtcreator.includes
touch qtcreator.creator
VCX_DIR_NAME := yosys-win32-vcxsrc-$(YOSYS_VER)
vcxsrc: $(GENFILES) $(EXTRA_TARGETS) kernel/version_$(GIT_REV).cc
rm -rf $(VCX_DIR_NAME){,.zip}
cp -f kernel/version_$(GIT_REV).cc kernel/version.cc
vcxsrc: $(GENFILES) $(EXTRA_TARGETS)
rm -rf yosys-win32-vcxsrc-$(YOSYS_VER){,.zip}
set -e; for f in `ls $(filter %.cc %.cpp,$(GENFILES)) $(addsuffix .cc,$(basename $(OBJS))) $(addsuffix .cpp,$(basename $(OBJS))) 2> /dev/null`; do \
echo "Analyse: $$f" >&2; cpp -std=c++17 -MM -I. -D_YOSYS_ $$f; done | sed 's,.*:,,; s,//*,/,g; s,/[^/]*/\.\./,/,g; y, \\,\n\n,;' | grep '^[^/]' | sort -u | grep -v kernel/version_ > srcfiles.txt
echo "libs/fst/fst_win_unistd.h" >> srcfiles.txt
echo "kernel/version.cc" >> srcfiles.txt
bash misc/create_vcxsrc.sh $(VCX_DIR_NAME) $(YOSYS_VER)
zip $(VCX_DIR_NAME)/genfiles.zip $(GENFILES) kernel/version.cc
zip -r $(VCX_DIR_NAME).zip $(VCX_DIR_NAME)/
bash misc/create_vcxsrc.sh yosys-win32-vcxsrc $(YOSYS_VER) $(GIT_REV)
echo "namespace Yosys { extern const char *yosys_version_str; const char *yosys_version_str=\"Yosys (Version Information Unavailable)\"; }" > kernel/version.cc
zip yosys-win32-vcxsrc-$(YOSYS_VER)/genfiles.zip $(GENFILES) kernel/version.cc
zip -r yosys-win32-vcxsrc-$(YOSYS_VER).zip yosys-win32-vcxsrc-$(YOSYS_VER)/
rm -f srcfiles.txt kernel/version.cc
config-clean: clean

2
abc

@ -1 +1 @@
Subproject commit 9182a8048d0bc86b39a6cb6b0488a7e1d10b2607
Subproject commit 1c5ed1ce378cc04beac30bb31abc4c37c8467042

View File

@ -24,7 +24,6 @@
#include "kernel/register.h"
#include "kernel/celltypes.h"
#include "kernel/rtlil.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
@ -846,14 +845,11 @@ struct XAigerAnalysis : Index<XAigerAnalysis, int, 0, 0> {
return false;
int max = 1;
for (auto wire : mod->wires()) {
if (wire->port_input && !wire->port_output) {
SigSpec port = driver->getPort(wire->name);
for (int i = 0; i < std::min(wire->width, port.size()); i++) {
int ilevel = visit(cursor, port[i]);
max = std::max(max, ilevel + 1);
}
}
for (auto wire : mod->wires())
if (wire->port_input && !wire->port_output)
for (int i = 0; i < wire->width; i++) {
int ilevel = visit(cursor, driver->getPort(wire->name)[i]);
max = std::max(max, ilevel + 1);
}
lits[idx] = max;

View File

@ -756,7 +756,7 @@ struct CxxrtlWorker {
// 1b. Generated identifiers for internal names (beginning with `$`) start with `i_`.
// 2. An underscore is escaped with another underscore, i.e. `__`.
// 3. Any other non-alnum character is escaped with underscores around its lowercase hex code, e.g. `@` as `_40_`.
std::string mangle_name(RTLIL::IdString name)
std::string mangle_name(const RTLIL::IdString &name)
{
std::string mangled;
bool first = true;
@ -786,7 +786,7 @@ struct CxxrtlWorker {
return mangled;
}
std::string mangle_module_name(RTLIL::IdString name, bool is_blackbox = false)
std::string mangle_module_name(const RTLIL::IdString &name, bool is_blackbox = false)
{
// Class namespace.
if (is_blackbox)
@ -794,19 +794,19 @@ struct CxxrtlWorker {
return mangle_name(name);
}
std::string mangle_memory_name(RTLIL::IdString name)
std::string mangle_memory_name(const RTLIL::IdString &name)
{
// Class member namespace.
return "memory_" + mangle_name(name);
}
std::string mangle_cell_name(RTLIL::IdString name)
std::string mangle_cell_name(const RTLIL::IdString &name)
{
// Class member namespace.
return "cell_" + mangle_name(name);
}
std::string mangle_wire_name(RTLIL::IdString name)
std::string mangle_wire_name(const RTLIL::IdString &name)
{
// Class member namespace.
return mangle_name(name);

View File

@ -188,27 +188,20 @@ struct SmtrModule {
Functional::IR ir;
SmtrScope scope;
std::string name;
bool use_assoc_list_helpers;
std::optional<std::string> input_helper_name;
std::optional<std::string> output_helper_name;
SmtrStruct input_struct;
SmtrStruct output_struct;
SmtrStruct state_struct;
SmtrModule(Module *module, bool assoc_list_helpers)
: ir(Functional::IR::from_module(module)), scope(), name(scope.unique_name(module->name)), use_assoc_list_helpers(assoc_list_helpers),
input_struct(scope.unique_name(module->name.str() + "_Inputs"), scope),
output_struct(scope.unique_name(module->name.str() + "_Outputs"), scope),
state_struct(scope.unique_name(module->name.str() + "_State"), scope)
SmtrModule(Module *module)
: ir(Functional::IR::from_module(module))
, scope()
, name(scope.unique_name(module->name))
, input_struct(scope.unique_name(module->name.str() + "_Inputs"), scope)
, output_struct(scope.unique_name(module->name.str() + "_Outputs"), scope)
, state_struct(scope.unique_name(module->name.str() + "_State"), scope)
{
scope.reserve(name + "_initial");
if (assoc_list_helpers) {
input_helper_name = scope.unique_name(module->name.str() + "_inputs_helper");
scope.reserve(*input_helper_name);
output_helper_name = scope.unique_name(module->name.str() + "_outputs_helper");
scope.reserve(*output_helper_name);
}
for (auto input : ir.inputs())
input_struct.insert(input->name, input->sort);
for (auto output : ir.outputs())
@ -264,45 +257,6 @@ struct SmtrModule {
w.pop();
}
void write_assoc_list_helpers(SExprWriter &w)
{
log_assert(output_helper_name && input_helper_name);
// Input struct keyword-based constructor.
w.push();
w.open(list("define"));
const auto inputs_name = "inputs";
w.open(list(*input_helper_name, inputs_name));
w.close();
w.open(list(input_struct.name));
for (auto input : ir.inputs()) {
w.push();
w.open(list("let"));
w.push();
w.open(list());
w.open(list("assoc-result"));
w << list("assoc", "\"" + RTLIL::unescape_id(input->name) + "\"", inputs_name);
w.pop();
w.open(list("if", "assoc-result"));
w << list("cdr", "assoc-result");
w.open(list("begin"));
w << list("fprintf", list("current-error-port"), "\"%s not found in inputs\"");
w << "'not-found";
w.pop();
}
w.pop();
// Output struct keyword-based destructuring
w.push();
w.open(list("define"));
const auto outputs_name = "outputs";
w << list(*output_helper_name, outputs_name);
w.open(list("list"));
for (auto output : ir.outputs()) {
w << list("cons", "\"" + RTLIL::unescape_id(output->name) + "\"", output_struct.access("outputs", output->name));
}
w.pop();
}
void write(std::ostream &out)
{
SExprWriter w(out);
@ -311,10 +265,6 @@ struct SmtrModule {
output_struct.write_definition(w);
state_struct.write_definition(w);
if (use_assoc_list_helpers) {
write_assoc_list_helpers(w);
}
write_eval(w);
write_initial(w);
}
@ -332,16 +282,12 @@ struct FunctionalSmtrBackend : public Backend {
log("\n");
log(" -provides\n");
log(" include 'provide' statement(s) for loading output as a module\n");
log(" -assoc-list-helpers\n");
log(" provide helper functions which convert inputs/outputs from/to association lists\n");
log(" \n");
log("\n");
}
void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) override
{
auto provides = false;
auto assoc_list_helpers = false;
log_header(design, "Executing Functional Rosette Backend.\n");
@ -350,8 +296,6 @@ struct FunctionalSmtrBackend : public Backend {
{
if (args[argidx] == "-provides")
provides = true;
else if (args[argidx] == "-assoc-list-helpers")
assoc_list_helpers = true;
else
break;
}
@ -363,8 +307,8 @@ struct FunctionalSmtrBackend : public Backend {
}
for (auto module : design->selected_modules()) {
log("Processing module `%s`.\n", module->name.c_str());
SmtrModule smtr(module, assoc_list_helpers);
log("Processing module `%s`.\n", module->name);
SmtrModule smtr(module);
smtr.write(*f);
}
}

View File

@ -61,9 +61,7 @@ void RTLIL_BACKEND::dump_const(std::ostream &f, const RTLIL::Const &data, int wi
return;
}
}
if ((data.flags & RTLIL::CONST_FLAG_UNSIZED) == 0) {
f << stringf("%d'", width);
}
f << stringf("%d'", width);
if (data.flags & RTLIL::CONST_FLAG_SIGNED) {
f << stringf("s");
}
@ -175,10 +173,9 @@ void RTLIL_BACKEND::dump_cell(std::ostream &f, std::string indent, const RTLIL::
dump_attributes(f, indent, cell);
f << stringf("%s" "cell %s %s\n", indent, cell->type, cell->name);
for (const auto& [name, param] : reversed(cell->parameters)) {
f << stringf("%s parameter%s%s%s %s ", indent,
f << stringf("%s parameter%s%s %s ", indent,
(param.flags & RTLIL::CONST_FLAG_SIGNED) != 0 ? " signed" : "",
(param.flags & RTLIL::CONST_FLAG_REAL) != 0 ? " real" : "",
(param.flags & RTLIL::CONST_FLAG_UNSIZED) != 0 ? " unsized" : "",
name);
dump_const(f, param);
f << stringf("\n");

View File

@ -108,30 +108,22 @@ IdString initial_id;
void reset_auto_counter_id(RTLIL::IdString id, bool may_rename)
{
auto it = id.begin();
auto it_end = id.end();
if (it == it_end)
return;
const char *str = id.c_str();
if (*it == '$' && may_rename && !norename)
if (*str == '$' && may_rename && !norename)
auto_name_map[id] = auto_name_counter++;
if (*it != '\\' || (it + 1) == it_end || *(it + 1) != '_' || (it + 2) == it_end)
if (str[0] != '\\' || str[1] != '_' || str[2] == 0)
return;
std::string s;
it += 2;
while (it != it_end) {
char ch = *it;
if (ch == '_' && (it + 1) == it_end)
break;
if (ch < '0' || ch > '9')
for (int i = 2; str[i] != 0; i++) {
if (str[i] == '_' && str[i+1] == 0)
continue;
if (str[i] < '0' || str[i] > '9')
return;
s.push_back(ch);
++it;
}
int num = atoi(s.c_str());
int num = atoi(str+2);
if (num >= auto_name_offset)
auto_name_offset = num + 1;
}

View File

@ -6,7 +6,7 @@ import os
project = 'YosysHQ Yosys'
author = 'YosysHQ GmbH'
copyright ='2025 YosysHQ GmbH'
yosys_ver = "0.60"
yosys_ver = "0.59"
# select HTML theme
html_theme = 'furo-ys'

View File

@ -110,8 +110,7 @@ struct Xaiger2Frontend : public Frontend {
for (int i = 0; i < (int) O; i++) {
int po;
*f >> po;
int c = f->get();
log_assert(c == '\n');
log_assert(f->get() == '\n');
outputs.push_back(po);
}

View File

@ -993,8 +993,6 @@ RTLIL::Const AstNode::asParaConst() const
RTLIL::Const val = asAttrConst();
if (is_signed)
val.flags |= RTLIL::CONST_FLAG_SIGNED;
if (is_unsized)
val.flags |= RTLIL::CONST_FLAG_UNSIZED;
return val;
}
@ -1768,10 +1766,7 @@ static std::string serialize_param_value(const RTLIL::Const &val) {
res.push_back('s');
if (val.flags & RTLIL::ConstFlags::CONST_FLAG_REAL)
res.push_back('r');
if (val.flags & RTLIL::ConstFlags::CONST_FLAG_UNSIZED)
res.push_back('u');
else
res += stringf("%d", GetSize(val));
res += stringf("%d", GetSize(val));
res.push_back('\'');
res.append(val.as_string("?"));
return res;
@ -1865,7 +1860,7 @@ std::string AstModule::derive_common(RTLIL::Design *design, const dict<RTLIL::Id
} else if ((it->second.flags & RTLIL::CONST_FLAG_STRING) != 0)
child->children[0] = AstNode::mkconst_str(loc, it->second.decode_string());
else
child->children[0] = AstNode::mkconst_bits(loc, it->second.to_bits(), (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0, (it->second.flags & RTLIL::CONST_FLAG_UNSIZED) != 0);
child->children[0] = AstNode::mkconst_bits(loc, it->second.to_bits(), (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0);
rewritten.insert(it->first);
}

View File

@ -844,7 +844,6 @@ struct AST_INTERNAL::ProcessGenerator
RTLIL::Cell *cell = current_module->addCell(cellname, ID($check));
set_src_attr(cell, ast);
cell->set_bool_attribute(ID(keep));
for (auto &attr : ast->attributes) {
if (attr.second->type != AST_CONSTANT)
log_file_error(*ast->location.begin.filename, ast->location.begin.line, "Attribute `%s' with non-constant value!\n", attr.first);

View File

@ -879,7 +879,7 @@ static void check_auto_nosync(AstNode *node)
}
// remove the attributes we've "consumed"
for (RTLIL::IdString str : attrs_to_drop) {
for (const RTLIL::IdString &str : attrs_to_drop) {
auto it = node->attributes.find(str);
node->attributes.erase(it);
}
@ -2265,13 +2265,9 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin
}
if (children[0]->type == AST_CONSTANT) {
if (width != int(children[0]->bits.size())) {
RTLIL::Const val;
if (children[0]->is_unsized) {
val = children[0]->bitsAsUnsizedConst(width);
} else {
val = children[0]->bitsAsConst(width);
}
children[0] = mkconst_bits(location, val.to_bits(), is_signed);
RTLIL::SigSpec sig(children[0]->bits);
sig.extend_u0(width, children[0]->is_signed);
children[0] = mkconst_bits(location, sig.as_const().to_bits(), is_signed);
fixup_hierarchy_flags();
}
children[0]->is_signed = is_signed;

View File

@ -245,7 +245,7 @@ void parse_blif(RTLIL::Design *design, std::istream &f, IdString dff_name, bool
if (undef_wire != nullptr)
module->rename(undef_wire, stringf("$undef$%d", ++blif_maxnum));
autoidx.ensure_at_least(blif_maxnum+1);
autoidx = std::max(autoidx, blif_maxnum+1);
blif_maxnum = 0;
}

View File

@ -40,14 +40,14 @@ static RTLIL::SigSpec parse_func_identifier(RTLIL::Module *module, const char *&
expr[id_len] == '_' || expr[id_len] == '[' || expr[id_len] == ']') id_len++;
if (id_len == 0)
log_error("Expected identifier at `%s' in %s.\n", expr, RTLIL::unescape_id(module->name));
log_error("Expected identifier at `%s'.\n", expr);
if (id_len == 1 && (*expr == '0' || *expr == '1'))
return *(expr++) == '0' ? RTLIL::State::S0 : RTLIL::State::S1;
std::string id = RTLIL::escape_id(std::string(expr, id_len));
if (!module->wires_.count(id))
log_error("Can't resolve wire name %s in %s.\n", RTLIL::unescape_id(id), RTLIL::unescape_id(module->name));
log_error("Can't resolve wire name %s.\n", RTLIL::unescape_id(id));
expr += id_len;
return module->wires_.at(id);
@ -174,7 +174,7 @@ static RTLIL::SigSpec parse_func_expr(RTLIL::Module *module, const char *expr)
#endif
if (stack.size() != 1 || stack.back().type != 3)
log_error("Parser error in function expr `%s'in %s.\n", orig_expr, RTLIL::unescape_id(module->name));
log_error("Parser error in function expr `%s'.\n", orig_expr);
return stack.back().sig;
}
@ -191,23 +191,11 @@ static RTLIL::SigSpec create_tristate(RTLIL::Module *module, RTLIL::SigSpec func
return cell->getPort(ID::Y);
}
static void create_latch_ff_wires(RTLIL::Module *module, const LibertyAst *node)
{
module->addWire(RTLIL::escape_id(node->args.at(0)));
module->addWire(RTLIL::escape_id(node->args.at(1)));
}
static std::pair<RTLIL::SigSpec, RTLIL::SigSpec> find_latch_ff_wires(RTLIL::Module *module, const LibertyAst *node)
{
auto* iq_wire = module->wire(RTLIL::escape_id(node->args.at(0)));
auto* iqn_wire = module->wire(RTLIL::escape_id(node->args.at(1)));
log_assert(iq_wire && iqn_wire);
return std::make_pair(iq_wire, iqn_wire);
}
static void create_ff(RTLIL::Module *module, const LibertyAst *node)
{
auto [iq_sig, iqn_sig] = find_latch_ff_wires(module, node);
RTLIL::SigSpec iq_sig(module->addWire(RTLIL::escape_id(node->args.at(0))));
RTLIL::SigSpec iqn_sig(module->addWire(RTLIL::escape_id(node->args.at(1))));
RTLIL::SigSpec clk_sig, data_sig, clear_sig, preset_sig;
bool clk_polarity = true, clear_polarity = true, preset_polarity = true;
@ -223,7 +211,7 @@ static void create_ff(RTLIL::Module *module, const LibertyAst *node)
}
if (clk_sig.size() == 0 || data_sig.size() == 0)
log_error("FF cell %s has no next_state and/or clocked_on attribute.\n", RTLIL::unescape_id(module->name));
log_error("FF cell %s has no next_state and/or clocked_on attribute.\n", log_id(module->name));
for (bool rerun_invert_rollback = true; rerun_invert_rollback;)
{
@ -282,7 +270,9 @@ static void create_ff(RTLIL::Module *module, const LibertyAst *node)
static bool create_latch(RTLIL::Module *module, const LibertyAst *node, bool flag_ignore_miss_data_latch)
{
auto [iq_sig, iqn_sig] = find_latch_ff_wires(module, node);
RTLIL::SigSpec iq_sig(module->addWire(RTLIL::escape_id(node->args.at(0))));
RTLIL::SigSpec iqn_sig(module->addWire(RTLIL::escape_id(node->args.at(1))));
RTLIL::SigSpec enable_sig, data_sig, clear_sig, preset_sig;
bool enable_polarity = true, clear_polarity = true, preset_polarity = true;
@ -299,9 +289,9 @@ static bool create_latch(RTLIL::Module *module, const LibertyAst *node, bool fla
if (enable_sig.size() == 0 || data_sig.size() == 0) {
if (!flag_ignore_miss_data_latch)
log_error("Latch cell %s has no data_in and/or enable attribute.\n", RTLIL::unescape_id(module->name));
log_error("Latch cell %s has no data_in and/or enable attribute.\n", log_id(module->name));
else
log("Ignored latch cell %s with no data_in and/or enable attribute.\n", RTLIL::unescape_id(module->name));
log("Ignored latch cell %s with no data_in and/or enable attribute.\n", log_id(module->name));
return false;
}
@ -592,9 +582,9 @@ struct LibertyFrontend : public Frontend {
{
if (!flag_ignore_miss_dir)
{
log_error("Missing or invalid direction for pin %s on cell %s.\n", node->args.at(0), RTLIL::unescape_id(module->name));
log_error("Missing or invalid direction for pin %s on cell %s.\n", node->args.at(0), log_id(module->name));
} else {
log("Ignoring cell %s with missing or invalid direction for pin %s.\n", RTLIL::unescape_id(module->name), node->args.at(0));
log("Ignoring cell %s with missing or invalid direction for pin %s.\n", log_id(module->name), node->args.at(0));
delete module;
goto skip_cell;
}
@ -606,13 +596,13 @@ struct LibertyFrontend : public Frontend {
if (node->id == "bus" && node->args.size() == 1)
{
if (flag_ignore_buses) {
log("Ignoring cell %s with a bus interface %s.\n", RTLIL::unescape_id(module->name), node->args.at(0));
log("Ignoring cell %s with a bus interface %s.\n", log_id(module->name), node->args.at(0));
delete module;
goto skip_cell;
}
if (!flag_lib)
log_error("Error in cell %s: bus interfaces are only supported in -lib mode.\n", RTLIL::unescape_id(cell_name));
log_error("Error in cell %s: bus interfaces are only supported in -lib mode.\n", log_id(cell_name));
const LibertyAst *dir = node->find("direction");
@ -623,7 +613,7 @@ struct LibertyFrontend : public Frontend {
}
if (!dir || (dir->value != "input" && dir->value != "output" && dir->value != "inout" && dir->value != "internal"))
log_error("Missing or invalid direction for bus %s on cell %s.\n", node->args.at(0), RTLIL::unescape_id(module->name));
log_error("Missing or invalid direction for bus %s on cell %s.\n", node->args.at(0), log_id(module->name));
simple_comb_cell = false;
@ -634,7 +624,7 @@ struct LibertyFrontend : public Frontend {
if (!bus_type_node || !type_map.count(bus_type_node->value))
log_error("Unknown or unsupported type for bus interface %s on cell %s.\n",
node->args.at(0).c_str(), RTLIL::unescape_id(cell_name));
node->args.at(0).c_str(), log_id(cell_name));
int bus_type_width = std::get<0>(type_map.at(bus_type_node->value));
int bus_type_offset = std::get<1>(type_map.at(bus_type_node->value));
@ -656,13 +646,6 @@ struct LibertyFrontend : public Frontend {
{
// some liberty files do not put ff/latch at the beginning of a cell
// try to find "ff" or "latch" and create FF/latch _before_ processing all other nodes
// but first, in case of balloon retention cells, we need all ff/latch output wires
// defined before we add ff/latch cells
for (auto node : cell->children)
{
if ((node->id == "ff" && node->args.size() == 2) || (node->id == "latch" && node->args.size() == 2))
create_latch_ff_wires(module, node);
}
for (auto node : cell->children)
{
if (node->id == "ff" && node->args.size() == 2)
@ -718,9 +701,9 @@ struct LibertyFrontend : public Frontend {
if (dir->value != "inout") { // allow inout with missing function, can be used for power pins
if (!flag_ignore_miss_func)
{
log_error("Missing function on output %s of cell %s.\n", RTLIL::unescape_id(wire->name), RTLIL::unescape_id(module->name));
log_error("Missing function on output %s of cell %s.\n", log_id(wire->name), log_id(module->name));
} else {
log("Ignoring cell %s with missing function on output %s.\n", RTLIL::unescape_id(module->name), RTLIL::unescape_id(wire->name));
log("Ignoring cell %s with missing function on output %s.\n", log_id(module->name), log_id(wire->name));
delete module;
goto skip_cell;
}
@ -774,13 +757,13 @@ struct LibertyFrontend : public Frontend {
if (design->has(cell_name)) {
Module *existing_mod = design->module(cell_name);
if (!flag_nooverwrite && !flag_overwrite && !existing_mod->get_bool_attribute(ID::blackbox)) {
log_error("Re-definition of cell/module %s!\n", RTLIL::unescape_id(cell_name));
log_error("Re-definition of cell/module %s!\n", log_id(cell_name));
} else if (flag_nooverwrite) {
log("Ignoring re-definition of module %s.\n", RTLIL::unescape_id(cell_name));
log("Ignoring re-definition of module %s.\n", log_id(cell_name));
delete module;
goto skip_cell;
} else {
log("Replacing existing%s module %s.\n", existing_mod->get_bool_attribute(ID::blackbox) ? " blackbox" : "", RTLIL::unescape_id(cell_name));
log("Replacing existing%s module %s.\n", existing_mod->get_bool_attribute(ID::blackbox) ? " blackbox" : "", log_id(cell_name));
design->remove(existing_mod);
}
}

View File

@ -567,13 +567,10 @@ struct RTLILFrontendWorker {
if (try_parse_keyword("parameter")) {
bool is_signed = false;
bool is_real = false;
bool is_unsized = false;
if (try_parse_keyword("signed")) {
is_signed = true;
} else if (try_parse_keyword("real")) {
is_real = true;
} else if (try_parse_keyword("unsized")) {
is_unsized = true;
}
RTLIL::IdString param_name = parse_id();
RTLIL::Const val = parse_const();
@ -581,8 +578,6 @@ struct RTLILFrontendWorker {
val.flags |= RTLIL::CONST_FLAG_SIGNED;
if (is_real)
val.flags |= RTLIL::CONST_FLAG_REAL;
if (is_unsized)
val.flags |= RTLIL::CONST_FLAG_UNSIZED;
cell->parameters.insert({std::move(param_name), std::move(val)});
expect_eol();
} else if (try_parse_keyword("connect")) {

View File

@ -1846,10 +1846,7 @@ struct VerificSvaImporter
if (mode_assume) c = module->addAssume(root_name, sig_a_q, sig_en_q);
if (mode_cover) c = module->addCover(root_name, sig_a_q, sig_en_q);
if (c) {
c->set_bool_attribute(ID(keep));
importer->import_attributes(c->attributes, root);
}
if (c) importer->import_attributes(c->attributes, root);
}
}
catch (ParserErrorException)

View File

@ -185,68 +185,50 @@ struct AigMaker
int or_gate(int A, int B)
{
int not_a = not_gate(A);
int not_b = not_gate(B);
return nand_gate(not_a, not_b);
return nand_gate(not_gate(A), not_gate(B));
}
int nor_gate(int A, int B)
{
int not_a = not_gate(A);
int not_b = not_gate(B);
return and_gate(not_a, not_b);
return and_gate(not_gate(A), not_gate(B));
}
int xor_gate(int A, int B)
{
int a_and_b = and_gate(A, B);
int a_nor_b = nor_gate(A, B);
return nor_gate(a_and_b, a_nor_b);
return nor_gate(and_gate(A, B), nor_gate(A, B));
}
int xnor_gate(int A, int B)
{
int a_and_b = and_gate(A, B);
int a_nor_b = nor_gate(A, B);
return or_gate(a_and_b, a_nor_b);
return or_gate(and_gate(A, B), nor_gate(A, B));
}
int andnot_gate(int A, int B)
{
int not_b = not_gate(B);
return and_gate(A, not_b);
return and_gate(A, not_gate(B));
}
int ornot_gate(int A, int B)
{
int not_b = not_gate(B);
return or_gate(A, not_b);
return or_gate(A, not_gate(B));
}
int mux_gate(int A, int B, int S)
{
int not_s = not_gate(S);
int a_active = and_gate(A, not_s);
int b_active = and_gate(B, S);
return or_gate(a_active, b_active);
return or_gate(and_gate(A, not_gate(S)), and_gate(B, S));
}
vector<int> adder(const vector<int> &A, const vector<int> &B, int carry_in, vector<int> *X = nullptr, vector<int> *CO = nullptr)
vector<int> adder(const vector<int> &A, const vector<int> &B, int carry, vector<int> *X = nullptr, vector<int> *CO = nullptr)
{
vector<int> Y(GetSize(A));
log_assert(GetSize(A) == GetSize(B));
for (int i = 0; i < GetSize(A); i++) {
int a_xor_b = xor_gate(A[i], B[i]);
int a_or_b = or_gate(A[i], B[i]);
int a_and_b = and_gate(A[i], B[i]);
Y[i] = xor_gate(a_xor_b, carry_in);
int tmp = and_gate(a_or_b, carry_in);
int carry_out = or_gate(a_and_b, tmp);
Y[i] = xor_gate(xor_gate(A[i], B[i]), carry);
carry = or_gate(and_gate(A[i], B[i]), and_gate(or_gate(A[i], B[i]), carry));
if (X != nullptr)
X->at(i) = a_xor_b;
X->at(i) = xor_gate(A[i], B[i]);
if (CO != nullptr)
CO->at(i) = carry_out;
carry_in = carry_out;
CO->at(i) = carry;
}
return Y;
}
@ -325,13 +307,13 @@ Aig::Aig(Cell *cell)
int A = mk.inport(ID::A, i);
int B = mk.inport(ID::B, i);
int Y = cell->type.in(ID($and), ID($_AND_)) ? mk.and_gate(A, B) :
cell->type.in(ID($_NAND_)) ? mk.nand_gate(A, B) :
cell->type.in(ID($_NAND_)) ? mk.nand_gate(A, B) :
cell->type.in(ID($or), ID($_OR_)) ? mk.or_gate(A, B) :
cell->type.in(ID($_NOR_)) ? mk.nor_gate(A, B) :
cell->type.in(ID($_NOR_)) ? mk.nor_gate(A, B) :
cell->type.in(ID($xor), ID($_XOR_)) ? mk.xor_gate(A, B) :
cell->type.in(ID($xnor), ID($_XNOR_)) ? mk.xnor_gate(A, B) :
cell->type.in(ID($_ANDNOT_)) ? mk.andnot_gate(A, B) :
cell->type.in(ID($_ORNOT_)) ? mk.ornot_gate(A, B) : -1;
cell->type.in(ID($_ANDNOT_)) ? mk.andnot_gate(A, B) :
cell->type.in(ID($_ORNOT_)) ? mk.ornot_gate(A, B) : -1;
mk.outport(Y, ID::Y, i);
}
goto optimize;
@ -483,8 +465,7 @@ Aig::Aig(Cell *cell)
int B = mk.inport(ID::B);
int C = mk.inport(ID::C);
int D = mk.inport(ID::D);
int a_and_b = mk.and_gate(A, B);
int Y = mk.nor_gate(a_and_b, mk.and_gate(C, D));
int Y = mk.nor_gate(mk.and_gate(A, B), mk.and_gate(C, D));
mk.outport(Y, ID::Y);
goto optimize;
}
@ -495,8 +476,7 @@ Aig::Aig(Cell *cell)
int B = mk.inport(ID::B);
int C = mk.inport(ID::C);
int D = mk.inport(ID::D);
int a_or_b = mk.or_gate(A, B);
int Y = mk.nand_gate(a_or_b, mk.or_gate(C, D));
int Y = mk.nand_gate(mk.or_gate(A, B), mk.or_gate(C, D));
mk.outport(Y, ID::Y);
goto optimize;
}

View File

@ -305,18 +305,18 @@ struct CellTypes
cell_types.clear();
}
bool cell_known(RTLIL::IdString type) const
bool cell_known(const RTLIL::IdString &type) const
{
return cell_types.count(type) != 0;
}
bool cell_output(RTLIL::IdString type, RTLIL::IdString port) const
bool cell_output(const RTLIL::IdString &type, const RTLIL::IdString &port) const
{
auto it = cell_types.find(type);
return it != cell_types.end() && it->second.outputs.count(port) != 0;
}
bool cell_input(RTLIL::IdString type, RTLIL::IdString port) const
bool cell_input(const RTLIL::IdString &type, const RTLIL::IdString &port) const
{
auto it = cell_types.find(type);
return it != cell_types.end() && it->second.inputs.count(port) != 0;
@ -332,7 +332,7 @@ struct CellTypes
return RTLIL::PortDir(is_input + is_output * 2);
}
bool cell_evaluable(RTLIL::IdString type) const
bool cell_evaluable(const RTLIL::IdString &type) const
{
auto it = cell_types.find(type);
return it != cell_types.end() && it->second.is_evaluable;

View File

@ -196,7 +196,6 @@ X($bweqx)
X($bwmux)
X($check)
X($concat)
X($connect)
X($cover)
X($demux)
X($dff)
@ -223,7 +222,6 @@ X($get_tag)
X($gt)
X($initstate)
X($input)
X($input_port)
X($lcu)
X($le)
X($live)

View File

@ -188,7 +188,7 @@ extern char yosys_path[PATH_MAX];
#endif
#ifdef YOSYS_ENABLE_TCL
namespace Yosys {
extern int yosys_tcl_interp_init(Tcl_Interp *interp);
extern int yosys_tcl_iterp_init(Tcl_Interp *interp);
extern void yosys_tcl_activate_repl();
};
#endif
@ -255,7 +255,6 @@ int main(int argc, char **argv)
("h,help", "print this help message. If given, print help for <command>.",
cxxopts::value<std::string>(), "[<command>]")
("V,version", "print version information and exit")
("git-hash", "print git commit hash and exit")
("infile", "input files", cxxopts::value<std::vector<std::string>>())
;
options.add_options("logging")
@ -333,10 +332,6 @@ int main(int argc, char **argv)
std::cout << yosys_version_str << std::endl;
exit(0);
}
if (result.count("git-hash")) {
std::cout << yosys_git_hash_str << std::endl;
exit(0);
}
if (result.count("S")) {
passes_commands.push_back("synth");
run_shell = false;
@ -615,7 +610,7 @@ int main(int argc, char **argv)
if (run_tcl_shell) {
#ifdef YOSYS_ENABLE_TCL
yosys_tcl_activate_repl();
Tcl_Main(argc, argv, yosys_tcl_interp_init);
Tcl_Main(argc, argv, yosys_tcl_iterp_init);
#else
log_error("Can't exectue TCL shell: this version of yosys is not built with TCL support enabled.\n");
#endif
@ -711,16 +706,9 @@ int main(int argc, char **argv)
for (auto &it : pass_register)
if (it.second->call_counter) {
auto pass_ns = it.second->runtime_ns + 1;
total_ns += pass_ns;
timedat.insert(make_tuple(pass_ns, it.second->call_counter, it.first));
total_ns += it.second->runtime_ns + 1;
timedat.insert(make_tuple(it.second->runtime_ns + 1, it.second->call_counter, it.first));
}
{
auto gc_ns = RTLIL::OwningIdString::garbage_collection_ns() + 1;
total_ns += gc_ns;
timedat.insert(make_tuple(gc_ns,
RTLIL::OwningIdString::garbage_collection_count(), "id_gc"));
}
if (timing_details)
{
@ -769,6 +757,33 @@ int main(int argc, char **argv)
}
}
#if defined(YOSYS_ENABLE_COVER) && (defined(__linux__) || defined(__FreeBSD__))
if (getenv("YOSYS_COVER_DIR") || getenv("YOSYS_COVER_FILE"))
{
string filename;
FILE *f;
if (getenv("YOSYS_COVER_DIR")) {
filename = stringf("%s/yosys_cover_%d_XXXXXX.txt", getenv("YOSYS_COVER_DIR"), getpid());
filename = make_temp_file(filename);
} else {
filename = getenv("YOSYS_COVER_FILE");
}
f = fopen(filename.c_str(), "a+");
if (f == NULL)
log_error("Can't create coverage file `%s'.\n", filename);
log("<writing coverage file \"%s\">\n", filename);
for (auto &it : get_coverage_data())
fprintf(f, "%-60s %10d %s\n", it.second.first.c_str(), it.second.second, it.first.c_str());
fclose(f);
}
#endif
log_check_expected();
yosys_atexit();

View File

@ -21,316 +21,245 @@
USING_YOSYS_NAMESPACE
// sorry
template<typename InputType, typename OutputType, typename = std::enable_if_t<std::is_base_of_v<FfTypeData, OutputType>>>
void manufacture_info(InputType flop, OutputType& info, FfInitVals *initvals) {
Cell* cell = nullptr;
IdString type;
constexpr bool have_cell = std::is_same_v<InputType, Cell*>;
if constexpr (std::is_same_v<InputType, IdString>) {
type = flop;
} else {
static_assert(std::is_same_v<InputType, Cell*>);
cell = flop;
type = flop->type;
}
if constexpr (have_cell) {
info.sig_q = cell->getPort(ID::Q);
info.width = GetSize(info.sig_q);
info.attributes = cell->attributes;
if (initvals)
info.val_init = (*initvals)(info.sig_q);
}
std::string type_str = type.str();
if (type.in(ID($anyinit), ID($ff), ID($dff), ID($dffe), ID($dffsr), ID($dffsre), ID($adff), ID($adffe), ID($aldff), ID($aldffe), ID($sdff), ID($sdffe), ID($sdffce), ID($dlatch), ID($adlatch), ID($dlatchsr), ID($sr))) {
if (type.in(ID($anyinit), ID($ff))) {
info.has_gclk = true;
if constexpr (have_cell)
info.sig_d = cell->getPort(ID::D);
if (type == ID($anyinit)) {
info.is_anyinit = true;
if constexpr (have_cell)
log_assert(info.val_init.is_fully_undef());
}
} else if (type == ID($sr)) {
// No data input at all.
} else if (type.in(ID($dlatch), ID($adlatch), ID($dlatchsr))) {
info.has_aload = true;
if constexpr (have_cell) {
info.sig_aload = cell->getPort(ID::EN);
info.pol_aload = cell->getParam(ID::EN_POLARITY).as_bool();
info.sig_ad = cell->getPort(ID::D);
}
} else {
info.has_clk = true;
if constexpr (have_cell) {
info.sig_clk = cell->getPort(ID::CLK);
info.pol_clk = cell->getParam(ID::CLK_POLARITY).as_bool();
info.sig_d = cell->getPort(ID::D);
}
}
if (type.in(ID($dffe), ID($dffsre), ID($adffe), ID($aldffe), ID($sdffe), ID($sdffce))) {
info.has_ce = true;
if constexpr (have_cell) {
info.sig_ce = cell->getPort(ID::EN);
info.pol_ce = cell->getParam(ID::EN_POLARITY).as_bool();
}
}
if (type.in(ID($dffsr), ID($dffsre), ID($dlatchsr), ID($sr))) {
info.has_sr = true;
if constexpr (have_cell) {
info.sig_clr = cell->getPort(ID::CLR);
info.sig_set = cell->getPort(ID::SET);
info.pol_clr = cell->getParam(ID::CLR_POLARITY).as_bool();
info.pol_set = cell->getParam(ID::SET_POLARITY).as_bool();
}
}
if (type.in(ID($aldff), ID($aldffe))) {
info.has_aload = true;
if constexpr (have_cell) {
info.sig_aload = cell->getPort(ID::ALOAD);
info.pol_aload = cell->getParam(ID::ALOAD_POLARITY).as_bool();
info.sig_ad = cell->getPort(ID::AD);
}
}
if (type.in(ID($adff), ID($adffe), ID($adlatch))) {
info.has_arst = true;
if constexpr (have_cell) {
info.sig_arst = cell->getPort(ID::ARST);
info.pol_arst = cell->getParam(ID::ARST_POLARITY).as_bool();
info.val_arst = cell->getParam(ID::ARST_VALUE);
}
}
if (type.in(ID($sdff), ID($sdffe), ID($sdffce))) {
info.has_srst = true;
if constexpr (have_cell) {
info.sig_srst = cell->getPort(ID::SRST);
info.pol_srst = cell->getParam(ID::SRST_POLARITY).as_bool();
info.val_srst = cell->getParam(ID::SRST_VALUE);
}
info.ce_over_srst = type == ID($sdffce);
}
} else if (type == ID($_FF_)) {
info.is_fine = true;
info.has_gclk = true;
if constexpr (have_cell)
info.sig_d = cell->getPort(ID::D);
} else if (type_str.substr(0, 5) == "$_SR_") {
info.is_fine = true;
info.has_sr = true;
info.pol_set = type_str[5] == 'P';
info.pol_clr = type_str[6] == 'P';
if constexpr (have_cell) {
info.sig_set = cell->getPort(ID::S);
info.sig_clr = cell->getPort(ID::R);
}
} else if (type_str.substr(0, 6) == "$_DFF_" && type_str.size() == 8) {
info.is_fine = true;
info.has_clk = true;
info.pol_clk = type_str[6] == 'P';
if constexpr (have_cell) {
info.sig_d = cell->getPort(ID::D);
info.sig_clk = cell->getPort(ID::C);
}
} else if (type_str.substr(0, 7) == "$_DFFE_" && type_str.size() == 10) {
info.is_fine = true;
info.has_clk = true;
info.pol_clk = type_str[7] == 'P';
info.has_ce = true;
info.pol_ce = type_str[8] == 'P';
if constexpr (have_cell) {
info.sig_d = cell->getPort(ID::D);
info.sig_clk = cell->getPort(ID::C);
info.sig_ce = cell->getPort(ID::E);
}
} else if (type_str.substr(0, 6) == "$_DFF_" && type_str.size() == 10) {
info.is_fine = true;
info.has_clk = true;
info.pol_clk = type_str[6] == 'P';
info.has_arst = true;
info.pol_arst = type_str[7] == 'P';
info.val_arst = type_str[8] == '1' ? State::S1 : State::S0;
if constexpr (have_cell) {
info.sig_d = cell->getPort(ID::D);
info.sig_clk = cell->getPort(ID::C);
info.sig_arst = cell->getPort(ID::R);
}
} else if (type_str.substr(0, 7) == "$_DFFE_" && type_str.size() == 12) {
info.is_fine = true;
info.has_clk = true;
info.pol_clk = type_str[7] == 'P';
info.has_arst = true;
info.pol_arst = type_str[8] == 'P';
info.val_arst = type_str[9] == '1' ? State::S1 : State::S0;
info.has_ce = true;
info.pol_ce = type_str[10] == 'P';
if constexpr (have_cell) {
info.sig_d = cell->getPort(ID::D);
info.sig_clk = cell->getPort(ID::C);
info.sig_arst = cell->getPort(ID::R);
info.sig_ce = cell->getPort(ID::E);
}
} else if (type_str.substr(0, 8) == "$_ALDFF_" && type_str.size() == 11) {
info.is_fine = true;
info.has_clk = true;
info.pol_clk = type_str[8] == 'P';
info.has_aload = true;
info.pol_aload = type_str[9] == 'P';
if constexpr (have_cell) {
info.sig_d = cell->getPort(ID::D);
info.sig_clk = cell->getPort(ID::C);
info.sig_aload = cell->getPort(ID::L);
info.sig_ad = cell->getPort(ID::AD);
}
} else if (type_str.substr(0, 9) == "$_ALDFFE_" && type_str.size() == 13) {
info.is_fine = true;
info.has_clk = true;
info.pol_clk = type_str[9] == 'P';
info.has_aload = true;
info.pol_aload = type_str[10] == 'P';
info.has_ce = true;
info.pol_ce = type_str[11] == 'P';
if constexpr (have_cell) {
info.sig_d = cell->getPort(ID::D);
info.sig_clk = cell->getPort(ID::C);
info.sig_aload = cell->getPort(ID::L);
info.sig_ad = cell->getPort(ID::AD);
info.sig_ce = cell->getPort(ID::E);
}
} else if (type_str.substr(0, 8) == "$_DFFSR_" && type_str.size() == 12) {
info.is_fine = true;
info.has_clk = true;
info.pol_clk = type_str[8] == 'P';
info.has_sr = true;
info.pol_set = type_str[9] == 'P';
info.pol_clr = type_str[10] == 'P';
if constexpr (have_cell) {
info.sig_d = cell->getPort(ID::D);
info.sig_clk = cell->getPort(ID::C);
info.sig_set = cell->getPort(ID::S);
info.sig_clr = cell->getPort(ID::R);
}
} else if (type_str.substr(0, 9) == "$_DFFSRE_" && type_str.size() == 14) {
info.is_fine = true;
info.has_clk = true;
info.pol_clk = type_str[9] == 'P';
info.has_sr = true;
info.pol_set = type_str[10] == 'P';
info.pol_clr = type_str[11] == 'P';
info.has_ce = true;
info.pol_ce = type_str[12] == 'P';
if constexpr (have_cell) {
info.sig_d = cell->getPort(ID::D);
info.sig_clk = cell->getPort(ID::C);
info.sig_set = cell->getPort(ID::S);
info.sig_clr = cell->getPort(ID::R);
info.sig_ce = cell->getPort(ID::E);
}
} else if (type_str.substr(0, 7) == "$_SDFF_" && type_str.size() == 11) {
info.is_fine = true;
info.has_clk = true;
info.pol_clk = type_str[7] == 'P';
info.has_srst = true;
info.pol_srst = type_str[8] == 'P';
info.val_srst = type_str[9] == '1' ? State::S1 : State::S0;
if constexpr (have_cell) {
info.sig_d = cell->getPort(ID::D);
info.sig_clk = cell->getPort(ID::C);
info.sig_srst = cell->getPort(ID::R);
}
} else if (type_str.substr(0, 8) == "$_SDFFE_" && type_str.size() == 13) {
info.is_fine = true;
info.has_clk = true;
info.pol_clk = type_str[8] == 'P';
info.has_srst = true;
info.pol_srst = type_str[9] == 'P';
info.val_srst = type_str[10] == '1' ? State::S1 : State::S0;
info.has_ce = true;
info.pol_ce = type_str[11] == 'P';
if constexpr (have_cell) {
info.sig_d = cell->getPort(ID::D);
info.sig_clk = cell->getPort(ID::C);
info.sig_srst = cell->getPort(ID::R);
info.sig_ce = cell->getPort(ID::E);
}
} else if (type_str.substr(0, 9) == "$_SDFFCE_" && type_str.size() == 14) {
info.is_fine = true;
info.has_clk = true;
info.pol_clk = type_str[9] == 'P';
info.has_srst = true;
info.pol_srst = type_str[10] == 'P';
info.val_srst = type_str[11] == '1' ? State::S1 : State::S0;
info.has_ce = true;
info.pol_ce = type_str[12] == 'P';
info.ce_over_srst = true;
if constexpr (have_cell) {
info.sig_d = cell->getPort(ID::D);
info.sig_clk = cell->getPort(ID::C);
info.sig_srst = cell->getPort(ID::R);
info.sig_ce = cell->getPort(ID::E);
}
} else if (type_str.substr(0, 9) == "$_DLATCH_" && type_str.size() == 11) {
info.is_fine = true;
info.has_aload = true;
info.has_aload = true;
info.pol_aload = type_str[9] == 'P';
if constexpr (have_cell) {
info.sig_ad = cell->getPort(ID::D);
info.sig_aload = cell->getPort(ID::E);
}
} else if (type_str.substr(0, 9) == "$_DLATCH_" && type_str.size() == 13) {
info.is_fine = true;
info.has_aload = true;
info.has_aload = true;
info.pol_aload = type_str[9] == 'P';
info.has_arst = true;
info.pol_arst = type_str[10] == 'P';
info.val_arst = type_str[11] == '1' ? State::S1 : State::S0;
if constexpr (have_cell) {
info.sig_ad = cell->getPort(ID::D);
info.sig_aload = cell->getPort(ID::E);
info.sig_arst = cell->getPort(ID::R);
}
} else if (type_str.substr(0, 11) == "$_DLATCHSR_" && type_str.size() == 15) {
info.is_fine = true;
info.has_aload = true;
info.has_aload = true;
info.pol_aload = type_str[11] == 'P';
info.has_sr = true;
info.pol_set = type_str[12] == 'P';
info.pol_clr = type_str[13] == 'P';
if constexpr (have_cell) {
info.sig_ad = cell->getPort(ID::D);
info.sig_aload = cell->getPort(ID::E);
info.sig_set = cell->getPort(ID::S);
info.sig_clr = cell->getPort(ID::R);
}
} else {
log_assert(0);
}
if constexpr (have_cell)
if (info.has_aload && !info.has_clk && !info.has_sr && !info.has_arst && info.sig_ad.is_fully_const()) {
// Plain D latches with const D treated specially.
info.has_aload = false;
info.has_arst = true;
info.sig_arst = info.sig_aload;
info.pol_arst = info.pol_aload;
info.val_arst = info.sig_ad.as_const();
}
}
FfTypeData::FfTypeData(IdString type) : FfTypeData()
{
manufacture_info(type, *this, nullptr);
}
FfData::FfData(FfInitVals *initvals, Cell *cell_) : FfData(cell_->module, initvals, cell_->name)
{
cell = cell_;
manufacture_info(cell, *this, initvals);
sig_q = cell->getPort(ID::Q);
width = GetSize(sig_q);
attributes = cell->attributes;
if (initvals)
val_init = (*initvals)(sig_q);
std::string type_str = cell->type.str();
if (cell->type.in(ID($anyinit), ID($ff), ID($dff), ID($dffe), ID($dffsr), ID($dffsre), ID($adff), ID($adffe), ID($aldff), ID($aldffe), ID($sdff), ID($sdffe), ID($sdffce), ID($dlatch), ID($adlatch), ID($dlatchsr), ID($sr))) {
if (cell->type.in(ID($anyinit), ID($ff))) {
has_gclk = true;
sig_d = cell->getPort(ID::D);
if (cell->type == ID($anyinit)) {
is_anyinit = true;
log_assert(val_init.is_fully_undef());
}
} else if (cell->type == ID($sr)) {
// No data input at all.
} else if (cell->type.in(ID($dlatch), ID($adlatch), ID($dlatchsr))) {
has_aload = true;
sig_aload = cell->getPort(ID::EN);
pol_aload = cell->getParam(ID::EN_POLARITY).as_bool();
sig_ad = cell->getPort(ID::D);
} else {
has_clk = true;
sig_clk = cell->getPort(ID::CLK);
pol_clk = cell->getParam(ID::CLK_POLARITY).as_bool();
sig_d = cell->getPort(ID::D);
}
if (cell->type.in(ID($dffe), ID($dffsre), ID($adffe), ID($aldffe), ID($sdffe), ID($sdffce))) {
has_ce = true;
sig_ce = cell->getPort(ID::EN);
pol_ce = cell->getParam(ID::EN_POLARITY).as_bool();
}
if (cell->type.in(ID($dffsr), ID($dffsre), ID($dlatchsr), ID($sr))) {
has_sr = true;
sig_clr = cell->getPort(ID::CLR);
sig_set = cell->getPort(ID::SET);
pol_clr = cell->getParam(ID::CLR_POLARITY).as_bool();
pol_set = cell->getParam(ID::SET_POLARITY).as_bool();
}
if (cell->type.in(ID($aldff), ID($aldffe))) {
has_aload = true;
sig_aload = cell->getPort(ID::ALOAD);
pol_aload = cell->getParam(ID::ALOAD_POLARITY).as_bool();
sig_ad = cell->getPort(ID::AD);
}
if (cell->type.in(ID($adff), ID($adffe), ID($adlatch))) {
has_arst = true;
sig_arst = cell->getPort(ID::ARST);
pol_arst = cell->getParam(ID::ARST_POLARITY).as_bool();
val_arst = cell->getParam(ID::ARST_VALUE);
}
if (cell->type.in(ID($sdff), ID($sdffe), ID($sdffce))) {
has_srst = true;
sig_srst = cell->getPort(ID::SRST);
pol_srst = cell->getParam(ID::SRST_POLARITY).as_bool();
val_srst = cell->getParam(ID::SRST_VALUE);
ce_over_srst = cell->type == ID($sdffce);
}
} else if (cell->type == ID($_FF_)) {
is_fine = true;
has_gclk = true;
sig_d = cell->getPort(ID::D);
} else if (type_str.substr(0, 5) == "$_SR_") {
is_fine = true;
has_sr = true;
pol_set = type_str[5] == 'P';
pol_clr = type_str[6] == 'P';
sig_set = cell->getPort(ID::S);
sig_clr = cell->getPort(ID::R);
} else if (type_str.substr(0, 6) == "$_DFF_" && type_str.size() == 8) {
is_fine = true;
sig_d = cell->getPort(ID::D);
has_clk = true;
pol_clk = type_str[6] == 'P';
sig_clk = cell->getPort(ID::C);
} else if (type_str.substr(0, 7) == "$_DFFE_" && type_str.size() == 10) {
is_fine = true;
sig_d = cell->getPort(ID::D);
has_clk = true;
pol_clk = type_str[7] == 'P';
sig_clk = cell->getPort(ID::C);
has_ce = true;
pol_ce = type_str[8] == 'P';
sig_ce = cell->getPort(ID::E);
} else if (type_str.substr(0, 6) == "$_DFF_" && type_str.size() == 10) {
is_fine = true;
sig_d = cell->getPort(ID::D);
has_clk = true;
pol_clk = type_str[6] == 'P';
sig_clk = cell->getPort(ID::C);
has_arst = true;
pol_arst = type_str[7] == 'P';
sig_arst = cell->getPort(ID::R);
val_arst = type_str[8] == '1' ? State::S1 : State::S0;
} else if (type_str.substr(0, 7) == "$_DFFE_" && type_str.size() == 12) {
is_fine = true;
sig_d = cell->getPort(ID::D);
has_clk = true;
pol_clk = type_str[7] == 'P';
sig_clk = cell->getPort(ID::C);
has_arst = true;
pol_arst = type_str[8] == 'P';
sig_arst = cell->getPort(ID::R);
val_arst = type_str[9] == '1' ? State::S1 : State::S0;
has_ce = true;
pol_ce = type_str[10] == 'P';
sig_ce = cell->getPort(ID::E);
} else if (type_str.substr(0, 8) == "$_ALDFF_" && type_str.size() == 11) {
is_fine = true;
sig_d = cell->getPort(ID::D);
has_clk = true;
pol_clk = type_str[8] == 'P';
sig_clk = cell->getPort(ID::C);
has_aload = true;
pol_aload = type_str[9] == 'P';
sig_aload = cell->getPort(ID::L);
sig_ad = cell->getPort(ID::AD);
} else if (type_str.substr(0, 9) == "$_ALDFFE_" && type_str.size() == 13) {
is_fine = true;
sig_d = cell->getPort(ID::D);
has_clk = true;
pol_clk = type_str[9] == 'P';
sig_clk = cell->getPort(ID::C);
has_aload = true;
pol_aload = type_str[10] == 'P';
sig_aload = cell->getPort(ID::L);
sig_ad = cell->getPort(ID::AD);
has_ce = true;
pol_ce = type_str[11] == 'P';
sig_ce = cell->getPort(ID::E);
} else if (type_str.substr(0, 8) == "$_DFFSR_" && type_str.size() == 12) {
is_fine = true;
sig_d = cell->getPort(ID::D);
has_clk = true;
pol_clk = type_str[8] == 'P';
sig_clk = cell->getPort(ID::C);
has_sr = true;
pol_set = type_str[9] == 'P';
pol_clr = type_str[10] == 'P';
sig_set = cell->getPort(ID::S);
sig_clr = cell->getPort(ID::R);
} else if (type_str.substr(0, 9) == "$_DFFSRE_" && type_str.size() == 14) {
is_fine = true;
sig_d = cell->getPort(ID::D);
has_clk = true;
pol_clk = type_str[9] == 'P';
sig_clk = cell->getPort(ID::C);
has_sr = true;
pol_set = type_str[10] == 'P';
pol_clr = type_str[11] == 'P';
sig_set = cell->getPort(ID::S);
sig_clr = cell->getPort(ID::R);
has_ce = true;
pol_ce = type_str[12] == 'P';
sig_ce = cell->getPort(ID::E);
} else if (type_str.substr(0, 7) == "$_SDFF_" && type_str.size() == 11) {
is_fine = true;
sig_d = cell->getPort(ID::D);
has_clk = true;
pol_clk = type_str[7] == 'P';
sig_clk = cell->getPort(ID::C);
has_srst = true;
pol_srst = type_str[8] == 'P';
sig_srst = cell->getPort(ID::R);
val_srst = type_str[9] == '1' ? State::S1 : State::S0;
} else if (type_str.substr(0, 8) == "$_SDFFE_" && type_str.size() == 13) {
is_fine = true;
sig_d = cell->getPort(ID::D);
has_clk = true;
pol_clk = type_str[8] == 'P';
sig_clk = cell->getPort(ID::C);
has_srst = true;
pol_srst = type_str[9] == 'P';
sig_srst = cell->getPort(ID::R);
val_srst = type_str[10] == '1' ? State::S1 : State::S0;
has_ce = true;
pol_ce = type_str[11] == 'P';
sig_ce = cell->getPort(ID::E);
} else if (type_str.substr(0, 9) == "$_SDFFCE_" && type_str.size() == 14) {
is_fine = true;
sig_d = cell->getPort(ID::D);
has_clk = true;
pol_clk = type_str[9] == 'P';
sig_clk = cell->getPort(ID::C);
has_srst = true;
pol_srst = type_str[10] == 'P';
sig_srst = cell->getPort(ID::R);
val_srst = type_str[11] == '1' ? State::S1 : State::S0;
has_ce = true;
pol_ce = type_str[12] == 'P';
sig_ce = cell->getPort(ID::E);
ce_over_srst = true;
} else if (type_str.substr(0, 9) == "$_DLATCH_" && type_str.size() == 11) {
is_fine = true;
has_aload = true;
sig_ad = cell->getPort(ID::D);
has_aload = true;
pol_aload = type_str[9] == 'P';
sig_aload = cell->getPort(ID::E);
} else if (type_str.substr(0, 9) == "$_DLATCH_" && type_str.size() == 13) {
is_fine = true;
has_aload = true;
sig_ad = cell->getPort(ID::D);
has_aload = true;
pol_aload = type_str[9] == 'P';
sig_aload = cell->getPort(ID::E);
has_arst = true;
pol_arst = type_str[10] == 'P';
sig_arst = cell->getPort(ID::R);
val_arst = type_str[11] == '1' ? State::S1 : State::S0;
} else if (type_str.substr(0, 11) == "$_DLATCHSR_" && type_str.size() == 15) {
is_fine = true;
has_aload = true;
sig_ad = cell->getPort(ID::D);
has_aload = true;
pol_aload = type_str[11] == 'P';
sig_aload = cell->getPort(ID::E);
has_sr = true;
pol_set = type_str[12] == 'P';
pol_clr = type_str[13] == 'P';
sig_set = cell->getPort(ID::S);
sig_clr = cell->getPort(ID::R);
} else {
log_assert(0);
}
if (has_aload && !has_clk && !has_sr && !has_arst && sig_ad.is_fully_const()) {
// Plain D latches with const D treated specially.
has_aload = false;
has_arst = true;
sig_arst = sig_aload;
pol_arst = pol_aload;
val_arst = sig_ad.as_const();
}
}
FfData FfData::slice(const std::vector<int> &bits) {

View File

@ -78,20 +78,31 @@ YOSYS_NAMESPACE_BEGIN
// - has_arst [does not correspond to a native cell, represented as dlatch with const D input]
// - empty set [not a cell — will be emitted as a simple direct connection]
struct FfTypeData {
FfTypeData(IdString type);
FfTypeData() {
has_clk = false;
has_gclk = false;
has_ce = false;
has_aload = false;
has_srst = false;
has_arst = false;
has_sr = false;
ce_over_srst = false;
is_fine = false;
is_anyinit = false;
}
struct FfData {
Module *module;
FfInitVals *initvals;
Cell *cell;
IdString name;
// The FF output.
SigSpec sig_q;
// The sync data input, present if has_clk or has_gclk.
SigSpec sig_d;
// The async data input, present if has_aload.
SigSpec sig_ad;
// The sync clock, present if has_clk.
SigSpec sig_clk;
// The clock enable, present if has_ce.
SigSpec sig_ce;
// The async load enable, present if has_aload.
SigSpec sig_aload;
// The async reset, preset if has_arst.
SigSpec sig_arst;
// The sync reset, preset if has_srst.
SigSpec sig_srst;
// The async clear (per-lane), present if has_sr.
SigSpec sig_clr;
// The async set (per-lane), present if has_sr.
SigSpec sig_set;
// True if this is a clocked (edge-sensitive) flip-flop.
bool has_clk;
// True if this is a $ff, exclusive with every other has_*.
@ -132,38 +143,9 @@ struct FfTypeData {
bool pol_clr;
bool pol_set;
// The value loaded by sig_arst.
// Zero length if unknowable from just type
Const val_arst;
// The value loaded by sig_srst.
// Zero length if unknowable from just type
Const val_srst;
};
struct FfData : FfTypeData {
Module *module;
FfInitVals *initvals;
Cell *cell;
IdString name;
// The FF output.
SigSpec sig_q;
// The sync data input, present if has_clk or has_gclk.
SigSpec sig_d;
// The async data input, present if has_aload.
SigSpec sig_ad;
// The sync clock, present if has_clk.
SigSpec sig_clk;
// The clock enable, present if has_ce.
SigSpec sig_ce;
// The async load enable, present if has_aload.
SigSpec sig_aload;
// The async reset, preset if has_arst.
SigSpec sig_arst;
// The sync reset, preset if has_srst.
SigSpec sig_srst;
// The async clear (per-lane), present if has_sr.
SigSpec sig_clr;
// The async set (per-lane), present if has_sr.
SigSpec sig_set;
// The initial value at power-up.
Const val_init;
// The FF data width in bits.
@ -172,6 +154,16 @@ struct FfData : FfTypeData {
FfData(Module *module = nullptr, FfInitVals *initvals = nullptr, IdString name = IdString()) : module(module), initvals(initvals), cell(nullptr), name(name) {
width = 0;
has_clk = false;
has_gclk = false;
has_ce = false;
has_aload = false;
has_srst = false;
has_arst = false;
has_sr = false;
ce_over_srst = false;
is_fine = false;
is_anyinit = false;
pol_clk = false;
pol_aload = false;
pol_ce = false;

View File

@ -602,11 +602,11 @@ void format_emit_string_view(std::string &result, std::string_view spec, int *dy
}
void format_emit_idstring(std::string &result, std::string_view spec, int *dynamic_ints,
DynamicIntCount num_dynamic_ints, const RTLIL::IdString &arg)
DynamicIntCount num_dynamic_ints, const IdString &arg)
{
if (spec == "%s") {
// Format checking will have guaranteed num_dynamic_ints == 0.
arg.append_to(&result);
result += arg.c_str();
return;
}
format_emit_stringf(result, spec, dynamic_ints, num_dynamic_ints, arg.c_str());

View File

@ -203,8 +203,6 @@ static void logv_string(std::string_view format, std::string str) {
void log_formatted_string(std::string_view format, std::string str)
{
log_assert(!Multithreading::active());
if (log_make_debug && !ys_debug(1))
return;
logv_string(format, std::move(str));
@ -212,8 +210,6 @@ void log_formatted_string(std::string_view format, std::string str)
void log_formatted_header(RTLIL::Design *design, std::string_view format, std::string str)
{
log_assert(!Multithreading::active());
bool pop_errfile = false;
log_spacer();
@ -253,8 +249,6 @@ void log_formatted_header(RTLIL::Design *design, std::string_view format, std::s
void log_formatted_warning(std::string_view prefix, std::string message)
{
log_assert(!Multithreading::active());
bool suppressed = false;
for (auto &re : log_nowarn_regexes)
@ -687,4 +681,55 @@ void log_check_expected()
check_err("prefixed error", pattern, item);
}
// ---------------------------------------------------
// This is the magic behind the code coverage counters
// ---------------------------------------------------
#if defined(YOSYS_ENABLE_COVER) && (defined(__linux__) || defined(__FreeBSD__))
dict<std::string, std::pair<std::string, int>> extra_coverage_data;
void cover_extra(std::string parent, std::string id, bool increment) {
if (extra_coverage_data.count(id) == 0) {
for (CoverData *p = __start_yosys_cover_list; p != __stop_yosys_cover_list; p++)
if (p->id == parent)
extra_coverage_data[id].first = stringf("%s:%d:%s", p->file, p->line, p->func);
log_assert(extra_coverage_data.count(id));
}
if (increment)
extra_coverage_data[id].second++;
}
dict<std::string, std::pair<std::string, int>> get_coverage_data()
{
dict<std::string, std::pair<std::string, int>> coverage_data;
for (auto &it : pass_register) {
std::string key = stringf("passes.%s", it.first);
coverage_data[key].first = stringf("%s:%d:%s", __FILE__, __LINE__, __FUNCTION__);
coverage_data[key].second += it.second->call_counter;
}
for (auto &it : extra_coverage_data) {
if (coverage_data.count(it.first))
log_warning("found duplicate coverage id \"%s\".\n", it.first);
coverage_data[it.first].first = it.second.first;
coverage_data[it.first].second += it.second.second;
}
for (CoverData *p = __start_yosys_cover_list; p != __stop_yosys_cover_list; p++) {
if (coverage_data.count(p->id))
log_warning("found duplicate coverage id \"%s\".\n", p->id);
coverage_data[p->id].first = stringf("%s:%d:%s", p->file, p->line, p->func);
coverage_data[p->id].second += p->counter;
}
for (auto &it : coverage_data)
if (!it.second.first.compare(0, strlen(YOSYS_SRC "/"), YOSYS_SRC "/"))
it.second.first = it.second.first.substr(strlen(YOSYS_SRC "/"));
return coverage_data;
}
#endif
YOSYS_NAMESPACE_END

View File

@ -24,7 +24,6 @@
#include <time.h>
#include <atomic>
#include <regex>
#define YS_REGEX_COMPILE(param) std::regex(param, \
std::regex_constants::nosubs | \
@ -291,6 +290,53 @@ void log_abort_internal(const char *file, int line);
#define log_ping() YOSYS_NAMESPACE_PREFIX log("-- %s:%d %s --\n", __FILE__, __LINE__, __PRETTY_FUNCTION__)
// ---------------------------------------------------
// This is the magic behind the code coverage counters
// ---------------------------------------------------
#if defined(YOSYS_ENABLE_COVER) && (defined(__linux__) || defined(__FreeBSD__))
#define cover(_id) do { \
static CoverData __d __attribute__((section("yosys_cover_list"), aligned(1), used)) = { __FILE__, __FUNCTION__, _id, __LINE__, 0 }; \
__d.counter++; \
} while (0)
struct CoverData {
const char *file, *func, *id;
int line, counter;
} YS_ATTRIBUTE(packed);
// this two symbols are created by the linker for the "yosys_cover_list" ELF section
extern "C" struct CoverData __start_yosys_cover_list[];
extern "C" struct CoverData __stop_yosys_cover_list[];
extern dict<std::string, std::pair<std::string, int>> extra_coverage_data;
void cover_extra(std::string parent, std::string id, bool increment = true);
dict<std::string, std::pair<std::string, int>> get_coverage_data();
#define cover_list(_id, ...) do { cover(_id); \
std::string r = cover_list_worker(_id, __VA_ARGS__); \
log_assert(r.empty()); \
} while (0)
static inline std::string cover_list_worker(std::string, std::string last) {
return last;
}
template<typename... T>
std::string cover_list_worker(std::string prefix, std::string first, T... rest) {
std::string selected = cover_list_worker(prefix, rest...);
cover_extra(prefix, prefix + "." + first, first == selected);
return first == selected ? "" : selected;
}
#else
# define cover(...) do { } while (0)
# define cover_list(...) do { } while (0)
#endif
// ------------------------------------------------------------
// everything below this line are utilities for troubleshooting
// ------------------------------------------------------------

View File

@ -161,7 +161,7 @@ struct ModIndex : public RTLIL::Monitor
#endif
}
void notify_connect(RTLIL::Cell *cell, RTLIL::IdString port, const RTLIL::SigSpec &old_sig, const RTLIL::SigSpec &sig) override
void notify_connect(RTLIL::Cell *cell, const RTLIL::IdString &port, const RTLIL::SigSpec &old_sig, const RTLIL::SigSpec &sig) override
{
log_assert(module == cell->module);

View File

@ -42,23 +42,6 @@ std::map<std::string, Backend*> backend_register;
std::vector<std::string> Frontend::next_args;
bool GarbageCollectionGuard::is_enabled_ = true;
static bool garbage_collection_requested = false;
void request_garbage_collection()
{
garbage_collection_requested = true;
}
void try_collect_garbage()
{
if (!GarbageCollectionGuard::is_enabled() || !garbage_collection_requested)
return;
garbage_collection_requested = false;
RTLIL::OwningIdString::collect_garbage();
}
Pass::Pass(std::string name, std::string short_help, source_location location) :
pass_name(name), short_help(short_help), location(location)
{
@ -129,11 +112,6 @@ void Pass::post_execute(Pass::pre_post_exec_state_t state)
int64_t time_ns = PerformanceTimer::query() - state.begin_ns;
runtime_ns += time_ns;
current_pass = state.parent_pass;
subtract_from_current_runtime_ns(time_ns);
}
void Pass::subtract_from_current_runtime_ns(int64_t time_ns)
{
if (current_pass)
current_pass->runtime_ns -= time_ns;
}
@ -285,19 +263,14 @@ void Pass::call(RTLIL::Design *design, std::vector<std::string> args)
if (pass_register.count(args[0]) == 0)
log_cmd_error("No such command: %s (type 'help' for a command overview)\n", args[0]);
Pass *pass = pass_register[args[0]];
// Collect garbage before the next pass if requested. No need to collect garbage after the last pass.
try_collect_garbage();
GarbageCollectionGuard gc_guard(pass->allow_garbage_collection_during_pass());
if (pass->experimental_flag)
if (pass_register[args[0]]->experimental_flag)
log_experimental(args[0]);
size_t orig_sel_stack_pos = design->selection_stack.size();
auto state = pass->pre_execute();
pass->execute(args, design);
pass->post_execute(state);
auto state = pass_register[args[0]]->pre_execute();
pass_register[args[0]]->execute(args, design);
pass_register[args[0]]->post_execute(state);
while (design->selection_stack.size() > orig_sel_stack_pos)
design->pop_selection();
}

View File

@ -50,30 +50,6 @@ struct source_location { // dummy placeholder
YOSYS_NAMESPACE_BEGIN
// Track whether garbage collection is enabled. Garbage collection must be disabled
// while any RTLIL objects (e.g. non-owning non-immortal IdStrings) exist outside Designs.
// Garbage collection is disabled whenever any GarbageCollectionGuard(false) is on the
// stack. These objects must be stack-allocated on the main thread.
class GarbageCollectionGuard
{
bool was_enabled;
static bool is_enabled_;
public:
GarbageCollectionGuard(bool allow) : was_enabled(is_enabled_) {
is_enabled_ &= allow;
}
~GarbageCollectionGuard() {
is_enabled_ = was_enabled;
}
static bool is_enabled() { return is_enabled_; }
};
// Call from anywhere to request GC at the next safe point.
void request_garbage_collection();
// GC if GarbageCollectionGuard::is_enabled() and GC was requested.
void try_collect_garbage();
struct Pass
{
std::string pass_name, short_help;
@ -95,8 +71,6 @@ struct Pass
bool experimental_flag = false;
bool internal_flag = false;
static void subtract_from_current_runtime_ns(int64_t time_ns);
void experimental() {
experimental_flag = true;
}
@ -134,10 +108,6 @@ struct Pass
virtual void on_register();
virtual void on_shutdown();
virtual bool replace_existing_pass() const { return false; }
// This should return false if the pass holds onto RTLIL objects outside a Design while it
// calls nested passes. For safety, we default to assuming the worst.
virtual bool allow_garbage_collection_during_pass() const { return false; }
};
struct ScriptPass : Pass
@ -156,8 +126,6 @@ struct ScriptPass : Pass
void run_nocheck(std::string command, std::string info = std::string());
void run_script(RTLIL::Design *design, std::string run_from = std::string(), std::string run_to = std::string());
void help_script();
bool allow_garbage_collection_during_pass() const override { return true; }
};
struct Frontend : Pass

File diff suppressed because it is too large Load Diff

View File

@ -53,11 +53,10 @@ namespace RTLIL
// Semantic metadata - how can this constant be interpreted?
// Values may be generally non-exclusive
enum ConstFlags : unsigned char {
CONST_FLAG_NONE = 0,
CONST_FLAG_STRING = 1,
CONST_FLAG_SIGNED = 2, // only used for parameters
CONST_FLAG_REAL = 4, // only used for parameters
CONST_FLAG_UNSIZED = 8, // only used for parameters
CONST_FLAG_NONE = 0,
CONST_FLAG_STRING = 1,
CONST_FLAG_SIGNED = 2, // only used for parameters
CONST_FLAG_REAL = 4 // only used for parameters
};
enum SelectPartials : unsigned char {
@ -121,30 +120,27 @@ namespace RTLIL
struct Process;
struct Binding;
struct IdString;
struct OwningIdString;
struct StaticIdString;
typedef std::pair<SigSpec, SigSpec> SigSig;
struct StaticIdString {
constexpr StaticIdString(StaticId id, const IdString &id_str) : id_str(id_str), id(id) {}
constexpr inline operator const IdString &() const { return id_str; }
constexpr inline int index() const { return static_cast<short>(id); }
constexpr inline const IdString &id_string() const { return id_str; }
const IdString &id_str;
const StaticId id;
};
};
struct RTLIL::IdString
{
struct Storage {
char *buf;
int size;
std::string_view str_view() const { return {buf, static_cast<size_t>(size)}; }
};
struct AutoidxStorage {
// Append the negated (i.e. positive) ID to this string to get
// the real string. The prefix strings must live forever.
const std::string *prefix;
// Cache of the full string, or nullptr if not cached yet.
std::atomic<char *> full_str;
AutoidxStorage(const std::string *prefix) : prefix(prefix), full_str(nullptr) {}
AutoidxStorage(AutoidxStorage&& other) : prefix(other.prefix), full_str(other.full_str.exchange(nullptr, std::memory_order_relaxed)) {}
~AutoidxStorage() { delete[] full_str.load(std::memory_order_acquire); }
};
#undef YOSYS_XTRACE_GET_PUT
#undef YOSYS_SORT_ID_FREE_LIST
#undef YOSYS_USE_STICKY_IDS
#undef YOSYS_NO_IDS_REFCNT
// the global id string cache
@ -154,82 +150,200 @@ struct RTLIL::IdString
~destruct_guard_t() { destruct_guard_ok = false; }
} destruct_guard;
// String storage for non-autoidx IDs
static std::vector<Storage> global_id_storage_;
// Lookup table for non-autoidx IDs
static std::vector<char*> global_id_storage_;
static std::unordered_map<std::string_view, int> global_id_index_;
// Storage for autoidx IDs, which have negative indices, i.e. all entries in this
// map have negative keys.
static std::unordered_map<int, AutoidxStorage> global_autoidx_id_storage_;
// All (index, refcount) pairs in this map have refcount > 0.
static std::unordered_map<int, int> global_refcount_storage_;
#ifndef YOSYS_NO_IDS_REFCNT
// For prepopulated IdStrings, the refcount is meaningless since they
// are never freed even if the refcount is zero. For code efficiency
// we increment the refcount of prepopulated IdStrings like any other string,
// but we never decrement the refcount or check whether it's zero.
// So, make this unsigned because refcounts of preopulated IdStrings may overflow
// and overflow of signed integers is undefined behavior.
static std::vector<uint32_t> global_refcount_storage_;
static std::vector<int> global_free_idx_list_;
#endif
static int refcount(int idx) {
auto it = global_refcount_storage_.find(idx);
if (it == global_refcount_storage_.end())
return 0;
return it->second;
}
#ifdef YOSYS_USE_STICKY_IDS
static int last_created_idx_ptr_;
static int last_created_idx_[8];
#endif
static inline void xtrace_db_dump()
{
#ifdef YOSYS_XTRACE_GET_PUT
for (int idx = 0; idx < GetSize(global_id_storage_); idx++)
{
if (global_id_storage_.at(idx).buf == nullptr)
if (global_id_storage_.at(idx) == nullptr)
log("#X# DB-DUMP index %d: FREE\n", idx);
else
log("#X# DB-DUMP index %d: '%s' (ref %u)\n", idx, global_id_storage_.at(idx).buf, refcount(idx));
log("#X# DB-DUMP index %d: '%s' (ref %u)\n", idx, global_id_storage_.at(idx), global_refcount_storage_.at(idx));
}
#endif
}
static inline void checkpoint()
{
#ifdef YOSYS_USE_STICKY_IDS
last_created_idx_ptr_ = 0;
for (int i = 0; i < 8; i++) {
if (last_created_idx_[i])
put_reference(last_created_idx_[i]);
last_created_idx_[i] = 0;
}
#endif
#ifdef YOSYS_SORT_ID_FREE_LIST
std::sort(global_free_idx_list_.begin(), global_free_idx_list_.end(), std::greater<int>());
#endif
}
static int insert(std::string_view p)
static inline int get_reference(int idx)
{
#ifndef YOSYS_NO_IDS_REFCNT
global_refcount_storage_[idx]++;
#endif
#ifdef YOSYS_XTRACE_GET_PUT
if (yosys_xtrace && idx >= static_cast<short>(StaticId::STATIC_ID_END))
log("#X# GET-BY-INDEX '%s' (index %d, refcount %u)\n", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx));
#endif
return idx;
}
static int get_reference(const char *p)
{
return get_reference(std::string_view(p));
}
static int get_reference(std::string_view p)
{
log_assert(destruct_guard_ok);
log_assert(!Multithreading::active());
auto it = global_id_index_.find(p);
if (it != global_id_index_.end()) {
#ifndef YOSYS_NO_IDS_REFCNT
global_refcount_storage_.at(it->second)++;
#endif
#ifdef YOSYS_XTRACE_GET_PUT
if (yosys_xtrace)
log("#X# GET-BY-NAME '%s' (index %d, refcount %u)\n", global_id_storage_.at(it->second).buf, it->second, refcount(it->second));
log("#X# GET-BY-NAME '%s' (index %d, refcount %u)\n", global_id_storage_.at(it->second), it->second, global_refcount_storage_.at(it->second));
#endif
return it->second;
}
return really_insert(p, it);
ensure_prepopulated();
if (p.empty())
return 0;
log_assert(p[0] == '$' || p[0] == '\\');
for (char ch : p)
if ((unsigned)ch <= (unsigned)' ')
log_error("Found control character or space (0x%02x) in string '%s' which is not allowed in RTLIL identifiers\n", ch, std::string(p).c_str());
#ifndef YOSYS_NO_IDS_REFCNT
if (global_free_idx_list_.empty()) {
log_assert(global_id_storage_.size() < 0x40000000);
global_free_idx_list_.push_back(global_id_storage_.size());
global_id_storage_.push_back(nullptr);
global_refcount_storage_.push_back(0);
}
int idx = global_free_idx_list_.back();
global_free_idx_list_.pop_back();
char* buf = static_cast<char*>(malloc(p.size() + 1));
memcpy(buf, p.data(), p.size());
buf[p.size()] = 0;
global_id_storage_.at(idx) = buf;
global_id_index_.insert(it, {std::string_view(buf, p.size()), idx});
global_refcount_storage_.at(idx)++;
#else
int idx = global_id_storage_.size();
global_id_storage_.push_back(strdup(p));
global_id_index_[global_id_storage_.back()] = idx;
#endif
if (yosys_xtrace) {
log("#X# New IdString '%s' with index %d.\n", global_id_storage_.at(idx), idx);
log_backtrace("-X- ", yosys_xtrace-1);
}
#ifdef YOSYS_XTRACE_GET_PUT
if (yosys_xtrace)
log("#X# GET-BY-NAME '%s' (index %d, refcount %u)\n", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx));
#endif
#ifdef YOSYS_USE_STICKY_IDS
// Avoid Create->Delete->Create pattern
if (last_created_idx_[last_created_idx_ptr_])
put_reference(last_created_idx_[last_created_idx_ptr_]);
last_created_idx_[last_created_idx_ptr_] = idx;
get_reference(last_created_idx_[last_created_idx_ptr_]);
last_created_idx_ptr_ = (last_created_idx_ptr_ + 1) & 7;
#endif
return idx;
}
// Inserts an ID with string `prefix + autoidx', incrementing autoidx.
// `prefix` must start with '$auto$', end with '$', and live forever.
static IdString new_autoidx_with_prefix(const std::string *prefix) {
log_assert(!Multithreading::active());
int index = -(autoidx++);
global_autoidx_id_storage_.insert({index, prefix});
return from_index(index);
#ifndef YOSYS_NO_IDS_REFCNT
static inline void put_reference(int idx)
{
// put_reference() may be called from destructors after the destructor of
// global_refcount_storage_ has been run. in this case we simply do nothing.
if (idx < static_cast<short>(StaticId::STATIC_ID_END) || !destruct_guard_ok)
return;
#ifdef YOSYS_XTRACE_GET_PUT
if (yosys_xtrace) {
log("#X# PUT '%s' (index %d, refcount %u)\n", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx));
}
#endif
uint32_t &refcount = global_refcount_storage_[idx];
if (--refcount > 0)
return;
free_reference(idx);
}
static inline void free_reference(int idx)
{
if (yosys_xtrace) {
log("#X# Removed IdString '%s' with index %d.\n", global_id_storage_.at(idx), idx);
log_backtrace("-X- ", yosys_xtrace-1);
}
log_assert(idx >= static_cast<short>(StaticId::STATIC_ID_END));
global_id_index_.erase(global_id_storage_.at(idx));
free(global_id_storage_.at(idx));
global_id_storage_.at(idx) = nullptr;
global_free_idx_list_.push_back(idx);
}
#else
static inline void put_reference(int) { }
#endif
// the actual IdString object is just is a single int
int index_;
constexpr inline IdString() : index_(0) { }
inline IdString(const char *str) : index_(insert(std::string_view(str))) { }
constexpr inline IdString(const IdString &str) : index_(str.index_) { }
inline IdString() : index_(0) { }
inline IdString(const char *str) : index_(get_reference(str)) { }
inline IdString(const IdString &str) : index_(get_reference(str.index_)) { }
inline IdString(IdString &&str) : index_(str.index_) { str.index_ = 0; }
inline IdString(const std::string &str) : index_(insert(std::string_view(str))) { }
inline IdString(std::string_view str) : index_(insert(str)) { }
constexpr inline IdString(StaticId id) : index_(static_cast<short>(id)) {}
inline IdString(const std::string &str) : index_(get_reference(std::string_view(str))) { }
inline IdString(std::string_view str) : index_(get_reference(str)) { }
inline IdString(StaticId id) : index_(static_cast<short>(id)) {}
inline ~IdString() { put_reference(index_); }
IdString &operator=(const IdString &rhs) = default;
inline void operator=(const IdString &rhs) {
put_reference(index_);
index_ = get_reference(rhs.index_);
}
inline void operator=(IdString &&rhs) {
put_reference(index_);
index_ = rhs.index_;
rhs.index_ = 0;
}
inline void operator=(const char *rhs) {
IdString id(rhs);
@ -241,168 +355,24 @@ struct RTLIL::IdString
*this = id;
}
inline const char *c_str() const {
if (index_ >= 0)
return global_id_storage_.at(index_).buf;
constexpr inline const IdString &id_string() const { return *this; }
AutoidxStorage &s = global_autoidx_id_storage_.at(index_);
char *full_str = s.full_str.load(std::memory_order_acquire);
if (full_str != nullptr)
return full_str;
const std::string &prefix = *s.prefix;
std::string suffix = std::to_string(-index_);
char *c = new char[prefix.size() + suffix.size() + 1];
memcpy(c, prefix.data(), prefix.size());
memcpy(c + prefix.size(), suffix.c_str(), suffix.size() + 1);
if (s.full_str.compare_exchange_strong(full_str, c, std::memory_order_acq_rel))
return c;
delete[] c;
return full_str;
inline const char *c_str() const {
return global_id_storage_.at(index_);
}
inline std::string str() const {
std::string result;
append_to(&result);
return result;
return std::string(global_id_storage_.at(index_));
}
inline void append_to(std::string *out) const {
if (index_ >= 0) {
*out += global_id_storage_.at(index_).str_view();
return;
}
*out += *global_autoidx_id_storage_.at(index_).prefix;
*out += std::to_string(-index_);
}
class Substrings {
std::string_view first_;
int suffix_number;
char buf[10];
public:
Substrings(const Storage &storage) : first_(storage.str_view()), suffix_number(-1) {}
// suffix_number must be non-negative
Substrings(const std::string *prefix, int suffix_number)
: first_(*prefix), suffix_number(suffix_number) {}
std::string_view first() { return first_; }
std::optional<std::string_view> next() {
if (suffix_number < 0)
return std::nullopt;
int i = sizeof(buf);
do {
--i;
buf[i] = (suffix_number % 10) + '0';
suffix_number /= 10;
} while (suffix_number > 0);
suffix_number = -1;
return std::string_view(buf + i, sizeof(buf) - i);
}
};
class const_iterator {
const std::string *prefix;
std::string suffix;
const char *c_str;
int c_str_len;
// When this is INT_MAX it's the generic "end" value.
int index;
public:
using iterator_category = std::forward_iterator_tag;
using value_type = char;
using difference_type = std::ptrdiff_t;
using pointer = const char*;
using reference = const char&;
const_iterator(const Storage &storage) : prefix(nullptr), c_str(storage.buf), c_str_len(storage.size), index(0) {}
const_iterator(const std::string *prefix, int number) :
prefix(prefix), suffix(std::to_string(number)), c_str(nullptr), c_str_len(0), index(0) {}
// Construct end-marker
const_iterator() : prefix(nullptr), c_str(nullptr), c_str_len(0), index(INT_MAX) {}
int size() const {
if (c_str != nullptr)
return c_str_len;
return GetSize(*prefix) + GetSize(suffix);
}
char operator*() const {
if (c_str != nullptr)
return c_str[index];
int prefix_size = GetSize(*prefix);
if (index < prefix_size)
return prefix->at(index);
return suffix[index - prefix_size];
}
const_iterator& operator++() { ++index; return *this; }
const_iterator operator++(int) { const_iterator result(*this); ++index; return result; }
const_iterator& operator+=(int i) { index += i; return *this; }
const_iterator operator+(int add) {
const_iterator result = *this;
result += add;
return result;
}
bool operator==(const const_iterator& other) const {
return index == other.index || (other.index == INT_MAX && index == size())
|| (index == INT_MAX && other.index == other.size());
}
bool operator!=(const const_iterator& other) const {
return !(*this == other);
}
};
const_iterator begin() const {
if (index_ >= 0) {
return const_iterator(global_id_storage_.at(index_));
}
return const_iterator(global_autoidx_id_storage_.at(index_).prefix, -index_);
}
const_iterator end() const {
return const_iterator();
}
Substrings substrings() const {
if (index_ >= 0) {
return Substrings(global_id_storage_.at(index_));
}
return Substrings(global_autoidx_id_storage_.at(index_).prefix, -index_);
}
inline bool lt_by_name(IdString rhs) const {
Substrings lhs_it = substrings();
Substrings rhs_it = rhs.substrings();
std::string_view lhs_substr = lhs_it.first();
std::string_view rhs_substr = rhs_it.first();
while (true) {
int min = std::min(GetSize(lhs_substr), GetSize(rhs_substr));
int diff = memcmp(lhs_substr.data(), rhs_substr.data(), min);
if (diff != 0)
return diff < 0;
lhs_substr = lhs_substr.substr(min);
rhs_substr = rhs_substr.substr(min);
if (rhs_substr.empty()) {
if (std::optional<std::string_view> s = rhs_it.next())
rhs_substr = *s;
else
return false;
}
if (lhs_substr.empty()) {
if (std::optional<std::string_view> s = lhs_it.next())
lhs_substr = *s;
else
return true;
}
}
}
inline bool operator<(IdString rhs) const {
inline bool operator<(const IdString &rhs) const {
return index_ < rhs.index_;
}
inline bool operator==(IdString rhs) const { return index_ == rhs.index_; }
inline bool operator!=(IdString rhs) const { return index_ != rhs.index_; }
inline bool operator==(const IdString &rhs) const { return index_ == rhs.index_; }
inline bool operator!=(const IdString &rhs) const { return index_ != rhs.index_; }
inline bool operator==(const StaticIdString &rhs) const;
inline bool operator!=(const StaticIdString &rhs) const;
// The methods below are just convenience functions for better compatibility with std::string.
@ -413,84 +383,45 @@ struct RTLIL::IdString
bool operator!=(const char *rhs) const { return strcmp(c_str(), rhs) != 0; }
char operator[](size_t i) const {
if (index_ >= 0) {
const Storage &storage = global_id_storage_.at(index_);
const char *p = c_str();
#ifndef NDEBUG
log_assert(static_cast<int>(i) < storage.size);
for (; i != 0; i--, p++)
log_assert(*p != 0);
return *p;
#else
return *(p + i);
#endif
return *(storage.buf + i);
}
const std::string &id_start = *global_autoidx_id_storage_.at(index_).prefix;
if (i < id_start.size())
return id_start[i];
i -= id_start.size();
std::string suffix = std::to_string(-index_);
#ifndef NDEBUG
// Allow indexing to access the trailing null.
log_assert(i <= suffix.size());
#endif
return suffix[i];
}
std::string substr(size_t pos = 0, size_t len = std::string::npos) const {
std::string result;
const_iterator it = begin() + pos;
const_iterator end_it = end();
if (len != std::string::npos && len < it.size() - pos) {
end_it = it + len;
}
std::copy(it, end_it, std::back_inserter(result));
return result;
if (len == std::string::npos || len >= strlen(c_str() + pos))
return std::string(c_str() + pos);
else
return std::string(c_str() + pos, len);
}
int compare(size_t pos, size_t len, const char* s) const {
const_iterator it = begin() + pos;
const_iterator end_it = end();
while (len > 0 && *s != 0 && it != end_it) {
int diff = *it - *s;
if (diff != 0)
return diff;
++it;
++s;
--len;
}
return 0;
return strncmp(c_str()+pos, s, len);
}
bool begins_with(std::string_view prefix) const {
Substrings it = substrings();
std::string_view substr = it.first();
while (true) {
int min = std::min(GetSize(substr), GetSize(prefix));
if (memcmp(substr.data(), prefix.data(), min) != 0)
return false;
prefix = prefix.substr(min);
if (prefix.empty())
return true;
substr = substr.substr(min);
if (substr.empty()) {
if (std::optional<std::string_view> s = it.next())
substr = *s;
else
return false;
}
}
bool begins_with(const char* prefix) const {
size_t len = strlen(prefix);
if (size() < len) return false;
return compare(0, len, prefix) == 0;
}
bool ends_with(std::string_view suffix) const {
size_t sz = size();
if (sz < suffix.size()) return false;
return compare(sz - suffix.size(), suffix.size(), suffix.data()) == 0;
bool ends_with(const char* suffix) const {
size_t len = strlen(suffix);
if (size() < len) return false;
return compare(size()-len, len, suffix) == 0;
}
bool contains(std::string_view s) const {
if (index_ >= 0)
return global_id_storage_.at(index_).str_view().find(s) != std::string::npos;
return str().find(s) != std::string::npos;
bool contains(const char* str) const {
return strstr(c_str(), str);
}
size_t size() const {
return begin().size();
return strlen(c_str());
}
bool empty() const {
@ -526,7 +457,8 @@ struct RTLIL::IdString
return (... || in(args));
}
bool in(IdString rhs) const { return *this == rhs; }
bool in(const IdString &rhs) const { return *this == rhs; }
bool in(const StaticIdString &rhs) const { return *this == rhs; }
bool in(const char *rhs) const { return *this == rhs; }
bool in(const std::string &rhs) const { return *this == rhs; }
inline bool in(const pool<IdString> &rhs) const;
@ -536,14 +468,6 @@ struct RTLIL::IdString
private:
static void prepopulate();
static int really_insert(std::string_view p, std::unordered_map<std::string_view, int>::iterator &it);
protected:
static IdString from_index(int index) {
IdString result;
result.index_ = index;
return result;
}
public:
static void ensure_prepopulated() {
@ -552,105 +476,16 @@ public:
}
};
struct RTLIL::OwningIdString : public RTLIL::IdString {
inline OwningIdString() { }
inline OwningIdString(const OwningIdString &str) : IdString(str) { get_reference(); }
inline OwningIdString(const char *str) : IdString(str) { get_reference(); }
inline OwningIdString(const IdString &str) : IdString(str) { get_reference(); }
inline OwningIdString(IdString &&str) : IdString(str) { get_reference(); }
inline OwningIdString(const std::string &str) : IdString(str) { get_reference(); }
inline OwningIdString(std::string_view str) : IdString(str) { get_reference(); }
inline OwningIdString(StaticId id) : IdString(id) {}
inline ~OwningIdString() {
put_reference();
}
inline OwningIdString &operator=(const OwningIdString &rhs) {
put_reference();
index_ = rhs.index_;
get_reference();
return *this;
}
inline OwningIdString &operator=(const IdString &rhs) {
put_reference();
index_ = rhs.index_;
get_reference();
return *this;
}
inline OwningIdString &operator=(OwningIdString &&rhs) {
std::swap(index_, rhs.index_);
return *this;
}
// Collect all non-owning references.
static void collect_garbage();
static int64_t garbage_collection_ns() { return gc_ns; }
static int garbage_collection_count() { return gc_count; }
// Used by the ID() macro to create an IdString with no destructor whose string will
// never be released. If ID() creates a closure-static `OwningIdString` then
// initialization of the static registers its destructor to run at exit, which is
// wasteful.
static IdString immortal(const char* str) {
IdString result(str);
get_reference(result.index_);
return result;
}
private:
static int64_t gc_ns;
static int gc_count;
void get_reference()
{
get_reference(index_);
}
static void get_reference(int idx)
{
log_assert(!Multithreading::active());
if (idx < static_cast<short>(StaticId::STATIC_ID_END))
return;
auto it = global_refcount_storage_.find(idx);
if (it == global_refcount_storage_.end())
global_refcount_storage_.insert(it, {idx, 1});
else
++it->second;
#ifdef YOSYS_XTRACE_GET_PUT
if (yosys_xtrace && idx >= static_cast<short>(StaticId::STATIC_ID_END))
log("#X# GET-BY-INDEX '%s' (index %d, refcount %u)\n", from_index(idx), idx, refcount(idx));
#endif
}
void put_reference()
{
log_assert(!Multithreading::active());
// put_reference() may be called from destructors after the destructor of
// global_refcount_storage_ has been run. in this case we simply do nothing.
if (index_ < static_cast<short>(StaticId::STATIC_ID_END) || !destruct_guard_ok)
return;
#ifdef YOSYS_XTRACE_GET_PUT
if (yosys_xtrace)
log("#X# PUT '%s' (index %d, refcount %u)\n", from_index(index_), index_, refcount(index_));
#endif
auto it = global_refcount_storage_.find(index_);
log_assert(it != global_refcount_storage_.end() && it->second >= 1);
if (--it->second == 0) {
global_refcount_storage_.erase(it);
}
}
};
namespace hashlib {
template <>
struct hash_ops<RTLIL::IdString> {
static inline bool cmp(RTLIL::IdString a, RTLIL::IdString b) {
static inline bool cmp(const RTLIL::IdString &a, const RTLIL::IdString &b) {
return a == b;
}
[[nodiscard]] static inline Hasher hash(RTLIL::IdString id) {
[[nodiscard]] static inline Hasher hash(const RTLIL::IdString &id) {
return id.hash_top();
}
[[nodiscard]] static inline Hasher hash_into(RTLIL::IdString id, Hasher h) {
[[nodiscard]] static inline Hasher hash_into(const RTLIL::IdString &id, Hasher h) {
return id.hash_into(h);
}
};
@ -666,9 +501,21 @@ inline bool RTLIL::IdString::in(const pool<IdString> &rhs) const { return rhs.co
[[deprecated]]
inline bool RTLIL::IdString::in(const pool<IdString> &&rhs) const { return rhs.count(*this) != 0; }
inline bool RTLIL::IdString::operator==(const RTLIL::StaticIdString &rhs) const {
return index_ == rhs.index();
}
inline bool RTLIL::IdString::operator!=(const RTLIL::StaticIdString &rhs) const {
return index_ != rhs.index();
}
namespace RTLIL {
namespace IDInternal {
#define X(_id) extern const IdString _id;
#include "kernel/constids.inc"
#undef X
}
namespace ID {
#define X(_id) constexpr IdString _id(StaticId::_id);
#define X(_id) constexpr StaticIdString _id(StaticId::_id, IDInternal::_id);
#include "kernel/constids.inc"
#undef X
}
@ -676,7 +523,7 @@ namespace RTLIL {
struct IdTableEntry {
const std::string_view name;
const RTLIL::IdString static_id;
const RTLIL::StaticIdString static_id;
};
constexpr IdTableEntry IdTable[] = {
@ -709,15 +556,15 @@ constexpr int lookup_well_known_id(std::string_view name)
//
// sed -i.orig -r 's/"\\\\([a-zA-Z0-9_]+)"/ID(\1)/g; s/"(\$[a-zA-Z0-9_]+)"/ID(\1)/g;' <filename>
//
typedef RTLIL::IdString IDMacroHelperFunc();
typedef const RTLIL::IdString &IDMacroHelperFunc();
template <int IdTableIndex> struct IDMacroHelper {
static constexpr RTLIL::IdString eval(IDMacroHelperFunc) {
static constexpr RTLIL::StaticIdString eval(IDMacroHelperFunc) {
return IdTable[IdTableIndex].static_id;
}
};
template <> struct IDMacroHelper<-1> {
static constexpr RTLIL::IdString eval(IDMacroHelperFunc func) {
static constexpr const RTLIL::IdString &eval(IDMacroHelperFunc func) {
return func();
}
};
@ -727,16 +574,16 @@ template <> struct IDMacroHelper<-1> {
YOSYS_NAMESPACE_PREFIX IDMacroHelper< \
YOSYS_NAMESPACE_PREFIX lookup_well_known_id(#_id) \
>::eval([]() \
-> YOSYS_NAMESPACE_PREFIX RTLIL::IdString { \
-> const YOSYS_NAMESPACE_PREFIX RTLIL::IdString & { \
const char *p = "\\" #_id, *q = p[1] == '$' ? p+1 : p; \
static const YOSYS_NAMESPACE_PREFIX RTLIL::IdString id = \
YOSYS_NAMESPACE_PREFIX RTLIL::OwningIdString::immortal(q); \
static const YOSYS_NAMESPACE_PREFIX RTLIL::IdString id(q); \
return id; \
})
namespace RTLIL {
extern dict<std::string, std::string> constpad;
[[deprecated("Call cell->is_builtin_ff() instead")]]
const pool<IdString> &builtin_ff_cell_types();
static inline std::string escape_id(const std::string &str) {
@ -757,11 +604,11 @@ namespace RTLIL {
return str.substr(1);
}
static inline std::string unescape_id(RTLIL::IdString str) {
static inline std::string unescape_id(const RTLIL::IdString &str) {
return unescape_id(str.str());
}
static inline const char *id2cstr(RTLIL::IdString str) {
static inline const char *id2cstr(const RTLIL::IdString &str) {
return log_id(str);
}
@ -773,13 +620,13 @@ namespace RTLIL {
template <typename T> struct sort_by_name_str {
bool operator()(T *a, T *b) const {
return a->name.lt_by_name(b->name);
return strcmp(a->name.c_str(), b->name.c_str()) < 0;
}
};
struct sort_by_id_str {
bool operator()(RTLIL::IdString a, RTLIL::IdString b) const {
return a.lt_by_name(b);
bool operator()(const RTLIL::IdString &a, const RTLIL::IdString &b) const {
return strcmp(a.c_str(), b.c_str()) < 0;
}
};
@ -1244,22 +1091,22 @@ struct RTLIL::AttrObject
{
dict<RTLIL::IdString, RTLIL::Const> attributes;
bool has_attribute(RTLIL::IdString id) const;
bool has_attribute(const RTLIL::IdString &id) const;
void set_bool_attribute(RTLIL::IdString id, bool value=true);
bool get_bool_attribute(RTLIL::IdString id) const;
void set_bool_attribute(const RTLIL::IdString &id, bool value=true);
bool get_bool_attribute(const RTLIL::IdString &id) const;
[[deprecated("Use Module::get_blackbox_attribute() instead.")]]
bool get_blackbox_attribute(bool ignore_wb=false) const {
return get_bool_attribute(ID::blackbox) || (!ignore_wb && get_bool_attribute(ID::whitebox));
}
void set_string_attribute(RTLIL::IdString id, string value);
string get_string_attribute(RTLIL::IdString id) const;
void set_string_attribute(const RTLIL::IdString& id, string value);
string get_string_attribute(const RTLIL::IdString &id) const;
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;
void set_strpool_attribute(const RTLIL::IdString& id, const pool<string> &data);
void add_strpool_attribute(const RTLIL::IdString& id, const pool<string> &data);
pool<string> get_strpool_attribute(const RTLIL::IdString &id) const;
void set_src_attribute(const std::string &src) {
set_string_attribute(ID::src, src);
@ -1271,8 +1118,8 @@ struct RTLIL::AttrObject
void set_hdlname_attribute(const vector<string> &hierarchy);
vector<string> get_hdlname_attribute() const;
void set_intvec_attribute(RTLIL::IdString id, const vector<int> &data);
vector<int> get_intvec_attribute(RTLIL::IdString id) const;
void set_intvec_attribute(const RTLIL::IdString& id, const vector<int> &data);
vector<int> get_intvec_attribute(const RTLIL::IdString &id) const;
};
struct RTLIL::NamedObject : public RTLIL::AttrObject
@ -1734,8 +1581,6 @@ public:
operator std::vector<RTLIL::SigChunk>() const;
operator std::vector<RTLIL::SigBit>() const { return to_sigbit_vector(); }
const RTLIL::SigBit &at(int offset, const RTLIL::SigBit &defval) { return offset < size() ? (*this)[offset] : defval; }
RTLIL::SigBit& at(int offset) { return (*this)[offset]; }
RTLIL::SigBit at(int offset) const { return (*this)[offset]; }
[[nodiscard]] Hasher hash_into(Hasher h) const {
Hasher::hash_t val;
@ -1779,18 +1624,18 @@ struct RTLIL::Selection
// checks if the given module exists in the current design and is a
// boxed module, warning the user if the current design is not set
bool boxed_module(RTLIL::IdString mod_name) const;
bool boxed_module(const RTLIL::IdString &mod_name) const;
// checks if the given module is included in this selection
bool selected_module(RTLIL::IdString mod_name) const;
bool selected_module(const RTLIL::IdString &mod_name) const;
// checks if the given module is wholly included in this selection,
// i.e. not partially selected
bool selected_whole_module(RTLIL::IdString mod_name) const;
bool selected_whole_module(const RTLIL::IdString &mod_name) const;
// checks if the given member from the given module is included in this
// selection
bool selected_member(RTLIL::IdString mod_name, RTLIL::IdString memb_name) const;
bool selected_member(const RTLIL::IdString &mod_name, const RTLIL::IdString &memb_name) const;
// optimizes this selection for the given design by:
// - removing non-existent modules and members, any boxed modules and
@ -1860,7 +1705,7 @@ struct RTLIL::Monitor
virtual ~Monitor() { }
virtual void notify_module_add(RTLIL::Module*) { }
virtual void notify_module_del(RTLIL::Module*) { }
virtual void notify_connect(RTLIL::Cell*, RTLIL::IdString, const RTLIL::SigSpec&, const RTLIL::SigSpec&) { }
virtual void notify_connect(RTLIL::Cell*, const RTLIL::IdString&, const RTLIL::SigSpec&, const RTLIL::SigSpec&) { }
virtual void notify_connect(RTLIL::Module*, const RTLIL::SigSig&) { }
virtual void notify_connect(RTLIL::Module*, const std::vector<RTLIL::SigSig>&) { }
virtual void notify_blackout(RTLIL::Module*) { }
@ -1895,11 +1740,11 @@ struct RTLIL::Design
~Design();
RTLIL::ObjRange<RTLIL::Module*> modules();
RTLIL::Module *module(RTLIL::IdString name);
const RTLIL::Module *module(RTLIL::IdString name) const;
RTLIL::Module *module(const RTLIL::IdString &name);
const RTLIL::Module *module(const RTLIL::IdString &name) const;
RTLIL::Module *top_module() const;
bool has(RTLIL::IdString id) const {
bool has(const RTLIL::IdString &id) const {
return modules_.count(id) != 0;
}
@ -1926,15 +1771,15 @@ struct RTLIL::Design
void optimize();
// checks if the given module is included in the current selection
bool selected_module(RTLIL::IdString mod_name) const;
bool selected_module(const RTLIL::IdString &mod_name) const;
// checks if the given module is wholly included in the current
// selection, i.e. not partially selected
bool selected_whole_module(RTLIL::IdString mod_name) const;
bool selected_whole_module(const RTLIL::IdString &mod_name) const;
// checks if the given member from the given module is included in the
// current selection
bool selected_member(RTLIL::IdString mod_name, RTLIL::IdString memb_name) const;
bool selected_member(const RTLIL::IdString &mod_name, const RTLIL::IdString &memb_name) const;
// checks if the given module is included in the current selection
bool selected_module(RTLIL::Module *mod) const;
@ -2031,7 +1876,9 @@ struct RTLIL::Design
// returns all selected unboxed whole modules, warning the user if any
// partially selected or boxed modules have been ignored
std::vector<RTLIL::Module*> selected_unboxed_whole_modules_warn() const { return selected_modules(SELECT_WHOLE_WARN, SB_UNBOXED_WARN); }
#ifdef YOSYS_ENABLE_PYTHON
static std::map<unsigned int, RTLIL::Design*> *get_all_designs(void);
#endif
};
struct RTLIL::Module : public RTLIL::NamedObject
@ -2066,7 +1913,7 @@ public:
virtual ~Module();
virtual RTLIL::IdString derive(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> &parameters, bool mayfail = false);
virtual RTLIL::IdString derive(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Const> &parameters, const dict<RTLIL::IdString, RTLIL::Module*> &interfaces, const dict<RTLIL::IdString, RTLIL::IdString> &modports, bool mayfail = false);
virtual size_t count_id(RTLIL::IdString id);
virtual size_t count_id(const RTLIL::IdString& id);
virtual void expand_interfaces(RTLIL::Design *design, const dict<RTLIL::IdString, RTLIL::Module *> &local_interfaces);
virtual bool reprocess_if_necessary(RTLIL::Design *design);
@ -2118,20 +1965,20 @@ public:
return design->selected_member(name, member->name);
}
RTLIL::Wire* wire(RTLIL::IdString id) {
RTLIL::Wire* wire(const RTLIL::IdString &id) {
auto it = wires_.find(id);
return it == wires_.end() ? nullptr : it->second;
}
RTLIL::Cell* cell(RTLIL::IdString id) {
RTLIL::Cell* cell(const RTLIL::IdString &id) {
auto it = cells_.find(id);
return it == cells_.end() ? nullptr : it->second;
}
const RTLIL::Wire* wire(RTLIL::IdString id) const{
const RTLIL::Wire* wire(const RTLIL::IdString &id) const{
auto it = wires_.find(id);
return it == wires_.end() ? nullptr : it->second;
}
const RTLIL::Cell* cell(RTLIL::IdString id) const {
const RTLIL::Cell* cell(const RTLIL::IdString &id) const {
auto it = cells_.find(id);
return it == cells_.end() ? nullptr : it->second;
}
@ -2488,23 +2335,23 @@ public:
dict<RTLIL::IdString, RTLIL::Const> parameters;
// access cell ports
bool hasPort(RTLIL::IdString portname) const;
void unsetPort(RTLIL::IdString portname);
void setPort(RTLIL::IdString portname, RTLIL::SigSpec signal);
const RTLIL::SigSpec &getPort(RTLIL::IdString portname) const;
bool hasPort(const RTLIL::IdString &portname) const;
void unsetPort(const RTLIL::IdString &portname);
void setPort(const RTLIL::IdString &portname, RTLIL::SigSpec signal);
const RTLIL::SigSpec &getPort(const RTLIL::IdString &portname) const;
const dict<RTLIL::IdString, RTLIL::SigSpec> &connections() const;
// information about cell ports
bool known() const;
bool input(RTLIL::IdString portname) const;
bool output(RTLIL::IdString portname) const;
PortDir port_dir(RTLIL::IdString portname) const;
bool input(const RTLIL::IdString &portname) const;
bool output(const RTLIL::IdString &portname) const;
PortDir port_dir(const RTLIL::IdString &portname) const;
// access cell parameters
bool hasParam(RTLIL::IdString paramname) const;
void unsetParam(RTLIL::IdString paramname);
void setParam(RTLIL::IdString paramname, RTLIL::Const value);
const RTLIL::Const &getParam(RTLIL::IdString paramname) const;
bool hasParam(const RTLIL::IdString &paramname) const;
void unsetParam(const RTLIL::IdString &paramname);
void setParam(const RTLIL::IdString &paramname, RTLIL::Const value);
const RTLIL::Const &getParam(const RTLIL::IdString &paramname) const;
void sort();
void check();

View File

@ -526,7 +526,7 @@ void RTLIL::Module::bufNormalize()
pending_deleted_cells.clear();
}
void RTLIL::Cell::unsetPort(RTLIL::IdString portname)
void RTLIL::Cell::unsetPort(const RTLIL::IdString& portname)
{
RTLIL::SigSpec signal;
auto conn_it = connections_.find(portname);
@ -586,7 +586,7 @@ void RTLIL::Cell::unsetPort(RTLIL::IdString portname)
}
}
void RTLIL::Cell::setPort(RTLIL::IdString portname, RTLIL::SigSpec signal)
void RTLIL::Cell::setPort(const RTLIL::IdString& portname, RTLIL::SigSpec signal)
{
auto r = connections_.insert(portname);
auto conn_it = r.first;

View File

@ -97,13 +97,13 @@ static const char *attr_prefix(ScopeinfoAttrs attrs)
}
}
bool scopeinfo_has_attribute(const RTLIL::Cell *scopeinfo, ScopeinfoAttrs attrs, RTLIL::IdString id)
bool scopeinfo_has_attribute(const RTLIL::Cell *scopeinfo, ScopeinfoAttrs attrs, const RTLIL::IdString &id)
{
log_assert(scopeinfo->type == ID($scopeinfo));
return scopeinfo->has_attribute(attr_prefix(attrs) + RTLIL::unescape_id(id));
}
RTLIL::Const scopeinfo_get_attribute(const RTLIL::Cell *scopeinfo, ScopeinfoAttrs attrs, RTLIL::IdString id)
RTLIL::Const scopeinfo_get_attribute(const RTLIL::Cell *scopeinfo, ScopeinfoAttrs attrs, const RTLIL::IdString &id)
{
log_assert(scopeinfo->type == ID($scopeinfo));
auto found = scopeinfo->attributes.find(attr_prefix(attrs) + RTLIL::unescape_id(id));

View File

@ -433,10 +433,10 @@ enum class ScopeinfoAttrs {
};
// Check whether the flattened module or flattened cell corresponding to a $scopeinfo cell had a specific attribute.
bool scopeinfo_has_attribute(const RTLIL::Cell *scopeinfo, ScopeinfoAttrs attrs, RTLIL::IdString id);
bool scopeinfo_has_attribute(const RTLIL::Cell *scopeinfo, ScopeinfoAttrs attrs, const RTLIL::IdString &id);
// Get a specific attribute from the flattened module or flattened cell corresponding to a $scopeinfo cell.
RTLIL::Const scopeinfo_get_attribute(const RTLIL::Cell *scopeinfo, ScopeinfoAttrs attrs, RTLIL::IdString id);
RTLIL::Const scopeinfo_get_attribute(const RTLIL::Cell *scopeinfo, ScopeinfoAttrs attrs, const RTLIL::IdString &id);
// Get all attribute from the flattened module or flattened cell corresponding to a $scopeinfo cell.
dict<RTLIL::IdString, RTLIL::Const> scopeinfo_attributes(const RTLIL::Cell *scopeinfo, ScopeinfoAttrs attrs);

View File

@ -533,7 +533,7 @@ static int tcl_set_param(ClientData, Tcl_Interp *interp, int objc, Tcl_Obj *cons
return TCL_OK;
}
int yosys_tcl_interp_init(Tcl_Interp *interp)
int yosys_tcl_iterp_init(Tcl_Interp *interp)
{
if (Tcl_Init(interp)!=TCL_OK)
log_warning("Tcl_Init() call failed - %s\n",Tcl_ErrnoMsg(Tcl_GetErrno()));

View File

@ -3,20 +3,6 @@
YOSYS_NAMESPACE_BEGIN
static int init_max_threads()
{
const char *v = getenv("YOSYS_MAX_THREADS");
if (v == nullptr)
return INT32_MAX;
return atoi(v);
}
static int get_max_threads()
{
static int max_threads = init_max_threads();
return max_threads;
}
void DeferredLogs::flush()
{
for (auto &m : logs)
@ -26,11 +12,10 @@ void DeferredLogs::flush()
YOSYS_NAMESPACE_PREFIX log("%s", m.text.c_str());
}
int ThreadPool::pool_size(int reserved_cores, int max_worker_threads)
int ThreadPool::pool_size(int reserved_cores, int max_threads)
{
#ifdef YOSYS_ENABLE_THREADS
int available_threads = std::min<int>(std::thread::hardware_concurrency(), get_max_threads());
int num_threads = std::min(available_threads - reserved_cores, max_worker_threads);
int num_threads = std::min<int>(std::thread::hardware_concurrency() - reserved_cores, max_threads);
return std::max(0, num_threads);
#else
return 0;

View File

@ -127,9 +127,9 @@ class ThreadPool
public:
// Computes the number of worker threads to use.
// `reserved_cores` cores are set aside for other threads (e.g. work on the main thread).
// `max_worker_threads` --- don't return more workers than this.
// `max_threads` --- don't return more workers than this.
// The result may be 0.
static int pool_size(int reserved_cores, int max_worker_threads);
static int pool_size(int reserved_cores, int max_threads);
// Create a pool of threads running the given closure (parameterized by thread number).
// `pool_size` must be the result of a `pool_size()` call.

View File

@ -19,7 +19,6 @@
#include "kernel/yosys.h"
#include "kernel/celltypes.h"
#include "kernel/log.h"
#ifdef YOSYS_ENABLE_READLINE
# include <readline/readline.h>
@ -81,7 +80,7 @@ extern "C" PyObject* PyInit_pyosys();
YOSYS_NAMESPACE_BEGIN
Autoidx autoidx(1);
int autoidx = 1;
int yosys_xtrace = 0;
bool yosys_write_versions = true;
const char* yosys_maybe_version() {
@ -96,7 +95,6 @@ CellTypes yosys_celltypes;
#ifdef YOSYS_ENABLE_TCL
Tcl_Interp *yosys_tcl_interp = NULL;
Tcl_Interp *yosys_sdc_interp = NULL;
#endif
std::set<std::string> yosys_input_files, yosys_output_files;
@ -109,30 +107,9 @@ uint32_t Hasher::fudge = 0;
std::string yosys_share_dirname;
std::string yosys_abc_executable;
bool Multithreading::active_ = false;
void init_share_dirname();
void init_abc_executable_name();
Multithreading::Multithreading() {
log_assert(!active_);
active_ = true;
}
Multithreading::~Multithreading() {
log_assert(active_);
active_ = false;
}
void Autoidx::ensure_at_least(int v) {
value = std::max(value, v);
}
int Autoidx::operator++(int) {
log_assert(!Multithreading::active());
return value++;
}
void memhasher_on()
{
#if defined(__linux__) || defined(__FreeBSD__)
@ -283,7 +260,6 @@ void yosys_shutdown()
delete yosys_design;
yosys_design = NULL;
RTLIL::OwningIdString::collect_garbage();
for (auto f : log_files)
if (f != stderr)
@ -319,35 +295,35 @@ void yosys_shutdown()
#endif
}
const std::string *create_id_prefix(std::string_view file, int line, std::string_view func)
RTLIL::IdString new_id(std::string file, int line, std::string func)
{
#ifdef _WIN32
size_t pos = file.find_last_of("/\\");
#else
size_t pos = file.find_last_of('/');
#endif
if (pos != std::string_view::npos)
if (pos != std::string::npos)
file = file.substr(pos+1);
pos = func.find_last_of(':');
if (pos != std::string_view::npos)
if (pos != std::string::npos)
func = func.substr(pos+1);
return new std::string(stringf("$auto$%s:%d:%s$", file, line, func));
return stringf("$auto$%s:%d:%s$%d", file, line, func, autoidx++);
}
RTLIL::IdString new_id_suffix(std::string_view file, int line, std::string_view func, std::string_view suffix)
RTLIL::IdString new_id_suffix(std::string file, int line, std::string func, std::string suffix)
{
#ifdef _WIN32
size_t pos = file.find_last_of("/\\");
#else
size_t pos = file.find_last_of('/');
#endif
if (pos != std::string_view::npos)
if (pos != std::string::npos)
file = file.substr(pos+1);
pos = func.find_last_of(':');
if (pos != std::string_view::npos)
if (pos != std::string::npos)
func = func.substr(pos+1);
return stringf("$auto$%s:%d:%s$%s$%d", file, line, func, suffix, autoidx++);
@ -416,18 +392,17 @@ void rewrite_filename(std::string &filename)
#ifdef YOSYS_ENABLE_TCL
// defined in tclapi.cc
extern int yosys_tcl_interp_init(Tcl_Interp *interp);
extern int yosys_tcl_iterp_init(Tcl_Interp *interp);
extern Tcl_Interp *yosys_get_tcl_interp()
{
if (yosys_tcl_interp == NULL) {
yosys_tcl_interp = Tcl_CreateInterp();
yosys_tcl_interp_init(yosys_tcl_interp);
yosys_tcl_iterp_init(yosys_tcl_interp);
}
return yosys_tcl_interp;
}
// Also see SdcPass
struct TclPass : public Pass {
TclPass() : Pass("tcl", "execute a TCL script file") { }
void help() override {
@ -470,7 +445,6 @@ struct TclPass : public Pass {
Tcl_Release(interp);
}
} TclPass;
#endif
#if defined(__linux__) || defined(__CYGWIN__)

View File

@ -81,7 +81,6 @@ extern std::set<std::string> yosys_input_files, yosys_output_files;
// from kernel/version_*.o (cc source generated from Makefile)
extern const char *yosys_version_str;
extern const char *yosys_git_hash_str;
const char* yosys_maybe_version();
// from passes/cmds/design.cc

View File

@ -267,41 +267,15 @@ int ceil_log2(int x) YS_ATTRIBUTE(const);
template<typename T> int GetSize(const T &obj) { return obj.size(); }
inline int GetSize(RTLIL::Wire *wire);
// When multiple threads are accessing RTLIL, one of these guard objects
// must exist.
struct Multithreading
{
Multithreading();
~Multithreading();
// Returns true when multiple threads are accessing RTLIL.
// autoidx cannot be used during such times.
// IdStrings cannot be created during such times.
static bool active() { return active_; }
private:
static bool active_;
};
struct Autoidx {
Autoidx(int value) : value(value) {}
operator int() const { return value; }
void ensure_at_least(int v);
int operator++(int);
private:
int value;
};
extern Autoidx autoidx;
extern int autoidx;
extern int yosys_xtrace;
extern bool yosys_write_versions;
const std::string *create_id_prefix(std::string_view file, int line, std::string_view func);
RTLIL::IdString new_id_suffix(std::string_view file, int line, std::string_view func, std::string_view suffix);
RTLIL::IdString new_id(std::string file, int line, std::string func);
RTLIL::IdString new_id_suffix(std::string file, int line, std::string func, std::string suffix);
#define NEW_ID \
YOSYS_NAMESPACE_PREFIX RTLIL::IdString::new_autoidx_with_prefix([](std::string_view func) -> const std::string * { \
static std::unique_ptr<const std::string> prefix(YOSYS_NAMESPACE_PREFIX create_id_prefix(__FILE__, __LINE__, func)); \
return prefix.get(); \
}(__FUNCTION__))
YOSYS_NAMESPACE_PREFIX new_id(__FILE__, __LINE__, __FUNCTION__)
#define NEW_ID_SUFFIX(suffix) \
YOSYS_NAMESPACE_PREFIX new_id_suffix(__FILE__, __LINE__, __FUNCTION__, suffix)

View File

@ -912,10 +912,6 @@ class SubCircuit::SolverWorker
bool pruneEnumerationMatrix(std::vector<std::set<int>> &enumerationMatrix, const GraphData &needle, const GraphData &haystack, int &nextRow, bool allowOverlap)
{
bool didSomething = true;
// Map of j:[i where j is used]
std::map<int, std::set<int>> usedNodes;
while (didSomething)
{
nextRow = -1;
@ -927,23 +923,13 @@ class SubCircuit::SolverWorker
didSomething = true;
else if (!allowOverlap && haystack.usedNodes[j])
didSomething = true;
else {
else
newRow.insert(j);
usedNodes[j].insert(i); // Store the needle index by haystack node index
}
}
// This indicates there are no available haystack nodes to assign to the needle
if (newRow.size() == 0)
return false;
// If there are multiple needles assigned to the haystack node, the solution is invalid
if (newRow.size() == 1 && usedNodes[*newRow.begin()].size() > 1)
return false;
if (newRow.size() >= 2 && (nextRow < 0 || needle.adjMatrix.at(nextRow).size() < needle.adjMatrix.at(i).size()))
nextRow = i;
enumerationMatrix[i].swap(newRow);
}
}

View File

@ -1,8 +1,9 @@
#!/bin/bash
set -ex
vcxsrc="$1"
vcxsrc="$1-$2"
yosysver="$2"
gitsha="$3"
rm -rf YosysVS-Tpl-v2.zip YosysVS
wget https://github.com/YosysHQ/yosys/releases/download/resources/YosysVS-Tpl-v2.zip
@ -32,6 +33,7 @@ popd
head -n$n "$vcxsrc"/YosysVS/YosysVS.vcxproj
egrep '\.(h|hh|hpp|inc)$' srcfiles.txt | sed 's,.*,<ClInclude Include="../yosys/&" />,'
egrep -v '\.(h|hh|hpp|inc)$' srcfiles.txt | sed 's,.*,<ClCompile Include="../yosys/&" />,'
echo '<ClCompile Include="../yosys/kernel/version.cc" />'
tail -n +$((n+1)) "$vcxsrc"/YosysVS/YosysVS.vcxproj
} > "$vcxsrc"/YosysVS/YosysVS.vcxproj.new
@ -46,6 +48,9 @@ mkdir -p "$vcxsrc"/yosys
tar -cf - -T srcfiles.txt | tar -xf - -C "$vcxsrc"/yosys
cp -r share "$vcxsrc"/
echo "namespace Yosys { extern const char *yosys_version_str; const char *yosys_version_str=\"Yosys" \
"$yosysver (git sha1 $gitsha, Visual Studio)\"; }" > "$vcxsrc"/yosys/kernel/version.cc
cat > "$vcxsrc"/readme-git.txt << EOT
Want to use a git working copy for the yosys source code?
Open "Git Bash" in this directory and run:

View File

@ -27,6 +27,7 @@ OBJS += passes/cmds/logcmd.o
OBJS += passes/cmds/tee.o
OBJS += passes/cmds/write_file.o
OBJS += passes/cmds/connwrappers.o
OBJS += passes/cmds/cover.o
OBJS += passes/cmds/trace.o
OBJS += passes/cmds/plugin.o
OBJS += passes/cmds/check.o
@ -57,6 +58,3 @@ OBJS += passes/cmds/test_select.o
OBJS += passes/cmds/timeest.o
OBJS += passes/cmds/linecoverage.o
OBJS += passes/cmds/sort.o
OBJS += passes/cmds/icell_liberty.o
include $(YOSYS_SRC)/passes/cmds/sdc/Makefile.inc

163
passes/cmds/cover.cc Normal file
View File

@ -0,0 +1,163 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2014 Claire Xenia Wolf <claire@yosyshq.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include "kernel/yosys.h"
#include "kernel/log_help.h"
#include <sys/types.h>
#ifndef _WIN32
# include <unistd.h>
#else
# include <io.h>
#endif
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct CoverPass : public Pass {
CoverPass() : Pass("cover", "print code coverage counters") {
internal();
}
bool formatted_help() override {
auto *help = PrettyHelp::get_current();
help->set_group("passes/status");
return false;
}
void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" cover [options] [pattern]\n");
log("\n");
log("Print the code coverage counters collected using the cover() macro in the Yosys\n");
log("C++ code. This is useful to figure out what parts of Yosys are utilized by a\n");
log("test bench.\n");
log("\n");
log(" -q\n");
log(" Do not print output to the normal destination (console and/or log file)\n");
log("\n");
log(" -o file\n");
log(" Write output to this file, truncate if exists.\n");
log("\n");
log(" -a file\n");
log(" Write output to this file, append if exists.\n");
log("\n");
log(" -d dir\n");
log(" Write output to a newly created file in the specified directory.\n");
log("\n");
log("When one or more pattern (shell wildcards) are specified, then only counters\n");
log("matching at least one pattern are printed.\n");
log("\n");
log("\n");
log("It is also possible to instruct Yosys to print the coverage counters on program\n");
log("exit to a file using environment variables:\n");
log("\n");
log(" YOSYS_COVER_DIR=\"{dir-name}\" yosys {args}\n");
log("\n");
log(" This will create a file (with an auto-generated name) in this\n");
log(" directory and write the coverage counters to it.\n");
log("\n");
log(" YOSYS_COVER_FILE=\"{file-name}\" yosys {args}\n");
log("\n");
log(" This will append the coverage counters to the specified file.\n");
log("\n");
log("\n");
log("Hint: Use the following AWK command to consolidate Yosys coverage files:\n");
log("\n");
log(" gawk '{ p[$3] = $1; c[$3] += $2; } END { for (i in p)\n");
log(" printf \"%%-60s %%10d %%s\\n\", p[i], c[i], i; }' {files} | sort -k3\n");
log("\n");
log("\n");
log("Coverage counters are only available in Yosys for Linux.\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
std::vector<FILE*> out_files;
std::vector<std::string> patterns;
bool do_log = true;
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
if (args[argidx] == "-q") {
do_log = false;
continue;
}
if ((args[argidx] == "-o" || args[argidx] == "-a" || args[argidx] == "-d") && argidx+1 < args.size()) {
const char *open_mode = args[argidx] == "-a" ? "a+" : "w";
const std::string &filename = args[++argidx];
FILE *f = nullptr;
if (args[argidx-1] == "-d") {
#if defined(_WIN32) || defined(__wasm)
log_cmd_error("The 'cover -d' option is not supported on this platform.\n");
#else
char filename_buffer[4096];
snprintf(filename_buffer, 4096, "%s/yosys_cover_%d_XXXXXX.txt", filename.c_str(), getpid());
f = fdopen(mkstemps(filename_buffer, 4), "w");
#endif
} else {
f = fopen(filename.c_str(), open_mode);
}
if (f == NULL) {
for (auto f : out_files)
fclose(f);
log_cmd_error("Can't create file %s%s.\n", args[argidx-1] == "-d" ? "in directory " : "", args[argidx]);
}
out_files.push_back(f);
continue;
}
break;
}
while (argidx < args.size() && args[argidx].compare(0, 1, "-") != 0)
patterns.push_back(args[argidx++]);
extra_args(args, argidx, design);
if (do_log) {
log_header(design, "Printing code coverage counters.\n");
log("\n");
}
#if defined(YOSYS_ENABLE_COVER) && (defined(__linux__) || defined(__FreeBSD__))
for (auto &it : get_coverage_data()) {
if (!patterns.empty()) {
for (auto &p : patterns)
if (patmatch(p.c_str(), it.first.c_str()))
goto pattern_match;
continue;
}
pattern_match:
for (auto f : out_files)
fprintf(f, "%-60s %10d %s\n", it.second.first.c_str(), it.second.second, it.first.c_str());
if (do_log)
log("%-60s %10d %s\n", it.second.first, it.second.second, it.first);
}
#else
for (auto f : out_files)
fclose(f);
log_cmd_error("This version of Yosys was not built with support for code coverage counters.\n");
#endif
for (auto f : out_files)
fclose(f);
}
} CoverPass;
PRIVATE_NAMESPACE_END

View File

@ -77,7 +77,7 @@ struct ExampleDtPass : public Pass
auto enqueue = [&](DriveSpec const &spec) {
int index = queue(spec);
if (index == GetSize(graph_nodes))
graph_nodes.emplace_back(compute_graph.add(ID($pending), index).index());
graph_nodes.emplace_back(compute_graph.add(ID($pending).id_string(), index).index());
//if (index >= GetSize(graph_nodes))
return compute_graph[graph_nodes[index]];
};

View File

@ -1,206 +0,0 @@
#include "kernel/yosys.h"
#include "kernel/celltypes.h"
#include "kernel/ff.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct LibertyStubber {
CellTypes ct;
LibertyStubber() {
ct.setup();
ct.setup_internals_ff();
}
void liberty_prefix(std::ostream& f)
{
f << "/*\n";
f << stringf("\tModels interfaces of select Yosys internal cell.\n");
f << stringf("\tLikely contains INCORRECT POLARITIES.\n");
f << stringf("\tImpractical for any simulation, synthesis, or timing.\n");
f << stringf("\tIntended purely for SDC expansion.\n");
f << stringf("\tDo not microwave or tumble dry.\n");
f << stringf("\tGenerated by %s\n", yosys_maybe_version());
f << "*/\n";
f << "library (yosys) {\n";
f << "\tinput_threshold_pct_fall : 50;\n";
f << "\tinput_threshold_pct_rise : 50;\n";
f << "\toutput_threshold_pct_fall : 50;\n";
f << "\toutput_threshold_pct_rise : 50;\n";
f << "\tslew_lower_threshold_pct_fall : 1;\n";
f << "\tslew_lower_threshold_pct_rise : 1;\n";
f << "\tslew_upper_threshold_pct_fall : 99;\n";
f << "\tslew_upper_threshold_pct_rise : 99;\n";
}
void liberty_suffix(std::ostream& f)
{
f << "}\n";
}
struct LibertyItemizer {
std::ostream& f;
int indent;
LibertyItemizer(std::ostream& f) : f(f), indent(0) {};
void item(std::string key, std::string val)
{
f << std::string(indent, '\t') << key << " : \"" << val << "\";\n";
}
};
void liberty_flop(Module* base, Module* derived, std::ostream& f)
{
auto base_name = base->name.str().substr(1);
auto derived_name = derived->name.str().substr(1);
FfTypeData ffType(base_name);
LibertyItemizer i(f);
if (ffType.has_gclk) {
log_warning("Formal flip flop %s can't be modeled\n", base_name.c_str());
return;
}
if (ffType.has_ce) {
log_warning("DFFE %s can't be modeled\n", base_name.c_str());
return;
}
f << "\tcell (\"" << derived_name << "\") {\n";
auto& base_type = ct.cell_types[base_name];
i.indent = 3;
auto sorted_ports = derived->ports;
// Hack for CLK and C coming before Q does
auto cmp = [](IdString l, IdString r) { return l.str() < r.str(); };
std::sort(sorted_ports.begin(), sorted_ports.end(), cmp);
std::string clock_pin_name = "";
for (auto x : sorted_ports) {
std::string port_name = RTLIL::unescape_id(x);
bool is_input = base_type.inputs.count(x);
bool is_output = base_type.outputs.count(x);
f << "\t\tpin (" << RTLIL::unescape_id(x.str()) << ") {\n";
if (is_input && !is_output) {
i.item("direction", "input");
} else if (!is_input && is_output) {
i.item("direction", "output");
} else {
i.item("direction", "inout");
}
if (port_name == "CLK" || port_name == "C") {
i.item("clock", "true");
clock_pin_name = port_name;
}
if (port_name == "Q") {
i.item("function", "IQ");
f << "\t\t\ttiming () {\n";
i.indent++;
log_assert(clock_pin_name.size());
i.item("related_pin", clock_pin_name);
i.indent--;
f << "\t\t\t}\n";
}
f << "\t\t}\n";
}
f << "\t\tff (\"IQ\",\"IQ_N\") {\n";
i.indent = 3;
// TODO polarities?
if (ffType.has_clk) {
auto pin = ffType.is_fine ? "C" : "CLK";
i.item("clocked_on", pin);
}
if (ffType.has_arst) {
auto meaning = (ffType.val_arst == State::S1) ? "preset" : "clear";
auto pin = ffType.is_fine ? "R" : "ARST";
i.item(meaning, pin);
}
auto next_state = ffType.has_ce ? "D & EN" : "D";
i.item("next_state", next_state);
f << "\t\t}\n";
f << "\t}\n";
}
void liberty_cell(Module* base, Module* derived, std::ostream& f)
{
auto base_name = base->name.str().substr(1);
auto derived_name = derived->name.str().substr(1);
if (!ct.cell_types.count(base_name)) {
log_debug("skip skeleton for %s\n", base_name.c_str());
return;
}
if (RTLIL::builtin_ff_cell_types().count(base_name))
return liberty_flop(base, derived, f);
auto& base_type = ct.cell_types[base_name];
f << "\tcell (\"" << derived_name << "\") {\n";
for (auto x : derived->ports) {
bool is_input = base_type.inputs.count(x);
bool is_output = base_type.outputs.count(x);
f << "\t\tpin (" << RTLIL::unescape_id(x.str()) << ") {\n";
if (is_input && !is_output) {
f << "\t\t\tdirection : input;\n";
} else if (!is_input && is_output) {
f << "\t\t\tdirection : output;\n";
} else {
f << "\t\t\tdirection : inout;\n";
}
f << "\t\t}\n";
}
f << "\t}\n";
}
};
struct IcellLiberty : Pass {
IcellLiberty() : Pass("icell_liberty", "write Liberty interfaces for used internal cells") {}
void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" icell_liberty <liberty_file>\n");
log("\n");
log("Write Liberty files modeling the interfaces of used internal cells.\n");
log("\n");
log("Models are not guaranteed to be logically sound.\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *d) override
{
log_header(d, "Executing ICELL_LIBERTY pass.\n");
size_t argidx;
std::string liberty_filename;
auto liberty_file = std::make_unique<std::ofstream>();
for (argidx = 1; argidx < args.size(); argidx++) {
break;
}
if (argidx < args.size())
liberty_filename = args[argidx++];
else
log_cmd_error("no Liberty filename specified\n");
if (liberty_filename.size()) {
liberty_file->open(liberty_filename.c_str());
if (liberty_file->fail()) {
log_cmd_error("Can't open file `%s' for writing: %s\n", liberty_filename.c_str(), strerror(errno));
}
}
pool<RTLIL::IdString> done;
LibertyStubber stubber = {};
stubber.liberty_prefix(*liberty_file);
for (auto module : d->selected_modules()) {
for (auto cell : module->selected_cells()) {
Module *inst_module = d->module(cell->type);
if (!inst_module || !inst_module->get_blackbox_attribute())
continue;
Module *base = inst_module;
if (!done.count(base->name)) {
stubber.liberty_cell(base, base, *liberty_file);
done.insert(base->name);
}
}
}
stubber.liberty_suffix(*liberty_file);
}
} IcellLiberty;
PRIVATE_NAMESPACE_END

View File

@ -45,7 +45,7 @@ struct PrintAttrsPass : public Pass {
return stringf("%*s", indent, "");
}
static void log_const(RTLIL::IdString s, const RTLIL::Const &x, const unsigned int indent) {
static void log_const(const RTLIL::IdString &s, const RTLIL::Const &x, const unsigned int indent) {
if (x.flags & RTLIL::CONST_FLAG_STRING)
log("%s(* %s=\"%s\" *)\n", get_indent_str(indent), log_id(s), x.decode_string());
else if (x.flags == RTLIL::CONST_FLAG_NONE || x.flags == RTLIL::CONST_FLAG_SIGNED)

View File

@ -1,3 +0,0 @@
OBJS += passes/cmds/sdc/sdc.o
$(eval $(call add_share_file,share/sdc,passes/cmds/sdc/graph-stubs.sdc))

View File

@ -1,42 +0,0 @@
proc unknown {args} {
# Check if it's a getter
if {[llength $args] > 0} {
set first_arg [lindex $args 0]
if {[string match "get_*" $first_arg]} {
# It's a getter, has it been redirected from specialized C++ code?
if {[llength $args] > 1} {
set second_arg [lindex $args 1]
if {$second_arg ne "-getter-validated"} {
error "Unknown getter: $first_arg"
}
} else {
error "Unknown getter: $first_arg"
}
}
}
# TODO this safety feature could be optional via a global
global sdc_call_index
global sdc_calls
if {![info exists sdc_call_index]} {
set sdc_call_index 0
}
if {![info exists sdc_calls]} {
set sdc_calls {}
}
set ret "YOSYS_SDC_MAGIC_NODE_$sdc_call_index"
incr sdc_call_index
lappend sdc_calls $args
# puts "unknown $args, returning YOSYS_SDC_MAGIC_NODE_$sdc_call_index"
return $ret
}
proc list {args} {
return [unknown "list" {*}$args]
}
proc get_clocks {args} {
# get_clocks isn't a design object getter
# because clocks aren't design objects, just aliases
# so the referred to clock pin already are being tracked
# as arguments of uninterpreted create_clock command or similar
return [unknown "get_clocks" "-getter-validated" {*}$args]
}

View File

@ -1,790 +0,0 @@
#ifdef YOSYS_ENABLE_TCL
#include "kernel/register.h"
#include "kernel/rtlil.h"
#include "kernel/log.h"
#include <tcl.h>
#include <list>
#include <optional>
#include <iostream>
#if TCL_MAJOR_VERSION < 9
typedef int YS_Tcl_Size;
#else
typedef Tcl_Size YS_Tcl_Size;
#endif
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct TclCall {
Tcl_Interp *interp;
int objc;
Tcl_Obj* const* objv;
};
static int redirect_unknown(TclCall call);
static size_t get_node_count(Tcl_Interp* interp);
struct BitSelection {
bool all = false;
std::vector<bool> bits = {};
void set_all() {
bits.clear();
all = true;
}
void clear() {
bits.clear();
all = false;
}
void set(size_t idx) {
if (all)
return;
if (idx >= bits.size())
bits.resize(idx + 1);
bits[idx] = true;
}
void merge(const BitSelection& other) {
if (all)
return;
if (other.all) {
set_all();
return;
}
if (other.bits.size() > bits.size())
bits.resize(other.bits.size());
for (size_t other_idx = 0; other_idx < other.bits.size(); other_idx++) {
bool other_bit = other.bits[other_idx];
if (other_bit)
set(other_idx);
}
}
void dump() {
if (!all) {
for (size_t i = 0; i < bits.size(); i++)
if (bits[i])
log("\t\t [%zu]\n", i);
} else {
log("\t\t FULL\n");
}
}
bool is_set(size_t idx) const {
if (all)
return true;
if (idx >= bits.size())
return false;
return bits[idx];
}
// TODO actually use this
void compress(size_t size) {
if (bits.size() < size)
return;
for (size_t i = 0; i < size; i++)
if (!bits[i])
return;
bits.clear();
bits.shrink_to_fit();
all = true;
}
};
struct SdcObjects {
enum CollectMode {
// getter-side object tracking with minimal features
SimpleGetter,
// getter-side object tracking with everything
FullGetter,
// constraint-side tracking
FullConstraint,
} collect_mode;
using CellPin = std::pair<Cell*, IdString>;
Design* design;
std::vector<std::pair<std::string, Wire*>> design_ports;
std::vector<std::pair<std::string, Cell*>> design_cells;
std::vector<std::pair<std::string, CellPin>> design_pins;
std::vector<std::pair<std::string, Wire*>> design_nets;
using PortPattern = std::tuple<std::string, Wire*, BitSelection>;
using PinPattern = std::tuple<std::string, SdcObjects::CellPin, BitSelection>;
std::vector<std::vector<PortPattern>> resolved_port_pattern_sets;
std::vector<std::vector<PinPattern>> resolved_pin_pattern_sets;
// TODO
dict<std::pair<std::string, Wire*>, BitSelection> constrained_ports;
pool<std::pair<std::string, Cell*>> constrained_cells;
dict<std::pair<std::string, CellPin>, BitSelection> constrained_pins;
dict<std::pair<std::string, Wire*>, BitSelection> constrained_nets;
void sniff_module(std::list<std::string>& hierarchy, Module* mod) {
std::string prefix;
for (auto mod_name : hierarchy) {
if (prefix.length())
prefix += "/"; // TODO seperator?
prefix += mod_name;
}
for (auto* wire : mod->wires()) {
std::string name = wire->name.str();
log_assert(name.length());
// TODO: really skip internal wires?
if (name[0] == '$')
continue;
name = name.substr(1);
std::string path = prefix;
if (path.length())
path += "/";
path += name;
design_nets.push_back(std::make_pair(path, wire));
}
for (auto* cell : mod->cells()) {
std::string name = cell->name.str();
// TODO: really skip internal cells?
if (name[0] == '$')
continue;
name = name.substr(1);
std::string path = prefix;
if (path.length())
path += "/";
path += name;
design_cells.push_back(std::make_pair(path, cell));
for (auto pin : cell->connections()) {
IdString pin_name = pin.first;
std::string pin_name_sdc = path + "/" + pin.first.str().substr(1);
design_pins.push_back(std::make_pair(pin_name_sdc, std::make_pair(cell, pin_name)));
}
if (auto sub_mod = mod->design->module(cell->type)) {
hierarchy.push_back(name);
sniff_module(hierarchy, sub_mod);
hierarchy.pop_back();
}
}
}
SdcObjects(Design* design) : design(design) {
Module* top = design->top_module();
if (!top)
log_error("Top module couldn't be determined. Check 'top' attribute usage");
for (auto port : top->ports) {
design_ports.push_back(std::make_pair(port.str().substr(1), top->wire(port)));
}
std::list<std::string> hierarchy{};
sniff_module(hierarchy, top);
}
~SdcObjects() = default;
template <typename T, typename U>
void build_normal_result(Tcl_Interp* interp, std::vector<std::tuple<std::string, T, BitSelection>>&& resolved, U& tgt, std::function<size_t(T&)> width, Tcl_Obj*& result) {
if (!result)
result = Tcl_NewListObj(resolved.size(), nullptr);
for (auto [name, obj, matching_bits] : resolved) {
for (size_t i = 0; i < width(obj); i++)
if (matching_bits.is_set(i)) {
Tcl_ListObjAppendElement(interp, result, Tcl_NewStringObj(name.c_str(), name.size()));
break;
}
}
size_t node_count = get_node_count(interp);
tgt.emplace_back(std::move(resolved));
log("%zu %zu\n", node_count, tgt.size());
log_assert(node_count == tgt.size());
}
template <typename T>
void merge_as_constrained(std::vector<std::tuple<std::string, T, BitSelection>>&& resolved) {
for (auto [name, obj, matching_bits] : resolved) {
merge_or_init(std::make_pair(name, obj), constrained_pins, matching_bits);
}
}
void dump() {
std::sort(design_ports.begin(), design_ports.end());
std::sort(design_cells.begin(), design_cells.end());
std::sort(design_pins.begin(), design_pins.end());
std::sort(design_nets.begin(), design_nets.end());
constrained_ports.sort();
constrained_cells.sort();
constrained_pins.sort();
constrained_nets.sort();
// log("Design ports:\n");
// for (auto name : design_ports) {
// log("\t%s\n", name.c_str());
// }
// log("Design cells:\n");
// for (auto [name, cell] : design_cells) {
// (void)cell;
// log("\t%s\n", name.c_str());
// }
// log("Design pins:\n");
// for (auto [name, pin] : design_pins) {
// (void)pin;
// log("\t%s\n", name.c_str());
// }
// log("Design nets:\n");
// for (auto [name, net] : design_nets) {
// (void)net;
// log("\t%s\n", name.c_str());
// }
// log("\n");
log("Constrained ports:\n");
for (auto [ref, bits] : constrained_ports) {
auto [name, port] = ref;
(void)port;
log("\t%s\n", name.c_str());
bits.dump();
}
log("Constrained cells:\n");
for (auto& [name, cell] : constrained_cells) {
(void)cell;
log("\t%s\n", name.c_str());
}
log("Constrained pins:\n");
for (auto& [ref, bits] : constrained_pins) {
auto [name, pin] = ref;
(void)pin;
log("\t%s\n", name.c_str());
bits.dump();
}
log("Constrained nets:\n");
for (auto& [ref, bits] : constrained_nets) {
auto [name, net] = ref;
(void)net;
log("\t%s\n", name.c_str());
bits.dump();
}
log("\n");
}
class KeepHierarchyWorker {
std::unordered_set<Module*> tracked_modules = {};
Design* design = nullptr;
bool mark(Module* mod) {
for (auto* cell : mod->cells()) {
if (auto* submod = design->module(cell->type))
if (mark(submod)) {
mod->set_bool_attribute(ID::keep_hierarchy);
return true;
}
}
if (tracked_modules.count(mod)) {
mod->set_bool_attribute(ID::keep_hierarchy);
return true;
}
return false;
}
public:
KeepHierarchyWorker(SdcObjects* objects, Design* d) : design(d) {
for (auto [ref, _] : objects->constrained_ports) {
tracked_modules.insert(ref.second->module);
}
for (auto& [_, cell] : objects->constrained_cells) {
tracked_modules.insert(cell->module);
}
for (auto& [ref, _] : objects->constrained_pins) {
tracked_modules.insert(ref.second.first->module);
}
for (auto& [ref, _] : objects->constrained_nets) {
tracked_modules.insert(ref.second->module);
}
log_debug("keep_hierarchy tracked modules:\n");
for (auto* mod : tracked_modules)
log_debug("\t%s\n", mod->name);
}
bool mark() {
return mark(design->top_module());
}
};
void keep_hierarchy() {
(void)KeepHierarchyWorker(this, design).mark();
}
};
// TODO vectors
// TODO cell arrays?
struct MatchConfig {
enum MatchMode {
WILDCARD,
REGEX,
} match;
bool match_case;
enum HierMode {
FLAT,
TREE,
} hier;
MatchConfig(bool regexp_flag, bool nocase_flag, bool hierarchical_flag) :
match(regexp_flag ? REGEX : WILDCARD),
match_case(!nocase_flag),
hier(hierarchical_flag ? FLAT : TREE) { }
};
static std::pair<bool, BitSelection> matches(std::string name, const std::string& pat, const MatchConfig& config) {
(void)config;
bool got_bit_index = false;;
int bit_idx;
std::string pat_base = pat;
size_t pos = pat.rfind('[');
if (pos != std::string::npos) {
got_bit_index = true;
pat_base = pat.substr(0, pos);
std::string bit_selector = pat.substr(pos + 1, pat.rfind(']') - pos - 1);
for (auto c : bit_selector)
if (!std::isdigit(c))
log_error("Unsupported bit selector %s in SDC pattern %s\n",
bit_selector.c_str(), pat.c_str());
bit_idx = std::stoi(bit_selector);
}
BitSelection bits = {};
if (name == pat_base) {
if (got_bit_index) {
bits.set(bit_idx);
return std::make_pair(true, bits);
} else {
bits.set_all();
return std::make_pair(true, bits);
}
} else {
return std::make_pair(false, bits);
}
}
static int getter_graph_node(TclCall call) {
// Insert -getter-validated as first argument for passing to unknown
// to distinguish resolved and unknown getters.
// For example, if call is ["get_foo", "-bar"]
// then newCall is ["get_foo", "-getter-validated", "-bar"]
Tcl_Obj* validity_tag = Tcl_NewStringObj("-getter-validated", -1);
Tcl_IncrRefCount(validity_tag);
std::vector<Tcl_Obj*> newObjv(call.objc + 1);
log_assert(call.objc > 0);
newObjv[0] = call.objv[0];
newObjv[1] = validity_tag;
for (int i = 1; i < call.objc; ++i) {
newObjv[i + 1] = call.objv[i];
}
// Send the vector to the Tcl land
Tcl_Obj** allocatedObjv = (Tcl_Obj**)Tcl_Alloc((call.objc + 1) * sizeof(Tcl_Obj*));
for (int i = 0; i < call.objc + 1; ++i) {
allocatedObjv[i] = newObjv[i];
}
TclCall newCall {
.interp = call.interp,
.objc = call.objc + 1,
.objv = allocatedObjv
};
// Finally, redirect to unknown handler
return redirect_unknown(newCall);
}
static int redirect_unknown(TclCall call) {
// TODO redirect to different command
Tcl_Obj *newCmd = Tcl_NewStringObj("unknown", -1);
auto newObjc = call.objc + 1;
Tcl_Obj** newObjv = (Tcl_Obj**)Tcl_Alloc(newObjc * sizeof(Tcl_Obj*));
newObjv[0] = newCmd;
for (int i = 1; i < newObjc; i++) {
newObjv[i] = call.objv[i - 1];
}
int result = Tcl_EvalObjv(call.interp, newObjc, newObjv, 0);
Tcl_DecrRefCount(newCmd);
Tcl_Free((char*) newObjv);
return result;
}
struct SdcGraphNode {
using Child = std::variant<SdcGraphNode*, std::string>;
std::vector<Child> children;
SdcGraphNode() = default;
void addChild(SdcGraphNode* child) {
children.push_back(child);
}
void addChild(std::string tcl_string) {
children.push_back(tcl_string);
}
void dump(std::ostream& os) const {
bool first = true;
for (auto child : children) {
if (first) {
first = false;
} else {
os << " ";
}
if (auto* s = std::get_if<std::string>(&child))
os << *s;
else if (SdcGraphNode*& c = *std::get_if<SdcGraphNode*>(&child)) {
os << "[";
c->dump(os);
os << "]";
} else {
log_assert(false);
}
}
}
};
static size_t get_node_count(Tcl_Interp* interp) {
const char* idx_raw = Tcl_GetVar(interp, "sdc_call_index", TCL_GLOBAL_ONLY);
log_assert(idx_raw);
std::string idx(idx_raw);
for (auto c : idx)
if (!std::isdigit(c))
log_error("sdc_call_index non-numeric value %s\n", idx.c_str());
return std::stoi(idx);
}
std::vector<std::vector<std::string>> gather_nested_calls(Tcl_Interp* interp) {
Tcl_Obj* listObj = Tcl_GetVar2Ex(interp, "sdc_calls", nullptr, TCL_GLOBAL_ONLY);
YS_Tcl_Size listLength;
std::vector<std::vector<std::string>> sdc_calls;
if (Tcl_ListObjLength(interp, listObj, &listLength) == TCL_OK) {
for (int i = 0; i < listLength; i++) {
Tcl_Obj* subListObj;
std::vector<std::string> subList;
if (Tcl_ListObjIndex(interp, listObj, i, &subListObj) != TCL_OK) {
log_error("broken list of lists\n");
}
YS_Tcl_Size subListLength;
if (Tcl_ListObjLength(interp, subListObj, &subListLength) == TCL_OK) {
// Valid list - extract elements
for (int j = 0; j < subListLength; j++) {
Tcl_Obj* elementObj;
if (Tcl_ListObjIndex(interp, subListObj, j, &elementObj) == TCL_OK) {
const char* elementStr = Tcl_GetString(elementObj);
subList.push_back(std::string(elementStr));
}
}
} else {
// Single element, not a list
const char* elementStr = Tcl_GetString(subListObj);
subList.push_back(std::string(elementStr));
}
sdc_calls.push_back(subList);
}
}
log_assert(sdc_calls.size() == get_node_count(interp));
return sdc_calls;
}
std::vector<SdcGraphNode> build_graph(const std::vector<std::vector<std::string>>& sdc_calls) {
size_t node_count = sdc_calls.size();
std::vector<SdcGraphNode> graph(node_count);
for (size_t i = 0; i < node_count; i++) {
auto& new_node = graph[i];
for (size_t j = 0; j < sdc_calls[i].size(); j++) {
auto arg = sdc_calls[i][j];
const std::string prefix = "YOSYS_SDC_MAGIC_NODE_";
auto pos = arg.find(prefix);
if (pos != std::string::npos) {
std::string rest = arg.substr(pos + prefix.length());
for (auto c : rest)
if (!std::isdigit(c))
log_error("weird thing %s in %s\n", rest.c_str(), arg.c_str());
size_t arg_node_idx = std::stoi(rest);
log_assert(arg_node_idx < graph.size());
new_node.addChild(&graph[arg_node_idx]);
} else {
new_node.addChild(arg);
}
}
}
return graph;
}
std::vector<bool> node_ownership(const std::vector<SdcGraphNode>& graph) {
std::vector<bool> has_parent(graph.size());
for (auto node : graph) {
for (auto child : node.children) {
if (SdcGraphNode** pp = std::get_if<SdcGraphNode*>(&child)) {
size_t idx = std::distance(&graph.front(), (const SdcGraphNode*)*pp);
log_assert(idx < has_parent.size());
has_parent[idx] = true;
}
}
}
return has_parent;
}
void dump_sdc_graph(const std::vector<SdcGraphNode>& graph, const std::vector<bool>& has_parent) {
for (size_t i = 0; i < graph.size(); i++) {
if (!has_parent[i]) {
graph[i].dump(std::cout);
std::cout << "\n";
}
}
}
void inspect_globals(Tcl_Interp* interp, bool dump_mode) {
std::vector<std::vector<std::string>> sdc_calls = gather_nested_calls(interp);
std::vector<SdcGraphNode> graph = build_graph(sdc_calls);
if (dump_mode)
dump_sdc_graph(graph, node_ownership(graph));
}
// patterns -> (pattern-object-bit)s
template <typename T, typename U>
std::vector<std::tuple<std::string, T, BitSelection>>
find_matching(U objects, const MatchConfig& config, const std::vector<std::string> &patterns, const char* obj_type)
{
std::vector<std::tuple<std::string, T, BitSelection>> resolved;
for (auto pat : patterns) {
bool found = false;
for (auto [name, obj] : objects) {
auto [does_match, matching_bits] = matches(name, pat, config);
if (does_match) {
found = true;
resolved.push_back(std::make_tuple(name, obj, matching_bits));
// TODO add a continue statement, conditional on config
}
}
if (!found)
log_warning("No matches in design for %s %s\n", obj_type, pat.c_str());
}
return resolved;
}
struct TclOpts {
const char* name;
std::initializer_list<const char*> legals;
TclOpts(const char* name, std::initializer_list<const char*> legals) : name(name), legals(legals) {}
bool parse_opt(Tcl_Obj* obj, const char* opt_name) {
char* arg = Tcl_GetString(obj);
std::string expected = std::string("-") + opt_name;
if (expected == arg) {
if (!std::find_if(legals.begin(), legals.end(),
[&opt_name](const char* str) { return opt_name == str; }))
log_cmd_error("Illegal argument %s for %s.\n", expected.c_str(), name);
return true;
}
return false;
}
};
struct GetterOpts : TclOpts {
bool hierarchical_flag = false;
bool regexp_flag = false;
bool nocase_flag = false;
std::string separator = "/";
Tcl_Obj* of_objects = nullptr;
std::vector<std::string> patterns = {};
GetterOpts(const char* name, std::initializer_list<const char*> legals) : TclOpts(name, legals) {}
template<typename T>
bool parse_flag(Tcl_Obj* obj, const char* flag_name, T& flag_var) {
bool ret = parse_opt(obj, flag_name);
if (ret)
flag_var = true;
return ret;
}
void parse(int objc, Tcl_Obj* const objv[]) {
int i = 1;
for (; i < objc; i++) {
if (parse_flag(objv[i], "hierarchical", hierarchical_flag)) continue;
if (parse_flag(objv[i], "hier", hierarchical_flag)) continue;
if (parse_flag(objv[i], "regexp", regexp_flag)) continue;
if (parse_flag(objv[i], "nocase", nocase_flag)) continue;
if (parse_opt(objv[i], "hsc")) {
log_assert(i + 1 < objc);
separator = Tcl_GetString(objv[++i]);
continue;
}
if (parse_opt(objv[i], "of_objects")) {
log_assert(i + 1 < objc);
of_objects = objv[++i];
continue;
}
break;
}
for (; i < objc; i++) {
patterns.push_back(Tcl_GetString(objv[i]));
}
};
void check_simple() {
if (regexp_flag || hierarchical_flag || nocase_flag || separator != "/" || of_objects) {
log_error("%s got unexpected flags in simple mode\n", name);
}
if (patterns.size() != 1)
log_error("%s got unexpected number of patterns in simple mode: %zu\n", name, patterns.size());
}
void check_simple_sep() {
if (separator != "/")
log_error("Only '/' accepted as separator");
}
};
template <typename T>
void merge_or_init(const T& key, dict<T, BitSelection>& dst, const BitSelection& src) {
if (dst.count(key) == 0) {
dst[key] = src;
} else {
dst[key].merge(src);
}
}
static int sdc_get_pins_cmd(ClientData data, Tcl_Interp *interp, int objc, Tcl_Obj* const objv[])
{
auto* objects = (SdcObjects*)data;
GetterOpts opts("get_pins", {"hierarchical", "hier", "regexp", "nocase", "hsc", "of_objects"});
opts.parse(objc, objv);
if (objects->collect_mode == SdcObjects::CollectMode::SimpleGetter)
opts.check_simple();
opts.check_simple_sep();
MatchConfig config(opts.regexp_flag, opts.nocase_flag, opts.hierarchical_flag);
std::vector<std::tuple<std::string, SdcObjects::CellPin, BitSelection>> resolved;
const auto& pins = objects->design_pins;
resolved = find_matching<SdcObjects::CellPin, decltype(pins)>(pins, config, opts.patterns, "pin");
return getter_graph_node(TclCall{interp, objc, objv});
}
static int sdc_get_ports_cmd(ClientData data, Tcl_Interp *interp, int objc, Tcl_Obj* const objv[])
{
auto* objects = (SdcObjects*)data;
GetterOpts opts("get_ports", {"regexp", "nocase"});
opts.parse(objc, objv);
if (objects->collect_mode == SdcObjects::CollectMode::SimpleGetter)
opts.check_simple();
MatchConfig config(opts.regexp_flag, opts.nocase_flag, false);
std::vector<std::tuple<std::string, Wire*, BitSelection>> resolved;
const auto& ports = objects->design_ports;
resolved = find_matching<Wire*, decltype(ports)>(ports, config, opts.patterns, "port");
for (auto [name, wire, matching_bits] : resolved) {
if (objects->collect_mode != SdcObjects::CollectMode::FullConstraint)
merge_or_init(std::make_pair(name, wire), objects->constrained_ports, matching_bits);
}
return getter_graph_node(TclCall{interp, objc, objv});
}
static int sdc_get_nets_cmd(ClientData data, Tcl_Interp *interp, int objc, Tcl_Obj* const objv[])
{
auto* objects = (SdcObjects*)data;
GetterOpts opts("get_nets", {"hierarchical", "hier", "regexp", "nocase", "hsc", "of_objects"});
opts.parse(objc, objv);
if (objects->collect_mode == SdcObjects::CollectMode::SimpleGetter)
opts.check_simple();
MatchConfig config(opts.regexp_flag, opts.nocase_flag, false);
std::vector<std::tuple<std::string, Wire*, BitSelection>> resolved;
const auto& ports = objects->design_nets;
resolved = find_matching<Wire*, decltype(ports)>(ports, config, opts.patterns, "net");
for (auto [name, wire, matching_bits] : resolved) {
if (objects->collect_mode != SdcObjects::CollectMode::FullConstraint)
merge_or_init(std::make_pair(name, wire), objects->constrained_nets, matching_bits);
}
return getter_graph_node(TclCall{interp, objc, objv});
}
class SDCInterpreter
{
private:
Tcl_Interp* interp = nullptr;
public:
std::unique_ptr<SdcObjects> objects;
~SDCInterpreter() {
if (interp)
Tcl_DeleteInterp(interp);
}
static SDCInterpreter& get() {
static SDCInterpreter instance;
return instance;
}
Tcl_Interp* fresh_interp(Design* design) {
if (interp)
Tcl_DeleteInterp(interp);
interp = Tcl_CreateInterp();
if (Tcl_Init(interp)!=TCL_OK)
log_error("Tcl_Init() call failed - %s\n",Tcl_ErrnoMsg(Tcl_GetErrno()));
objects = std::make_unique<SdcObjects>(design);
objects->collect_mode = SdcObjects::CollectMode::SimpleGetter;
Tcl_CreateObjCommand(interp, "get_pins", sdc_get_pins_cmd, (ClientData) objects.get(), NULL);
Tcl_CreateObjCommand(interp, "get_nets", sdc_get_nets_cmd, (ClientData) objects.get(), NULL);
Tcl_CreateObjCommand(interp, "get_ports", sdc_get_ports_cmd, (ClientData) objects.get(), NULL);
return interp;
}
};
// Also see TclPass
struct SdcPass : public Pass {
void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" sdc [options] file\n");
log("\n");
log("Read the SDC file for the current design.\n");
log("\n");
log(" -dump\n");
log(" Dump the referenced design objects.\n");
log("\n");
log(" -dump-graph\n");
log(" Dump the uninterpreted call graph.\n");
log("\n");
log(" -keep_hierarchy\n");
log(" Add keep_hierarchy attributes while retaining SDC validity.\n");
log("\n");
}
SdcPass() : Pass("sdc", "Read an SDC file") { }
void execute(std::vector<std::string> args, RTLIL::Design *design) override {
log_header(design, "Executing SDC pass.\n");
log_experimental("sdc");
size_t argidx;
bool dump_mode = false;
bool dump_graph_mode = false;
bool keep_hierarchy_mode = false;
std::vector<std::string> stubs_paths;
for (argidx = 1; argidx < args.size(); argidx++) {
if (args[argidx] == "-dump") {
dump_mode = true;
continue;
} else if (args[argidx] == "-dump-graph") {
dump_graph_mode = true;
continue;
} else if (args[argidx] == "-keep_hierarchy") {
keep_hierarchy_mode = true;
continue;
} else if (args[argidx] == "-stubs" && argidx+1 < args.size()) {
stubs_paths.push_back(args[++argidx]);
continue;
}
break;
}
if (argidx >= args.size())
log_cmd_error("Missing SDC file.\n");
std::string sdc_path = args[argidx++];
if (argidx < args.size())
log_cmd_error("Unexpected extra positional argument %s after SDC file %s.\n", args[argidx], sdc_path);
SDCInterpreter& sdc = SDCInterpreter::get();
Tcl_Interp *interp = sdc.fresh_interp(design);
Tcl_Preserve(interp);
std::string stub_path = "+/sdc/graph-stubs.sdc";
rewrite_filename(stub_path);
if (Tcl_EvalFile(interp, stub_path.c_str()) != TCL_OK)
log_cmd_error("SDC interpreter returned an error in stub preamble file: %s\n", Tcl_GetStringResult(interp));
for (auto path : stubs_paths)
if (Tcl_EvalFile(interp, path.c_str()) != TCL_OK)
log_cmd_error("SDC interpreter returned an error in OpenSTA stub file %s: %s\n", path.c_str(), Tcl_GetStringResult(interp));
if (Tcl_EvalFile(interp, sdc_path.c_str()) != TCL_OK)
log_cmd_error("SDC interpreter returned an error: %s\n", Tcl_GetStringResult(interp));
if (dump_mode)
sdc.objects->dump();
if (keep_hierarchy_mode)
sdc.objects->keep_hierarchy();
inspect_globals(interp, dump_graph_mode);
Tcl_Release(interp);
}
} SdcPass;
YOSYS_NAMESPACE_END
#endif

View File

@ -36,7 +36,7 @@ struct TraceMonitor : public RTLIL::Monitor
log("#TRACE# Module delete: %s\n", log_id(module));
}
void notify_connect(RTLIL::Cell *cell, RTLIL::IdString port, const RTLIL::SigSpec &old_sig, const RTLIL::SigSpec &sig) override
void notify_connect(RTLIL::Cell *cell, const RTLIL::IdString &port, const RTLIL::SigSpec &old_sig, const RTLIL::SigSpec &sig) override
{
log("#TRACE# Cell connect: %s.%s.%s = %s (was: %s)\n", log_id(cell->module), log_id(cell), log_id(port), log_signal(sig), log_signal(old_sig));
}

View File

@ -199,15 +199,8 @@ static void detect_fsm(RTLIL::Wire *wire, bool ignore_self_reset=false)
}
SigSpec sig_y = sig_d, sig_undef;
if (!ignore_self_reset) {
if (cellport.first->type == ID($adff)) {
SigSpec sig_arst = assign_map(cellport.first->getPort(ID::ARST));
if (ce.eval(sig_arst, sig_undef))
is_self_resetting = true;
}
else if (ce.eval(sig_y, sig_undef))
is_self_resetting = true;
}
if (!ignore_self_reset && ce.eval(sig_y, sig_undef))
is_self_resetting = true;
}
if (has_fsm_encoding_attr)

View File

@ -283,7 +283,7 @@ bool compare_signals(RTLIL::SigBit &s1, RTLIL::SigBit &s2, SigPool &regs, SigPoo
if (attrs1 != attrs2)
return attrs2 > attrs1;
return w2->name.lt_by_name(w1->name);
return strcmp(w2->name.c_str(), w1->name.c_str()) < 0;
}
bool check_public_name(RTLIL::IdString id)
@ -722,8 +722,6 @@ struct OptCleanPass : public Pass {
ct_reg.clear();
ct_all.clear();
log_pop();
request_garbage_collection();
}
} OptCleanPass;
@ -786,8 +784,6 @@ struct CleanPass : public Pass {
keep_cache.reset();
ct_reg.clear();
ct_all.clear();
request_garbage_collection();
}
} CleanPass;

View File

@ -297,6 +297,8 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ
log_debug("\n");
}
cover_list("opt.opt_expr.fine.group", "$not", "$pos", "$and", "$or", "$xor", "$xnor", cell->type.str());
module->remove(cell);
did_something = true;
return true;
@ -518,7 +520,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
for (auto cell : cells.sorted)
{
#define ACTION_DO(_p_, _s_) do { replace_cell(assign_map, module, cell, input.as_string(), _p_, _s_); goto next_cell; } while (0)
#define ACTION_DO(_p_, _s_) do { cover("opt.opt_expr.action_" S__LINE__); replace_cell(assign_map, module, cell, input.as_string(), _p_, _s_); goto next_cell; } while (0)
#define ACTION_DO_Y(_v_) ACTION_DO(ID::Y, RTLIL::SigSpec(RTLIL::State::S ## _v_))
bool detect_const_and = false;
@ -565,16 +567,19 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
}
if (detect_const_and && (found_zero || found_inv || (found_undef && consume_x))) {
cover("opt.opt_expr.const_and");
replace_cell(assign_map, module, cell, "const_and", ID::Y, RTLIL::State::S0);
goto next_cell;
}
if (detect_const_or && (found_one || found_inv || (found_undef && consume_x))) {
cover("opt.opt_expr.const_or");
replace_cell(assign_map, module, cell, "const_or", ID::Y, RTLIL::State::S1);
goto next_cell;
}
if (non_const_input != State::Sm && !found_undef) {
cover("opt.opt_expr.and_or_buffer");
replace_cell(assign_map, module, cell, "and_or_buffer", ID::Y, non_const_input);
goto next_cell;
}
@ -586,10 +591,12 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
SigBit sig_b = assign_map(cell->getPort(ID::B));
if (!keepdc && (sig_a == sig_b || sig_a == State::Sx || sig_a == State::Sz || sig_b == State::Sx || sig_b == State::Sz)) {
if (cell->type.in(ID($xor), ID($_XOR_))) {
cover("opt.opt_expr.const_xor");
replace_cell(assign_map, module, cell, "const_xor", ID::Y, RTLIL::State::S0);
goto next_cell;
}
if (cell->type.in(ID($xnor), ID($_XNOR_))) {
cover("opt.opt_expr.const_xnor");
// For consistency since simplemap does $xnor -> $_XOR_ + $_NOT_
int width = GetSize(cell->getPort(ID::Y));
replace_cell(assign_map, module, cell, "const_xnor", ID::Y, SigSpec(RTLIL::State::S1, width));
@ -602,6 +609,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
std::swap(sig_a, sig_b);
if (sig_b == State::S0 || sig_b == State::S1) {
if (cell->type.in(ID($xor), ID($_XOR_))) {
cover("opt.opt_expr.xor_buffer");
SigSpec sig_y;
if (cell->type == ID($xor))
sig_y = (sig_b == State::S1 ? module->Not(NEW_ID, sig_a).as_bit() : sig_a);
@ -612,6 +620,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
goto next_cell;
}
if (cell->type.in(ID($xnor), ID($_XNOR_))) {
cover("opt.opt_expr.xnor_buffer");
SigSpec sig_y;
if (cell->type == ID($xnor)) {
sig_y = (sig_b == State::S1 ? sig_a : module->Not(NEW_ID, sig_a).as_bit());
@ -632,11 +641,13 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
GetSize(cell->getPort(ID::A)) == 1 && GetSize(cell->getPort(ID::Y)) == 1)
{
if (cell->type == ID($reduce_xnor)) {
cover("opt.opt_expr.reduce_xnor_not");
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 = ID($not);
did_something = true;
} else {
cover("opt.opt_expr.unary_buffer");
replace_cell(assign_map, module, cell, "unary_buffer", ID::Y, cell->getPort(ID::A));
}
goto next_cell;
@ -652,6 +663,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
if (a_fully_const != b_fully_const)
{
cover("opt.opt_expr.bitwise_logic_one_const");
log_debug("Replacing %s cell `%s' in module `%s' having one fully constant input\n",
log_id(cell->type), log_id(cell->name), log_id(module));
RTLIL::SigSpec sig_y = assign_map(cell->getPort(ID::Y));
@ -803,6 +815,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
new_sig_a.append(neutral_bit);
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_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(ID::A, new_sig_a);
@ -825,6 +838,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
new_sig_b.append(neutral_bit);
if (GetSize(new_sig_b) < GetSize(sig_b)) {
cover_list("opt.opt_expr.fine.neutral_B", "$logic_and", "$logic_or", cell->type.str());
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(ID::B, new_sig_b);
@ -850,6 +864,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_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(ID::A, sig_a = new_a);
@ -875,6 +890,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_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(ID::A, sig_a = new_a);
@ -900,6 +916,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_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(ID::B, sig_b = new_b);
@ -934,6 +951,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
break;
}
if (i > 0) {
cover_list("opt.opt_expr.fine", "$add", "$sub", cell->type.str());
log_debug("Stripping %d LSB bits of %s cell %s in module %s.\n", i, log_id(cell->type), log_id(cell), log_id(module));
SigSpec new_a = sig_a.extract_end(i);
SigSpec new_b = sig_b.extract_end(i);
@ -990,6 +1008,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
break;
}
if (i > 0) {
cover("opt.opt_expr.fine.$alu");
log_debug("Stripping %d LSB bits of %s cell %s in module %s.\n", i, log_id(cell->type), log_id(cell), log_id(module));
SigSpec new_a = sig_a.extract_end(i);
SigSpec new_b = sig_b.extract_end(i);
@ -1028,6 +1047,8 @@ skip_fine_alu:
if (0) {
found_the_x_bit:
cover_list("opt.opt_expr.xbit", "$reduce_xor", "$reduce_xnor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx",
"$lt", "$le", "$ge", "$gt", "$neg", "$add", "$sub", "$mul", "$div", "$mod", "$divfloor", "$modfloor", "$pow", cell->type.str());
if (cell->type.in(ID($reduce_xor), ID($reduce_xnor), ID($lt), ID($le), ID($ge), ID($gt)))
replace_cell(assign_map, module, cell, "x-bit in input", ID::Y, RTLIL::State::Sx);
else
@ -1049,6 +1070,7 @@ skip_fine_alu:
}
if (width < GetSize(sig_a)) {
cover_list("opt.opt_expr.trim", "$shiftx", "$shift", cell->type.str());
sig_a.remove(width, GetSize(sig_a)-width);
cell->setPort(ID::A, sig_a);
cell->setParam(ID::A_WIDTH, width);
@ -1059,11 +1081,13 @@ skip_fine_alu:
if (cell->type.in(ID($_NOT_), ID($not), ID($logic_not)) && GetSize(cell->getPort(ID::Y)) == 1 &&
invert_map.count(assign_map(cell->getPort(ID::A))) != 0) {
cover_list("opt.opt_expr.invert.double", "$_NOT_", "$not", "$logic_not", cell->type.str());
replace_cell(assign_map, module, cell, "double_invert", ID::Y, invert_map.at(assign_map(cell->getPort(ID::A))));
goto next_cell;
}
if (cell->type.in(ID($_MUX_), ID($mux)) && invert_map.count(assign_map(cell->getPort(ID::S))) != 0) {
cover_list("opt.opt_expr.invert.muxsel", "$_MUX_", "$mux", cell->type.str());
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(ID::A);
cell->setPort(ID::A, cell->getPort(ID::B));
@ -1146,6 +1170,7 @@ skip_fine_alu:
if (input.match(" 1")) ACTION_DO(ID::Y, input.extract(1, 1));
if (input.match("01 ")) ACTION_DO(ID::Y, input.extract(0, 1));
if (input.match("10 ")) {
cover("opt.opt_expr.mux_to_inv");
cell->type = ID($_NOT_);
cell->setPort(ID::A, input.extract(0, 1));
cell->unsetPort(ID::B);
@ -1172,6 +1197,7 @@ skip_fine_alu:
if (input == State::S1)
ACTION_DO(ID::Y, cell->getPort(ID::A));
if (input == State::S0 && !a.is_fully_undef()) {
cover("opt.opt_expr.action_" S__LINE__);
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(ID::A, SigSpec(State::Sx, GetSize(a)));
@ -1196,6 +1222,7 @@ skip_fine_alu:
log_assert(GetSize(a) == GetSize(b));
for (int i = 0; i < GetSize(a); i++) {
if (a[i].wire == NULL && b[i].wire == NULL && a[i] != b[i] && a[i].data <= RTLIL::State::S1 && b[i].data <= RTLIL::State::S1) {
cover_list("opt.opt_expr.eqneq.isneq", "$eq", "$ne", "$eqx", "$nex", cell->type.str());
RTLIL::SigSpec new_y = RTLIL::SigSpec(cell->type.in(ID($eq), ID($eqx)) ? RTLIL::State::S0 : RTLIL::State::S1);
new_y.extend_u0(cell->parameters[ID::Y_WIDTH].as_int(), false);
replace_cell(assign_map, module, cell, "isneq", ID::Y, new_y);
@ -1208,6 +1235,7 @@ skip_fine_alu:
}
if (new_a.size() == 0) {
cover_list("opt.opt_expr.eqneq.empty", "$eq", "$ne", "$eqx", "$nex", cell->type.str());
RTLIL::SigSpec new_y = RTLIL::SigSpec(cell->type.in(ID($eq), ID($eqx)) ? RTLIL::State::S1 : RTLIL::State::S0);
new_y.extend_u0(cell->parameters[ID::Y_WIDTH].as_int(), false);
replace_cell(assign_map, module, cell, "empty", ID::Y, new_y);
@ -1215,6 +1243,7 @@ skip_fine_alu:
}
if (new_a.size() < a.size() || new_b.size() < b.size()) {
cover_list("opt.opt_expr.eqneq.resize", "$eq", "$ne", "$eqx", "$nex", cell->type.str());
cell->setPort(ID::A, new_a);
cell->setPort(ID::B, new_b);
cell->parameters[ID::A_WIDTH] = new_a.size();
@ -1229,6 +1258,7 @@ skip_fine_alu:
RTLIL::SigSpec b = assign_map(cell->getPort(ID::B));
if (a.is_fully_const() && !b.is_fully_const()) {
cover_list("opt.opt_expr.eqneq.swapconst", "$eq", "$ne", cell->type.str());
cell->setPort(ID::A, b);
cell->setPort(ID::B, a);
std::swap(a, b);
@ -1243,6 +1273,7 @@ skip_fine_alu:
RTLIL::SigSpec input = b;
ACTION_DO(ID::Y, cell->getPort(ID::A));
} else {
cover_list("opt.opt_expr.eqneq.isnot", "$eq", "$ne", cell->type.str());
log_debug("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell->type), log_id(cell), log_id(module));
cell->type = ID($not);
cell->parameters.erase(ID::B_WIDTH);
@ -1257,6 +1288,7 @@ skip_fine_alu:
if (cell->type.in(ID($eq), ID($ne)) &&
(assign_map(cell->getPort(ID::A)).is_fully_zero() || assign_map(cell->getPort(ID::B)).is_fully_zero()))
{
cover_list("opt.opt_expr.eqneq.cmpzero", "$eq", "$ne", cell->type.str());
log_debug("Replacing %s cell `%s' in module `%s' with %s.\n", log_id(cell->type), log_id(cell),
log_id(module), cell->type == ID($eq) ? "$logic_not" : "$reduce_bool");
cell->type = cell->type == ID($eq) ? ID($logic_not) : ID($reduce_bool);
@ -1304,6 +1336,8 @@ skip_fine_alu:
sig_y[i] = sig_a[GetSize(sig_a)-1];
}
cover_list("opt.opt_expr.constshift", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", cell->type.str());
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(ID::B))), shift_bits, log_id(module), log_signal(sig_y));
@ -1376,6 +1410,11 @@ skip_fine_alu:
if (identity_wrt_a || identity_wrt_b)
{
if (identity_wrt_a)
cover_list("opt.opt_expr.identwrt.a", "$add", "$sub", "$alu", "$or", "$xor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", "$mul", "$div", cell->type.str());
if (identity_wrt_b)
cover_list("opt.opt_expr.identwrt.b", "$add", "$sub", "$alu", "$or", "$xor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", "$mul", "$div", cell->type.str());
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');
@ -1424,12 +1463,14 @@ skip_identity:
if (mux_bool && cell->type.in(ID($mux), ID($_MUX_)) &&
cell->getPort(ID::A) == State::S0 && cell->getPort(ID::B) == State::S1) {
cover_list("opt.opt_expr.mux_bool", "$mux", "$_MUX_", cell->type.str());
replace_cell(assign_map, module, cell, "mux_bool", ID::Y, cell->getPort(ID::S));
goto next_cell;
}
if (mux_bool && cell->type.in(ID($mux), ID($_MUX_)) &&
cell->getPort(ID::A) == State::S1 && cell->getPort(ID::B) == State::S0) {
cover_list("opt.opt_expr.mux_invert", "$mux", "$_MUX_", cell->type.str());
log_debug("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell->type), log_id(cell), log_id(module));
cell->setPort(ID::A, cell->getPort(ID::S));
cell->unsetPort(ID::B);
@ -1448,6 +1489,7 @@ skip_identity:
}
if (consume_x && mux_bool && cell->type.in(ID($mux), ID($_MUX_)) && cell->getPort(ID::A) == State::S0) {
cover_list("opt.opt_expr.mux_and", "$mux", "$_MUX_", cell->type.str());
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(ID::A, cell->getPort(ID::S));
cell->unsetPort(ID::S);
@ -1467,6 +1509,7 @@ skip_identity:
}
if (consume_x && mux_bool && cell->type.in(ID($mux), ID($_MUX_)) && cell->getPort(ID::B) == State::S1) {
cover_list("opt.opt_expr.mux_or", "$mux", "$_MUX_", cell->type.str());
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(ID::B, cell->getPort(ID::S));
cell->unsetPort(ID::S);
@ -1490,6 +1533,7 @@ skip_identity:
int width = GetSize(cell->getPort(ID::A));
if ((cell->getPort(ID::A).is_fully_undef() && cell->getPort(ID::B).is_fully_undef()) ||
cell->getPort(ID::S).is_fully_undef()) {
cover_list("opt.opt_expr.mux_undef", "$mux", "$pmux", cell->type.str());
replace_cell(assign_map, module, cell, "mux_undef", ID::Y, cell->getPort(ID::A));
goto next_cell;
}
@ -1508,14 +1552,17 @@ skip_identity:
new_s = new_s.extract(0, new_s.size()-1);
}
if (new_s.size() == 0) {
cover_list("opt.opt_expr.mux_empty", "$mux", "$pmux", cell->type.str());
replace_cell(assign_map, module, cell, "mux_empty", ID::Y, new_a);
goto next_cell;
}
if (new_a == RTLIL::SigSpec(RTLIL::State::S0) && new_b == RTLIL::SigSpec(RTLIL::State::S1)) {
cover_list("opt.opt_expr.mux_sel01", "$mux", "$pmux", cell->type.str());
replace_cell(assign_map, module, cell, "mux_sel01", ID::Y, new_s);
goto next_cell;
}
if (cell->getPort(ID::S).size() != new_s.size()) {
cover_list("opt.opt_expr.mux_reduce", "$mux", "$pmux", cell->type.str());
log_debug("Optimized away %d select inputs of %s cell `%s' in module `%s'.\n",
GetSize(cell->getPort(ID::S)) - GetSize(new_s), log_id(cell->type), log_id(cell), log_id(module));
cell->setPort(ID::A, new_a);
@ -1555,6 +1602,7 @@ skip_identity:
RTLIL::SigSpec y(RTLIL::const_ ## _t(a.as_const(), dummy_arg, \
cell->parameters[ID::A_SIGNED].as_bool(), false, \
cell->parameters[ID::Y_WIDTH].as_int())); \
cover("opt.opt_expr.const.$" #_t); \
replace_cell(assign_map, module, cell, stringf("%s", log_signal(a)), ID::Y, y); \
goto next_cell; \
} \
@ -1569,6 +1617,7 @@ skip_identity:
cell->parameters[ID::A_SIGNED].as_bool(), \
cell->parameters[ID::B_SIGNED].as_bool(), \
cell->parameters[ID::Y_WIDTH].as_int())); \
cover("opt.opt_expr.const.$" #_t); \
replace_cell(assign_map, module, cell, stringf("%s, %s", log_signal(a), log_signal(b)), ID::Y, y); \
goto next_cell; \
} \
@ -1580,6 +1629,7 @@ skip_identity:
assign_map.apply(a), assign_map.apply(b); \
if (a.is_fully_const() && b.is_fully_const()) { \
RTLIL::SigSpec y(RTLIL::const_ ## _t(a.as_const(), b.as_const())); \
cover("opt.opt_expr.const.$" #_t); \
replace_cell(assign_map, module, cell, stringf("%s, %s", log_signal(a), log_signal(b)), ID::Y, y); \
goto next_cell; \
} \
@ -1592,6 +1642,7 @@ skip_identity:
assign_map.apply(a), assign_map.apply(b), assign_map.apply(s); \
if (a.is_fully_const() && b.is_fully_const() && s.is_fully_const()) { \
RTLIL::SigSpec y(RTLIL::const_ ## _t(a.as_const(), b.as_const(), s.as_const())); \
cover("opt.opt_expr.const.$" #_t); \
replace_cell(assign_map, module, cell, stringf("%s, %s, %s", log_signal(a), log_signal(b), log_signal(s)), ID::Y, y); \
goto next_cell; \
} \
@ -1708,6 +1759,8 @@ skip_identity:
{
if (sig_a.is_fully_zero())
{
cover("opt.opt_expr.mul_shift.zero");
log_debug("Replacing multiply-by-zero cell `%s' in module `%s' with zero-driver.\n",
cell->name.c_str(), module->name.c_str());
@ -1721,6 +1774,11 @@ skip_identity:
int exp;
if (sig_a.is_onehot(&exp) && !(a_signed && exp == GetSize(sig_a) - 1))
{
if (swapped_ab)
cover("opt.opt_expr.mul_shift.swapped");
else
cover("opt.opt_expr.mul_shift.unswapped");
log_debug("Replacing multiply-by-%s cell `%s' in module `%s' with shift-by-%d.\n",
log_signal(sig_a), cell->name.c_str(), module->name.c_str(), exp);
@ -1754,6 +1812,8 @@ skip_identity:
break;
if (a_zeros || b_zeros) {
int y_zeros = a_zeros + b_zeros;
cover("opt.opt_expr.mul_low_zeros");
log_debug("Removing low %d A and %d B bits from cell `%s' in module `%s'.\n",
a_zeros, b_zeros, cell->name.c_str(), module->name.c_str());
@ -1795,6 +1855,8 @@ skip_identity:
{
if (sig_b.is_fully_zero())
{
cover("opt.opt_expr.divmod_zero");
log_debug("Replacing divide-by-zero cell `%s' in module `%s' with undef-driver.\n",
cell->name.c_str(), module->name.c_str());
@ -1810,6 +1872,8 @@ skip_identity:
{
if (cell->type.in(ID($div), ID($divfloor)))
{
cover("opt.opt_expr.div_shift");
bool is_truncating = cell->type == ID($div);
log_debug("Replacing %s-divide-by-%s cell `%s' in module `%s' with shift-by-%d.\n",
is_truncating ? "truncating" : "flooring",
@ -1838,6 +1902,8 @@ skip_identity:
}
else if (cell->type.in(ID($mod), ID($modfloor)))
{
cover("opt.opt_expr.mod_mask");
bool is_truncating = cell->type == ID($mod);
log_debug("Replacing %s-modulo-by-%s cell `%s' in module `%s' with bitmask.\n",
is_truncating ? "truncating" : "flooring",
@ -1962,6 +2028,7 @@ skip_identity:
sig_ci = p.second;
}
cover("opt.opt_expr.alu_split");
module->remove(cell);
did_something = true;

View File

@ -227,11 +227,6 @@ struct OptMergeWorker
ct.cell_types.erase(ID($anyconst));
ct.cell_types.erase(ID($allseq));
ct.cell_types.erase(ID($allconst));
ct.cell_types.erase(ID($check));
ct.cell_types.erase(ID($assert));
ct.cell_types.erase(ID($assume));
ct.cell_types.erase(ID($live));
ct.cell_types.erase(ID($cover));
log("Finding identical cells in module `%s'.\n", module->name);
assign_map.set(module);

View File

@ -252,8 +252,8 @@ std::optional<AbcProcess> spawn_abc(const char* abc_exe, DeferredLogs &logs) {
char arg1[] = "-s";
char* argv[] = { strdup(abc_exe), arg1, nullptr };
if (0 != posix_spawnp(&result.pid, abc_exe, &file_actions, nullptr, argv, environ)) {
logs.log_error("posix_spawnp %s failed (errno=%s)", abc_exe, strerrorname_np(errno));
if (0 != posix_spawn(&result.pid, abc_exe, &file_actions, nullptr, argv, environ)) {
logs.log_error("posix_spawn %s failed", abc_exe);
return std::nullopt;
}
free(argv[0]);
@ -611,7 +611,7 @@ std::string AbcModuleState::remap_name(RTLIL::IdString abc_name, RTLIL::Wire **o
}
}
}
return stringf("$abc$%d$%s", map_autoidx, abc_name.substr(1));
return stringf("$abc$%d$%s", map_autoidx, abc_name.c_str()+1);
}
void AbcModuleState::dump_loop_graph(FILE *f, int &nr, dict<int, pool<int>> &edges, pool<int> &workpool, std::vector<int> &in_counts)
@ -1064,7 +1064,7 @@ void AbcModuleState::prepare_module(RTLIL::Design *design, RTLIL::Module *module
abc_script += stringf("; write_blif %s/output.blif", run_abc.tempdir_name);
abc_script = add_echos_to_abc_cmd(abc_script);
#if defined(__linux__) && !defined(YOSYS_DISABLE_SPAWN)
abc_script += "; echo; echo \"YOSYS_ABC_DONE\"\n";
abc_script += "; echo \"YOSYS_ABC_DONE\"\n";
#endif
for (size_t i = 0; i+1 < abc_script.size(); i++)

View File

@ -38,8 +38,7 @@ std::vector<Module*> order_modules(Design *design, std::vector<Module *> modules
sort.edge(submodule, m);
}
}
bool is_sorted = sort.sort();
log_assert(is_sorted);
log_assert(sort.sort());
return sort.sorted;
}

View File

@ -415,7 +415,7 @@ struct BufnormPass : public Pass {
return mapped_bits.at(bit);
};
auto make_buffer_f = [&](IdString type, const SigSpec &src, const SigSpec &dst)
auto make_buffer_f = [&](const IdString &type, const SigSpec &src, const SigSpec &dst)
{
auto it = old_buffers.find(pair<IdString, SigSpec>(type, dst));

View File

@ -827,17 +827,6 @@ std::string vlog_identifier(std::string str)
return str;
}
void event2vl_wire(std::string &edge, LibertyExpression& parsed, const std::string& wire)
{
edge.clear();
if (parsed.kind == LibertyExpression::Kind::NOT) {
edge = "negedge " + wire;
// parsed = parsed.children[0];
} else {
edge = "posedge " + wire;
}
}
void event2vl(const LibertyAst *ast, std::string &edge, std::string &expr)
{
edge.clear();
@ -854,160 +843,33 @@ void event2vl(const LibertyAst *ast, std::string &edge, std::string &expr)
}
}
enum ClearPresetVar {
Error,
L,
H,
T,
X,
};
ClearPresetVar clear_preset_var(std::string type)
void clear_preset_var(std::string var, std::string type)
{
if (type.find('L') != std::string::npos) {
return ClearPresetVar::L;
}
if (type.find('H') != std::string::npos) {
return ClearPresetVar::H;
}
if (type.find('T') != std::string::npos) {
return ClearPresetVar::T;
}
if (type.find('X') != std::string::npos) {
return ClearPresetVar::X;
}
return ClearPresetVar::X;
}
void print_clear_preset_var(std::string var, ClearPresetVar type)
{
if (type == ClearPresetVar::L) {
printf(" %s <= 0;\n", var.c_str());
return;
}
if (type == ClearPresetVar::H) {
if (type.find('H') != std::string::npos) {
printf(" %s <= 1;\n", var.c_str());
return;
}
if (type == ClearPresetVar::T) {
if (type.find('T') != std::string::npos) {
printf(" %s <= ~%s;\n", var.c_str(), var.c_str());
return;
}
if (type == ClearPresetVar::X) {
if (type.find('X') != std::string::npos) {
printf(" %s <= 'bx;\n", var.c_str());
return;
}
}
struct FfEdge {
std::string edge;
std::string expr;
};
struct FfEdges {
FfEdge clock;
FfEdge clear;
FfEdge preset;
std::string edge;
void wired(FfEdge& edge, const LibertyAst* ast, const std::string& wire, const char* tag) {
auto* found = ast->find(tag);
if (!found)
return;
auto lexer = LibertyExpression::Lexer(found->value);
auto expr = LibertyExpression::parse(lexer);
event2vl_wire(edge.edge, expr, wire);
edge.expr = expr.vlog_str();
}
FfEdges(LibertyAst* child, const std::string& clear_wire, const std::string& preset_wire) {
wired(clear, child, clear_wire, "clear");
wired(preset, child, preset_wire, "preset");
event2vl(child->find("clocked_on"), clock.edge, clock.expr);
edge = "";
if (!clock.edge.empty())
edge += (edge.empty() ? "" : ", ") + clock.edge;
if (!clear.edge.empty())
edge += (edge.empty() ? "" : ", ") + clear.edge;
if (!preset.edge.empty())
edge += (edge.empty() ? "" : ", ") + preset.edge;
}
};
struct FfVar {
std::string var;
std::string edge;
FfEdge clear;
FfEdge preset;
// Value for both asserted
const char* clear_preset_var_name;
std::string next_state;
const char* else_prefix = "";
public:
void proc_header() {
printf(" always @(%s) begin\n", edge.c_str());
}
void proc_footer() {
if (*else_prefix)
printf(" end\n");
printf(" end\n");
}
void proc_cond(FfEdge& edge, const char* value) {
printf(" %sif (%s) begin\n", else_prefix, edge.expr.c_str());
printf(" %s <= %s;\n", var.c_str(), value);
printf(" end\n");
else_prefix = "else ";
}
void proc_cond_clear() { proc_cond(clear, "0"); }
void proc_cond_preset() { proc_cond(preset, "1"); }
void proc_next_state() {
if (*else_prefix)
printf(" %sbegin\n", else_prefix);
printf(" %s <= %s;\n", var.c_str(), next_state.c_str());
}
void proc(LibertyAst* child) {
else_prefix = "";
proc_header();
if (!clear.expr.empty() && !preset.expr.empty()) {
ClearPresetVar clear_preset = clear_preset_var(find_non_null(child, clear_preset_var_name)->value);
if (clear_preset == ClearPresetVar::L) {
proc_cond_clear();
proc_cond_preset();
proc_next_state();
proc_footer();
return;
} else if (clear_preset == ClearPresetVar::H) {
// Notice that preset and clear are swapped
proc_cond_preset();
proc_cond_clear();
proc_next_state();
proc_footer();
return;
} else {
// Boo, we have to emit non-synthesizable verilog
printf(" %sif ((%s) && (%s)) begin\n", else_prefix, clear.expr.c_str(), preset.expr.c_str());
print_clear_preset_var(var, clear_preset);
printf(" end\n");
else_prefix = "else ";
}
}
if (!clear.expr.empty()) {
proc_cond_clear();
}
if (!preset.expr.empty()) {
proc_cond_preset();
}
proc_next_state();
proc_footer();
}
};
void gen_verilogsim_cell(const LibertyAst *ast)
{
if (ast->find("statetable") != NULL)
return;
CHECK_NV(ast->args.size(), == 1);
auto module_name = vlog_identifier(ast->args[0]);
printf("module %s (", module_name.c_str());
printf("module %s (", vlog_identifier(ast->args[0]).c_str());
bool first = true;
for (auto child : ast->children) {
if (child->id != "pin")
@ -1021,29 +883,13 @@ void gen_verilogsim_cell(const LibertyAst *ast)
for (auto child : ast->children) {
if (child->id != "ff" && child->id != "latch")
continue;
printf(" reg ");
first = true;
std::string iq = "";
for (auto arg : child->args) {
if (first)
printf(" reg ");
printf("%s%s", first ? "" : ", ", vlog_identifier(arg).c_str());
if (first)
iq = vlog_identifier(arg);
first = false;
}
if (!first)
printf(";\n");
first = true;
for (auto gchild : child->children) {
if (gchild->id == "clear" || gchild->id == "preset") {
if (first)
printf(" wire ");
printf("%s%s_%s", first ? "" : ", ", iq.c_str(), gchild->id.c_str());
first = false;
}
}
if (!first)
printf(";\n");
printf(";\n");
}
for (auto child : ast->children) {
@ -1063,45 +909,63 @@ void gen_verilogsim_cell(const LibertyAst *ast)
if (child->id != "ff" || child->args.size() != 2)
continue;
auto iq_name = vlog_identifier(child->args[0]);
auto clear_wire = iq_name + "_clear";
auto preset_wire = iq_name + "_preset";
FfEdges edges(child, clear_wire, preset_wire);
std::string iq_var = vlog_identifier(child->args[0]);
std::string iqn_var = vlog_identifier(child->args[1]);
if (edges.edge.empty())
std::string clock_edge, clock_expr;
event2vl(child->find("clocked_on"), clock_edge, clock_expr);
std::string clear_edge, clear_expr;
event2vl(child->find("clear"), clear_edge, clear_expr);
std::string preset_edge, preset_expr;
event2vl(child->find("preset"), preset_edge, preset_expr);
std::string edge = "";
if (!clock_edge.empty())
edge += (edge.empty() ? "" : ", ") + clock_edge;
if (!clear_edge.empty())
edge += (edge.empty() ? "" : ", ") + clear_edge;
if (!preset_edge.empty())
edge += (edge.empty() ? "" : ", ") + preset_edge;
if (edge.empty())
continue;
std::string next_state = func2vl(find_non_null(child, "next_state")->value);
std::string not_next_state = std::string("~(") + next_state + ")";
printf(" always @(%s) begin\n", edge.c_str());
const char *else_prefix = "";
if (!clear_expr.empty() && !preset_expr.empty()) {
printf(" %sif ((%s) && (%s)) begin\n", else_prefix, clear_expr.c_str(), preset_expr.c_str());
clear_preset_var(iq_var, find_non_null(child, "clear_preset_var1")->value);
clear_preset_var(iqn_var, find_non_null(child, "clear_preset_var2")->value);
printf(" end\n");
else_prefix = "else ";
}
if (!clear_expr.empty()) {
printf(" %sif (%s) begin\n", else_prefix, clear_expr.c_str());
printf(" %s <= 0;\n", iq_var.c_str());
printf(" %s <= 1;\n", iqn_var.c_str());
printf(" end\n");
else_prefix = "else ";
}
if (!preset_expr.empty()) {
printf(" %sif (%s) begin\n", else_prefix, preset_expr.c_str());
printf(" %s <= 1;\n", iq_var.c_str());
printf(" %s <= 0;\n", iqn_var.c_str());
printf(" end\n");
else_prefix = "else ";
}
if (*else_prefix)
printf(" %sbegin\n", else_prefix);
std::string expr = find_non_null(child, "next_state")->value;
printf(" // %s\n", expr.c_str());
printf(" %s <= %s;\n", iq_var.c_str(), func2vl(expr).c_str());
printf(" %s <= ~(%s);\n", iqn_var.c_str(), func2vl(expr).c_str());
if (*else_prefix)
printf(" end\n");
if (edges.clear.expr.length())
std::swap(clear_wire, edges.clear.expr);
if (edges.preset.expr.length())
std::swap(preset_wire, edges.preset.expr);
auto iq = FfVar {
.var = vlog_identifier(child->args[0]),
.edge = edges.edge,
.clear = edges.clear,
.preset = edges.preset,
.clear_preset_var_name = "clear_preset_var1",
.next_state = next_state,
};
auto iqn = FfVar {
.var = vlog_identifier(child->args[1]),
.edge = edges.edge,
// Swapped clear and preset
.clear = edges.preset,
.preset = edges.clear,
.clear_preset_var_name = "clear_preset_var2",
.next_state = not_next_state,
};
iq.proc(child);
iqn.proc(child);
if (edges.clear.expr.length())
printf(" assign %s = %s;\n", edges.clear.expr.c_str(), clear_wire.c_str());
if (edges.preset.expr.length())
printf(" assign %s = %s;\n", edges.preset.expr.c_str(), preset_wire.c_str());
printf(" end\n");
}
for (auto child : ast->children)
@ -1126,8 +990,8 @@ void gen_verilogsim_cell(const LibertyAst *ast)
const char *else_prefix = "";
if (!clear_expr.empty() && !preset_expr.empty()) {
printf(" %sif ((%s) && (%s)) begin\n", else_prefix, clear_expr.c_str(), preset_expr.c_str());
print_clear_preset_var(iq_var, clear_preset_var(find_non_null(child, "clear_preset_var1")->value));
print_clear_preset_var(iqn_var, clear_preset_var(find_non_null(child, "clear_preset_var2")->value));
clear_preset_var(iq_var, find_non_null(child, "clear_preset_var1")->value);
clear_preset_var(iqn_var, find_non_null(child, "clear_preset_var2")->value);
printf(" end\n");
else_prefix = "else ";
}

View File

@ -27,7 +27,7 @@
USING_YOSYS_NAMESPACE
YOSYS_NAMESPACE_BEGIN
static void transfer_attr (Cell* to, const Cell* from, IdString attr) {
static void transfer_attr (Cell* to, const Cell* from, const IdString& attr) {
if (from->has_attribute(attr))
to->attributes[attr] = from->attributes.at(attr);
}

View File

@ -1143,29 +1143,7 @@ struct TestCellPass : public Pass {
else
uut = create_gold_module(design, cell_type, cell_types.at(cell_type), constmode, muxdiv);
if (!write_prefix.empty()) {
string writer = "write_rtlil";
string suffix = "il";
if (techmap_cmd.compare("aigmap") == 0) {
// try to convert to aiger
Pass::call(design, techmap_cmd);
bool is_unconverted = false;
for (auto *mod : design->selected_modules())
for (auto *cell : mod->selected_cells())
if (!cell->type.in(ID::$_NOT_, ID::$_AND_)) {
is_unconverted = true;
break;
}
if (is_unconverted) {
// skip unconverted cells
log_warning("Skipping %s\n", cell_type);
delete design;
break;
} else {
writer = "write_aiger -ascii";
suffix = "aag";
}
}
Pass::call(design, stringf("%s %s_%s_%05d.%s", writer, write_prefix, cell_type.c_str()+1, i, suffix));
Pass::call(design, stringf("write_rtlil %s_%s_%05d.il", write_prefix, cell_type.c_str()+1, i));
} else if (edges) {
Pass::call(design, "dump gold");
run_edges_test(design, verbose);

View File

@ -164,11 +164,11 @@ pyosys_headers = [
{
"global_id_storage_",
"global_id_index_",
"global_autoidx_id_storage_",
"global_refcount_storage_",
"global_free_idx_list_",
"last_created_idx_ptr_",
"last_created_idx_",
"builtin_ff_cell_types",
"substrings",
}
),
),
@ -192,7 +192,7 @@ pyosys_headers = [
),
PyosysClass("SigChunk"),
PyosysClass("SigBit", hash_expr="s"),
PyosysClass("SigSpec", hash_expr="s", denylist=frozenset({"chunks"})),
PyosysClass("SigSpec", hash_expr="s", denylist={"chunks"}),
PyosysClass(
"Cell",
ref_only=True,
@ -453,7 +453,7 @@ class PyosysWrapperGenerator(object):
) -> str:
is_method = isinstance(function, Method)
function_return_type = function.return_type.format()
if class_basename in {"Const","IdString"} and function_return_type in {
if class_basename == "Const" and function_return_type in {
"iterator",
"const_iterator",
}:
@ -538,8 +538,6 @@ class PyosysWrapperGenerator(object):
python_name_override = "__ne__"
elif function.operator == "<":
python_name_override = "__lt__"
elif function.operator == "[]" and function.const:
python_name_override = "__getitem__"
else:
return
@ -593,10 +591,7 @@ class PyosysWrapperGenerator(object):
# care
return
self.register_containers(field)
rvp = "py::return_value_policy::copy"
if isinstance(field.type, Pointer):
rvp = "py::return_value_policy::reference_internal"
has_containers = self.register_containers(field)
definition_fn = f"def_{'readonly' if field.type.const else 'readwrite'}"
if field.static:
@ -608,7 +603,7 @@ class PyosysWrapperGenerator(object):
f'"{field_python_basename}"',
f"&{metadata.name}::{field.name}",
]
def_args.append(rvp)
def_args.append("py::return_value_policy::copy")
print(
f"\t\t\t.{definition_fn}({', '.join(def_args)})",
file=self.f,

View File

@ -112,7 +112,7 @@ namespace pyosys {
void notify_connect(
RTLIL::Cell *cell,
RTLIL::IdString port,
const RTLIL::IdString &port,
const RTLIL::SigSpec &old_sig,
const RTLIL::SigSpec &sig
) override {
@ -228,7 +228,7 @@ namespace pyosys {
"notify_connect",
py::overload_cast<
RTLIL::Cell *,
RTLIL::IdString,
const RTLIL::IdString &,
const RTLIL::SigSpec &,
const RTLIL::SigSpec &
>(&RTLIL::Monitor::notify_connect)

View File

@ -2,8 +2,6 @@
ifneq ($(SMALL),1)
OBJS += techlibs/common/synth.o
OBJS += techlibs/common/prep.o
OBJS += techlibs/common/opensta.o
OBJS += techlibs/common/sdc_expand.o
endif
GENFILES += techlibs/common/simlib_help.inc
@ -30,6 +28,7 @@ $(eval $(call add_share_file,share,techlibs/common/adff2dff.v))
$(eval $(call add_share_file,share,techlibs/common/dff2ff.v))
$(eval $(call add_share_file,share,techlibs/common/gate2lut.v))
$(eval $(call add_share_file,share,techlibs/common/cmp2lut.v))
$(eval $(call add_share_file,share,techlibs/common/cells.lib))
$(eval $(call add_share_file,share,techlibs/common/mul2dsp.v))
$(eval $(call add_share_file,share,techlibs/common/abc9_model.v))
$(eval $(call add_share_file,share,techlibs/common/abc9_map.v))

108
techlibs/common/cells.lib Normal file
View File

@ -0,0 +1,108 @@
library(yosys_cells) {
cell(DFF_N) {
ff(IQ, IQN) {
clocked_on: "!C";
next_state: "D";
}
pin(D) { direction: input; }
pin(C) { direction: input; clock: true; }
pin(Q) { direction: output; function: "IQ"; }
}
cell(DFF_P) {
ff(IQ, IQN) {
clocked_on: "C";
next_state: "D";
}
pin(D) { direction: input; }
pin(C) { direction: input; clock: true; }
pin(Q) { direction: output; function: "IQ"; }
}
cell(DFF_NN0) {
ff(IQ, IQN) {
clocked_on: "!C";
next_state: "D";
clear: "!R";
}
pin(D) { direction: input; }
pin(R) { direction: input; }
pin(C) { direction: input; clock: true; }
pin(Q) { direction: output; function: "IQ"; }
}
cell(DFF_NN1) {
ff(IQ, IQN) {
clocked_on: "!C";
next_state: "D";
preset: "!R";
}
pin(D) { direction: input; }
pin(R) { direction: input; }
pin(C) { direction: input; clock: true; }
pin(Q) { direction: output; function: "IQ"; }
}
cell(DFF_NP0) {
ff(IQ, IQN) {
clocked_on: "!C";
next_state: "D";
clear: "R";
}
pin(D) { direction: input; }
pin(R) { direction: input; }
pin(C) { direction: input; clock: true; }
pin(Q) { direction: output; function: "IQ"; }
}
cell(DFF_NP1) {
ff(IQ, IQN) {
clocked_on: "!C";
next_state: "D";
preset: "R";
}
pin(D) { direction: input; }
pin(R) { direction: input; }
pin(C) { direction: input; clock: true; }
pin(Q) { direction: output; function: "IQ"; }
}
cell(DFF_PN0) {
ff(IQ, IQN) {
clocked_on: "C";
next_state: "D";
clear: "!R";
}
pin(D) { direction: input; }
pin(R) { direction: input; }
pin(C) { direction: input; clock: true; }
pin(Q) { direction: output; function: "IQ"; }
}
cell(DFF_PN1) {
ff(IQ, IQN) {
clocked_on: "C";
next_state: "D";
preset: "!R";
}
pin(D) { direction: input; }
pin(R) { direction: input; }
pin(C) { direction: input; clock: true; }
pin(Q) { direction: output; function: "IQ"; }
}
cell(DFF_PP0) {
ff(IQ, IQN) {
clocked_on: "C";
next_state: "D";
clear: "R";
}
pin(D) { direction: input; }
pin(R) { direction: input; }
pin(C) { direction: input; clock: true; }
pin(Q) { direction: output; function: "IQ"; }
}
cell(DFF_PP1) {
ff(IQ, IQN) {
clocked_on: "C";
next_state: "D";
preset: "R";
}
pin(D) { direction: input; }
pin(R) { direction: input; }
pin(C) { direction: input; clock: true; }
pin(Q) { direction: output; function: "IQ"; }
}
}

View File

@ -1,128 +0,0 @@
#include "kernel/rtlil.h"
#include "kernel/log.h"
#include "techlibs/common/opensta.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
#if !defined(YOSYS_DISABLE_SPAWN)
struct OpenstaPass : public Pass
{
OpenstaPass() : Pass("opensta", "run OpenSTA") { }
void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" opensta [options]\n");
log("\n");
log("Expand SDC file with OpenSTA.\n");
log("Internal command like abc. Requires a well-formed design.\n");
log("For general SDC expansion with OpenSTA, use the sdc_expand command.\n");
log("\n");
log(" -exe <command>\n");
log(" use <command> to run OpenSTA instead of \"%s\"\n", default_opensta_cmd);
log("\n");
log(" -sdc-in <filename>\n");
log(" expand SDC input file <filename>\n");
log("\n");
log(" -sdc-out <filename>\n");
log(" expand SDC file to output file <filename>\n");
log("\n");
log(" -nocleanup\n");
log("\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
string run_from, run_to;
string opensta_exe = design->scratchpad_get_string("opensta.exe", default_opensta_cmd);
string sdc_filename, sdc_expanded_filename;
string tempdir_name, script_filename;
string verilog_filename, liberty_filename;
bool cleanup = design->scratchpad_get_bool("opensta.cleanup", true);
log_header(design, "Executing OPENSTA pass.\n");
log_experimental("opensta");
log_push();
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
if (args[argidx] == "-exe" && argidx+1 < args.size()) {
opensta_exe = args[++argidx];
continue;
}
if (args[argidx] == "-sdc-in" && argidx+1 < args.size()) {
sdc_filename = args[++argidx];
continue;
}
if (args[argidx] == "-sdc-out" && argidx+1 < args.size()) {
sdc_expanded_filename = args[++argidx];
continue;
}
if (args[argidx] == "-verilog" && argidx+1 < args.size()) {
verilog_filename = args[++argidx];
continue;
}
if (args[argidx] == "-liberty" && argidx+1 < args.size()) {
liberty_filename = args[++argidx];
continue;
}
if (args[argidx] == "-nocleanup") {
cleanup = false;
continue;
}
break;
}
extra_args(args, argidx, design);
if (!design->full_selection())
log_cmd_error("This command only operates on fully selected designs!\n");
if (cleanup)
tempdir_name = get_base_tmpdir() + "/";
else
tempdir_name = "_tmp_";
tempdir_name += proc_program_prefix() + "yosys-opensta-XXXXXX";
tempdir_name = make_temp_dir(tempdir_name);
script_filename = tempdir_name + "/opensta.tcl";
// script_filename
auto top_mod = design->top_module();
if (!top_mod)
log_error("Can't find top module in current design!\n");
std::ofstream f_script;
f_script.open(script_filename);
f_script << "read_verilog " << verilog_filename << "\n";
f_script << "read_lib " << liberty_filename << "\n";
f_script << "link_design " << RTLIL::unescape_id(top_mod->name) << "\n";
f_script << "read_sdc " << sdc_filename << "\n";
f_script << "write_sdc " << sdc_expanded_filename << "\n";
f_script.close();
std::string command = opensta_exe + " -exit " + script_filename;
auto process_line = [](const std::string &line) {
if (line.find("Creating black box") != std::string::npos)
return;
if (line.find("does not match net size") != std::string::npos)
return;
log("OpenSTA: %s", line.c_str());
};
int ret = run_command(command, process_line);
if (ret)
log_error("OpenSTA returned %d (error)\n", ret);
else
log("sdc_expanded_filename: %s\n", sdc_expanded_filename.c_str());
if (cleanup) {
log("Removing temp directory.\n");
remove_directory(tempdir_name);
}
log_pop();
}
} OpenstaPass;
#endif
PRIVATE_NAMESPACE_END

View File

@ -1,8 +0,0 @@
#include "kernel/yosys_common.h"
#ifndef OPENSTA_H
YOSYS_NAMESPACE_BEGIN
static const char* default_opensta_cmd = "sta";
YOSYS_NAMESPACE_END
#endif /* OPENSTA_H */

View File

@ -1,156 +0,0 @@
#include "kernel/rtlil.h"
#include "kernel/log.h"
#include "techlibs/common/opensta.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct SdcExpandPass : public ScriptPass
{
SdcExpandPass() : ScriptPass("sdc_expand", "expand SDC design with opensta") { }
void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" sdc_expand [options]\n");
log("\n");
log("Expand SDC file with opensta based on arbitrary current design.\n");
log("Changes the design but only temporarily.\n");
log("\n");
log(" -exe <command>\n");
log(" use <command> to run OpenSTA instead of \"%s\"\n", default_opensta_cmd);
log("\n");
log(" -sdc-in <filename>\n");
log(" expand SDC file <filename>\n");
log("\n");
log(" -nocleanup\n");
log("\n");
log("\n");
log("The following commands are executed by this synthesis command:\n");
help_script();
log("\n");
}
string opensta_exe, sdc_filename, sdc_expanded_filename;
bool cleanup;
void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing SDC_EXPAND pass.\n");
log_experimental("sdc_expand");
string run_from, run_to;
opensta_exe = "";
cleanup = design->scratchpad_get_bool("sdc_expand.cleanup", true);
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
if (args[argidx] == "-exe" && argidx+1 < args.size()) {
opensta_exe = args[++argidx];
continue;
}
if (args[argidx] == "-sdc-in" && argidx+1 < args.size()) {
sdc_filename = args[++argidx];
continue;
}
if (args[argidx] == "-sdc-out" && argidx+1 < args.size()) {
sdc_expanded_filename = args[++argidx];
continue;
}
if (args[argidx] == "-nocleanup") {
cleanup = false;
continue;
}
if (args[argidx] == "-run" && argidx+1 < args.size()) {
size_t pos = args[argidx+1].find(':');
if (pos == std::string::npos) {
run_from = args[++argidx];
run_to = args[argidx];
} else {
run_from = args[++argidx].substr(0, pos);
run_to = args[argidx].substr(pos+1);
}
continue;
}
break;
}
if (sdc_filename.empty())
log_cmd_error("Missing -sdc-in argument\n");
if (sdc_expanded_filename.empty())
log_cmd_error("Missing -sdc-out argument\n");
extra_args(args, argidx, design);
if (!design->full_selection())
log_cmd_error("This command only operates on fully selected designs!\n");
log_header(design, "Executing OPENSTA pass.\n");
log_push();
run_script(design, run_from, run_to);
log_pop();
}
void script() override
{
std::string tempdir_name;
run("design -save pre_expand");
run("proc");
run("memory");
// run("dfflegalize -cell $dff");
if (help_mode) {
tempdir_name = "<tmp_dir>";
} else {
if (cleanup)
tempdir_name = get_base_tmpdir() + "/";
else
tempdir_name = "_tmp_";
tempdir_name += proc_program_prefix() + "yosys-sdc_expand-XXXXXX";
tempdir_name = make_temp_dir(tempdir_name);
}
std::string verilog_path = tempdir_name + "/elaborated.v";
std::string write_verilog_cmd = "write_verilog -norename -noexpr -attr2comment -defparam ";
run(write_verilog_cmd + verilog_path);
run("read_verilog -setattr whitebox -defer -DSIMLIB_NOCHECKS +/simlib.v");
run("proc");
run("hierarchy -auto-top");
run("chtype -publish_icells");
std::string liberty_path = tempdir_name + "/yosys.lib";
run("icell_liberty " + liberty_path);
std::string opensta_pass_call = "opensta ";
if (opensta_exe.length()) {
opensta_pass_call += "-exe ";
opensta_pass_call += help_mode ? "<exe>" : opensta_exe;
}
opensta_pass_call += " -sdc-in ";
opensta_pass_call += help_mode ? "<sdc-in>" : sdc_filename;
opensta_pass_call += " -sdc-out ";
opensta_pass_call += help_mode ? "<sdc-out>" : sdc_expanded_filename;
opensta_pass_call += " -verilog ";
opensta_pass_call += help_mode ? "<verilog>" : verilog_path;
opensta_pass_call += " -liberty ";
opensta_pass_call += help_mode ? "<tmp_dir>/yosys.lib" : liberty_path;
if (!cleanup)
opensta_pass_call += " -nocleanup";
run(opensta_pass_call);
if (!help_mode) {
if (cleanup) {
log("Removing temp directory.\n");
remove_directory(tempdir_name);
} else {
log("Keeping temp directory %s\n", tempdir_name.c_str());
}
}
run("design -load pre_expand");
}
} SdcExpandPass;
PRIVATE_NAMESPACE_END

View File

@ -117,7 +117,7 @@ static void run_ice40_opts(Module *module)
if (GetSize(replacement_output)) {
optimized_co.insert(sigmap(cell->getPort(ID::CO)[0]));
auto it = cell->attributes.find(IdString{"\\SB_LUT4.name"});
auto it = cell->attributes.find(ID(SB_LUT4.name));
if (it != cell->attributes.end()) {
module->rename(cell, it->second.decode_string());
decltype(Cell::attributes) new_attr;
@ -126,7 +126,7 @@ static void run_ice40_opts(Module *module)
new_attr[a.first.c_str() + strlen("\\SB_LUT4.")] = a.second;
else if (a.first == ID::src)
new_attr.insert(std::make_pair(a.first, a.second));
else if (a.first.in(IdString{"\\SB_LUT4.name"}, ID::keep, ID::module_not_derived))
else if (a.first.in(ID(SB_LUT4.name), ID::keep, ID::module_not_derived))
continue;
else if (a.first.begins_with("\\SB_CARRY.\\"))
continue;

View File

@ -62,7 +62,7 @@ void create_ice40_wrapcarry(ice40_wrapcarry_pm &pm)
cell->attributes[stringf("\\SB_CARRY.%s", a.first)] = a.second;
for (const auto &a : st.lut->attributes)
cell->attributes[stringf("\\SB_LUT4.%s", a.first)] = a.second;
cell->attributes[IdString{"\\SB_LUT4.name"}] = Const(st.lut->name.str());
cell->attributes[ID(SB_LUT4.name)] = Const(st.lut->name.str());
if (st.carry->get_bool_attribute(ID::keep) || st.lut->get_bool_attribute(ID::keep))
cell->attributes[ID::keep] = true;
@ -122,7 +122,7 @@ struct Ice40WrapCarryPass : public Pass {
carry->setPort(ID::CI, cell->getPort(ID::CI));
carry->setPort(ID::CO, cell->getPort(ID::CO));
module->swap_names(carry, cell);
auto lut_name = cell->attributes.at(IdString{"\\SB_LUT4.name"}, Const(NEW_ID.str())).decode_string();
auto lut_name = cell->attributes.at(ID(SB_LUT4.name), Const(NEW_ID.str())).decode_string();
auto lut = module->addCell(lut_name, ID($lut));
lut->setParam(ID::WIDTH, 4);
lut->setParam(ID::LUT, cell->getParam(ID::LUT));
@ -138,7 +138,7 @@ struct Ice40WrapCarryPass : public Pass {
lut->attributes[a.first.c_str() + strlen("\\SB_LUT4.")] = a.second;
else if (a.first == ID::src)
src = a.second;
else if (a.first.in(IdString{"\\SB_LUT4.name"}, ID::keep, ID::module_not_derived, ID::src))
else if (a.first.in(ID(SB_LUT4.name), ID::keep, ID::module_not_derived))
continue;
else
log_abort();

View File

@ -268,7 +268,7 @@ endmatch
code
if (postAdd)
{
if (postAdd->type.in($sub) && postAddAB == \A) {
if (postAdd->type.in(ID($sub)) && postAddAB == \A) {
// if $sub, the multiplier output must match to $sub.B, otherwise no match
} else {
u_postAddAB = postAddAB;

View File

@ -115,9 +115,9 @@ finally
Wire *cascade = module->addWire(NEW_ID, 48);
// zero port C and move wire to cascade
dsp_pcin->setPort(\C, Const(0, 48));
dsp_pcin->setPort(\CDIN, cascade);
dsp->setPort(\CDOUT, cascade);
dsp_pcin->setPort(ID(C), Const(0, 48));
dsp_pcin->setPort(ID(CDIN), cascade);
dsp->setPort(ID(CDOUT), cascade);
// Configure wire to cascade the dsps
add_siguser(cascade, dsp_pcin);

View File

@ -90,9 +90,9 @@ finally
if (i % MAX_DSP_CASCADE > 0) {
if (P >= 0) {
Wire *cascade = module->addWire(NEW_ID, 48);
dsp_pcin->setPort(\C, Const(0, 48));
dsp_pcin->setPort(\PCIN, cascade);
dsp->setPort(\PCOUT, cascade);
dsp_pcin->setPort(ID(C), Const(0, 48));
dsp_pcin->setPort(ID(PCIN), cascade);
dsp->setPort(ID(PCOUT), cascade);
add_siguser(cascade, dsp_pcin);
add_siguser(cascade, dsp);
@ -118,15 +118,15 @@ finally
}
if (AREG >= 0) {
Wire *cascade = module->addWire(NEW_ID, 30);
dsp_pcin->setPort(\A, Const(0, 30));
dsp_pcin->setPort(\ACIN, cascade);
dsp->setPort(\ACOUT, cascade);
dsp_pcin->setPort(ID(A), Const(0, 30));
dsp_pcin->setPort(ID(ACIN), cascade);
dsp->setPort(ID(ACOUT), cascade);
add_siguser(cascade, dsp_pcin);
add_siguser(cascade, dsp);
if (dsp->type.in(\DSP48E1))
dsp->setParam(\ACASCREG, AREG);
dsp_pcin->setParam(\A_INPUT, Const("CASCADE"));
dsp->setParam(ID(ACASCREG), AREG);
dsp_pcin->setParam(ID(A_INPUT), Const("CASCADE"));
log_debug("ACOUT -> ACIN cascade for %s -> %s\n", log_id(dsp), log_id(dsp_pcin));
}
@ -138,18 +138,18 @@ finally
// BCOUT from an adjacent DSP48A1 slice. The tools then
// translate BCOUT cascading to the dedicated BCIN input
// and set the B_INPUT attribute for implementation."
dsp_pcin->setPort(\B, cascade);
dsp_pcin->setPort(ID(B), cascade);
}
else {
dsp_pcin->setPort(\B, Const(0, 18));
dsp_pcin->setPort(\BCIN, cascade);
dsp_pcin->setPort(ID(B), Const(0, 18));
dsp_pcin->setPort(ID(BCIN), cascade);
}
dsp->setPort(\BCOUT, cascade);
dsp->setPort(ID(BCOUT), cascade);
add_siguser(cascade, dsp_pcin);
add_siguser(cascade, dsp);
if (dsp->type.in(\DSP48E1)) {
dsp->setParam(\BCASCREG, BREG);
dsp->setParam(ID(BCASCREG), BREG);
// According to UG389 p13 [https://www.xilinx.com/support/documentation/user_guides/ug389.pdf]
// "The attribute is only used by place and route tools and
// is not necessary for the users to set for synthesis. The
@ -158,7 +158,7 @@ finally
// BCOUT of another DSP48A1 slice, then the tools automatically
// set the attribute to 'CASCADE', otherwise it is set to
// 'DIRECT'".
dsp_pcin->setParam(\B_INPUT, Const("CASCADE"));
dsp_pcin->setParam(ID(B_INPUT), Const("CASCADE"));
}
log_debug("BCOUT -> BCIN cascade for %s -> %s\n", log_id(dsp), log_id(dsp_pcin));

View File

@ -1,3 +1,2 @@
/*_ref.v
/neg.out/
/gate/

View File

@ -1,7 +0,0 @@
aag 3 2 0 1 1
2
4
6
6 5 2
c
Generated by Yosys

View File

@ -1,7 +0,0 @@
aag 3 2 0 1 1
2
4
6
6 4 2
c
Generated by Yosys

View File

@ -1,9 +0,0 @@
aag 5 3 0 1 2
2
4
6
10
8 4 2
10 9 7
c
Generated by Yosys

View File

@ -1,11 +0,0 @@
aag 7 4 0 1 3
2
4
6
8
14
10 4 2
12 8 6
14 13 11
c
Generated by Yosys

View File

@ -1,5 +0,0 @@
aag 1 1 0 1 0
2
2
c
Generated by Yosys

View File

@ -1,10 +0,0 @@
aag 6 3 0 1 3
2
4
6
13
8 7 2
10 6 4
12 11 9
c
Generated by Yosys

View File

@ -1,7 +0,0 @@
aag 3 2 0 1 1
2
4
7
6 4 2
c
Generated by Yosys

View File

@ -1,10 +0,0 @@
aag 6 3 0 1 3
2
4
6
12
8 7 2
10 6 4
12 11 9
c
Generated by Yosys

View File

@ -1,7 +0,0 @@
aag 3 2 0 1 1
2
4
6
6 5 3
c
Generated by Yosys

View File

@ -1,5 +0,0 @@
aag 1 1 0 1 0
2
3
c
Generated by Yosys

View File

@ -1,9 +0,0 @@
aag 5 3 0 1 2
2
4
6
11
8 5 3
10 9 6
c
Generated by Yosys

View File

@ -1,11 +0,0 @@
aag 7 4 0 1 3
2
4
6
8
15
10 5 3
12 9 7
14 13 11
c
Generated by Yosys

View File

@ -1,7 +0,0 @@
aag 3 2 0 1 1
2
4
7
6 4 3
c
Generated by Yosys

View File

@ -1,7 +0,0 @@
aag 3 2 0 1 1
2
4
7
6 5 3
c
Generated by Yosys

View File

@ -1,9 +0,0 @@
aag 5 2 0 1 3
2
4
11
6 4 2
8 5 3
10 9 7
c
Generated by Yosys

View File

@ -1,9 +0,0 @@
aag 5 2 0 1 3
2
4
10
6 4 2
8 5 3
10 9 7
c
Generated by Yosys

View File

@ -1,62 +0,0 @@
aag 51 4 0 8 47
2
4
6
8
14
30
42
54
66
78
90
102
10 6 2
12 7 3
14 13 11
16 6 2
18 8 4
20 9 5
22 21 19
24 22 16
26 21 19
28 27 11
30 29 25
32 21 16
34 33 19
36 35 22
38 33 19
40 38 27
42 41 37
44 35 21
46 45 19
48 47 22
50 45 19
52 50 27
54 53 49
56 47 21
58 57 19
60 59 22
62 57 19
64 62 27
66 65 61
68 59 21
70 69 19
72 71 22
74 69 19
76 74 27
78 77 73
80 71 21
82 81 19
84 83 22
86 81 19
88 86 27
90 89 85
92 83 21
94 93 19
96 95 22
98 93 19
100 98 27
102 101 97
c
Generated by Yosys

View File

@ -1,45 +0,0 @@
aag 33 5 0 9 28
2
4
6
8
10
27
35
36
38
40
8
48
58
66
12 8 6
14 9 7
16 15 13
18 16 2
20 15 13
22 21 3
24 23 10
26 25 19
28 8 4
30 9 5
32 31 27
34 33 29
36 35 8
38 23 19
40 31 29
42 38 10
44 23 19
46 45 11
48 47 43
50 40 27
52 31 29
54 25 19
56 54 53
58 57 51
60 35 8
62 33 29
64 62 9
66 65 61
c
Generated by Yosys

View File

@ -1,28 +0,0 @@
aag 17 11 0 8 6
2
4
6
8
10
12
14
16
18
20
22
24
26
28
30
32
34
34
34
24 14 2
26 16 4
28 18 6
30 20 8
32 22 10
34 22 12
c
Generated by Yosys

View File

@ -1,15 +0,0 @@
aag 6 6 0 6 0
2
4
6
8
10
12
2
4
6
8
10
12
c
Generated by Yosys

View File

@ -1,46 +0,0 @@
aag 38 11 0 5 27
2
4
6
8
10
12
14
16
18
20
22
76
0
0
0
0
24 10 2
26 11 3
28 27 25
30 12 4
32 13 5
34 33 31
36 35 29
38 14 6
40 15 7
42 41 39
44 43 36
46 16 8
48 17 9
50 49 47
52 51 44
54 18 8
56 19 9
58 57 55
60 59 52
62 20 8
64 21 9
66 65 63
68 67 60
70 22 8
72 23 9
74 73 71
76 75 68
c
Generated by Yosys

View File

@ -1,9 +0,0 @@
aag 3 2 0 3 1
2
4
7
0
0
6 4 3
c
Generated by Yosys

View File

@ -1,48 +0,0 @@
aag 43 10 0 2 33
2
4
6
8
10
12
14
16
18
20
86
0
22 20 7
24 21 6
26 25 23
28 18 7
30 16 7
32 14 7
34 12 7
36 10 5
38 9 2
40 8 3
42 41 38
44 11 4
46 45 43
48 47 37
50 13 6
52 51 49
54 53 35
56 15 6
58 57 55
60 59 33
62 17 6
64 63 61
66 65 31
68 19 6
70 69 67
72 71 29
74 73 25
76 75 23
78 77 26
80 25 23
82 75 23
84 82 81
86 85 79
c
Generated by Yosys

View File

@ -1,52 +0,0 @@
aag 47 12 0 2 35
2
4
6
8
10
12
14
16
18
20
22
24
94
0
26 25 8
28 24 9
30 29 27
32 23 8
34 21 8
36 19 8
38 17 8
40 15 6
42 13 4
44 11 2
46 12 5
48 47 44
50 49 43
52 14 7
54 53 51
56 55 41
58 16 9
60 59 57
62 61 39
64 18 9
66 65 63
68 67 37
70 20 9
72 71 69
74 73 35
76 22 9
78 77 75
80 79 33
82 81 29
84 83 27
86 85 30
88 29 27
90 83 27
92 90 89
94 93 87
c
Generated by Yosys

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