3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2026-06-26 18:48:51 +00:00

Merge branch 'YosysHQ:main' into master

This commit is contained in:
Eder Monteiro 2025-04-17 14:20:36 -03:00 committed by GitHub
commit 088240c037
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
97 changed files with 2087 additions and 683 deletions

View file

@ -16,7 +16,9 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v4
with:
submodules: true
submodules: true
persist-credentials: false
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:

View file

@ -25,7 +25,8 @@ jobs:
steps:
- uses: actions/checkout@v4
with:
submodules: true
submodules: true
persist-credentials: false
- name: Build
run: make vcxsrc YOSYS_VER=latest
- uses: actions/upload-artifact@v4
@ -59,7 +60,8 @@ jobs:
steps:
- uses: actions/checkout@v4
with:
submodules: true
submodules: true
persist-credentials: false
- name: Build
run: |
WASI_SDK=wasi-sdk-19.0
@ -95,6 +97,7 @@ jobs:
- uses: actions/checkout@v4
with:
submodules: true
persist-credentials: false
- uses: cachix/install-nix-action@v26
with:
install_url: https://releases.nixos.org/nix/nix-2.18.1/install

View file

@ -20,7 +20,7 @@ jobs:
# only run on push *or* pull_request, not both
concurrent_skipping: ${{ env.docs_export && 'never' || 'same_content_newer'}}
- id: docs_var
run: echo "docs_export=${{ env.docs_export }}" >> $GITHUB_OUTPUT
run: echo "docs_export=${docs_export}" >> $GITHUB_OUTPUT
prepare-docs:
# docs builds are needed for anything on main, any tagged versions, and any tag
@ -47,12 +47,12 @@ jobs:
echo "ENABLE_VERIFIC_LIBERTY := 1" >> Makefile.conf
echo "ENABLE_VERIFIC_YOSYSHQ_EXTENSIONS := 1" >> Makefile.conf
echo "ENABLE_CCACHE := 1" >> Makefile.conf
make -j${{ env.procs }} ENABLE_LTO=1
make -j$procs ENABLE_LTO=1
- name: Prepare docs
shell: bash
run:
make docs/prep -j${{ env.procs }} TARGETS= EXTRA_TARGETS=
make docs/prep -j$procs TARGETS= EXTRA_TARGETS=
- name: Upload artifact
uses: actions/upload-artifact@v4
@ -72,7 +72,7 @@ jobs:
- name: Test build docs
shell: bash
run: |
make -C docs html -j${{ env.procs }} TARGETS= EXTRA_TARGETS=
make -C docs html -j$procs TARGETS= EXTRA_TARGETS=
- name: Trigger RTDs build
if: ${{ needs.check_docs_rebuild.outputs.docs_export == 'true' }}

View file

@ -10,6 +10,7 @@ jobs:
uses: actions/checkout@v4
with:
submodules: 'recursive'
persist-credentials: false
- name: Create clean tarball
run: |

View file

@ -46,6 +46,7 @@ jobs:
uses: actions/checkout@v4
with:
submodules: true
persist-credentials: false
- name: Setup environment
uses: ./.github/actions/setup-build-env
@ -91,6 +92,8 @@ jobs:
steps:
- name: Checkout Yosys
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Setup environment
uses: ./.github/actions/setup-build-env
@ -117,7 +120,7 @@ jobs:
uses: actions/cache@v4
with:
path: .local/
key: ${{ matrix.os }}-${{ env.IVERILOG_GIT }}
key: ${{ matrix.os }}-${IVERILOG_GIT}
- name: Build iverilog
if: steps.cache-iverilog.outputs.cache-hit != 'true'
@ -169,6 +172,8 @@ jobs:
steps:
- name: Checkout Yosys
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Setup environment
uses: ./.github/actions/setup-build-env
@ -190,7 +195,7 @@ jobs:
- name: Run tests
shell: bash
run: |
make -C docs test -j${{ env.procs }}
make -C docs test -j$procs
test-docs-build:
name: Try build docs
@ -206,6 +211,7 @@ jobs:
uses: actions/checkout@v4
with:
submodules: true
persist-credentials: false
- name: Runtime environment
run: |
@ -215,7 +221,7 @@ jobs:
run: |
make config-clang
echo "ENABLE_CCACHE := 1" >> Makefile.conf
make -j${{ env.procs }}
make -j$procs
- name: Install doc prereqs
shell: bash
@ -225,7 +231,7 @@ jobs:
- name: Build docs
shell: bash
run: |
make docs DOC_TARGET=${{ matrix.docs-target }} -j${{ env.procs }}
make docs DOC_TARGET=${{ matrix.docs-target }} -j$procs
- name: Store docs build artifact
uses: actions/upload-artifact@v4

View file

@ -45,6 +45,7 @@ jobs:
uses: actions/checkout@v4
with:
submodules: true
persist-credentials: false
- name: Setup environment
uses: ./.github/actions/setup-build-env

View file

@ -40,7 +40,7 @@ jobs:
echo "ENABLE_VERIFIC_YOSYSHQ_EXTENSIONS := 1" >> Makefile.conf
echo "ENABLE_CCACHE := 1" >> Makefile.conf
echo "ENABLE_FUNCTIONAL_TESTS := 1" >> Makefile.conf
make -j${{ env.procs }} ENABLE_LTO=1
make -j$procs ENABLE_LTO=1
- name: Install Yosys
run: |
@ -51,6 +51,7 @@ jobs:
with:
repository: 'YosysHQ/sby'
path: 'sby'
persist-credentials: false
- name: Build SBY
run: |
@ -58,7 +59,7 @@ jobs:
- name: Run Yosys tests
run: |
make -j${{ env.procs }} test
make -j$procs test
- name: Run Verific specific Yosys tests
run: |

View file

@ -10,6 +10,8 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
persist-credentials: false
- name: Install Nix
uses: DeterminateSystems/nix-installer-action@main
- name: Update flake.lock

View file

@ -14,6 +14,7 @@ jobs:
with:
fetch-depth: 0
submodules: true
persist-credentials: false
- name: Take last commit
id: log
run: echo "message=$(git log --no-merges -1 --oneline)" >> $GITHUB_OUTPUT

View file

@ -1,6 +1,10 @@
name: Build Wheels for PyPI
# run every Sunday at 10 AM
on:
workflow_dispatch:
schedule:
- cron: '0 10 * * 0'
jobs:
build_wheels:
@ -14,16 +18,12 @@ jobs:
runner: "ubuntu-22.04",
archs: "x86_64",
},
## Aarch64 is disabled for now: GitHub is committing to EOY
## for free aarch64 runners for open-source projects and
## emulation times out:
## https://github.com/orgs/community/discussions/19197#discussioncomment-10550689
# {
# name: "Ubuntu 22.04",
# family: "linux",
# runner: "ubuntu-22.04",
# archs: "aarch64",
# },
{
name: "Ubuntu 22.04",
family: "linux",
runner: "ubuntu-22.04-arm",
archs: "aarch64",
},
{
name: "macOS 13",
family: "macos",
@ -53,6 +53,7 @@ jobs:
with:
fetch-depth: 0
submodules: true
persist-credentials: false
- if: ${{ matrix.os.family == 'linux' }}
name: "[Linux] Set up QEMU"
uses: docker/setup-qemu-action@v3

View file

@ -102,6 +102,7 @@ LIBS := $(LIBS) -lstdc++ -lm
PLUGIN_LINKFLAGS :=
PLUGIN_LIBS :=
EXE_LINKFLAGS :=
EXE_LIBS :=
ifeq ($(OS), MINGW)
EXE_LINKFLAGS := -Wl,--export-all-symbols -Wl,--out-implib,libyosys_exe.a
PLUGIN_LINKFLAGS += -L"$(LIBDIR)"
@ -159,7 +160,7 @@ ifeq ($(OS), Haiku)
CXXFLAGS += -D_DEFAULT_SOURCE
endif
YOSYS_VER := 0.52+0
YOSYS_VER := 0.52+63
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)
@ -209,11 +210,11 @@ PYTHON_VERSION_TESTCODE := "import sys;t='{v[0]}.{v[1]}'.format(v=list(sys.versi
PYTHON_VERSION := $(shell $(PYTHON_EXECUTABLE) -c ""$(PYTHON_VERSION_TESTCODE)"")
PYTHON_MAJOR_VERSION := $(shell echo $(PYTHON_VERSION) | cut -f1 -d.)
ENABLE_PYTHON_CONFIG_EMBED ?= $(shell $(PYTHON_EXECUTABLE)-config --embed --libs > /dev/null && echo 1)
ifeq ($(ENABLE_PYTHON_CONFIG_EMBED),1)
PYTHON_CONFIG := $(PYTHON_EXECUTABLE)-config --embed
else
PYTHON_CONFIG := $(PYTHON_EXECUTABLE)-config
PYTHON_CONFIG_FOR_EXE := $(PYTHON_CONFIG)
PYTHON_CONFIG_EMBED_AVAILABLE ?= $(shell $(PYTHON_EXECUTABLE)-config --embed --libs > /dev/null && echo 1)
ifeq ($(PYTHON_CONFIG_EMBED_AVAILABLE),1)
PYTHON_CONFIG_FOR_EXE := $(PYTHON_CONFIG) --embed
endif
PYTHON_DESTDIR := $(shell $(PYTHON_EXECUTABLE) -c "import site; print(site.getsitepackages()[-1]);")
@ -346,11 +347,11 @@ ifeq ($(ENABLE_PYOSYS),1)
# python-config --ldflags includes -l and -L, but LINKFLAGS is only -L
LINKFLAGS += $(filter-out -l%,$(shell $(PYTHON_CONFIG) --ldflags))
LIBS += $(shell $(PYTHON_CONFIG) --libs)
EXE_LIBS += $(filter-out $(LIBS),$(shell $(PYTHON_CONFIG_FOR_EXE) --libs))
CXXFLAGS += $(shell $(PYTHON_CONFIG) --includes) -DWITH_PYTHON
EXTRA_TARGETS += wheel
# Detect name of boost_python library. Some distros use boost_python-py<version>, other boost_python<version>, some only use the major version number, some a concatenation of major and minor version numbers
CHECK_BOOST_PYTHON = (echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null $(LINKFLAGS) $(LIBS) -l$(1) - > /dev/null 2>&1 && echo "-l$(1)")
CHECK_BOOST_PYTHON = (echo "int main(int argc, char ** argv) {return 0;}" | $(CXX) -xc -o /dev/null $(LINKFLAGS) $(EXE_LIBS) $(LIBS) -l$(1) - > /dev/null 2>&1 && echo "-l$(1)")
BOOST_PYTHON_LIB ?= $(shell \
$(call CHECK_BOOST_PYTHON,boost_python-py$(subst .,,$(PYTHON_VERSION))) || \
$(call CHECK_BOOST_PYTHON,boost_python-py$(PYTHON_MAJOR_VERSION)) || \
@ -735,7 +736,7 @@ share: $(EXTRA_TARGETS)
@echo ""
$(PROGRAM_PREFIX)yosys$(EXE): $(OBJS)
$(P) $(CXX) -o $(PROGRAM_PREFIX)yosys$(EXE) $(EXE_LINKFLAGS) $(LINKFLAGS) $(OBJS) $(LIBS) $(LIBS_VERIFIC)
$(P) $(CXX) -o $(PROGRAM_PREFIX)yosys$(EXE) $(EXE_LINKFLAGS) $(LINKFLAGS) $(OBJS) $(EXE_LIBS) $(LIBS) $(LIBS_VERIFIC)
libyosys.so: $(filter-out kernel/driver.o,$(OBJS))
ifeq ($(OS), Darwin)
@ -890,6 +891,7 @@ SH_TEST_DIRS += tests/rpc
SH_TEST_DIRS += tests/memfile
SH_TEST_DIRS += tests/fmt
SH_TEST_DIRS += tests/cxxrtl
SH_TEST_DIRS += tests/liberty
ifeq ($(ENABLE_FUNCTIONAL_TESTS),1)
SH_TEST_DIRS += tests/functional
endif
@ -966,20 +968,6 @@ unit-test: libyosys.so
clean-unit-test:
@$(MAKE) -C $(UNITESTPATH) clean
ifeq ($(ENABLE_PYOSYS),1)
wheel: $(TARGETS)
$(PYTHON_EXECUTABLE) -m pip wheel .
install-wheel: wheel
$(PYTHON_EXECUTABLE) -m pip install pyosys-$(YOSYS_MAJOR).$(YOSYS_MINOR).$(YOSYS_COMMIT)-*.whl --force-reinstall
else
wheel:
$(error Pyosys is not enabled. Set ENABLE_PYOSYS=1 to enable it.)
install-wheel:
$(error Pyosys is not enabled. Set ENABLE_PYOSYS=1 to enable it.)
endif
install: $(TARGETS) $(EXTRA_TARGETS)
$(INSTALL_SUDO) mkdir -p $(DESTDIR)$(BINDIR)
$(INSTALL_SUDO) cp $(filter-out libyosys.so,$(TARGETS)) $(DESTDIR)$(BINDIR)
@ -999,7 +987,13 @@ ifeq ($(ENABLE_LIBYOSYS),1)
$(INSTALL_SUDO) cp libyosys.so $(DESTDIR)$(LIBDIR)/
$(INSTALL_SUDO) $(STRIP) -S $(DESTDIR)$(LIBDIR)/libyosys.so
ifeq ($(ENABLE_PYOSYS),1)
$(INSTALL_SUDO) @$(MAKE) install-wheel
$(INSTALL_SUDO) mkdir -p $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys
$(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)
$(INSTALL_SUDO) cp yosys-abc $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys/yosys-abc
endif
$(INSTALL_SUDO) cp misc/__init__.py $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys/
endif
endif
ifeq ($(ENABLE_PLUGINS),1)
@ -1015,7 +1009,9 @@ uninstall:
ifeq ($(ENABLE_LIBYOSYS),1)
$(INSTALL_SUDO) rm -vf $(DESTDIR)$(LIBDIR)/libyosys.so
ifeq ($(ENABLE_PYOSYS),1)
$(INSTALL_SUDO) $(PYTHON_EXECUTABLE) -m pip uninstall -y pyosys
$(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
$(INSTALL_SUDO) rmdir $(DESTDIR)$(PYTHON_DESTDIR)/$(subst -,_,$(PROGRAM_PREFIX))pyosys
endif
endif

View file

@ -200,7 +200,7 @@ bool is_extending_cell(RTLIL::IdString type)
bool is_inlinable_cell(RTLIL::IdString type)
{
return is_unary_cell(type) || is_binary_cell(type) || type.in(
ID($mux), ID($concat), ID($slice), ID($pmux), ID($bmux), ID($demux));
ID($mux), ID($concat), ID($slice), ID($pmux), ID($bmux), ID($demux), ID($bwmux));
}
bool is_ff_cell(RTLIL::IdString type)
@ -1198,6 +1198,14 @@ struct CxxrtlWorker {
f << ">(";
dump_sigspec_rhs(cell->getPort(ID::S), for_debug);
f << ").val()";
// Bitwise muxes
} else if (cell->type == ID($bwmux)) {
dump_sigspec_rhs(cell->getPort(ID::A), for_debug);
f << ".bwmux(";
dump_sigspec_rhs(cell->getPort(ID::B), for_debug);
f << ",";
dump_sigspec_rhs(cell->getPort(ID::S), for_debug);
f << ").val()";
// Demuxes
} else if (cell->type == ID($demux)) {
dump_sigspec_rhs(cell->getPort(ID::A), for_debug);

View file

@ -498,6 +498,11 @@ struct value : public expr_base<value<Bits>> {
return result;
}
CXXRTL_ALWAYS_INLINE
value<Bits> bwmux(const value<Bits> &b, const value<Bits> &s) const {
return (bit_and(s.bit_not())).bit_or(b.bit_and(s));
}
template<size_t ResultBits, size_t SelBits>
value<ResultBits> demux(const value<SelBits> &sel) const {
static_assert(Bits << SelBits == ResultBits, "invalid sizes used in demux()");

View file

@ -1215,9 +1215,6 @@ struct FirrtlBackend : public Backend {
}
extra_args(f, filename, args, argidx);
if (!design->full_selection())
log_cmd_error("This command only operates on fully selected designs!\n");
log_header(design, "Executing FIRRTL backend.\n");
log_push();
@ -1230,7 +1227,7 @@ struct FirrtlBackend : public Backend {
autoid_counter = 0;
// Get the top module, or a reasonable facsimile - we need something for the circuit name.
Module *top = design->top_module();
Module *top = nullptr;
Module *last = nullptr;
// Generate module and wire names.
for (auto module : design->modules()) {

View file

@ -304,8 +304,8 @@ void RTLIL_BACKEND::dump_conn(std::ostream &f, std::string indent, const RTLIL::
void RTLIL_BACKEND::dump_module(std::ostream &f, std::string indent, RTLIL::Module *module, RTLIL::Design *design, bool only_selected, bool flag_m, bool flag_n)
{
bool print_header = flag_m || design->selected_whole_module(module->name);
bool print_body = !flag_n || !design->selected_whole_module(module->name);
bool print_header = flag_m || module->is_selected_whole();
bool print_body = !flag_n || !module->is_selected_whole();
if (print_header)
{

View file

@ -51,10 +51,10 @@ struct Test2Pass : public Pass {
Test2Pass() : Pass("test2", "demonstrating sigmap on test module") { }
void execute(std::vector<std::string>, RTLIL::Design *design) override
{
if (design->selection_stack.back().empty())
if (design->selection().empty())
log_cmd_error("This command can't operator on an empty selection!\n");
RTLIL::Module *module = design->modules_.at("\\test");
RTLIL::Module *module = design->module("\\test");
RTLIL::SigSpec a(module->wire("\\a")), x(module->wire("\\x")), y(module->wire("\\y"));
log("%d %d %d\n", a == x, x == y, y == a); // will print "0 0 0"

View file

@ -0,0 +1,114 @@
Dataflow tracking
-------------------
Yosys can be used to answer questions such as "can this signal affect this other
signal?" via its *dataflow tracking* support. For this, four special cells,
`$get_tag`, `$set_tag`, `$overwrite_tag` and `$original_tag` are inserted into
the design (e.g. by a custom Yosys pass) and then the `dft_tag` is run, which
converts these cells into ordinary logic. Typically, one would then use `SBY`_
to prove assertions involving these cells.
.. _SBY: https://yosyshq.readthedocs.io/projects/sby
Ordinarily in Yosys, the state of a bit is simply ``0`` or ``1`` (or one of the
special values, ``z`` and ``x``). During dataflow tracking they are augmented
with a set of tags. For example, the state of a bit could be ``0`` and the set
of tags ``"KEY"`` and ``"OVERFLOW"``.
In addition to their usual operations on the logical bits, Yosys operations must
now also process the status of the tags. For this, tags are simply *forwarded*
or *propagated* (i.e. copied) from inputs to outputs, according to the following
general rule:
A tag is forwarded from an input to an output if the input can affect the
output, for that particular state of all other inputs.
For example, XOR, AND and OR cells propagate tags as follows:
#. XOR simply forwards all tags from its inputs to its output, because inputs to
XOR can always affect the output.
#. AND forwards tags on a given input only if the other input is ``1``. Because
if one input is ``0``, the other input can never affect the output.
#. Similarly, OR forwards tags only if the other input is ``0``.
There are two exceptions to this rule:
#. In general, propagation is only determined approximately. For example, unless
the ``dft_tag`` code knows about a cell, it simply assumes the worst-case
behaviour that all inputs can affect all outputs. Further, the code also does
not consider that, when a signal affects multiple inputs of a cell, the
resulting simultaneous changes of the inputs can cancel each other out, for
example ``A ^ A`` or ``A ^ (B ^ A)`` is independent of ``A``, but its tags
would be propagated nonetheless.
#. If tag groups are used, the rules are modified (see below).
Because of this propagation behaviour, we can answer questions about what
signals are affected by a certain signal, by injecting a tag at that point in
the circuit, and observing where the tag is visible.
Example use cases
~~~~~~~~~~~~~~~~~~
As an example use case, consider a cryptographic processor which is not supposed
to expose its secret keys to the outside world. We can tag all key bits with the
``"KEY"`` tag and use `SBY`_ to formally verify that no external signal ever
carries the ``"KEY"`` tag, meaning that key information is not visible to the
outside. As a caveat, we have to manually clear the ``"KEY"`` tag during
cryptographic operations, as proving that the cryptographic operations
themselves do not leak key information is beyond the ability of Yosys. However
we can still easily detect, if e.g. an engineer forgot to remove debugging code
that allows reading back key data.
As a different use case, we can modify all adders in the design to set the
``"OVERFLOW"`` tag on their output bits, if the addition overflowed, and then
add asserts to all flip-flop inputs and output signals that they do not carry
the ``"OVERFLOW"`` tag, i.e. that the results of overflowed additions never
affect system state. Note that in this particular example we use the ability of
tag insertion to be conditional on logic, in this case the overflow condition of
an adder.
Semantics of dataflow tracking cells
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
``$set_tag`` has inputs ``A``, ``SET``, ``CLR``, an output ``Y`` and a string
parameter ``TAG``. The logic value of ``A`` and all tags other than the one
named by the ``TAG`` parameter are simply copied to ``Y``. If ``SET`` is ``1``,
then the named tag is added to ``Y``. Otherwise, if ``CLR`` is ``1``, then the
named tag is removed. Otherwise, the tag is unchanged, i.e. it is present in
``Y`` if it is present in ``A``.
``$get_tag`` has an input ``A`` and an output ``Y`` and a string parameter
``TAG``. ``$get_tag`` inspects ``A`` for the presence or absence of a tag of the
given name and sets ``Y`` to ``1`` if the tag is present. The logical value of
``A`` is completely ignored.
``$overwrite_tag`` functions like ``$set_tag``, but lacks the ``Y`` output.
Instead of providing a modified version of the input signal, it modifies the
signal ``A`` "in-place", i.e. if a signal is input to ``$overwrite_tag``, that
is equivalent to interposing a ``$set_tag`` between its driver and all cells it
is connected to. The main purpose of ``$overwrite_tag`` is adding tags to
signals produced within a module that cannot or should not be modified itself.
``$original_tag`` functions identically to ``$get_tag``, but ignores
``$overwrite_tag``, i.e. when converting the ``$overwrite_tag`` to ``$set_tag``
as described above, it is equivalent to inserting the ``$get_tag`` *before* the
``$set_tag``.
Tag groups
~~~~~~~~~~~~~~
Tag groups are an advanced feature that modify the propagation rule discussed
above. To use tag groups, simply name tags according to the schema
``"group:name"``. For example, ``"key:0"``, ``"key:a"``, ``"key:b"`` would be
three tags in the ``"key"`` group.
The propagation rule is then amended by
Inputs cannot block the propagation of each other's tags for tags of the same
group.
For example, an AND gate will propagate a given tag on one input, if the other
input is either 1 or carries a tag of the same group. So if one input is ``0,
"key:a"`` and the other is ``0, "key:b"`` the result would be ``0, "key:a",
"key:b"``, rather than simply ``0``. Note that if we add an unrelated
``"overflow"`` tag to the first input, it would still not be propagated.

View file

@ -12,5 +12,6 @@ More scripting
selections
interactive_investigation
model_checking
data_flow_tracking
.. troubleshooting

View file

@ -237,7 +237,7 @@ Use ``log_cmd_error()`` to report a recoverable error:
.. code:: C++
if (design->selection_stack.back().empty())
if (design->selection().empty())
log_cmd_error("This command can't operator on an empty selection!\n");
Use ``log_assert()`` and ``log_abort()`` instead of ``assert()`` and ``abort()``.

View file

@ -315,7 +315,7 @@ struct ConstEval
Macc macc;
macc.from_cell(cell);
for (auto &port : macc.ports) {
for (auto &port : macc.terms) {
if (!eval(port.in_a, undef, cell))
return false;
if (!eval(port.in_b, undef, cell))

View file

@ -1,4 +1,5 @@
#include "kernel/cost.h"
#include "kernel/macc.h"
USING_YOSYS_NAMESPACE
@ -148,6 +149,9 @@ unsigned int CellCosts::get(RTLIL::Cell *cell)
log_assert(cell->hasPort(ID::Q) && "Weird flip flop");
log_debug("%s is ff\n", cell->name.c_str());
return cell->getParam(ID::WIDTH).as_int();
} else if (cell->type.in(ID($mem), ID($mem_v2))) {
log_debug("%s is mem\n", cell->name.c_str());
return cell->getParam(ID::WIDTH).as_int() * cell->getParam(ID::SIZE).as_int();
} else if (y_coef(cell->type)) {
// linear with Y_WIDTH or WIDTH
log_assert((cell->hasParam(ID::Y_WIDTH) || cell->hasParam(ID::WIDTH)) && "Unknown width");
@ -173,6 +177,22 @@ unsigned int CellCosts::get(RTLIL::Cell *cell)
unsigned int coef = cell->type == ID($mul) ? 3 : 5;
log_debug("%s coef*(sum**2) %d * %d\n", cell->name.c_str(), coef, sum * sum);
return coef * sum * sum;
} else if (cell->type.in(ID($macc), ID($macc_v2))) {
// quadratic per term
unsigned int cost_sum = 0;
Macc macc;
macc.from_cell(cell);
unsigned int y_width = cell->getParam(ID::Y_WIDTH).as_int();
for (auto &term: macc.terms) {
if (term.in_b.empty()) {
// neglect addends
continue;
}
unsigned a_width = term.in_a.size(), b_width = term.in_b.size();
unsigned int sum = a_width + b_width + std::min(y_width, a_width + b_width);
cost_sum += 3 * sum * sum;
}
return cost_sum;
} else if (cell->type == ID($lut)) {
int width = cell->getParam(ID::WIDTH).as_int();
unsigned int cost = 1U << (unsigned int)width;
@ -187,8 +207,8 @@ unsigned int CellCosts::get(RTLIL::Cell *cell)
log_debug("%s is free\n", cell->name.c_str());
return 0;
}
// TODO: $fsm $mem.* $macc
// ignored: $pow
// TODO: $fsm
// ignored: $pow $memrd $memwr $meminit (and v2 counterparts)
log_warning("Can't determine cost of %s cell (%d parameters).\n", log_id(cell->type), GetSize(cell->parameters));
return 1;

View file

@ -111,7 +111,7 @@ void run(const char *command)
log_last_error = "";
} catch (...) {
while (GetSize(yosys_get_design()->selection_stack) > selSize)
yosys_get_design()->selection_stack.pop_back();
yosys_get_design()->pop_selection();
throw;
}
}

View file

@ -26,18 +26,18 @@ YOSYS_NAMESPACE_BEGIN
struct Macc
{
struct port_t {
struct term_t {
RTLIL::SigSpec in_a, in_b;
bool is_signed, do_subtract;
};
std::vector<port_t> ports;
std::vector<term_t> terms;
void optimize(int width)
{
std::vector<port_t> new_ports;
std::vector<term_t> new_terms;
RTLIL::Const off(0, width);
for (auto &port : ports)
for (auto &port : terms)
{
if (GetSize(port.in_a) == 0 && GetSize(port.in_b) == 0)
continue;
@ -68,25 +68,25 @@ struct Macc
port.in_b.remove(GetSize(port.in_b)-1);
}
new_ports.push_back(port);
new_terms.push_back(port);
}
if (off.as_bool()) {
port_t port;
term_t port;
port.in_a = off;
port.is_signed = false;
port.do_subtract = false;
new_ports.push_back(port);
new_terms.push_back(port);
}
new_ports.swap(ports);
new_terms.swap(terms);
}
void from_cell_v1(RTLIL::Cell *cell)
{
RTLIL::SigSpec port_a = cell->getPort(ID::A);
ports.clear();
terms.clear();
auto config_bits = cell->getParam(ID::CONFIG);
int config_cursor = 0;
@ -105,7 +105,7 @@ struct Macc
{
log_assert(config_cursor + 2 + 2*num_bits <= config_width);
port_t this_port;
term_t this_port;
this_port.is_signed = config_bits[config_cursor++] == State::S1;
this_port.do_subtract = config_bits[config_cursor++] == State::S1;
@ -126,11 +126,11 @@ struct Macc
port_a_cursor += size_b;
if (size_a || size_b)
ports.push_back(this_port);
terms.push_back(this_port);
}
for (auto bit : cell->getPort(ID::B))
ports.push_back(port_t{{bit}, {}, false, false});
terms.push_back(term_t{{bit}, {}, false, false});
log_assert(config_cursor == config_width);
log_assert(port_a_cursor == GetSize(port_a));
@ -148,7 +148,7 @@ struct Macc
RTLIL::SigSpec port_b = cell->getPort(ID::B);
RTLIL::SigSpec port_c = cell->getPort(ID::C);
ports.clear();
terms.clear();
int nproducts = cell->getParam(ID::NPRODUCTS).as_int();
const Const &product_neg = cell->getParam(ID::PRODUCT_NEGATED);
@ -158,7 +158,7 @@ struct Macc
const Const &b_signed = cell->getParam(ID::B_SIGNED);
int ai = 0, bi = 0;
for (int i = 0; i < nproducts; i++) {
port_t term;
term_t term;
log_assert(a_signed[i] == b_signed[i]);
term.is_signed = (a_signed[i] == State::S1);
@ -171,7 +171,7 @@ struct Macc
bi += b_width;
term.do_subtract = (product_neg[i] == State::S1);
ports.push_back(term);
terms.push_back(term);
}
log_assert(port_a.size() == ai);
log_assert(port_b.size() == bi);
@ -182,7 +182,7 @@ struct Macc
const Const &c_signed = cell->getParam(ID::C_SIGNED);
int ci = 0;
for (int i = 0; i < naddends; i++) {
port_t term;
term_t term;
term.is_signed = (c_signed[i] == State::S1);
int c_width = c_widths.extract(16 * i, 16).as_int(false);
@ -191,7 +191,7 @@ struct Macc
ci += c_width;
term.do_subtract = (addend_neg[i] == State::S1);
ports.push_back(term);
terms.push_back(term);
}
log_assert(port_c.size() == ci);
}
@ -205,23 +205,23 @@ struct Macc
Const c_signed, c_widths, addend_negated;
SigSpec a, b, c;
for (int i = 0; i < (int) ports.size(); i++) {
SigSpec term_a = ports[i].in_a, term_b = ports[i].in_b;
for (int i = 0; i < (int) terms.size(); i++) {
SigSpec term_a = terms[i].in_a, term_b = terms[i].in_b;
if (term_b.empty()) {
// addend
c_widths.append(Const(term_a.size(), 16));
c_signed.append(ports[i].is_signed ? RTLIL::S1 : RTLIL::S0);
addend_negated.append(ports[i].do_subtract ? RTLIL::S1 : RTLIL::S0);
c_signed.append(terms[i].is_signed ? RTLIL::S1 : RTLIL::S0);
addend_negated.append(terms[i].do_subtract ? RTLIL::S1 : RTLIL::S0);
c.append(term_a);
naddends++;
} else {
// product
a_widths.append(Const(term_a.size(), 16));
b_widths.append(Const(term_b.size(), 16));
a_signed.append(ports[i].is_signed ? RTLIL::S1 : RTLIL::S0);
b_signed.append(ports[i].is_signed ? RTLIL::S1 : RTLIL::S0);
product_negated.append(ports[i].do_subtract ? RTLIL::S1 : RTLIL::S0);
a_signed.append(terms[i].is_signed ? RTLIL::S1 : RTLIL::S0);
b_signed.append(terms[i].is_signed ? RTLIL::S1 : RTLIL::S0);
product_negated.append(terms[i].do_subtract ? RTLIL::S1 : RTLIL::S0);
a.append(term_a);
b.append(term_b);
nproducts++;
@ -265,7 +265,7 @@ struct Macc
for (auto &bit : result.bits())
bit = State::S0;
for (auto &port : ports)
for (auto &port : terms)
{
if (!port.in_a.is_fully_const() || !port.in_b.is_fully_const())
return false;
@ -287,9 +287,9 @@ struct Macc
bool is_simple_product()
{
return ports.size() == 1 &&
!ports[0].in_b.empty() &&
!ports[0].do_subtract;
return terms.size() == 1 &&
!terms[0].in_b.empty() &&
!terms[0].do_subtract;
}
Macc(RTLIL::Cell *cell = nullptr)

View file

@ -260,18 +260,18 @@ void Pass::call(RTLIL::Design *design, std::vector<std::string> args)
pass_register[args[0]]->execute(args, design);
pass_register[args[0]]->post_execute(state);
while (design->selection_stack.size() > orig_sel_stack_pos)
design->selection_stack.pop_back();
design->pop_selection();
}
void Pass::call_on_selection(RTLIL::Design *design, const RTLIL::Selection &selection, std::string command)
{
std::string backup_selected_active_module = design->selected_active_module;
design->selected_active_module.clear();
design->selection_stack.push_back(selection);
design->push_selection(selection);
Pass::call(design, command);
design->selection_stack.pop_back();
design->pop_selection();
design->selected_active_module = backup_selected_active_module;
}
@ -279,11 +279,11 @@ void Pass::call_on_selection(RTLIL::Design *design, const RTLIL::Selection &sele
{
std::string backup_selected_active_module = design->selected_active_module;
design->selected_active_module.clear();
design->selection_stack.push_back(selection);
design->push_selection(selection);
Pass::call(design, args);
design->selection_stack.pop_back();
design->pop_selection();
design->selected_active_module = backup_selected_active_module;
}
@ -291,12 +291,12 @@ void Pass::call_on_module(RTLIL::Design *design, RTLIL::Module *module, std::str
{
std::string backup_selected_active_module = design->selected_active_module;
design->selected_active_module = module->name.str();
design->selection_stack.push_back(RTLIL::Selection(false));
design->selection_stack.back().select(module);
design->push_empty_selection();
design->select(module);
Pass::call(design, command);
design->selection_stack.pop_back();
design->pop_selection();
design->selected_active_module = backup_selected_active_module;
}
@ -304,12 +304,12 @@ void Pass::call_on_module(RTLIL::Design *design, RTLIL::Module *module, std::vec
{
std::string backup_selected_active_module = design->selected_active_module;
design->selected_active_module = module->name.str();
design->selection_stack.push_back(RTLIL::Selection(false));
design->selection_stack.back().select(module);
design->push_empty_selection();
design->select(module);
Pass::call(design, args);
design->selection_stack.pop_back();
design->pop_selection();
design->selected_active_module = backup_selected_active_module;
}
@ -651,7 +651,7 @@ void Backend::backend_call(RTLIL::Design *design, std::ostream *f, std::string f
}
while (design->selection_stack.size() > orig_sel_stack_pos)
design->selection_stack.pop_back();
design->pop_selection();
}
struct SimHelper {

View file

@ -766,8 +766,23 @@ vector<int> RTLIL::AttrObject::get_intvec_attribute(const RTLIL::IdString &id) c
return data;
}
bool RTLIL::Selection::boxed_module(const RTLIL::IdString &mod_name) const
{
if (current_design != nullptr) {
auto module = current_design->module(mod_name);
return module && module->get_blackbox_attribute();
} else {
log_warning("Unable to check if module is boxed for null design.\n");
return false;
}
}
bool RTLIL::Selection::selected_module(const RTLIL::IdString &mod_name) const
{
if (complete_selection)
return true;
if (!selects_boxes && boxed_module(mod_name))
return false;
if (full_selection)
return true;
if (selected_modules.count(mod_name) > 0)
@ -779,6 +794,10 @@ bool RTLIL::Selection::selected_module(const RTLIL::IdString &mod_name) const
bool RTLIL::Selection::selected_whole_module(const RTLIL::IdString &mod_name) const
{
if (complete_selection)
return true;
if (!selects_boxes && boxed_module(mod_name))
return false;
if (full_selection)
return true;
if (selected_modules.count(mod_name) > 0)
@ -788,6 +807,10 @@ bool RTLIL::Selection::selected_whole_module(const RTLIL::IdString &mod_name) co
bool RTLIL::Selection::selected_member(const RTLIL::IdString &mod_name, const RTLIL::IdString &memb_name) const
{
if (complete_selection)
return true;
if (!selects_boxes && boxed_module(mod_name))
return false;
if (full_selection)
return true;
if (selected_modules.count(mod_name) > 0)
@ -800,7 +823,17 @@ bool RTLIL::Selection::selected_member(const RTLIL::IdString &mod_name, const RT
void RTLIL::Selection::optimize(RTLIL::Design *design)
{
if (full_selection) {
if (design != current_design) {
current_design = design;
}
if (selects_boxes && full_selection)
complete_selection = true;
if (complete_selection) {
full_selection = false;
selects_boxes = true;
}
if (selects_all()) {
selected_modules.clear();
selected_members.clear();
return;
@ -810,7 +843,7 @@ void RTLIL::Selection::optimize(RTLIL::Design *design)
del_list.clear();
for (auto mod_name : selected_modules) {
if (design->modules_.count(mod_name) == 0)
if (current_design->modules_.count(mod_name) == 0 || (!selects_boxes && boxed_module(mod_name)))
del_list.push_back(mod_name);
selected_members.erase(mod_name);
}
@ -819,7 +852,7 @@ void RTLIL::Selection::optimize(RTLIL::Design *design)
del_list.clear();
for (auto &it : selected_members)
if (design->modules_.count(it.first) == 0)
if (current_design->modules_.count(it.first) == 0 || (!selects_boxes && boxed_module(it.first)))
del_list.push_back(it.first);
for (auto mod_name : del_list)
selected_members.erase(mod_name);
@ -827,7 +860,7 @@ void RTLIL::Selection::optimize(RTLIL::Design *design)
for (auto &it : selected_members) {
del_list.clear();
for (auto memb_name : it.second)
if (design->modules_[it.first]->count_id(memb_name) == 0)
if (current_design->modules_[it.first]->count_id(memb_name) == 0)
del_list.push_back(memb_name);
for (auto memb_name : del_list)
it.second.erase(memb_name);
@ -838,8 +871,8 @@ void RTLIL::Selection::optimize(RTLIL::Design *design)
for (auto &it : selected_members)
if (it.second.size() == 0)
del_list.push_back(it.first);
else if (it.second.size() == design->modules_[it.first]->wires_.size() + design->modules_[it.first]->memories.size() +
design->modules_[it.first]->cells_.size() + design->modules_[it.first]->processes.size())
else if (it.second.size() == current_design->modules_[it.first]->wires_.size() + current_design->modules_[it.first]->memories.size() +
current_design->modules_[it.first]->cells_.size() + current_design->modules_[it.first]->processes.size())
add_list.push_back(it.first);
for (auto mod_name : del_list)
selected_members.erase(mod_name);
@ -848,13 +881,24 @@ void RTLIL::Selection::optimize(RTLIL::Design *design)
selected_modules.insert(mod_name);
}
if (selected_modules.size() == design->modules_.size()) {
full_selection = true;
if (selected_modules.size() == current_design->modules_.size()) {
selected_modules.clear();
selected_members.clear();
if (selects_boxes)
complete_selection = true;
else
full_selection = true;
}
}
void RTLIL::Selection::clear()
{
full_selection = false;
complete_selection = false;
selected_modules.clear();
selected_members.clear();
}
RTLIL::Design::Design()
: verilog_defines (new define_map_t)
{
@ -863,7 +907,7 @@ RTLIL::Design::Design()
hashidx_ = hashidx_count;
refcount_modules_ = 0;
selection_stack.push_back(RTLIL::Selection());
push_full_selection();
#ifdef WITH_PYTHON
RTLIL::Design::get_all_designs()->insert(std::pair<unsigned int, RTLIL::Design*>(hashidx_, this));
@ -908,7 +952,7 @@ const RTLIL::Module *RTLIL::Design::module(const RTLIL::IdString& name) const
return modules_.count(name) ? modules_.at(name) : NULL;
}
RTLIL::Module *RTLIL::Design::top_module()
RTLIL::Module *RTLIL::Design::top_module() const
{
RTLIL::Module *module = nullptr;
int module_count = 0;
@ -1066,6 +1110,7 @@ void RTLIL::Design::sort()
void RTLIL::Design::check()
{
#ifndef NDEBUG
log_assert(!selection_stack.empty());
for (auto &it : modules_) {
log_assert(this == it.second->design);
log_assert(it.first == it.second->name);
@ -1089,27 +1134,21 @@ bool RTLIL::Design::selected_module(const RTLIL::IdString& mod_name) const
{
if (!selected_active_module.empty() && mod_name != selected_active_module)
return false;
if (selection_stack.size() == 0)
return true;
return selection_stack.back().selected_module(mod_name);
return selection().selected_module(mod_name);
}
bool RTLIL::Design::selected_whole_module(const RTLIL::IdString& mod_name) const
{
if (!selected_active_module.empty() && mod_name != selected_active_module)
return false;
if (selection_stack.size() == 0)
return true;
return selection_stack.back().selected_whole_module(mod_name);
return selection().selected_whole_module(mod_name);
}
bool RTLIL::Design::selected_member(const RTLIL::IdString& mod_name, const RTLIL::IdString& memb_name) const
{
if (!selected_active_module.empty() && mod_name != selected_active_module)
return false;
if (selection_stack.size() == 0)
return true;
return selection_stack.back().selected_member(mod_name, memb_name);
return selection().selected_member(mod_name, memb_name);
}
bool RTLIL::Design::selected_module(RTLIL::Module *mod) const
@ -1122,37 +1161,86 @@ bool RTLIL::Design::selected_whole_module(RTLIL::Module *mod) const
return selected_whole_module(mod->name);
}
std::vector<RTLIL::Module*> RTLIL::Design::selected_modules() const
void RTLIL::Design::push_selection(RTLIL::Selection sel)
{
std::vector<RTLIL::Module*> result;
result.reserve(modules_.size());
for (auto &it : modules_)
if (selected_module(it.first) && !it.second->get_blackbox_attribute())
result.push_back(it.second);
return result;
sel.current_design = this;
selection_stack.push_back(sel);
}
std::vector<RTLIL::Module*> RTLIL::Design::selected_whole_modules() const
void RTLIL::Design::push_empty_selection()
{
std::vector<RTLIL::Module*> result;
result.reserve(modules_.size());
for (auto &it : modules_)
if (selected_whole_module(it.first) && !it.second->get_blackbox_attribute())
result.push_back(it.second);
return result;
push_selection(RTLIL::Selection::EmptySelection(this));
}
std::vector<RTLIL::Module*> RTLIL::Design::selected_whole_modules_warn(bool include_wb) const
void RTLIL::Design::push_full_selection()
{
push_selection(RTLIL::Selection::FullSelection(this));
}
void RTLIL::Design::push_complete_selection()
{
push_selection(RTLIL::Selection::CompleteSelection(this));
}
void RTLIL::Design::pop_selection()
{
selection_stack.pop_back();
// Default to a full_selection if we ran out of stack
if (selection_stack.empty())
push_full_selection();
}
std::vector<RTLIL::Module*> RTLIL::Design::selected_modules(RTLIL::SelectPartials partials, RTLIL::SelectBoxes boxes) const
{
bool include_partials = partials == RTLIL::SELECT_ALL;
bool exclude_boxes = (boxes & RTLIL::SB_UNBOXED_ONLY) != 0;
bool ignore_wb = (boxes & RTLIL::SB_INCL_WB) != 0;
std::vector<RTLIL::Module*> result;
result.reserve(modules_.size());
for (auto &it : modules_)
if (it.second->get_blackbox_attribute(include_wb))
continue;
else if (selected_whole_module(it.first))
result.push_back(it.second);
else if (selected_module(it.first))
log_warning("Ignoring partially selected module %s.\n", log_id(it.first));
if (selected_whole_module(it.first) || (include_partials && selected_module(it.first))) {
if (!(exclude_boxes && it.second->get_blackbox_attribute(ignore_wb)))
result.push_back(it.second);
else
switch (boxes)
{
case RTLIL::SB_UNBOXED_WARN:
log_warning("Ignoring boxed module %s.\n", log_id(it.first));
break;
case RTLIL::SB_EXCL_BB_WARN:
log_warning("Ignoring blackbox module %s.\n", log_id(it.first));
break;
case RTLIL::SB_UNBOXED_ERR:
log_error("Unsupported boxed module %s.\n", log_id(it.first));
break;
case RTLIL::SB_EXCL_BB_ERR:
log_error("Unsupported blackbox module %s.\n", log_id(it.first));
break;
case RTLIL::SB_UNBOXED_CMDERR:
log_cmd_error("Unsupported boxed module %s.\n", log_id(it.first));
break;
case RTLIL::SB_EXCL_BB_CMDERR:
log_cmd_error("Unsupported blackbox module %s.\n", log_id(it.first));
break;
default:
break;
}
} else if (!include_partials && selected_module(it.first)) {
switch(partials)
{
case RTLIL::SELECT_WHOLE_WARN:
log_warning("Ignoring partially selected module %s.\n", log_id(it.first));
break;
case RTLIL::SELECT_WHOLE_ERR:
log_error("Unsupported partially selected module %s.\n", log_id(it.first));
break;
case RTLIL::SELECT_WHOLE_CMDERR:
log_cmd_error("Unsupported partially selected module %s.\n", log_id(it.first));
break;
default:
break;
}
}
return result;
}
@ -2052,7 +2140,7 @@ namespace {
param(ID::TYPE);
check_expected();
std::string scope_type = cell->getParam(ID::TYPE).decode_string();
if (scope_type != "module" && scope_type != "struct")
if (scope_type != "module" && scope_type != "struct" && scope_type != "blackbox")
error(__LINE__);
return;
}
@ -2284,6 +2372,13 @@ void RTLIL::Module::check()
log_assert(!packed_memids.count(memid));
packed_memids.insert(memid);
}
auto cell_mod = design->module(it.first);
if (cell_mod != nullptr) {
// assertion check below to make sure that there are no
// cases where a cell has a blackbox attribute since
// that is deprecated
log_assert(!it.second->get_blackbox_attribute());
}
}
for (auto &it : processes) {
@ -2411,6 +2506,16 @@ bool RTLIL::Module::has_processes_warn() const
return !processes.empty();
}
bool RTLIL::Module::is_selected() const
{
return design->selected_module(this->name);
}
bool RTLIL::Module::is_selected_whole() const
{
return design->selected_whole_module(this->name);
}
std::vector<RTLIL::Wire*> RTLIL::Module::selected_wires() const
{
std::vector<RTLIL::Wire*> result;
@ -2431,6 +2536,40 @@ std::vector<RTLIL::Cell*> RTLIL::Module::selected_cells() const
return result;
}
std::vector<RTLIL::Memory*> RTLIL::Module::selected_memories() const
{
std::vector<RTLIL::Memory*> result;
result.reserve(memories.size());
for (auto &it : memories)
if (design->selected(this, it.second))
result.push_back(it.second);
return result;
}
std::vector<RTLIL::Process*> RTLIL::Module::selected_processes() const
{
std::vector<RTLIL::Process*> result;
result.reserve(processes.size());
for (auto &it : processes)
if (design->selected(this, it.second))
result.push_back(it.second);
return result;
}
std::vector<RTLIL::NamedObject*> RTLIL::Module::selected_members() const
{
std::vector<RTLIL::NamedObject*> result;
auto cells = selected_cells();
auto memories = selected_memories();
auto wires = selected_wires();
auto processes = selected_processes();
result.insert(result.end(), cells.begin(), cells.end());
result.insert(result.end(), memories.begin(), memories.end());
result.insert(result.end(), wires.begin(), wires.end());
result.insert(result.end(), processes.begin(), processes.end());
return result;
}
void RTLIL::Module::add(RTLIL::Wire *wire)
{
log_assert(!wire->name.empty());

View file

@ -56,8 +56,33 @@ namespace RTLIL
CONST_FLAG_REAL = 4 // only used for parameters
};
enum SelectPartials : unsigned char {
SELECT_ALL = 0, // include partial modules
SELECT_WHOLE_ONLY = 1, // ignore partial modules
SELECT_WHOLE_WARN = 2, // call log_warning on partial module
SELECT_WHOLE_ERR = 3, // call log_error on partial module
SELECT_WHOLE_CMDERR = 4 // call log_cmd_error on partial module
};
enum SelectBoxes : unsigned char {
SB_ALL = 0, // include boxed modules
SB_WARN = 1, // helper for log_warning (not for direct use)
SB_ERR = 2, // helper for log_error (not for direct use)
SB_CMDERR = 3, // helper for log_cmd_error (not for direct use)
SB_UNBOXED_ONLY = 4, // ignore boxed modules
SB_UNBOXED_WARN = 5, // call log_warning on boxed module
SB_UNBOXED_ERR = 6, // call log_error on boxed module
SB_UNBOXED_CMDERR = 7, // call log_cmd_error on boxed module
SB_INCL_WB = 8, // helper for white boxes (not for direct use)
SB_EXCL_BB_ONLY = 12, // ignore black boxes, but not white boxes
SB_EXCL_BB_WARN = 13, // call log_warning on black boxed module
SB_EXCL_BB_ERR = 14, // call log_error on black boxed module
SB_EXCL_BB_CMDERR = 15 // call log_cmd_error on black boxed module
};
struct Const;
struct AttrObject;
struct NamedObject;
struct Selection;
struct Monitor;
struct Design;
@ -869,6 +894,11 @@ struct RTLIL::AttrObject
vector<int> get_intvec_attribute(const RTLIL::IdString &id) const;
};
struct RTLIL::NamedObject : public RTLIL::AttrObject
{
RTLIL::IdString name;
};
struct RTLIL::SigChunk
{
RTLIL::Wire *wire;
@ -1134,32 +1164,94 @@ public:
struct RTLIL::Selection
{
// selection includes boxed modules
bool selects_boxes;
// selection covers full design, including boxed modules
bool complete_selection;
// selection covers full design, not including boxed modules
bool full_selection;
pool<RTLIL::IdString> selected_modules;
dict<RTLIL::IdString, pool<RTLIL::IdString>> selected_members;
RTLIL::Design *current_design;
Selection(bool full = true) : full_selection(full) { }
// create a new selection
Selection(
// should the selection cover the full design
bool full = true,
// should the selection include boxed modules
bool boxes = false,
// the design to select from
RTLIL::Design *design = nullptr
) :
selects_boxes(boxes), complete_selection(full && boxes), full_selection(full && !boxes), current_design(design) { }
// 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(const RTLIL::IdString &mod_name) const;
// checks if the given module is included in this selection
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(const RTLIL::IdString &mod_name) const;
// checks if the given member from the given module is included in this
// selection
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
// their members (if selection does not include boxes), and any
// partially selected modules with no selected members;
// - marking partially selected modules as wholly selected if all
// members of that module are selected; and
// - marking selection as a complete_selection if all modules in the
// given design are selected, or a full_selection if it does not
// include boxes.
void optimize(RTLIL::Design *design);
// checks if selection covers full design (may or may not include
// boxed-modules)
bool selects_all() const {
return full_selection || complete_selection;
}
// add whole module to this selection
template<typename T1> void select(T1 *module) {
if (!full_selection && selected_modules.count(module->name) == 0) {
if (!selects_all() && selected_modules.count(module->name) == 0) {
selected_modules.insert(module->name);
selected_members.erase(module->name);
if (module->get_blackbox_attribute())
selects_boxes = true;
}
}
// add member of module to this selection
template<typename T1, typename T2> void select(T1 *module, T2 *member) {
if (!full_selection && selected_modules.count(module->name) == 0)
if (!selects_all() && selected_modules.count(module->name) == 0) {
selected_members[module->name].insert(member->name);
if (module->get_blackbox_attribute())
selects_boxes = true;
}
}
// checks if selection is empty
bool empty() const {
return !full_selection && selected_modules.empty() && selected_members.empty();
return !selects_all() && selected_modules.empty() && selected_members.empty();
}
// clear this selection, leaving it empty
void clear();
// create a new selection which is empty
static Selection EmptySelection(RTLIL::Design *design = nullptr) { return Selection(false, false, design); };
// create a new selection with all non-boxed modules
static Selection FullSelection(RTLIL::Design *design = nullptr) { return Selection(true, false, design); };
// create a new selection with all modules, including boxes
static Selection CompleteSelection(RTLIL::Design *design = nullptr) { return Selection(true, true, design); };
};
struct RTLIL::Monitor
@ -1213,7 +1305,7 @@ struct RTLIL::Design
RTLIL::ObjRange<RTLIL::Module*> modules();
RTLIL::Module *module(const RTLIL::IdString &name);
const RTLIL::Module *module(const RTLIL::IdString &name) const;
RTLIL::Module *top_module();
RTLIL::Module *top_module() const;
bool has(const RTLIL::IdString &id) const {
return modules_.count(id) != 0;
@ -1240,57 +1332,118 @@ struct RTLIL::Design
void check();
void optimize();
// checks if the given module is included in the current selection
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(const RTLIL::IdString &mod_name) const;
// checks if the given member from the given module is included in the
// current selection
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;
// checks if the given module is wholly included in the current
// selection, i.e. not partially selected
bool selected_whole_module(RTLIL::Module *mod) const;
// push the given selection to the selection stack
void push_selection(RTLIL::Selection sel);
// push a new selection to the selection stack, with nothing selected
void push_empty_selection();
// push a new selection to the selection stack, with all non-boxed
// modules selected
void push_full_selection();
// push a new selection to the selection stack, with all modules
// selected including boxes
void push_complete_selection();
// pop the current selection from the stack, returning to a full
// selection (no boxes) if the stack is empty
void pop_selection();
// get the current selection
RTLIL::Selection &selection() {
return selection_stack.back();
}
// get the current selection
const RTLIL::Selection &selection() const {
return selection_stack.back();
}
// is the current selection a full selection (no boxes)
bool full_selection() const {
return selection_stack.back().full_selection;
return selection().full_selection;
}
// is the given module in the current selection
template<typename T1> bool selected(T1 *module) const {
return selected_module(module->name);
}
// is the given member of the given module in the current selection
template<typename T1, typename T2> bool selected(T1 *module, T2 *member) const {
return selected_member(module->name, member->name);
}
// add whole module to the current selection
template<typename T1> void select(T1 *module) {
if (selection_stack.size() > 0) {
RTLIL::Selection &sel = selection_stack.back();
sel.select(module);
}
RTLIL::Selection &sel = selection();
sel.select(module);
}
// add member of module to the current selection
template<typename T1, typename T2> void select(T1 *module, T2 *member) {
if (selection_stack.size() > 0) {
RTLIL::Selection &sel = selection_stack.back();
sel.select(module, member);
}
RTLIL::Selection &sel = selection();
sel.select(module, member);
}
std::vector<RTLIL::Module*> selected_modules() const;
std::vector<RTLIL::Module*> selected_whole_modules() const;
std::vector<RTLIL::Module*> selected_whole_modules_warn(bool include_wb = false) const;
// returns all selected modules
std::vector<RTLIL::Module*> selected_modules(
// controls if partially selected modules are included
RTLIL::SelectPartials partials = SELECT_ALL,
// controls if boxed modules are included
RTLIL::SelectBoxes boxes = SB_UNBOXED_WARN
) const;
// returns all selected modules, and may include boxes
std::vector<RTLIL::Module*> all_selected_modules() const { return selected_modules(SELECT_ALL, SB_ALL); }
// returns all selected unboxed modules, silently ignoring any boxed
// modules in the selection
std::vector<RTLIL::Module*> selected_unboxed_modules() const { return selected_modules(SELECT_ALL, SB_UNBOXED_ONLY); }
// returns all selected unboxed modules, warning the user if any boxed
// modules have been ignored
std::vector<RTLIL::Module*> selected_unboxed_modules_warn() const { return selected_modules(SELECT_ALL, SB_UNBOXED_WARN); }
[[deprecated("Use select_unboxed_whole_modules() to maintain prior behaviour, or consider one of the other selected whole module helpers.")]]
std::vector<RTLIL::Module*> selected_whole_modules() const { return selected_modules(SELECT_WHOLE_ONLY, SB_UNBOXED_WARN); }
// returns all selected whole modules, silently ignoring partially
// selected modules, and may include boxes
std::vector<RTLIL::Module*> all_selected_whole_modules() const { return selected_modules(SELECT_WHOLE_ONLY, SB_ALL); }
// returns all selected whole modules, warning the user if any partially
// selected or boxed modules have been ignored; optionally includes
// selected whole modules with the 'whitebox' attribute
std::vector<RTLIL::Module*> selected_whole_modules_warn(
// should whole modules with the 'whitebox' attribute be
// included
bool include_wb = false
) const { return selected_modules(SELECT_WHOLE_WARN, include_wb ? SB_EXCL_BB_WARN : SB_UNBOXED_WARN); }
// returns all selected unboxed whole modules, silently ignoring
// partially selected or boxed modules
std::vector<RTLIL::Module*> selected_unboxed_whole_modules() const { return selected_modules(SELECT_WHOLE_ONLY, SB_UNBOXED_ONLY); }
// 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 WITH_PYTHON
static std::map<unsigned int, RTLIL::Design*> *get_all_designs(void);
#endif
};
struct RTLIL::Module : public RTLIL::AttrObject
struct RTLIL::Module : public RTLIL::NamedObject
{
Hasher::hash_t hashidx_;
[[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; }
@ -1313,7 +1466,6 @@ public:
std::vector<RTLIL::SigSig> connections_;
std::vector<RTLIL::Binding*> bindings_;
RTLIL::IdString name;
idict<RTLIL::IdString> avail_parameters;
dict<RTLIL::IdString, RTLIL::Const> parameter_default_values;
dict<RTLIL::IdString, RTLIL::Memory*> memories;
@ -1358,8 +1510,14 @@ public:
bool has_memories_warn() const;
bool has_processes_warn() const;
bool is_selected() const;
bool is_selected_whole() const;
std::vector<RTLIL::Wire*> selected_wires() const;
std::vector<RTLIL::Cell*> selected_cells() const;
std::vector<RTLIL::Memory*> selected_memories() const;
std::vector<RTLIL::Process*> selected_processes() const;
std::vector<RTLIL::NamedObject*> selected_members() const;
template<typename T> bool selected(T *member) const {
return design->selected_member(name, member->name);
@ -1645,7 +1803,7 @@ namespace RTLIL_BACKEND {
void dump_wire(std::ostream &f, std::string indent, const RTLIL::Wire *wire);
}
struct RTLIL::Wire : public RTLIL::AttrObject
struct RTLIL::Wire : public RTLIL::NamedObject
{
Hasher::hash_t hashidx_;
[[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; }
@ -1668,7 +1826,6 @@ public:
void operator=(RTLIL::Wire &other) = delete;
RTLIL::Module *module;
RTLIL::IdString name;
int width, start_offset, port_id;
bool port_input, port_output, upto, is_signed;
@ -1697,14 +1854,13 @@ inline int GetSize(RTLIL::Wire *wire) {
return wire->width;
}
struct RTLIL::Memory : public RTLIL::AttrObject
struct RTLIL::Memory : public RTLIL::NamedObject
{
Hasher::hash_t hashidx_;
[[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; }
Memory();
RTLIL::IdString name;
int width, start_offset, size;
#ifdef WITH_PYTHON
~Memory();
@ -1712,7 +1868,7 @@ struct RTLIL::Memory : public RTLIL::AttrObject
#endif
};
struct RTLIL::Cell : public RTLIL::AttrObject
struct RTLIL::Cell : public RTLIL::NamedObject
{
Hasher::hash_t hashidx_;
[[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; }
@ -1729,7 +1885,6 @@ public:
void operator=(RTLIL::Cell &other) = delete;
RTLIL::Module *module;
RTLIL::IdString name;
RTLIL::IdString type;
dict<RTLIL::IdString, RTLIL::SigSpec> connections_;
dict<RTLIL::IdString, RTLIL::Const> parameters;
@ -1822,7 +1977,7 @@ struct RTLIL::SyncRule
RTLIL::SyncRule *clone() const;
};
struct RTLIL::Process : public RTLIL::AttrObject
struct RTLIL::Process : public RTLIL::NamedObject
{
Hasher::hash_t hashidx_;
[[nodiscard]] Hasher hash_into(Hasher h) const { h.eat(hashidx_); return h; }
@ -1834,7 +1989,6 @@ protected:
~Process();
public:
RTLIL::IdString name;
RTLIL::Module *module;
RTLIL::CaseRule root_case;
std::vector<RTLIL::SyncRule*> syncs;

View file

@ -750,7 +750,7 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep)
std::vector<int> tmp(GetSize(y), ez->CONST_FALSE);
for (auto &port : macc.ports)
for (auto &port : macc.terms)
{
std::vector<int> in_a = importDefSigSpec(port.in_a, timestep);
std::vector<int> in_b = importDefSigSpec(port.in_b, timestep);

View file

@ -114,7 +114,7 @@ static int tcl_yosys_cmd(ClientData, Tcl_Interp *interp, int argc, const char *a
if (in_repl) {
auto design = yosys_get_design();
while (design->selection_stack.size() > 1)
design->selection_stack.pop_back();
design->pop_selection();
log_reset_stack();
}
Tcl_SetResult(interp, (char *)"Yosys command produced an error", TCL_STATIC);

View file

@ -312,11 +312,11 @@ const char *create_prompt(RTLIL::Design *design, int recursion_counter)
str += "yosys";
if (!design->selected_active_module.empty())
str += stringf(" [%s]", RTLIL::unescape_id(design->selected_active_module).c_str());
if (!design->selection_stack.empty() && !design->selection_stack.back().full_selection) {
if (!design->full_selection()) {
if (design->selected_active_module.empty())
str += "*";
else if (design->selection_stack.back().selected_modules.size() != 1 || design->selection_stack.back().selected_members.size() != 0 ||
design->selection_stack.back().selected_modules.count(design->selected_active_module) == 0)
else if (design->selection().selected_modules.size() != 1 || design->selection().selected_members.size() != 0 ||
design->selection().selected_modules.count(design->selected_active_module) == 0)
str += "*";
}
snprintf(buffer, 100, "%s> ", str.c_str());
@ -979,7 +979,7 @@ void shell(RTLIL::Design *design)
Pass::call(design, command);
} catch (log_cmd_error_exception) {
while (design->selection_stack.size() > 1)
design->selection_stack.pop_back();
design->pop_selection();
log_reset_stack();
}
design->check();

View file

@ -977,6 +977,7 @@ sources = [
WClass("IdString", link_types.ref_copy, None, "str()", ""),
WClass("Const", link_types.ref_copy, None, "as_string()", ""),
WClass("AttrObject", link_types.ref_copy, None, None, None),
WClass("NamedObject", link_types.ref_copy, None, None, None),
WClass("Selection", link_types.ref_copy, None, None, None),
WClass("Monitor", link_types.derive, None, None, None),
WClass("CaseRule",link_types.ref_copy, None, None, None, True),

View file

@ -54,3 +54,4 @@ OBJS += passes/cmds/portarcs.o
OBJS += passes/cmds/wrapcell.o
OBJS += passes/cmds/setenv.o
OBJS += passes/cmds/abstract.o
OBJS += passes/cmds/test_select.o

View file

@ -102,7 +102,7 @@ static void add_wire(RTLIL::Design *design, RTLIL::Module *module, std::string n
RTLIL::Module *mod = design->module(cell->type);
if (mod == nullptr)
continue;
if (!design->selected_whole_module(mod->name))
if (!mod->is_selected_whole())
continue;
if (mod->get_blackbox_attribute())
continue;

View file

@ -213,22 +213,15 @@ struct DesignPass : public Pass {
if (copy_from_design != design && argidx == args.size() && !import_mode)
cmd_error(args, argidx, "Missing selection.");
RTLIL::Selection sel;
if (argidx != args.size()) {
handle_extra_select_args(this, args, argidx, args.size(), copy_from_design);
sel = copy_from_design->selection_stack.back();
copy_from_design->selection_stack.pop_back();
argidx = args.size();
} else {
copy_from_design->push_complete_selection();
}
for (auto mod : copy_from_design->modules()) {
if (sel.selected_whole_module(mod->name)) {
copy_src_modules.push_back(mod);
continue;
}
if (sel.selected_module(mod->name))
log_cmd_error("Module %s is only partly selected.\n", log_id(mod->name));
}
for (auto mod : copy_from_design->selected_modules(RTLIL::SELECT_WHOLE_CMDERR, RTLIL::SB_ALL))
copy_src_modules.push_back(mod);
if (import_mode) {
std::vector<RTLIL::Module*> candidates;
@ -246,6 +239,8 @@ struct DesignPass : public Pass {
if (GetSize(candidates) == 1)
copy_src_modules = std::move(candidates);
}
copy_from_design->pop_selection();
}
extra_args(args, argidx, design, false);
@ -368,7 +363,7 @@ struct DesignPass : public Pass {
design->selection_vars.clear();
design->selected_active_module.clear();
design->selection_stack.push_back(RTLIL::Selection());
design->push_full_selection();
}
if (reset_mode || reset_vlog_mode || !load_name.empty() || push_mode || pop_mode)

View file

@ -340,7 +340,7 @@ struct SccPass : public Pass {
int origSelectPos = design->selection_stack.size() - 1;
extra_args(args, argidx, design);
RTLIL::Selection newSelection(false);
auto newSelection = RTLIL::Selection::EmptySelection(design);
int scc_counter = 0;
for (auto mod : design->selected_modules())

View file

@ -141,24 +141,42 @@ static bool match_attr(const dict<RTLIL::IdString, RTLIL::Const> &attributes, co
return match_attr(attributes, match_expr, std::string(), 0);
}
static void select_all(RTLIL::Design *design, RTLIL::Selection &lhs)
{
if (!lhs.selects_all())
return;
lhs.current_design = design;
lhs.selected_modules.clear();
for (auto mod : design->modules()) {
if (!lhs.selects_boxes && mod->get_blackbox_attribute())
continue;
lhs.selected_modules.insert(mod->name);
}
lhs.full_selection = false;
lhs.complete_selection = false;
}
static void select_op_neg(RTLIL::Design *design, RTLIL::Selection &lhs)
{
if (lhs.full_selection) {
lhs.full_selection = false;
lhs.selected_modules.clear();
lhs.selected_members.clear();
if (lhs.selects_all()) {
lhs.clear();
return;
}
if (lhs.selected_modules.size() == 0 && lhs.selected_members.size() == 0) {
lhs.full_selection = true;
if (lhs.selects_boxes)
lhs.complete_selection = true;
else
lhs.full_selection = true;
return;
}
RTLIL::Selection new_sel(false);
auto new_sel = RTLIL::Selection::EmptySelection();
for (auto mod : design->modules())
{
if (!lhs.selects_boxes && mod->get_blackbox_attribute())
continue;
if (lhs.selected_whole_module(mod->name))
continue;
if (!lhs.selected_module(mod->name)) {
@ -212,7 +230,7 @@ static void select_op_random(RTLIL::Design *design, RTLIL::Selection &lhs, int c
}
}
lhs = RTLIL::Selection(false);
lhs = RTLIL::Selection(false, lhs.selects_boxes, design);
while (!objects.empty() && count-- > 0)
{
@ -243,7 +261,7 @@ static void select_op_submod(RTLIL::Design *design, RTLIL::Selection &lhs)
static void select_op_cells_to_modules(RTLIL::Design *design, RTLIL::Selection &lhs)
{
RTLIL::Selection new_sel(false);
RTLIL::Selection new_sel(false, lhs.selects_boxes, design);
for (auto mod : design->modules())
if (lhs.selected_module(mod->name))
for (auto cell : mod->cells())
@ -254,7 +272,7 @@ static void select_op_cells_to_modules(RTLIL::Design *design, RTLIL::Selection &
static void select_op_module_to_cells(RTLIL::Design *design, RTLIL::Selection &lhs)
{
RTLIL::Selection new_sel(false);
RTLIL::Selection new_sel(false, lhs.selects_boxes, design);
for (auto mod : design->modules())
for (auto cell : mod->cells())
if ((design->module(cell->type) != nullptr) && lhs.selected_whole_module(cell->type))
@ -274,6 +292,8 @@ static void select_op_alias(RTLIL::Design *design, RTLIL::Selection &lhs)
{
for (auto mod : design->modules())
{
if (!lhs.selects_boxes && mod->get_blackbox_attribute())
continue;
if (lhs.selected_whole_module(mod->name))
continue;
if (!lhs.selected_module(mod->name))
@ -292,18 +312,38 @@ static void select_op_alias(RTLIL::Design *design, RTLIL::Selection &lhs)
}
}
static void select_op_union(RTLIL::Design*, RTLIL::Selection &lhs, const RTLIL::Selection &rhs)
static void select_op_union(RTLIL::Design* design, RTLIL::Selection &lhs, const RTLIL::Selection &rhs)
{
if (rhs.full_selection) {
lhs.full_selection = true;
lhs.selected_modules.clear();
lhs.selected_members.clear();
if (lhs.complete_selection)
return;
else if (rhs.complete_selection) {
lhs.complete_selection = true;
lhs.optimize(design);
return;
}
if (lhs.full_selection)
if (rhs.selects_boxes) {
if (lhs.full_selection) {
select_all(design, lhs);
}
lhs.selects_boxes = true;
}
else if (lhs.full_selection)
return;
if (rhs.full_selection) {
if (lhs.selects_boxes) {
auto new_rhs = RTLIL::Selection(rhs);
select_all(design, new_rhs);
for (auto mod : new_rhs.selected_modules)
lhs.selected_modules.insert(mod);
} else {
lhs.clear();
lhs.full_selection = true;
}
return;
}
for (auto &it : rhs.selected_members)
for (auto &it2 : it.second)
lhs.selected_members[it.first].insert(it2);
@ -316,21 +356,31 @@ static void select_op_union(RTLIL::Design*, RTLIL::Selection &lhs, const RTLIL::
static void select_op_diff(RTLIL::Design *design, RTLIL::Selection &lhs, const RTLIL::Selection &rhs)
{
if (rhs.full_selection) {
lhs.full_selection = false;
lhs.selected_modules.clear();
lhs.selected_members.clear();
if (rhs.complete_selection) {
lhs.clear();
return;
}
if (lhs.full_selection) {
if (!rhs.full_selection && rhs.selected_modules.size() == 0 && rhs.selected_members.size() == 0)
return;
lhs.full_selection = false;
for (auto mod : design->modules())
lhs.selected_modules.insert(mod->name);
if (rhs.full_selection) {
if (lhs.selects_boxes) {
auto new_rhs = RTLIL::Selection(rhs);
select_all(design, new_rhs);
select_all(design, lhs);
for (auto mod : new_rhs.selected_modules) {
lhs.selected_modules.erase(mod);
lhs.selected_members.erase(mod);
}
} else {
lhs.clear();
}
return;
}
if (rhs.empty() || lhs.empty())
return;
select_all(design, lhs);
for (auto &it : rhs.selected_modules) {
lhs.selected_modules.erase(it);
lhs.selected_members.erase(it);
@ -366,38 +416,46 @@ static void select_op_diff(RTLIL::Design *design, RTLIL::Selection &lhs, const R
static void select_op_intersect(RTLIL::Design *design, RTLIL::Selection &lhs, const RTLIL::Selection &rhs)
{
if (rhs.full_selection)
if (rhs.complete_selection)
return;
if (lhs.full_selection) {
lhs.full_selection = false;
for (auto mod : design->modules())
lhs.selected_modules.insert(mod->name);
if (rhs.full_selection && !lhs.selects_boxes)
return;
if (lhs.empty())
return;
if (rhs.empty()) {
lhs.clear();
return;
}
select_all(design, lhs);
std::vector<RTLIL::IdString> del_list;
for (auto &it : lhs.selected_modules)
if (rhs.selected_modules.count(it) == 0) {
if (rhs.selected_members.count(it) > 0)
for (auto &it2 : rhs.selected_members.at(it))
lhs.selected_members[it].insert(it2);
del_list.push_back(it);
}
for (auto mod_name : lhs.selected_modules) {
if (rhs.selected_whole_module(mod_name))
continue;
if (rhs.selected_module(mod_name))
for (auto memb_name : rhs.selected_members.at(mod_name))
lhs.selected_members[mod_name].insert(memb_name);
del_list.push_back(mod_name);
}
for (auto &it : del_list)
lhs.selected_modules.erase(it);
del_list.clear();
for (auto &it : lhs.selected_members) {
if (rhs.selected_modules.count(it.first) > 0)
if (rhs.selected_whole_module(it.first))
continue;
if (rhs.selected_members.count(it.first) == 0) {
if (!rhs.selected_module(it.first)) {
del_list.push_back(it.first);
continue;
}
std::vector<RTLIL::IdString> del_list2;
for (auto &it2 : it.second)
if (rhs.selected_members.at(it.first).count(it2) == 0)
if (!rhs.selected_member(it.first, it2))
del_list2.push_back(it2);
for (auto &it2 : del_list2)
it.second.erase(it2);
@ -610,9 +668,7 @@ static void select_filter_active_mod(RTLIL::Design *design, RTLIL::Selection &se
return;
if (sel.full_selection) {
sel.full_selection = false;
sel.selected_modules.clear();
sel.selected_members.clear();
sel.clear();
sel.selected_modules.insert(design->selected_active_module);
return;
}
@ -645,8 +701,7 @@ static void select_stmt(RTLIL::Design *design, std::string arg, bool disable_emp
if (arg[0] == '%') {
if (arg == "%") {
if (design->selection_stack.size() > 0)
work_stack.push_back(design->selection_stack.back());
work_stack.push_back(design->selection());
} else
if (arg == "%%") {
while (work_stack.size() > 1) {
@ -796,15 +851,16 @@ static void select_stmt(RTLIL::Design *design, std::string arg, bool disable_emp
}
}
work_stack.push_back(RTLIL::Selection());
bool full_selection = (arg == "*" && arg_mod == "*");
work_stack.push_back(RTLIL::Selection(full_selection, select_blackboxes, design));
RTLIL::Selection &sel = work_stack.back();
if (arg == "*" && arg_mod == "*" && select_blackboxes) {
if (sel.full_selection) {
if (sel.selects_boxes) sel.optimize(design);
select_filter_active_mod(design, work_stack.back());
return;
}
sel.full_selection = false;
for (auto mod : design->modules())
{
if (!select_blackboxes && mod->get_blackbox_attribute())
@ -945,38 +1001,33 @@ static void select_stmt(RTLIL::Design *design, std::string arg, bool disable_emp
for (auto &it : arg_mod_found) {
if (it.second == false && !disable_empty_warning) {
log_warning("Selection \"%s\" did not match any module.\n", it.first.c_str());
std::string selection_str = select_blackboxes ? "=" : "";
selection_str += it.first;
log_warning("Selection \"%s\" did not match any module.\n", selection_str.c_str());
}
}
for (auto &it : arg_memb_found) {
if (it.second == false && !disable_empty_warning) {
log_warning("Selection \"%s\" did not match any object.\n", it.first.c_str());
std::string selection_str = select_blackboxes ? "=" : "";
selection_str += it.first;
log_warning("Selection \"%s\" did not match any object.\n", selection_str.c_str());
}
}
}
static std::string describe_selection_for_assert(RTLIL::Design *design, RTLIL::Selection *sel, bool whole_modules = false)
{
bool push_selection = &design->selection() != sel;
if (push_selection) design->push_selection(*sel);
std::string desc = "Selection contains:\n";
for (auto mod : design->modules())
for (auto mod : design->all_selected_modules())
{
if (sel->selected_module(mod->name)) {
if (whole_modules && sel->selected_whole_module(mod->name))
desc += stringf("%s\n", id2cstr(mod->name));
for (auto wire : mod->wires())
if (sel->selected_member(mod->name, wire->name))
desc += stringf("%s/%s\n", id2cstr(mod->name), id2cstr(wire->name));
for (auto &it : mod->memories)
if (sel->selected_member(mod->name, it.first))
desc += stringf("%s/%s\n", id2cstr(mod->name), id2cstr(it.first));
for (auto cell : mod->cells())
if (sel->selected_member(mod->name, cell->name))
desc += stringf("%s/%s\n", id2cstr(mod->name), id2cstr(cell->name));
for (auto &it : mod->processes)
if (sel->selected_member(mod->name, it.first))
desc += stringf("%s/%s\n", id2cstr(mod->name), id2cstr(it.first));
}
if (whole_modules && sel->selected_whole_module(mod->name))
desc += stringf("%s\n", id2cstr(mod->name));
for (auto it : mod->selected_members())
desc += stringf("%s/%s\n", id2cstr(mod->name), id2cstr(it->name));
}
if (push_selection) design->pop_selection();
return desc;
}
@ -1001,9 +1052,9 @@ void handle_extra_select_args(Pass *pass, const vector<string> &args, size_t arg
work_stack.pop_back();
}
if (work_stack.empty())
design->selection_stack.push_back(RTLIL::Selection(false));
design->push_empty_selection();
else
design->selection_stack.push_back(work_stack.back());
design->push_selection(work_stack.back());
}
// extern decl. in register.h
@ -1017,7 +1068,7 @@ RTLIL::Selection eval_select_args(const vector<string> &args, RTLIL::Design *des
work_stack.pop_back();
}
if (work_stack.empty())
return RTLIL::Selection(false);
return RTLIL::Selection::EmptySelection(design);
return work_stack.back();
}
@ -1390,7 +1441,7 @@ struct SelectPass : public Pass {
if (f.fail())
log_error("Can't open '%s' for reading: %s\n", read_file.c_str(), strerror(errno));
RTLIL::Selection sel(false);
auto sel = RTLIL::Selection::EmptySelection(design);
string line;
while (std::getline(f, line)) {
@ -1431,7 +1482,7 @@ struct SelectPass : public Pass {
log_cmd_error("Option -unset can not be combined with -list, -write, -count, -set, %s.\n", common_flagset);
if (work_stack.size() == 0 && got_module) {
RTLIL::Selection sel;
auto sel = RTLIL::Selection::FullSelection(design);
select_filter_active_mod(design, sel);
work_stack.push_back(sel);
}
@ -1441,16 +1492,16 @@ struct SelectPass : public Pass {
work_stack.pop_back();
}
log_assert(design->selection_stack.size() > 0);
log_assert(!design->selection_stack.empty());
if (clear_mode) {
design->selection_stack.back() = RTLIL::Selection(true);
design->selection() = RTLIL::Selection::FullSelection(design);
design->selected_active_module = std::string();
return;
}
if (none_mode) {
design->selection_stack.back() = RTLIL::Selection(false);
design->selection() = RTLIL::Selection::EmptySelection(design);
return;
}
@ -1465,28 +1516,17 @@ struct SelectPass : public Pass {
if (f == nullptr)
log_error("Can't open '%s' for writing: %s\n", write_file.c_str(), strerror(errno));
}
RTLIL::Selection *sel = &design->selection_stack.back();
if (work_stack.size() > 0)
sel = &work_stack.back();
design->push_selection(work_stack.back());
RTLIL::Selection *sel = &design->selection();
sel->optimize(design);
for (auto mod : design->modules())
for (auto mod : design->all_selected_modules())
{
if (sel->selected_whole_module(mod->name) && list_mode)
log("%s\n", id2cstr(mod->name));
if (sel->selected_module(mod->name) && !list_mod_mode) {
for (auto wire : mod->wires())
if (sel->selected_member(mod->name, wire->name))
LOG_OBJECT("%s/%s\n", id2cstr(mod->name), id2cstr(wire->name))
for (auto &it : mod->memories)
if (sel->selected_member(mod->name, it.first))
LOG_OBJECT("%s/%s\n", id2cstr(mod->name), id2cstr(it.first))
for (auto cell : mod->cells())
if (sel->selected_member(mod->name, cell->name))
LOG_OBJECT("%s/%s\n", id2cstr(mod->name), id2cstr(cell->name))
for (auto &it : mod->processes)
if (sel->selected_member(mod->name, it.first))
LOG_OBJECT("%s/%s\n", id2cstr(mod->name), id2cstr(it.first))
}
if (!list_mod_mode)
for (auto it : mod->selected_members())
LOG_OBJECT("%s/%s\n", id2cstr(mod->name), id2cstr(it->name))
}
if (count_mode)
{
@ -1495,6 +1535,8 @@ struct SelectPass : public Pass {
}
if (f != nullptr)
fclose(f);
if (work_stack.size() > 0)
design->pop_selection();
#undef LOG_OBJECT
return;
}
@ -1503,8 +1545,8 @@ struct SelectPass : public Pass {
{
if (work_stack.size() == 0)
log_cmd_error("Nothing to add to selection.\n");
select_op_union(design, design->selection_stack.back(), work_stack.back());
design->selection_stack.back().optimize(design);
select_op_union(design, design->selection(), work_stack.back());
design->selection().optimize(design);
return;
}
@ -1512,8 +1554,8 @@ struct SelectPass : public Pass {
{
if (work_stack.size() == 0)
log_cmd_error("Nothing to delete from selection.\n");
select_op_diff(design, design->selection_stack.back(), work_stack.back());
design->selection_stack.back().optimize(design);
select_op_diff(design, design->selection(), work_stack.back());
design->selection().optimize(design);
return;
}
@ -1553,23 +1595,13 @@ struct SelectPass : public Pass {
if (work_stack.size() == 0)
log_cmd_error("No selection to check.\n");
RTLIL::Selection *sel = &work_stack.back();
design->push_selection(*sel);
sel->optimize(design);
for (auto mod : design->modules())
if (sel->selected_module(mod->name)) {
module_count++;
for (auto wire : mod->wires())
if (sel->selected_member(mod->name, wire->name))
total_count++;
for (auto &it : mod->memories)
if (sel->selected_member(mod->name, it.first))
total_count++;
for (auto cell : mod->cells())
if (sel->selected_member(mod->name, cell->name))
total_count++;
for (auto &it : mod->processes)
if (sel->selected_member(mod->name, it.first))
total_count++;
}
for (auto mod : design->all_selected_modules()) {
module_count++;
for ([[maybe_unused]] auto member_name : mod->selected_members())
total_count++;
}
if (assert_modcount >= 0 && assert_modcount != module_count)
{
log_error("Assertion failed: selection contains %d modules instead of the asserted %d:%s\n",
@ -1593,13 +1625,14 @@ struct SelectPass : public Pass {
log_error("Assertion failed: selection contains %d elements, less than the minimum number %d:%s\n%s",
total_count, assert_min, sel_str.c_str(), desc.c_str());
}
design->pop_selection();
return;
}
if (!set_name.empty())
{
if (work_stack.size() == 0)
design->selection_vars[set_name] = RTLIL::Selection(false);
design->selection_vars[set_name] = RTLIL::Selection::EmptySelection(design);
else
design->selection_vars[set_name] = work_stack.back();
return;
@ -1613,7 +1646,7 @@ struct SelectPass : public Pass {
}
if (work_stack.size() == 0) {
RTLIL::Selection &sel = design->selection_stack.back();
RTLIL::Selection &sel = design->selection();
if (sel.full_selection)
log("*\n");
for (auto &it : sel.selected_modules)
@ -1624,8 +1657,8 @@ struct SelectPass : public Pass {
return;
}
design->selection_stack.back() = work_stack.back();
design->selection_stack.back().optimize(design);
design->selection() = work_stack.back();
design->selection().optimize(design);
}
} SelectPass;
@ -1665,7 +1698,8 @@ struct CdPass : public Pass {
log_cmd_error("Invalid number of arguments.\n");
if (args.size() == 1 || args[1] == "/") {
design->selection_stack.back() = RTLIL::Selection(true);
design->pop_selection();
design->push_full_selection();
design->selected_active_module = std::string();
return;
}
@ -1674,7 +1708,8 @@ struct CdPass : public Pass {
{
string modname = design->selected_active_module;
design->selection_stack.back() = RTLIL::Selection(true);
design->pop_selection();
design->push_full_selection();
design->selected_active_module = std::string();
while (1)
@ -1691,9 +1726,10 @@ struct CdPass : public Pass {
continue;
design->selected_active_module = modname;
design->selection_stack.back() = RTLIL::Selection();
select_filter_active_mod(design, design->selection_stack.back());
design->selection_stack.back().optimize(design);
design->pop_selection();
design->push_full_selection();
select_filter_active_mod(design, design->selection());
design->selection().optimize(design);
return;
}
@ -1710,9 +1746,10 @@ struct CdPass : public Pass {
if (design->module(modname) != nullptr) {
design->selected_active_module = modname;
design->selection_stack.back() = RTLIL::Selection();
select_filter_active_mod(design, design->selection_stack.back());
design->selection_stack.back().optimize(design);
design->pop_selection();
design->push_full_selection();
select_filter_active_mod(design, design->selection());
design->selection().optimize(design);
return;
}
@ -1759,7 +1796,7 @@ struct LsPass : public Pass {
{
std::vector<IdString> matches;
for (auto mod : design->selected_modules())
for (auto mod : design->all_selected_modules())
matches.push_back(mod->name);
if (!matches.empty()) {

View file

@ -96,32 +96,16 @@ struct SetattrPass : public Pass {
}
extra_args(args, argidx, design);
for (auto module : design->modules())
for (auto module : design->all_selected_modules())
{
if (flag_mod) {
if (design->selected_whole_module(module->name))
if (module->is_selected_whole())
do_setunset(module->attributes, setunset_list);
continue;
}
if (!design->selected(module))
continue;
for (auto wire : module->wires())
if (design->selected(module, wire))
do_setunset(wire->attributes, setunset_list);
for (auto &it : module->memories)
if (design->selected(module, it.second))
do_setunset(it.second->attributes, setunset_list);
for (auto cell : module->cells())
if (design->selected(module, cell))
do_setunset(cell->attributes, setunset_list);
for (auto &it : module->processes)
if (design->selected(module, it.second))
do_setunset(it.second->attributes, setunset_list);
for (auto memb : module->selected_members())
do_setunset(memb->attributes, setunset_list);
}
}
} SetattrPass;
@ -152,16 +136,8 @@ struct WbflipPass : public Pass {
}
extra_args(args, argidx, design);
for (Module *module : design->modules())
{
if (!design->selected(module))
continue;
if (module->get_bool_attribute(ID::blackbox))
continue;
for (auto *module : design->selected_modules(RTLIL::SELECT_ALL, RTLIL::SB_EXCL_BB_ONLY))
module->set_bool_attribute(ID::whitebox, !module->get_bool_attribute(ID::whitebox));
}
}
} WbflipPass;

View file

@ -802,8 +802,8 @@ struct ShowPass : public Pass {
std::pair<std::string, RTLIL::Selection> data;
data.first = args[++argidx], argidx++;
handle_extra_select_args(this, args, argidx, argidx+1, design);
data.second = design->selection_stack.back();
design->selection_stack.pop_back();
data.second = design->selection();
design->pop_selection();
color_selections.push_back(data);
continue;
}
@ -811,8 +811,8 @@ struct ShowPass : public Pass {
std::pair<std::string, RTLIL::Selection> data;
data.first = args[++argidx], argidx++;
handle_extra_select_args(this, args, argidx, argidx+1, design);
data.second = design->selection_stack.back();
design->selection_stack.pop_back();
data.second = design->selection();
design->pop_selection();
label_selections.push_back(data);
continue;
}

View file

@ -468,7 +468,7 @@ struct StatPass : public Pass {
first_module = false;
} else {
log("\n");
log("=== %s%s ===\n", log_id(mod->name), design->selected_whole_module(mod->name) ? "" : " (partially selected)");
log("=== %s%s ===\n", log_id(mod->name), mod->is_selected_whole() ? "" : " (partially selected)");
log("\n");
data.log_data(mod->name, false);
}

172
passes/cmds/test_select.cc Normal file
View file

@ -0,0 +1,172 @@
#include "kernel/yosys.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
struct TestSelectPass : public Pass {
TestSelectPass() : Pass("test_select", "call internal selection methods on design for testing purposes") { }
void help() override
{
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
log("\n");
log(" test_select [options]\n");
log("\n");
log("Test semantics of internal 'RTLIL::Design::selected_modules()' by modifying the\n");
log("current selection to only include the results of the call.\n");
log("\n");
log("Includes partially selected modules by default, use one of the following options\n");
log("to remove them instead:\n");
log("\n");
log(" -whole_only\n");
log("\n");
log(" -whole_warn\n");
log(" -whole_err\n");
log(" -whole_cmderr\n");
log(" remove partially selected modules, raising warning, error, or cmd error\n");
log("\n");
log(" test_select -unboxed_only [options]\n");
log("\n");
log("Remove boxed modules from selection.\n");
log("\n");
log(" -include_wb\n");
log(" don't remove white boxes from selection\n");
log("\n");
log(" -warn_boxes\n");
log(" -err_boxes\n");
log(" -cmderr_boxes\n");
log(" raise warning, error, or cmd error if a box is removed\n");
log("\n");
}
void execute(vector<string> args, RTLIL::Design *design) override
{
log_header(design, "Executing TEST_SELECTION pass.\n");
bool whole_only = false;
bool whole_warn = false;
bool whole_err = false;
bool whole_cmderr = false;
int whole_opts = 0;
bool warn_boxes = false;
bool err_boxes = false;
bool cmderr_boxes = false;
int box_level = 0;
bool unboxed_only = false;
bool include_wb = false;
int argidx;
for (argidx = 1; argidx < GetSize(args); argidx++)
{
if (args[argidx] == "-whole_only") {
whole_only = true;
whole_opts++;
continue;
}
if (args[argidx] == "-whole_warn") {
whole_warn = true;
whole_opts++;
continue;
}
if (args[argidx] == "-whole_err") {
whole_err = true;
whole_opts++;
continue;
}
if (args[argidx] == "-whole_cmderr") {
whole_cmderr = true;
whole_opts++;
continue;
}
if (args[argidx] == "-warn_boxes") {
warn_boxes = true;
box_level++;
continue;
}
if (args[argidx] == "-err_boxes") {
err_boxes = true;
box_level++;
continue;
}
if (args[argidx] == "-cmderr_boxes") {
cmderr_boxes = true;
box_level++;
continue;
}
if (args[argidx] == "-unboxed_only") {
unboxed_only = true;
continue;
}
if (args[argidx] == "-include_wb") {
include_wb = true;
continue;
}
break;
}
if (whole_opts > 1)
log_cmd_error("Only one of -whole_only, -whole_warn, -whole_err, or -whole_cmderr may be selected.\n");
if (include_wb && !unboxed_only)
log_cmd_error("-include_wb option requires -unboxed_only.\n");
if (box_level > 0 && !unboxed_only)
log_cmd_error("-*_boxes options require -unboxed_only.\n");
if (box_level > 1)
log_cmd_error("Only one of -warn_boxes, -err_boxes, or -cmderr_boxes may be selected.\n");
extra_args(args, argidx, design, false);
// construct enums
RTLIL::SelectPartials partials;
if (whole_only)
partials = RTLIL::SELECT_WHOLE_ONLY;
else if (whole_warn)
partials = RTLIL::SELECT_WHOLE_WARN;
else if (whole_err)
partials = RTLIL::SELECT_WHOLE_ERR;
else if (whole_cmderr)
partials = RTLIL::SELECT_WHOLE_CMDERR;
else
partials = RTLIL::SELECT_ALL;
char boxes = RTLIL::SB_ALL;
if (warn_boxes) boxes |= RTLIL::SB_WARN;
if (err_boxes) boxes |= RTLIL::SB_ERR;
if (cmderr_boxes) boxes |= RTLIL::SB_CMDERR;
if (unboxed_only) boxes |= RTLIL::SB_UNBOXED_ONLY;
if (include_wb) boxes |= RTLIL::SB_INCL_WB;
// get sub selection and store the results
auto sub_sel = design->selected_modules(partials, (RTLIL::SelectBoxes)boxes);
pool<RTLIL::IdString> selected_modules;
dict<RTLIL::IdString, pool<RTLIL::NamedObject*>> selected_members;
for (auto *mod : sub_sel) {
if (mod->is_selected_whole()) {
log_debug(" Adding %s.\n", id2cstr(mod->name));
selected_modules.insert(mod->name);
} else for (auto *memb : mod->selected_members()) {
log_debug(" Adding %s.%s.\n", id2cstr(mod->name), id2cstr(memb->name));
selected_members[mod->name].insert(memb);
}
}
// fully reset current selection
design->selection() = RTLIL::Selection::EmptySelection(design);
// add back sub selection
for (auto modname : selected_modules)
design->selection().select(design->module(modname));
for (auto &it : selected_members) {
auto mod = design->module(it.first);
for (auto memb : it.second)
design->selection().select(mod, memb);
}
// optimize
design->selection().optimize(design);
}
} TestSelectPass;
PRIVATE_NAMESPACE_END

View file

@ -950,8 +950,8 @@ struct VizPass : public Pass {
auto type = arg == "-g" || arg == "-G" ? VizConfig::TYPE_G :
arg == "-u" || arg == "-U" ? VizConfig::TYPE_U :
arg == "-x" || arg == "-X" ? VizConfig::TYPE_X : VizConfig::TYPE_S;
config.groups.push_back({type, design->selection_stack.back()});
design->selection_stack.pop_back();
config.groups.push_back({type, design->selection()});
design->pop_selection();
continue;
}
if (arg == "-0" || arg == "-1" || arg == "-2" || arg == "-3" || arg == "-4" ||

View file

@ -978,6 +978,11 @@ struct HierarchyPass : public Pass {
}
}
bool verific_mod = false;
#ifdef YOSYS_ENABLE_VERIFIC
verific_mod = verific_import_pending;
#endif
if (top_mod == nullptr && !load_top_mod.empty()) {
#ifdef YOSYS_ENABLE_VERIFIC
if (verific_import_pending) {
@ -1418,13 +1423,18 @@ struct HierarchyPass : public Pass {
if (m == nullptr)
continue;
if (m->get_blackbox_attribute() && !cell->parameters.empty() && m->get_bool_attribute(ID::dynports)) {
IdString new_m_name = m->derive(design, cell->parameters, true);
if (new_m_name.empty())
continue;
if (new_m_name != m->name) {
m = design->module(new_m_name);
blackbox_derivatives.insert(m);
bool boxed_params = false;
if (m->get_blackbox_attribute() && !cell->parameters.empty()) {
if (m->get_bool_attribute(ID::dynports)) {
IdString new_m_name = m->derive(design, cell->parameters, true);
if (new_m_name.empty())
continue;
if (new_m_name != m->name) {
m = design->module(new_m_name);
blackbox_derivatives.insert(m);
}
} else {
boxed_params = true;
}
}
@ -1440,8 +1450,12 @@ struct HierarchyPass : public Pass {
SigSpec sig = conn.second;
if (!keep_portwidths && GetSize(w) != GetSize(conn.second))
{
bool resize_widths = !keep_portwidths && GetSize(w) != GetSize(conn.second);
if (resize_widths && verific_mod && boxed_params)
log_warning("Ignoring width mismatch on %s.%s.%s from verific, is port width parametrizable?\n",
log_id(module), log_id(cell), log_id(conn.first)
);
else if (resize_widths) {
if (GetSize(w) < GetSize(conn.second))
{
int n = GetSize(conn.second) - GetSize(w);

View file

@ -246,7 +246,7 @@ struct SubmodWorker
SubmodWorker(RTLIL::Design *design, RTLIL::Module *module, bool copy_mode = false, bool hidden_mode = false, std::string opt_name = std::string()) :
design(design), module(module), sigmap(module), copy_mode(copy_mode), hidden_mode(hidden_mode), opt_name(opt_name)
{
if (!design->selected_whole_module(module->name) && opt_name.empty())
if (!module->is_selected_whole() && opt_name.empty())
return;
if (module->processes.size() > 0) {

View file

@ -2232,11 +2232,11 @@ struct MemoryLibMapPass : public Pass {
if (module->has_processes_warn())
continue;
MapWorker worker(module);
auto worker = std::make_unique<MapWorker>(module);
auto mems = Mem::get_selected_memories(module);
for (auto &mem : mems)
{
MemMapping map(worker, mem, lib, opts);
MemMapping map(*worker, mem, lib, opts);
int idx = -1;
int best = map.logic_cost;
if (!map.logic_ok) {
@ -2259,7 +2259,7 @@ struct MemoryLibMapPass : public Pass {
} else {
map.emit(map.cfgs[idx]);
// Rebuild indices after modifying module
worker = MapWorker(module);
worker = std::make_unique<MapWorker>(module);
}
}
}

View file

@ -734,7 +734,7 @@ struct CleanPass : public Pass {
count_rm_cells = 0;
count_rm_wires = 0;
for (auto module : design->selected_whole_modules()) {
for (auto module : design->selected_unboxed_whole_modules()) {
if (module->has_processes())
continue;
rmunused_module(module, purge_mode, ys_debug(), true);

View file

@ -110,7 +110,7 @@ struct ShareWorker
// Code for sharing and comparing MACC cells
// ---------------------------------------------------
static int bits_macc_port(const Macc::port_t &p, int width)
static int bits_macc_term(const Macc::term_t &p, int width)
{
if (GetSize(p.in_a) == 0 || GetSize(p.in_b) == 0)
return min(max(GetSize(p.in_a), GetSize(p.in_b)), width);
@ -120,8 +120,8 @@ struct ShareWorker
static int bits_macc(const Macc &m, int width)
{
int bits = 0;
for (auto &p : m.ports)
bits += bits_macc_port(p, width);
for (auto &p : m.terms)
bits += bits_macc_term(p, width);
return bits;
}
@ -132,7 +132,7 @@ struct ShareWorker
return bits_macc(m, width);
}
static bool cmp_macc_ports(const Macc::port_t &p1, const Macc::port_t &p2)
static bool cmp_macc_ports(const Macc::term_t &p1, const Macc::term_t &p2)
{
bool mul1 = GetSize(p1.in_a) && GetSize(p1.in_b);
bool mul2 = GetSize(p2.in_a) && GetSize(p2.in_b);
@ -161,7 +161,7 @@ struct ShareWorker
return false;
}
int share_macc_ports(Macc::port_t &p1, Macc::port_t &p2, int w1, int w2,
int share_macc_ports(Macc::term_t &p1, Macc::term_t &p2, int w1, int w2,
RTLIL::SigSpec act = RTLIL::SigSpec(), Macc *supermacc = nullptr, pool<RTLIL::Cell*> *supercell_aux = nullptr)
{
if (p1.do_subtract != p2.do_subtract)
@ -216,12 +216,12 @@ struct ShareWorker
supercell_aux->insert(module->addMux(NEW_ID, sig_b2, sig_b1, act, sig_b));
}
Macc::port_t p;
Macc::term_t p;
p.in_a = sig_a;
p.in_b = sig_b;
p.is_signed = force_signed;
p.do_subtract = p1.do_subtract;
supermacc->ports.push_back(p);
supermacc->terms.push_back(p);
}
int score = 1000 + abs(GetSize(p1.in_a) - GetSize(p2.in_a)) * max(abs(GetSize(p1.in_b) - GetSize(p2.in_b)), 1);
@ -248,15 +248,15 @@ struct ShareWorker
m1.optimize(w1);
m2.optimize(w2);
std::sort(m1.ports.begin(), m1.ports.end(), cmp_macc_ports);
std::sort(m2.ports.begin(), m2.ports.end(), cmp_macc_ports);
std::sort(m1.terms.begin(), m1.terms.end(), cmp_macc_ports);
std::sort(m2.terms.begin(), m2.terms.end(), cmp_macc_ports);
std::set<int> m1_unmapped, m2_unmapped;
for (int i = 0; i < GetSize(m1.ports); i++)
for (int i = 0; i < GetSize(m1.terms); i++)
m1_unmapped.insert(i);
for (int i = 0; i < GetSize(m2.ports); i++)
for (int i = 0; i < GetSize(m2.terms); i++)
m2_unmapped.insert(i);
while (1)
@ -265,7 +265,7 @@ struct ShareWorker
for (int i : m1_unmapped)
for (int j : m2_unmapped) {
int score = share_macc_ports(m1.ports[i], m2.ports[j], w1, w2);
int score = share_macc_ports(m1.terms[i], m2.terms[j], w1, w2);
if (score >= 0 && (best_i < 0 || best_score > score))
best_i = i, best_j = j, best_score = score;
}
@ -273,55 +273,55 @@ struct ShareWorker
if (best_i >= 0) {
m1_unmapped.erase(best_i);
m2_unmapped.erase(best_j);
share_macc_ports(m1.ports[best_i], m2.ports[best_j], w1, w2, act, &supermacc, supercell_aux);
share_macc_ports(m1.terms[best_i], m2.terms[best_j], w1, w2, act, &supermacc, supercell_aux);
} else
break;
}
for (int i : m1_unmapped)
{
RTLIL::SigSpec sig_a = m1.ports[i].in_a;
RTLIL::SigSpec sig_b = m1.ports[i].in_b;
RTLIL::SigSpec sig_a = m1.terms[i].in_a;
RTLIL::SigSpec sig_b = m1.terms[i].in_b;
if (supercell_aux && GetSize(sig_a)) {
sig_a = module->addWire(NEW_ID, GetSize(sig_a));
supercell_aux->insert(module->addMux(NEW_ID, RTLIL::SigSpec(0, GetSize(sig_a)), m1.ports[i].in_a, act, sig_a));
supercell_aux->insert(module->addMux(NEW_ID, RTLIL::SigSpec(0, GetSize(sig_a)), m1.terms[i].in_a, act, sig_a));
}
if (supercell_aux && GetSize(sig_b)) {
sig_b = module->addWire(NEW_ID, GetSize(sig_b));
supercell_aux->insert(module->addMux(NEW_ID, RTLIL::SigSpec(0, GetSize(sig_b)), m1.ports[i].in_b, act, sig_b));
supercell_aux->insert(module->addMux(NEW_ID, RTLIL::SigSpec(0, GetSize(sig_b)), m1.terms[i].in_b, act, sig_b));
}
Macc::port_t p;
Macc::term_t p;
p.in_a = sig_a;
p.in_b = sig_b;
p.is_signed = m1.ports[i].is_signed;
p.do_subtract = m1.ports[i].do_subtract;
supermacc.ports.push_back(p);
p.is_signed = m1.terms[i].is_signed;
p.do_subtract = m1.terms[i].do_subtract;
supermacc.terms.push_back(p);
}
for (int i : m2_unmapped)
{
RTLIL::SigSpec sig_a = m2.ports[i].in_a;
RTLIL::SigSpec sig_b = m2.ports[i].in_b;
RTLIL::SigSpec sig_a = m2.terms[i].in_a;
RTLIL::SigSpec sig_b = m2.terms[i].in_b;
if (supercell_aux && GetSize(sig_a)) {
sig_a = module->addWire(NEW_ID, GetSize(sig_a));
supercell_aux->insert(module->addMux(NEW_ID, m2.ports[i].in_a, RTLIL::SigSpec(0, GetSize(sig_a)), act, sig_a));
supercell_aux->insert(module->addMux(NEW_ID, m2.terms[i].in_a, RTLIL::SigSpec(0, GetSize(sig_a)), act, sig_a));
}
if (supercell_aux && GetSize(sig_b)) {
sig_b = module->addWire(NEW_ID, GetSize(sig_b));
supercell_aux->insert(module->addMux(NEW_ID, m2.ports[i].in_b, RTLIL::SigSpec(0, GetSize(sig_b)), act, sig_b));
supercell_aux->insert(module->addMux(NEW_ID, m2.terms[i].in_b, RTLIL::SigSpec(0, GetSize(sig_b)), act, sig_b));
}
Macc::port_t p;
Macc::term_t p;
p.in_a = sig_a;
p.in_b = sig_b;
p.is_signed = m2.ports[i].is_signed;
p.do_subtract = m2.ports[i].do_subtract;
supermacc.ports.push_back(p);
p.is_signed = m2.terms[i].is_signed;
p.do_subtract = m2.terms[i].do_subtract;
supermacc.terms.push_back(p);
}
if (supercell)
@ -1000,6 +1000,61 @@ struct ShareWorker
}
}
pool<std::pair<SigBit, State>> pattern_bits(const pool<ssc_pair_t> &activation_patterns)
{
pool<std::pair<SigBit, State>> bits;
for (auto const &pattern : activation_patterns) {
for (int i = 0; i < GetSize(pattern.second); ++i) {
SigBit bit = pattern.first[i];
State val = pattern.second[i];
bits.emplace(bit, val);
}
}
return bits;
}
bool onesided_restrict_activation_patterns(
pool<ssc_pair_t> &activation_patterns, const pool<std::pair<SigBit, State>> &other_bits)
{
pool<ssc_pair_t> new_activation_patterns;
bool simplified = false;
for (auto const &pattern : activation_patterns) {
ssc_pair_t new_pair;
for (int i = 0; i < GetSize(pattern.second); ++i) {
SigBit bit = pattern.first[i];
State val = pattern.second[i];
if (other_bits.count({bit, val == State::S0 ? State::S1 : State::S0})) {
new_pair.first.append(bit);
new_pair.second.append(val);
} else {
simplified = true;
}
}
new_activation_patterns.emplace(std::move(new_pair));
}
activation_patterns = std::move(new_activation_patterns);
return simplified;
}
// Only valid if the patterns on their own (i.e. without considering their input cone) are mutually exclusive!
bool restrict_activation_patterns(pool<ssc_pair_t> &activation_patterns, pool<ssc_pair_t> &other_activation_patterns)
{
pool<std::pair<SigBit, State>> bits = pattern_bits(activation_patterns);
pool<std::pair<SigBit, State>> other_bits = pattern_bits(other_activation_patterns);
bool simplified = false;
simplified |= onesided_restrict_activation_patterns(activation_patterns, other_bits);
simplified |= onesided_restrict_activation_patterns(other_activation_patterns, bits);
optimize_activation_patterns(activation_patterns);
optimize_activation_patterns(other_activation_patterns);
return simplified;
}
RTLIL::SigSpec make_cell_activation_logic(const pool<ssc_pair_t> &activation_patterns, pool<RTLIL::Cell*> &supercell_aux)
{
RTLIL::Wire *all_cases_wire = module->addWire(NEW_ID, 0);
@ -1299,17 +1354,18 @@ struct ShareWorker
other_cell_active.push_back(qcsat.ez->vec_eq(qcsat.importSig(p.first), qcsat.importSig(p.second)));
all_ctrl_signals.append(p.first);
}
int sub1 = qcsat.ez->expression(qcsat.ez->OpOr, cell_active);
int sub2 = qcsat.ez->expression(qcsat.ez->OpOr, other_cell_active);
bool pattern_only_solve = qcsat.ez->solve(qcsat.ez->AND(sub1, sub2));
qcsat.prepare();
int sub1 = qcsat.ez->expression(qcsat.ez->OpOr, cell_active);
if (!qcsat.ez->solve(sub1)) {
log(" According to the SAT solver the cell %s is never active. Sharing is pointless, we simply remove it.\n", log_id(cell));
cells_to_remove.insert(cell);
break;
}
int sub2 = qcsat.ez->expression(qcsat.ez->OpOr, other_cell_active);
if (!qcsat.ez->solve(sub2)) {
log(" According to the SAT solver the cell %s is never active. Sharing is pointless, we simply remove it.\n", log_id(other_cell));
cells_to_remove.insert(other_cell);
@ -1317,28 +1373,43 @@ struct ShareWorker
continue;
}
qcsat.ez->non_incremental();
pool<ssc_pair_t> optimized_cell_activation_patterns = filtered_cell_activation_patterns;
pool<ssc_pair_t> optimized_other_cell_activation_patterns = filtered_other_cell_activation_patterns;
all_ctrl_signals.sort_and_unify();
std::vector<int> sat_model = qcsat.importSig(all_ctrl_signals);
std::vector<bool> sat_model_values;
if (pattern_only_solve) {
qcsat.ez->non_incremental();
qcsat.ez->assume(qcsat.ez->AND(sub1, sub2));
all_ctrl_signals.sort_and_unify();
std::vector<int> sat_model = qcsat.importSig(all_ctrl_signals);
std::vector<bool> sat_model_values;
log(" Size of SAT problem: %zu cells, %d variables, %d clauses\n",
qcsat.imported_cells.size(), qcsat.ez->numCnfVariables(), qcsat.ez->numCnfClauses());
qcsat.ez->assume(qcsat.ez->AND(sub1, sub2));
if (qcsat.ez->solve(sat_model, sat_model_values)) {
log(" According to the SAT solver this pair of cells can not be shared.\n");
log(" Model from SAT solver: %s = %d'", log_signal(all_ctrl_signals), GetSize(sat_model_values));
for (int i = GetSize(sat_model_values)-1; i >= 0; i--)
log("%c", sat_model_values[i] ? '1' : '0');
log("\n");
continue;
log(" Size of SAT problem: %zu cells, %d variables, %d clauses\n",
qcsat.imported_cells.size(), qcsat.ez->numCnfVariables(), qcsat.ez->numCnfClauses());
if (qcsat.ez->solve(sat_model, sat_model_values)) {
log(" According to the SAT solver this pair of cells can not be shared.\n");
log(" Model from SAT solver: %s = %d'", log_signal(all_ctrl_signals), GetSize(sat_model_values));
for (int i = GetSize(sat_model_values)-1; i >= 0; i--)
log("%c", sat_model_values[i] ? '1' : '0');
log("\n");
continue;
}
log(" According to the SAT solver this pair of cells can be shared.\n");
} else {
log(" According to the SAT solver this pair of cells can be shared. (Pattern only case)\n");
if (restrict_activation_patterns(optimized_cell_activation_patterns, optimized_other_cell_activation_patterns)) {
for (auto &p : optimized_cell_activation_patterns)
log(" Simplified activation pattern for cell %s: %s = %s\n", log_id(cell), log_signal(p.first), log_signal(p.second));
for (auto &p : optimized_other_cell_activation_patterns)
log(" Simplified activation pattern for cell %s: %s = %s\n", log_id(other_cell), log_signal(p.first), log_signal(p.second));
}
}
log(" According to the SAT solver this pair of cells can be shared.\n");
if (find_in_input_cone(cell, other_cell)) {
log(" Sharing not possible: %s is in input cone of %s.\n", log_id(other_cell), log_id(cell));
continue;
@ -1354,20 +1425,20 @@ struct ShareWorker
int cell_select_score = 0;
int other_cell_select_score = 0;
for (auto &p : filtered_cell_activation_patterns)
for (auto &p : optimized_cell_activation_patterns)
cell_select_score += p.first.size();
for (auto &p : filtered_other_cell_activation_patterns)
for (auto &p : optimized_other_cell_activation_patterns)
other_cell_select_score += p.first.size();
RTLIL::Cell *supercell;
pool<RTLIL::Cell*> supercell_aux;
if (cell_select_score <= other_cell_select_score) {
RTLIL::SigSpec act = make_cell_activation_logic(filtered_cell_activation_patterns, supercell_aux);
RTLIL::SigSpec act = make_cell_activation_logic(optimized_cell_activation_patterns, supercell_aux);
supercell = make_supercell(cell, other_cell, act, supercell_aux);
log(" Activation signal for %s: %s\n", log_id(cell), log_signal(act));
} else {
RTLIL::SigSpec act = make_cell_activation_logic(filtered_other_cell_activation_patterns, supercell_aux);
RTLIL::SigSpec act = make_cell_activation_logic(optimized_other_cell_activation_patterns, supercell_aux);
supercell = make_supercell(other_cell, cell, act, supercell_aux);
log(" Activation signal for %s: %s\n", log_id(other_cell), log_signal(act));
}

View file

@ -37,10 +37,20 @@ struct CutpointPass : public Pass {
log(" set cutpoint nets to undef (x). the default behavior is to create\n");
log(" an $anyseq cell and drive the cutpoint net from that\n");
log("\n");
log(" -noscopeinfo\n");
log(" do not create '$scopeinfo' cells that preserve attributes of cells that\n");
log(" were removed by this pass\n");
log("\n");
log(" cutpoint -blackbox [options]\n");
log("\n");
log("Replace all instances of blackboxes in the design with a formal cut point.\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
bool flag_undef = false;
bool flag_undef = false;
bool flag_scopeinfo = true;
bool flag_blackbox = false;
log_header(design, "Executing CUTPOINT pass.\n");
@ -51,26 +61,31 @@ struct CutpointPass : public Pass {
flag_undef = true;
continue;
}
if (args[argidx] == "-noscopeinfo") {
flag_scopeinfo = false;
continue;
}
if (args[argidx] == "-blackbox") {
flag_blackbox = true;
continue;
}
break;
}
extra_args(args, argidx, design);
for (auto module : design->selected_modules())
{
if (design->selected_whole_module(module->name)) {
log("Making all outputs of module %s cut points, removing module contents.\n", log_id(module));
module->new_connections(std::vector<RTLIL::SigSig>());
for (auto cell : vector<Cell*>(module->cells()))
module->remove(cell);
vector<Wire*> output_wires;
for (auto wire : module->wires())
if (wire->port_output)
output_wires.push_back(wire);
for (auto wire : output_wires)
module->connect(wire, flag_undef ? Const(State::Sx, GetSize(wire)) : module->Anyseq(NEW_ID, GetSize(wire)));
continue;
}
if (flag_blackbox) {
if (!design->full_selection())
log_cmd_error("This command only operates on fully selected designs!\n");
design->push_empty_selection();
auto &selection = design->selection();
for (auto module : design->modules())
for (auto cell : module->cells())
if (selection.boxed_module(cell->type))
selection.select(module, cell);
}
for (auto module : design->all_selected_modules())
{
SigMap sigmap(module);
pool<SigBit> cutpoint_bits;
@ -82,7 +97,26 @@ struct CutpointPass : public Pass {
if (cell->output(conn.first))
module->connect(conn.second, flag_undef ? Const(State::Sx, GetSize(conn.second)) : module->Anyseq(NEW_ID, GetSize(conn.second)));
}
RTLIL::Cell *scopeinfo = nullptr;
auto cell_name = cell->name;
if (flag_scopeinfo && cell_name.isPublic()) {
auto scopeinfo = module->addCell(NEW_ID, ID($scopeinfo));
scopeinfo->setParam(ID::TYPE, RTLIL::Const("blackbox"));
for (auto const &attr : cell->attributes)
{
if (attr.first == ID::hdlname)
scopeinfo->attributes.insert(attr);
else
scopeinfo->attributes.emplace(stringf("\\cell_%s", RTLIL::unescape_id(attr.first).c_str()), attr.second);
}
}
module->remove(cell);
if (scopeinfo != nullptr)
module->rename(scopeinfo, cell_name);
}
for (auto wire : module->selected_wires()) {

View file

@ -2887,7 +2887,7 @@ struct SimPass : public Pass {
if (!top_mod)
log_cmd_error("Design has no top module, use the 'hierarchy' command to specify one.\n");
} else {
auto mods = design->selected_whole_modules();
auto mods = design->selected_unboxed_whole_modules();
if (GetSize(mods) != 1)
log_cmd_error("Only one top module must be selected.\n");
top_mod = mods.front();
@ -3016,7 +3016,7 @@ struct Fst2TbPass : public Pass {
if (!top_mod)
log_cmd_error("Design has no top module, use the 'hierarchy' command to specify one.\n");
} else {
auto mods = design->selected_whole_modules();
auto mods = design->selected_unboxed_whole_modules();
if (GetSize(mods) != 1)
log_cmd_error("Only one top module must be selected.\n");
top_mod = mods.front();

View file

@ -54,6 +54,7 @@ OBJS += passes/techmap/flowmap.o
OBJS += passes/techmap/extractinv.o
OBJS += passes/techmap/cellmatch.o
OBJS += passes/techmap/clockgate.o
OBJS += passes/techmap/constmap.o
endif
ifeq ($(DISABLE_SPAWN),0)
@ -62,5 +63,5 @@ EXTRA_OBJS += passes/techmap/filterlib.o
$(PROGRAM_PREFIX)yosys-filterlib$(EXE): passes/techmap/filterlib.o
$(Q) mkdir -p $(dir $@)
$(P) $(CXX) -o $(PROGRAM_PREFIX)yosys-filterlib$(EXE) $(LINKFLAGS) $^ $(LIBS)
$(P) $(CXX) -o $(PROGRAM_PREFIX)yosys-filterlib$(EXE) $(LINKFLAGS) $^ $(EXE_LIBS) $(LIBS)
endif

View file

@ -306,9 +306,10 @@ struct Abc9Pass : public ScriptPass
}
run("design -stash $abc9");
run("design -load $abc9_map");
run("proc");
if (help_mode) run("select =*");
else active_design->push_complete_selection();
run("wbflip");
run("techmap -wb -map %$abc9 -map +/techmap.v A:abc9_flop");
run("techmap -autoproc -wb -map %$abc9 -map +/techmap.v A:abc9_flop");
run("opt -nodffe -nosdff");
if (dff_mode || help_mode) {
if (!help_mode)
@ -369,6 +370,8 @@ struct Abc9Pass : public ScriptPass
if (saved_designs.count("$abc9_holes") || help_mode) {
run("design -stash $abc9");
run("design -load $abc9_holes");
if (help_mode) run("select =*");
else active_design->push_complete_selection();
run("techmap -wb -map %$abc9 -map +/techmap.v");
run("opt -purge");
run("aigmap");
@ -391,7 +394,7 @@ struct Abc9Pass : public ScriptPass
}
else {
auto selected_modules = active_design->selected_modules();
active_design->selection_stack.emplace_back(false);
active_design->push_empty_selection();
for (auto mod : selected_modules) {
if (mod->processes.size() > 0) {
@ -400,8 +403,9 @@ struct Abc9Pass : public ScriptPass
}
log_push();
active_design->selection().select(mod);
active_design->select(mod);
// this check does nothing because the above line adds the whole module to the selection
if (!active_design->selected_whole_module(mod))
log_error("Can't handle partially selected module %s!\n", log_id(mod));
@ -452,7 +456,7 @@ struct Abc9Pass : public ScriptPass
log_pop();
}
active_design->selection_stack.pop_back();
active_design->pop_selection();
}
}

View file

@ -454,7 +454,7 @@ void prep_bypass(RTLIL::Design *design)
void prep_dff(RTLIL::Design *design)
{
auto r = design->selection_vars.insert(std::make_pair(ID($abc9_flops), RTLIL::Selection(false)));
auto r = design->selection_vars.insert(std::make_pair(ID($abc9_flops), RTLIL::Selection::EmptySelection(design)));
auto &modules_sel = r.first->second;
for (auto module : design->selected_modules())

View file

@ -139,7 +139,7 @@ struct AbcNewPass : public ScriptPass {
if (!help_mode) {
selected_modules = order_modules(active_design,
active_design->selected_whole_modules_warn());
active_design->selection_stack.emplace_back(false);
active_design->push_empty_selection();
} else {
selected_modules = {nullptr};
run("foreach module in selection");
@ -157,7 +157,7 @@ struct AbcNewPass : public ScriptPass {
exe_options = abc_exe_options;
log_header(active_design, "Mapping module '%s'.\n", log_id(mod));
log_push();
active_design->selection().select(mod);
active_design->select(mod);
}
std::string script_save;
@ -194,7 +194,7 @@ struct AbcNewPass : public ScriptPass {
}
if (!help_mode) {
active_design->selection_stack.pop_back();
active_design->pop_selection();
}
}
}

View file

@ -171,8 +171,7 @@ struct AigmapPass : public Pass {
module->remove(cell);
if (select_mode) {
log_assert(!design->selection_stack.empty());
RTLIL::Selection& sel = design->selection_stack.back();
RTLIL::Selection& sel = design->selection();
sel.selected_members[module->name] = std::move(new_sel);
}

View file

@ -142,7 +142,7 @@ struct AlumaccWorker
log(" creating $macc model for %s (%s).\n", log_id(cell), log_id(cell->type));
maccnode_t *n = new maccnode_t;
Macc::port_t new_port;
Macc::term_t new_term;
n->cell = cell;
n->y = sigmap(cell->getPort(ID::Y));
@ -153,32 +153,32 @@ struct AlumaccWorker
if (cell->type.in(ID($pos), ID($neg)))
{
new_port.in_a = sigmap(cell->getPort(ID::A));
new_port.is_signed = cell->getParam(ID::A_SIGNED).as_bool();
new_port.do_subtract = cell->type == ID($neg);
n->macc.ports.push_back(new_port);
new_term.in_a = sigmap(cell->getPort(ID::A));
new_term.is_signed = cell->getParam(ID::A_SIGNED).as_bool();
new_term.do_subtract = cell->type == ID($neg);
n->macc.terms.push_back(new_term);
}
if (cell->type.in(ID($add), ID($sub)))
{
new_port.in_a = sigmap(cell->getPort(ID::A));
new_port.is_signed = cell->getParam(ID::A_SIGNED).as_bool();
new_port.do_subtract = false;
n->macc.ports.push_back(new_port);
new_term.in_a = sigmap(cell->getPort(ID::A));
new_term.is_signed = cell->getParam(ID::A_SIGNED).as_bool();
new_term.do_subtract = false;
n->macc.terms.push_back(new_term);
new_port.in_a = sigmap(cell->getPort(ID::B));
new_port.is_signed = cell->getParam(ID::B_SIGNED).as_bool();
new_port.do_subtract = cell->type == ID($sub);
n->macc.ports.push_back(new_port);
new_term.in_a = sigmap(cell->getPort(ID::B));
new_term.is_signed = cell->getParam(ID::B_SIGNED).as_bool();
new_term.do_subtract = cell->type == ID($sub);
n->macc.terms.push_back(new_term);
}
if (cell->type.in(ID($mul)))
{
new_port.in_a = sigmap(cell->getPort(ID::A));
new_port.in_b = sigmap(cell->getPort(ID::B));
new_port.is_signed = cell->getParam(ID::A_SIGNED).as_bool();
new_port.do_subtract = false;
n->macc.ports.push_back(new_port);
new_term.in_a = sigmap(cell->getPort(ID::A));
new_term.in_b = sigmap(cell->getPort(ID::B));
new_term.is_signed = cell->getParam(ID::A_SIGNED).as_bool();
new_term.do_subtract = false;
n->macc.terms.push_back(new_term);
}
log_assert(sig_macc.count(n->y) == 0);
@ -190,7 +190,7 @@ struct AlumaccWorker
{
std::vector<int> port_sizes;
for (auto &port : macc.ports) {
for (auto &port : macc.terms) {
if (port.is_signed != is_signed)
return true;
if (!port.is_signed && port.do_subtract)
@ -235,9 +235,9 @@ struct AlumaccWorker
if (delete_nodes.count(n))
continue;
for (int i = 0; i < GetSize(n->macc.ports); i++)
for (int i = 0; i < GetSize(n->macc.terms); i++)
{
auto &port = n->macc.ports[i];
auto &port = n->macc.terms[i];
if (GetSize(port.in_b) > 0 || sig_macc.count(port.in_a) == 0)
continue;
@ -253,13 +253,13 @@ struct AlumaccWorker
log(" merging $macc model for %s into %s.\n", log_id(other_n->cell), log_id(n->cell));
bool do_subtract = port.do_subtract;
for (int j = 0; j < GetSize(other_n->macc.ports); j++) {
for (int j = 0; j < GetSize(other_n->macc.terms); j++) {
if (do_subtract)
other_n->macc.ports[j].do_subtract = !other_n->macc.ports[j].do_subtract;
other_n->macc.terms[j].do_subtract = !other_n->macc.terms[j].do_subtract;
if (j == 0)
n->macc.ports[i--] = other_n->macc.ports[j];
n->macc.terms[i--] = other_n->macc.terms[j];
else
n->macc.ports.push_back(other_n->macc.ports[j]);
n->macc.terms.push_back(other_n->macc.terms[j]);
}
delete_nodes.insert(other_n);
@ -288,7 +288,7 @@ struct AlumaccWorker
bool subtract_b = false;
alunode_t *alunode;
for (auto &port : n->macc.ports)
for (auto &port : n->macc.terms)
if (GetSize(port.in_b) > 0) {
goto next_macc;
} else if (GetSize(port.in_a) == 1 && !port.is_signed && !port.do_subtract) {

View file

@ -227,9 +227,9 @@ struct BoothPassWorker {
continue;
}
A = macc.ports[0].in_a;
B = macc.ports[0].in_b;
is_signed = macc.ports[0].is_signed;
A = macc.terms[0].in_a;
B = macc.terms[0].in_b;
is_signed = macc.terms[0].is_signed;
Y = cell->getPort(ID::Y);
} else {
continue;

View file

@ -333,7 +333,7 @@ struct ClockgatePass : public Pass {
dict<ClkNetInfo, GClkNetInfo> clk_nets;
int gated_flop_count = 0;
for (auto module : design->selected_whole_modules()) {
for (auto module : design->selected_unboxed_whole_modules()) {
for (auto cell : module->cells()) {
if (!RTLIL::builtin_ff_cell_types().count(cell->type))
continue;

106
passes/techmap/constmap.cc Normal file
View file

@ -0,0 +1,106 @@
/*
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2025 King Lok Chung <king.chung@manchester.ac.uk>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#include "kernel/register.h"
#include "kernel/rtlil.h"
#include "kernel/log.h"
USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN
static std::string celltype, cell_portname, cell_paramname;
static RTLIL::Module *module;
static RTLIL::SigChunk value;
void constmap_worker(RTLIL::SigSpec &sig)
{
if (sig.is_fully_const()){
value = module->addWire(NEW_ID, sig.size());
RTLIL::Cell *cell = module->addCell(NEW_ID, celltype);
cell->setParam(cell_paramname, sig.as_const());
cell->setPort(cell_portname, value);
sig = value;
}
}
struct ConstmapPass : public Pass {
ConstmapPass() : Pass("constmap", "technology mapping of coarse constant value") { }
void help() override
{
log("\n");
log(" constmap [options] [selection]\n");
log("\n");
log("Map constants to a driver cell.\n");
log("\n");
log(" -cell <celltype> <portname> <paramname>\n");
log(" Replace constant bits with this cell.\n");
log(" The value of the constant will be stored to the parameter specified.\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
log_header(design, "Executing CONSTMAP pass (mapping to constant driver).\n");
size_t argidx;
for (argidx = 1; argidx < args.size(); argidx++)
{
if (args[argidx] == "-cell" && argidx+3 < args.size()){
celltype = RTLIL::escape_id(args[++argidx]);
cell_portname = RTLIL::escape_id(args[++argidx]);
cell_paramname = RTLIL::escape_id(args[++argidx]);
continue;
}
break;
}
extra_args(args, argidx, design);
if (design->has(celltype)) {
Module *existing = design->module(celltype);
bool has_port = false;
for (auto &p : existing->ports){
if (p == cell_portname){
has_port = true;
break;
}
}
if (!has_port)
log_cmd_error("Cell type '%s' does not have port '%s'.\n", celltype.c_str(), cell_portname.c_str());
bool has_param = false;
for (auto &p : existing->avail_parameters){
if (p == cell_paramname)
has_param = true;
}
if (!has_param)
log_cmd_error("Cell type '%s' does not have parameter '%s'.\n", celltype.c_str(), cell_paramname.c_str());
}
for (auto mod : design->selected_modules())
{
module = mod;
module->rewrite_sigspecs(constmap_worker);
}
}
} ConstmapPass;
PRIVATE_NAMESPACE_END

View file

@ -75,7 +75,7 @@ bool LibertyInputStream::extend_buffer_once()
buffer.resize(buf_end + chunk_size);
}
size_t read_size = f.rdbuf()->sgetn(buffer.data() + buf_end, chunk_size);
size_t read_size = f.rdbuf()->sgetn((char *)buffer.data() + buf_end, chunk_size);
buf_end += read_size;
if (read_size < chunk_size)
eof = true;
@ -417,7 +417,77 @@ int LibertyParser::lexer(std::string &str)
return c;
}
LibertyAst *LibertyParser::parse()
void LibertyParser::report_unexpected_token(int tok)
{
std::string eReport;
switch(tok)
{
case 'n':
error("Unexpected newline.");
break;
case '[':
case ']':
case '}':
case '{':
case '\"':
case ':':
eReport = "Unexpected '";
eReport += static_cast<char>(tok);
eReport += "'.";
error(eReport);
break;
case EOF:
error("Unexpected end of file");
break;
default:
eReport = "Unexpected token: ";
eReport += static_cast<char>(tok);
error(eReport);
}
}
// FIXME: the AST needs to be extended to store
// these vector ranges.
void LibertyParser::parse_vector_range(int tok)
{
// parse vector range [A] or [A:B]
std::string arg;
tok = lexer(arg);
if (tok != 'v')
{
// expected a vector array index
error("Expected a number.");
}
else
{
// fixme: check for number A
}
tok = lexer(arg);
// optionally check for : in case of [A:B]
// if it isn't we just expect ']'
// as we have [A]
if (tok == ':')
{
tok = lexer(arg);
if (tok != 'v')
{
// expected a vector array index
error("Expected a number.");
}
else
{
// fixme: check for number B
tok = lexer(arg);
}
}
// expect a closing bracket of array range
if (tok != ']')
{
error("Expected ']' on array range.");
}
}
LibertyAst *LibertyParser::parse(bool top_level)
{
std::string str;
@ -431,30 +501,17 @@ LibertyAst *LibertyParser::parse()
while ((tok == 'n') || (tok == ';'))
tok = lexer(str);
if (tok == '}' || tok < 0)
if (tok == EOF) {
if (top_level)
return NULL;
report_unexpected_token(tok);
}
if (tok == '}')
return NULL;
if (tok != 'v') {
std::string eReport;
switch(tok)
{
case 'n':
error("Unexpected newline.");
break;
case '[':
case ']':
case '}':
case '{':
case '\"':
case ':':
eReport = "Unexpected '";
eReport += static_cast<char>(tok);
eReport += "'.";
error(eReport);
break;
default:
error();
}
report_unexpected_token(tok);
}
LibertyAst *ast = new LibertyAst;
@ -472,7 +529,11 @@ LibertyAst *LibertyParser::parse()
if (tok == ':' && ast->value.empty()) {
tok = lexer(ast->value);
if (tok == 'v') {
tok = lexer(str);
tok = lexer(str);
if (tok == '[') {
parse_vector_range(tok);
tok = lexer(str);
}
}
while (tok == '+' || tok == '-' || tok == '*' || tok == '/' || tok == '!') {
ast->value += tok;
@ -503,67 +564,15 @@ LibertyAst *LibertyParser::parse()
if (tok == ')')
break;
// FIXME: the AST needs to be extended to store
// these vector ranges.
if (tok == '[')
{
// parse vector range [A] or [A:B]
std::string arg;
tok = lexer(arg);
if (tok != 'v')
{
// expected a vector array index
error("Expected a number.");
}
else
{
// fixme: check for number A
}
tok = lexer(arg);
// optionally check for : in case of [A:B]
// if it isn't we just expect ']'
// as we have [A]
if (tok == ':')
{
tok = lexer(arg);
if (tok != 'v')
{
// expected a vector array index
error("Expected a number.");
}
else
{
// fixme: check for number B
tok = lexer(arg);
}
}
// expect a closing bracket of array range
if (tok != ']')
{
error("Expected ']' on array range.");
}
parse_vector_range(tok);
continue;
}
if (tok == 'n')
continue;
if (tok != 'v') {
std::string eReport;
switch(tok)
{
case 'n':
continue;
case '[':
case ']':
case '}':
case '{':
case '\"':
case ':':
eReport = "Unexpected '";
eReport += static_cast<char>(tok);
eReport += "'.";
error(eReport);
break;
default:
error();
}
report_unexpected_token(tok);
}
ast->args.push_back(arg);
}
@ -571,16 +580,22 @@ LibertyAst *LibertyParser::parse()
}
if (tok == '{') {
bool terminated = false;
while (1) {
LibertyAst *child = parse();
if (child == NULL)
LibertyAst *child = parse(false);
if (child == NULL) {
terminated = true;
break;
}
ast->children.push_back(child);
}
if (!terminated) {
report_unexpected_token(EOF);
}
break;
}
error();
report_unexpected_token(tok);
}
return ast;

View file

@ -92,7 +92,7 @@ namespace Yosys
class LibertyInputStream {
std::istream &f;
std::vector<char> buffer;
std::vector<unsigned char> buffer;
size_t buf_pos = 0;
size_t buf_end = 0;
bool eof = false;
@ -107,7 +107,7 @@ namespace Yosys
LibertyInputStream(std::istream &f) : f(f) {}
size_t buffered_size() { return buf_end - buf_pos; }
const char *buffered_data() { return buffer.data() + buf_pos; }
const unsigned char *buffered_data() { return buffer.data() + buf_pos; }
int get() {
if (buf_pos == buf_end)
@ -163,7 +163,9 @@ namespace Yosys
*/
int lexer(std::string &str);
LibertyAst *parse();
void report_unexpected_token(int tok);
void parse_vector_range(int tok);
LibertyAst *parse(bool top_level);
void error() const;
void error(const std::string &str) const;
@ -172,18 +174,29 @@ namespace Yosys
const LibertyAst *ast = nullptr;
LibertyParser(std::istream &f) : f(f), line(1) {
shared_ast.reset(parse());
shared_ast.reset(parse(true));
ast = shared_ast.get();
if (!ast) {
#ifdef FILTERLIB
fprintf(stderr, "No entries found in liberty file.\n");
exit(1);
#else
log_error("No entries found in liberty file.\n");
#endif
}
}
#ifndef FILTERLIB
LibertyParser(std::istream &f, const std::string &fname) : f(f), line(1) {
shared_ast = LibertyAstCache::instance.cached_ast(fname);
if (!shared_ast) {
shared_ast.reset(parse());
shared_ast.reset(parse(true));
LibertyAstCache::instance.parsed_ast(fname, shared_ast);
}
ast = shared_ast.get();
if (!ast) {
log_error("No entries found in liberty file `%s'.\n", fname.c_str());
}
}
#endif
};

View file

@ -278,42 +278,42 @@ void maccmap(RTLIL::Module *module, RTLIL::Cell *cell, bool unmap)
return;
}
for (auto &port : macc.ports)
if (GetSize(port.in_b) == 0)
log(" %s %s (%d bits, %s)\n", port.do_subtract ? "sub" : "add", log_signal(port.in_a),
GetSize(port.in_a), port.is_signed ? "signed" : "unsigned");
for (auto &term : macc.terms)
if (GetSize(term.in_b) == 0)
log(" %s %s (%d bits, %s)\n", term.do_subtract ? "sub" : "add", log_signal(term.in_a),
GetSize(term.in_a), term.is_signed ? "signed" : "unsigned");
else
log(" %s %s * %s (%dx%d bits, %s)\n", port.do_subtract ? "sub" : "add", log_signal(port.in_a), log_signal(port.in_b),
GetSize(port.in_a), GetSize(port.in_b), port.is_signed ? "signed" : "unsigned");
log(" %s %s * %s (%dx%d bits, %s)\n", term.do_subtract ? "sub" : "add", log_signal(term.in_a), log_signal(term.in_b),
GetSize(term.in_a), GetSize(term.in_b), term.is_signed ? "signed" : "unsigned");
if (unmap)
{
typedef std::pair<RTLIL::SigSpec, bool> summand_t;
std::vector<summand_t> summands;
RTLIL::SigSpec bit_ports;
RTLIL::SigSpec bit_terms;
for (auto &port : macc.ports) {
for (auto &term : macc.terms) {
summand_t this_summand;
if (GetSize(port.in_b)) {
if (GetSize(term.in_b)) {
this_summand.first = module->addWire(NEW_ID, width);
module->addMul(NEW_ID, port.in_a, port.in_b, this_summand.first, port.is_signed);
} else if (GetSize(port.in_a) == 1 && GetSize(port.in_b) == 0 && !port.is_signed && !port.do_subtract) {
// Mimic old 'bit_ports' treatment in case it's relevant for performance,
module->addMul(NEW_ID, term.in_a, term.in_b, this_summand.first, term.is_signed);
} else if (GetSize(term.in_a) == 1 && GetSize(term.in_b) == 0 && !term.is_signed && !term.do_subtract) {
// Mimic old 'bit_terms' treatment in case it's relevant for performance,
// i.e. defer single-bit summands to be the last ones
bit_ports.append(port.in_a);
bit_terms.append(term.in_a);
continue;
} else if (GetSize(port.in_a) != width) {
} else if (GetSize(term.in_a) != width) {
this_summand.first = module->addWire(NEW_ID, width);
module->addPos(NEW_ID, port.in_a, this_summand.first, port.is_signed);
module->addPos(NEW_ID, term.in_a, this_summand.first, term.is_signed);
} else {
this_summand.first = port.in_a;
this_summand.first = term.in_a;
}
this_summand.second = port.do_subtract;
this_summand.second = term.do_subtract;
summands.push_back(this_summand);
}
for (auto &bit : bit_ports)
for (auto &bit : bit_terms)
summands.push_back(summand_t(bit, false));
if (GetSize(summands) == 0)
@ -350,20 +350,20 @@ void maccmap(RTLIL::Module *module, RTLIL::Cell *cell, bool unmap)
else
{
MaccmapWorker worker(module, width);
RTLIL::SigSpec bit_ports;
RTLIL::SigSpec bit_terms;
for (auto &port : macc.ports) {
// Mimic old 'bit_ports' treatment in case it's relevant for performance,
for (auto &term : macc.terms) {
// Mimic old 'bit_terms' treatment in case it's relevant for performance,
// i.e. defer single-bit summands to be the last ones
if (GetSize(port.in_a) == 1 && GetSize(port.in_b) == 0 && !port.is_signed && !port.do_subtract)
bit_ports.append(port.in_a);
else if (GetSize(port.in_b) == 0)
worker.add(port.in_a, port.is_signed, port.do_subtract);
if (GetSize(term.in_a) == 1 && GetSize(term.in_b) == 0 && !term.is_signed && !term.do_subtract)
bit_terms.append(term.in_a);
else if (GetSize(term.in_b) == 0)
worker.add(term.in_a, term.is_signed, term.do_subtract);
else
worker.add(port.in_a, port.in_b, port.is_signed, port.do_subtract);
worker.add(term.in_a, term.in_b, term.is_signed, term.do_subtract);
}
for (auto bit : bit_ports)
for (auto bit : bit_terms)
worker.add(bit, 0);
module->connect(cell->getPort(ID::Y), worker.synth());

View file

@ -42,7 +42,7 @@ struct NlutmapWorker
RTLIL::Selection get_selection()
{
RTLIL::Selection sel(false);
auto sel = RTLIL::Selection::EmptySelection(module->design);
for (auto cell : module->cells())
if (!mapped_cells.count(cell))
sel.select(module, cell);

View file

@ -189,17 +189,17 @@ static RTLIL::Cell* create_gold_module(RTLIL::Design *design, RTLIL::IdString ce
} else
size_b = 0;
Macc::port_t this_port;
Macc::term_t this_term;
wire_a->width += size_a;
this_port.in_a = RTLIL::SigSpec(wire_a, wire_a->width - size_a, size_a);
this_term.in_a = RTLIL::SigSpec(wire_a, wire_a->width - size_a, size_a);
wire_a->width += size_b;
this_port.in_b = RTLIL::SigSpec(wire_a, wire_a->width - size_b, size_b);
this_term.in_b = RTLIL::SigSpec(wire_a, wire_a->width - size_b, size_b);
this_port.is_signed = xorshift32(2) == 1;
this_port.do_subtract = xorshift32(2) == 1;
macc.ports.push_back(this_port);
this_term.is_signed = xorshift32(2) == 1;
this_term.do_subtract = xorshift32(2) == 1;
macc.terms.push_back(this_term);
}
// Macc::to_cell sets the input ports
macc.to_cell(cell);

View file

@ -40,8 +40,6 @@ class libyosys_so_ext(Extension):
)
self.args = [
"ENABLE_PYOSYS=1",
# Wheel meant to be imported from interpreter
"ENABLE_PYTHON_CONFIG_EMBED=0",
# Would need to be installed separately by the user
"ENABLE_TCL=0",
"ENABLE_READLINE=0",
@ -87,9 +85,6 @@ class libyosys_so_ext(Extension):
shutil.copytree("share", share_target)
# I don't know how debug info is getting here.
class custom_build_ext(build_ext):
def build_extension(self, ext) -> None:
if not hasattr(ext, "custom_build"):

View file

@ -1,4 +1,5 @@
logger -nowarn "Yosys has only limited support for tri-state logic at the moment\. .*"
logger -nowarn "Ignoring boxed module .*\."
read_verilog <<EOT
module top(input C, D, output [7:0] Q);

View file

@ -1,4 +1,5 @@
logger -nowarn "Yosys has only limited support for tri-state logic at the moment\. .*"
logger -nowarn "Ignoring boxed module .*\."
read_verilog <<EOT
module top(input [24:0] A, input [17:0] B, output [47:0] P);

View file

@ -13,5 +13,5 @@ run_subtest value
run_subtest value_fuzz
# Compile-only test.
../../yosys -p "read_verilog test_unconnected_output.v; proc; clean; write_cxxrtl cxxrtl-test-unconnected_output.cc"
../../yosys -p "read_verilog test_unconnected_output.v; select =*; proc; clean; write_cxxrtl cxxrtl-test-unconnected_output.cc"
${CC:-gcc} -std=c++11 -c -o cxxrtl-test-unconnected_output -I../../backends/cxxrtl/runtime cxxrtl-test-unconnected_output.cc

View file

@ -9,7 +9,7 @@ library(ls05_stdcells) {
}
pin(Y) {
direction : output ;
function : !(B&!A|!B&A) ;
function : "!(B&!A|!B&A)" ;
}
}
}

View file

@ -2,5 +2,5 @@ module XNOR2X1 (B, A, Y);
input B;
input A;
output Y;
assign Y = !(B&!A|!B&A); // !(B&!A|!B&A)
assign Y = !(B&!A|!B&A); // "!(B&!A|!B&A)"
endmodule

View file

@ -0,0 +1,6 @@
library("foobar") {
pin("foo") {
bar : baz[0] ;
}
}

View file

@ -0,0 +1,2 @@
library("foobar") {
}

View file

View file

@ -0,0 +1,14 @@
// The parser used to choke on the copyright symbol even in comments
// © ® ø Φ
library(dummy) {
cell(buffer) {
area : 1 ;
pin(A) {
direction : input ;
}
pin(Y) {
direction : output ;
function : "A" ;
}
}
}

View file

@ -0,0 +1,12 @@
library(dummy) {
cell(buffer) {
area : 1 ;
pin(A) {
direction : input ;
}
pin(Y) {
direction : output ;
function : "A" ;
}
}
}

View file

@ -0,0 +1,5 @@
module buffer (A, Y);
input A;
output Y;
assign Y = A; // "A"
endmodule

View file

@ -6,7 +6,7 @@ library(supergate) {
}
pin(Y) {
direction : output ;
function : A' ;
function : "A'" ;
}
}
cell(tri_inv) {
@ -19,7 +19,7 @@ library(supergate) {
}
pin(Z) {
direction : output ;
function : A' ;
function : "A'" ;
}
}
cell(buffer) {
@ -29,7 +29,7 @@ library(supergate) {
}
pin(Y) {
direction : output ;
function : A ;
function : "A" ;
}
}
cell(nand2) {
@ -42,7 +42,7 @@ library(supergate) {
}
pin(Y) {
direction : output ;
function : (A * B)' ;
function : "(A * B)'" ;
}
}
cell(nor2) {
@ -55,7 +55,7 @@ library(supergate) {
}
pin(Y) {
direction : output ;
function : (A + B)' ;
function : "(A + B)'" ;
}
}
cell(xor2) {
@ -68,7 +68,7 @@ library(supergate) {
}
pin(Y) {
direction : output ;
function : (A *B') + (A' * B) ;
function : "(A *B') + (A' * B)" ;
}
}
cell(imux2) {
@ -84,16 +84,16 @@ library(supergate) {
}
pin(Y) {
direction : output ;
function : ( (A * S) + (B * S') )' ;
function : "( (A * S) + (B * S') )'" ;
}
}
cell(dff) {
area : 6 ;
ff(IQ, IQN) {
next_state : D ;
clocked_on : CLK ;
clear : RESET ;
preset : PRESET ;
ff("IQ", "IQN") {
next_state : "D" ;
clocked_on : "CLK" ;
clear : "RESET" ;
preset : "PRESET" ;
clear_preset_var1 : L ;
clear_preset_var2 : L ;
}
@ -111,18 +111,18 @@ library(supergate) {
}
pin(Q) {
direction : output ;
function : IQ ;
function : "IQ" ;
}
pin(QN) {
direction : output ;
function : IQN ;
function : "IQN" ;
}
}
cell(latch) {
area : 5 ;
latch(IQ, IQN) {
enable : G ;
data_in : D ;
latch("IQ", "IQN") {
enable : "G" ;
data_in : "D" ;
}
pin(D) {
direction : input ;
@ -132,11 +132,11 @@ library(supergate) {
}
pin(Q) {
direction : output ;
function : IQ ;
function : "IQ" ;
}
pin(QN) {
direction : output ;
function : IQN ;
function : "IQN" ;
}
}
cell(aoi211) {
@ -152,7 +152,7 @@ library(supergate) {
}
pin(Y) {
direction : output ;
function : ((A * B) + C)' ;
function : "((A * B) + C)'" ;
}
}
cell(oai211) {
@ -168,7 +168,7 @@ library(supergate) {
}
pin(Y) {
direction : output ;
function : ((A + B) * C)' ;
function : "((A + B) * C)'" ;
}
}
cell(halfadder) {
@ -181,11 +181,11 @@ library(supergate) {
}
pin(C) {
direction : output ;
function : (A * B) ;
function : "(A * B)" ;
}
pin(Y) {
direction : output ;
function : (A *B') + (A' * B) ;
function : "(A *B') + (A' * B)" ;
}
}
cell(fulladder) {
@ -201,11 +201,11 @@ library(supergate) {
}
pin(CO) {
direction : output ;
function : (((A * B)+(B * CI))+(CI * A)) ;
function : "(((A * B)+(B * CI))+(CI * A))" ;
}
pin(Y) {
direction : output ;
function : ((A^B)^CI) ;
function : "((A^B)^CI)" ;
}
}
}

View file

@ -1,86 +1,86 @@
module inv (A, Y);
input A;
output Y;
assign Y = ~A; // A'
assign Y = ~A; // "A'"
endmodule
module tri_inv (A, S, Z);
input A;
input S;
output Z;
assign Z = ~A; // A'
assign Z = ~A; // "A'"
endmodule
module buffer (A, Y);
input A;
output Y;
assign Y = A; // A
assign Y = A; // "A"
endmodule
module nand2 (A, B, Y);
input A;
input B;
output Y;
assign Y = ~(A&B); // (A * B)'
assign Y = ~(A&B); // "(A * B)'"
endmodule
module nor2 (A, B, Y);
input A;
input B;
output Y;
assign Y = ~(A|B); // (A + B)'
assign Y = ~(A|B); // "(A + B)'"
endmodule
module xor2 (A, B, Y);
input A;
input B;
output Y;
assign Y = (A&~B)|(~A&B); // (A *B') + (A' * B)
assign Y = (A&~B)|(~A&B); // "(A *B') + (A' * B)"
endmodule
module imux2 (A, B, S, Y);
input A;
input B;
input S;
output Y;
assign Y = ~(&(A&S)|(B&~S)&); // ( (A * S) + (B * S') )'
assign Y = ~(&(A&S)|(B&~S)&); // "( (A * S) + (B * S') )'"
endmodule
module dff (D, CLK, RESET, PRESET, Q, QN);
reg IQ, IQN;
reg "IQ", "IQN";
input D;
input CLK;
input RESET;
input PRESET;
output Q;
assign Q = IQ; // IQ
assign Q = IQ; // "IQ"
output QN;
assign QN = IQN; // IQN
assign QN = IQN; // "IQN"
always @(posedge CLK, posedge RESET, posedge PRESET) begin
if ((RESET) && (PRESET)) begin
IQ <= 0;
IQN <= 0;
"IQ" <= 0;
"IQN" <= 0;
end
else if (RESET) begin
IQ <= 0;
IQN <= 1;
"IQ" <= 0;
"IQN" <= 1;
end
else if (PRESET) begin
IQ <= 1;
IQN <= 0;
"IQ" <= 1;
"IQN" <= 0;
end
else begin
// D
IQ <= D;
IQN <= ~(D);
// "D"
"IQ" <= D;
"IQN" <= ~(D);
end
end
endmodule
module latch (D, G, Q, QN);
reg IQ, IQN;
reg "IQ", "IQN";
input D;
input G;
output Q;
assign Q = IQ; // IQ
assign Q = IQ; // "IQ"
output QN;
assign QN = IQN; // IQN
assign QN = IQN; // "IQN"
always @* begin
if (G) begin
IQ <= D;
IQN <= ~(D);
"IQ" <= D;
"IQN" <= ~(D);
end
end
endmodule
@ -89,29 +89,29 @@ module aoi211 (A, B, C, Y);
input B;
input C;
output Y;
assign Y = ~((A&B)|C); // ((A * B) + C)'
assign Y = ~((A&B)|C); // "((A * B) + C)'"
endmodule
module oai211 (A, B, C, Y);
input A;
input B;
input C;
output Y;
assign Y = ~((A|B)&C); // ((A + B) * C)'
assign Y = ~((A|B)&C); // "((A + B) * C)'"
endmodule
module halfadder (A, B, C, Y);
input A;
input B;
output C;
assign C = (A&B); // (A * B)
assign C = (A&B); // "(A * B)"
output Y;
assign Y = (A&~B)|(~A&B); // (A *B') + (A' * B)
assign Y = (A&~B)|(~A&B); // "(A *B') + (A' * B)"
endmodule
module fulladder (A, B, CI, CO, Y);
input A;
input B;
input CI;
output CO;
assign CO = (((A&B)|(B&CI))|(CI&A)); // (((A * B)+(B * CI))+(CI * A))
assign CO = (((A&B)|(B&CI))|(CI&A)); // "(((A * B)+(B * CI))+(CI * A))"
output Y;
assign Y = ((A^B)^CI); // ((A^B)^CI)
assign Y = ((A^B)^CI); // "((A^B)^CI)"
endmodule

View file

@ -7,9 +7,10 @@ for x in *.lib; do
../../yosys-filterlib - $x 2>/dev/null > $x.filtered
../../yosys-filterlib -verilogsim $x > $x.verilogsim
diff $x.filtered $x.filtered.ok && diff $x.verilogsim $x.verilogsim.ok
done
done || exit 1
for x in *.ys; do
echo "Running $x.."
../../yosys -q -s $x -l ${x%.ys}.log
done
done || exit 1

View file

@ -10,8 +10,8 @@ library(supergate) {
clock : true ;
}
ff(IQ, IQN) {
clocked_on : CK ;
next_state : D ;
clocked_on : "CK" ;
next_state : "D" ;
}
pin(Q) {
direction : output ;

View file

@ -4,7 +4,7 @@ module DFF (D, CK, Q);
input CK;
output Q;
always @(posedge CK) begin
// D
// "D"
IQ <= D;
IQN <= ~(D);
end

View file

@ -12,11 +12,11 @@ library(supergate) {
}
pin(CO) {
direction : output ;
function : (((A * B)+(B * CI))+(CI * A)) ;
function : "(((A * B)+(B * CI))+(CI * A))" ;
}
pin(Y) {
direction : output ;
function : ((A^B)^CI) ;
function : "((A^B)^CI)" ;
}
}
}

View file

@ -3,7 +3,7 @@ module fulladder (A, B, CI, CO, Y);
input B;
input CI;
output CO;
assign CO = (((A&B)|(B&CI))|(CI&A)); // (((A * B)+(B * CI))+(CI * A))
assign CO = (((A&B)|(B&CI))|(CI&A)); // "(((A * B)+(B * CI))+(CI * A))"
output Y;
assign Y = ((A^B)^CI); // ((A^B)^CI)
assign Y = ((A^B)^CI); // "((A^B)^CI)"
endmodule

View file

@ -30,3 +30,26 @@ module test_2(
end
endmodule
module test_3(
input [3:0] s,
input [7:0] a, b, c,
output reg [7:0] y0,
output reg [7:0] y1,
output reg [7:0] y2,
output reg [7:0] y3,
);
wire is_onehot = s & (s - 1);
always @* begin
y0 <= 0;
y1 <= 0;
y2 <= 0;
y3 <= 0;
if (s < 3) y0 <= b / c;
if (3 <= s && s < 6) y1 <= c / b;
if (6 <= s && s < 9) y2 <= a / b;
if (9 <= s && s < 12) y3 <= b / a;
end
endmodule

View file

@ -3,11 +3,13 @@ proc;;
copy test_1 gold_1
copy test_2 gold_2
share test_1 test_2;;
copy test_3 gold_3
share test_1 test_2 test_3;;
select -assert-count 1 test_1/t:$mul
select -assert-count 1 test_2/t:$mul
select -assert-count 1 test_2/t:$div
select -assert-count 1 test_3/t:$div
miter -equiv -flatten -make_outputs -make_outcmp gold_1 test_1 miter_1
sat -verify -prove trigger 0 -show-inputs -show-outputs miter_1
@ -15,3 +17,5 @@ sat -verify -prove trigger 0 -show-inputs -show-outputs miter_1
miter -equiv -flatten -make_outputs -make_outcmp gold_2 test_2 miter_2
sat -verify -prove trigger 0 -show-inputs -show-outputs miter_2
miter -equiv -flatten -make_outputs -make_outcmp gold_3 test_3 miter_3
sat -verify -prove trigger 0 -show-inputs -show-outputs miter_3

View file

@ -1,4 +1,3 @@
read_verilog -specify <<EOT
module top(input a, b, output o);
assign o = a & b;
endmodule
@ -15,14 +14,3 @@ endmodule
module wb(input a, b, output o);
assign o = a ^ b;
endmodule
EOT
clean
select -assert-count 1 c:*
select -assert-none t:* t:$and %d
select -assert-count 3 w:*
select -assert-count 4 *
select -assert-count 3 =c:*
select -assert-count 10 =w:*
select -assert-count 13 =*

View file

@ -0,0 +1,7 @@
read_verilog -specify boxes.v
clean
select -set top top
select -assert-count 4 @top
select -set boxes =?b
select -assert-count 9 @boxes

View file

@ -0,0 +1,38 @@
read_verilog -specify boxes.v
clean
# wb = 4w1c, bb = 3w1c, top = 3w1c
select =wb
select -assert-count 5 %
select -add =bb
select -assert-count 9 %
select -del =wb
select -assert-count 4 %
# unions
select -assert-count 8 =bb * %u
select -assert-count 8 * =bb %u
select -assert-count 13 top =* %u
select -assert-count 8 =bb top %u
select -assert-count 8 top =bb %u
# intersections
select -assert-count 3 =w:* =bb %i
select -assert-count 4 =* * %i
select -assert-count 4 * =* %i
# inverses
select -assert-count 8 =wb %n
select -assert-none top %n
select -assert-none * %n
select -assert-none =* %n
select -assert-count 9 =top %n
# differences
select -assert-count 9 =* top %d
select -assert-count 0 top =* %d
select -assert-count 9 =* * %d
select -assert-count 0 * =* %d
# random
select -assert-any =?b %R

View file

@ -0,0 +1,7 @@
read_verilog -specify boxes.v
clean
select -assert-none ?b
select -assert-count 4 =bb
select -assert-count 5 =wb
select -assert-count 9 =?b

View file

@ -0,0 +1,6 @@
read_verilog -specify boxes.v
clean
select -assert-count 3 =c:*
select -assert-count 10 =w:*
select -assert-count 13 =*

View file

@ -0,0 +1,29 @@
read_verilog -specify boxes.v
design -save read
logger -expect-no-warnings
delete =bb %n
select -assert-mod-count 1 =*
design -stash just_bb
design -import just_bb
select -assert-mod-count 0 *
select -assert-mod-count 1 =*
design -reset
design -import just_bb -as new
select -assert-mod-count 0 *
select -assert-mod-count 1 =*
design -reset
design -import read -as new_top top
design -import read -as new_bb =bb
select -assert-mod-count 1 *
select -assert-mod-count 2 =*
logger -check-expected
logger -expect warning "Selection .wb. did not match any module\." 1
logger -expect error "No top module found in source design\." 1
design -import read -as new_wb wb

View file

@ -0,0 +1,7 @@
read_verilog -specify boxes.v
clean
select -assert-count 1 c:*
select -assert-none t:* t:$and %d
select -assert-count 3 w:*
select -assert-count 4 *

View file

@ -0,0 +1,18 @@
read_verilog -specify boxes.v
logger -expect warning "did not match any module" 2
clean wb
opt_clean wb
logger -check-expected
select -clear
logger -expect warning "did not match any module" 2
clean wb
opt_clean wb
logger -check-expected
select -none
logger -expect warning "did not match any module" 2
clean wb
opt_clean wb
logger -check-expected

View file

@ -0,0 +1,39 @@
read_verilog -specify boxes.v
design -save read
select -assert-none =a:test_attr
select -assert-none =A:test_attr
# setattr =* affects all modules
setattr -set test_attr 1 =*
select -assert-mod-count 3 =a:test_attr
select -assert-none =A:test_attr
design -load read
setattr -mod -set test_attr 1 =*
select -assert-none =a:test_attr
select -assert-mod-count 3 =A:test_attr
# setattr * doesn't affect boxed modules
design -load read
setattr -mod -set test_attr 1 *
select -assert-mod-count 1 =A:test_attr
# setattr can set and unset whitebox attr
design -load read
setattr -mod -unset whitebox =wb
select -assert-mod-count 2 *
setattr -mod -set whitebox 1 wb
select -assert-mod-count 1 *
# wbflip works on all non-bb in selection
design -load read
select -assert-mod-count 1 =A:whitebox
wbflip
select -assert-mod-count 2 =A:whitebox
wbflip
select -assert-mod-count 2 =A:whitebox
wbflip =wb
select -assert-mod-count 1 =A:whitebox
wbflip =bb
select -assert-mod-count 1 =A:whitebox

View file

@ -0,0 +1,29 @@
read_verilog -specify boxes.v
clean
# default selection == select *
select -assert-count 4 *
select -assert-count 4 %
# -none replaces default selection
select -none
select -assert-none %
select -assert-count 13 =*
# select replaces current selection
select =*
select -assert-count 13 %
# -module changes module
select -module wb
select -assert-none %
select -assert-count 5 =*
# -none maintains module
select -none
select -assert-count 5 =*
# -clear clears current selection and module
select -clear
select -assert-count 4 %
select -assert-count 13 =*

View file

@ -0,0 +1,165 @@
read_verilog boxes.v
## base case, no warnings ##
logger -expect-no-warnings
select =*
select -assert-count 13 %
select -assert-mod-count 3 %
test_select # SELECT_ALL && SB_ALL
select -assert-count 13 %
select -assert-mod-count 3 %
select =*
select -assert-mod-count 3 %
test_select -whole_only # SELECT_WHOLE_ONLY
select -assert-mod-count 3 %
select =*
select -assert-count 13 %
test_select -unboxed_only -include_wb # SB_EXCL_BB_ONLY
select -assert-count 10 %
select =*
select -assert-count 13 %
test_select -unboxed_only # SB_UNBOXED_ONLY
select -assert-count 5 %
logger -check-expected
## don't add to selection ##
select *
select -assert-count 5 %
select -assert-mod-count 1 %
test_select # SELECT_ALL && SB_ALL
select -assert-count 5 %
select -assert-mod-count 1 %
select =wb/a %n
select -assert-mod-count 3 %
test_select -whole_only # SELECT_WHOLE_ONLY
select -assert-mod-count 2 %
select =w:*
select -assert-mod-count 3 %
test_select -whole_only # SELECT_WHOLE_ONLY
select -assert-mod-count 1 %
select =w:*
select -assert-mod-count 3 %
test_select -whole_only -unboxed_only # SELECT_WHOLE_ONLY && SB_UNBOXED_ONLY
select -assert-none %
select =w:* %n
select -assert-mod-count 2 %
test_select -whole_only # SELECT_WHOLE_ONLY
select -assert-none %
select =?b
select -assert-count 8 %
test_select -unboxed_only -include_wb # SB_EXCL_BB_ONLY
select -assert-count 5 %
select =?b
select -assert-count 8 %
test_select -unboxed_only # SB_UNBOXED_ONLY
select -assert-none %
select =wb %n
select -assert-count 8 %
test_select -unboxed_only -include_wb # SB_EXCL_BB_ONLY
select -assert-count 5 %
select =top/a %n
select -assert-count 12 %
select -assert-mod-count 3 %
test_select -whole_only -unboxed_only -include_wb # SELECT_WHOLE_ONLY && SB_EXCL_BB_ONLY
select -assert-count 5 %
select -assert-mod-count 1 %
## warnings work ##
logger -expect warning "Ignoring blackbox module bb." 1
select =*
test_select -unboxed_only -include_wb -warn_boxes # SB_EXCL_BB_WARN
logger -check-expected
logger -expect warning "Ignoring boxed module .b." 2
select =*
test_select -unboxed_only -warn_boxes # SB_UNBOXED_WARN
logger -check-expected
logger -expect warning "Ignoring partially selected module [wb|top]." 2
select =w:*
test_select -whole_warn # SELECT_WHOLE_WARN
logger -check-expected
logger -expect warning "Ignoring partially selected module [wb|top]." 2
logger -expect warning "Ignoring blackbox module bb." 1
select =w:*
test_select -whole_warn -unboxed_only -include_wb -warn_boxes # SELECT_WHOLE_WARN && SB_EXCL_BB_WARN
logger -check-expected
logger -expect warning "Ignoring partially selected module [wb|top]." 2
logger -expect warning "Ignoring boxed module bb." 1
select =w:*
test_select -whole_warn -unboxed_only -warn_boxes # SELECT_WHOLE_WARN && SB_UNBOXED_WARN
logger -check-expected
## partials warn before boxes ##
logger -expect warning "Ignoring partially selected module wb." 1
select =wb/a
test_select -whole_warn -unboxed_only -warn_boxes # SELECT_WHOLE_WARN && SB_UNBOXED_WARN
logger -check-expected
## boxes won't warn if they've been removed because of partial selection ##
logger -expect-no-warnings
select =wb/a
test_select -whole_only -unboxed_only -warn_boxes # SELECT_WHOLE_ONLY && SB_UNBOXED_WARN
logger -check-expected
## boxes still warn if they're not partially selected
logger -expect warning "Ignoring boxed module wb." 1
select =bb %n
test_select -whole_only -unboxed_only -warn_boxes # SELECT_WHOLE_ONLY && SB_UNBOXED_WARN
logger -check-expected
## don't warn if it's not selected ##
logger -expect-no-warnings
select =bb %n
test_select -unboxed_only -include_wb -warn_boxes # SB_EXCL_BB_WARN
logger -check-expected
logger -expect-no-warnings
select *
test_select -unboxed_only -warn_boxes # SB_UNBOXED_WARN
logger -check-expected
logger -expect warning "Ignoring boxed module bb." 1
select =wb %n
test_select -unboxed_only -warn_boxes # SB_UNBOXED_WARN
logger -check-expected
## don't error if it's not selected ##
logger -expect-no-warnings
select =bb %n
test_select -unboxed_only -include_wb -err_boxes # SB_EXCL_BB_ERR
select =bb %n
test_select -unboxed_only -include_wb -cmderr_boxes # SB_EXCL_BB_CMDERR
select *
test_select -unboxed_only -err_boxes # SB_UNBOXED_ERR
select *
test_select -unboxed_only -cmderr_boxes # SB_UNBOXED_CMDERR
select *
test_select -whole_err # SELECT_WHOLE_ERR
select *
test_select -whole_cmderr # SELECT_WHOLE_CMDERR
logger -check-expected
##

View file

@ -49,6 +49,6 @@ exec ${MAKE:-make} -f ../tools/autotest.mk $seed *.v *.sv EXTRA_FLAGS="-f \"veri
clean; \
check -assert * abc9_test037 %d; \
select -assert-none t:${DOLLAR}_NOT_ t:${DOLLAR}_AND_ %%; \
setattr -mod -unset blackbox -unset whitebox'"
setattr -mod -unset blackbox -unset whitebox =*'"
# NOTE: Skip 'check -assert' on abc9_test037 because it intentionally has a combinatorial loop

43
tests/techmap/constmap.ys Normal file
View file

@ -0,0 +1,43 @@
read_verilog << EOT
module test();
wire [31:0] in;
wire [31:0] out;
assign out = in + 16;
endmodule
EOT
constmap -cell const_cell O value
select -assert-count 1 t:const_cell r:value=16 %i
design -reset
read_verilog -lib << EOT
module const_cell(O);
parameter value=0;
output O;
endmodule
EOT
read_verilog << EOT
module test();
wire [31:0] in;
wire [31:0] out1;
wire [31:0] out2;
assign out1 = in + 16;
assign out2 = in + 32;
endmodule
EOT
constmap -cell const_cell O value
select -assert-count 2 t:const_cell
select -assert-count 1 r:value=16
select -assert-count 1 r:value=32
select -assert-count 1 test/out1 %ci* r:value=16 %i
select -assert-count 1 test/out2 %ci* r:value=32 %i
select -assert-count 1 t:const_cell r:value=16 %i
select -assert-count 1 t:const_cell r:value=32 %i

View file

@ -1,5 +1,6 @@
/*.log
/*.out
/*.sel
/write_gzip.v
/write_gzip.v.gz
/run-test.mk

View file

@ -0,0 +1,72 @@
read_verilog -specify << EOT
module top(input a, b, output o);
wire c, d, e;
bb #(.SOME_PARAM(1)) bb1 (.a (a), .b (b), .o (c));
bb #(.SOME_PARAM(2)) bb2 (.a (a), .b (b), .o (d));
wb wb1 (.a (a), .b (b), .o (e));
some_mod some_inst (.a (c), .b (d), .c (e), .o (o));
endmodule
(* blackbox *)
module bb #( parameter SOME_PARAM=0 ) (input a, b, output o);
assign o = a | b;
specify
(a => o) = 1;
endspecify
endmodule
(* whitebox *)
module wb(input a, b, output o);
assign o = a ^ b;
endmodule
module some_mod(input a, b, c, output o);
assign o = a & (b | c);
endmodule
EOT
hierarchy -top top
design -save hier
select -assert-none t:$anyseq
select -assert-count 3 =t:?b
cutpoint -blackbox
select -assert-none =t:?b
select -assert-none r:SOME_PARAM
select -assert-count 3 t:$anyseq
select -assert-count 3 t:$scopeinfo
select -assert-count 3 t:$scopeinfo r:TYPE=blackbox %i
select -assert-count 3 t:$scopeinfo n:*cutpoint.cc* %i
# -noscopeinfo works with -blackbox
design -load hier
cutpoint -blackbox -noscopeinfo
select -assert-none t:$scopeinfo
# cutpoint -blackbox === cutpoint =A:whitebox =A:blackbox %u %C
# (simplified to =A:*box %C)
design -load hier
cutpoint -blackbox
rename -enumerate -pattern A_% t:$scopeinfo
rename -enumerate -pattern B_% t:$anyseq
rename -enumerate -pattern C_% w:*Anyseq*
design -save gold
select -write cutpoint.gold.sel =*
design -load hier
cutpoint =A:*box %C
rename -enumerate -pattern A_% t:$scopeinfo
rename -enumerate -pattern B_% t:$anyseq
rename -enumerate -pattern C_% w:*Anyseq*
design -save gate
select -write cutpoint.gate.sel
select -read cutpoint.gold.sel
# nothing in gate but not gold
select -assert-none % %n
design -load gold
select -read cutpoint.gate.sel
# nothing in gold but not gate
select -assert-none % %n