From e609a59325e2539e534fe8ad86edec067b9f8192 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Thu, 12 Dec 2024 15:59:16 +1300 Subject: [PATCH 01/44] CI: Fixes from zizmor > A static analysis tool for Github Actions https://github.com/woodruffw/zizmor Mostly means adding `persist-credentials: false` to checkouts and replacing `{{ env.VARNAME }}` with shell substitution. --- .github/workflows/codeql.yml | 4 +++- .github/workflows/extra-builds.yml | 7 +++++-- .github/workflows/prepare-docs.yml | 8 ++++---- .github/workflows/source-vendor.yml | 1 + .github/workflows/test-build.yml | 14 ++++++++++---- .github/workflows/test-compile.yml | 1 + .github/workflows/test-verific.yml | 5 +++-- .github/workflows/update-flake-lock.yml | 2 ++ .github/workflows/version.yml | 1 + .github/workflows/wheels.yml | 1 + 10 files changed, 31 insertions(+), 13 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 24ae7c898..75d799fe1 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -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: diff --git a/.github/workflows/extra-builds.yml b/.github/workflows/extra-builds.yml index 1a00d0163..0c3146e41 100644 --- a/.github/workflows/extra-builds.yml +++ b/.github/workflows/extra-builds.yml @@ -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 diff --git a/.github/workflows/prepare-docs.yml b/.github/workflows/prepare-docs.yml index 79dfb7912..fb1fab426 100644 --- a/.github/workflows/prepare-docs.yml +++ b/.github/workflows/prepare-docs.yml @@ -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' }} diff --git a/.github/workflows/source-vendor.yml b/.github/workflows/source-vendor.yml index 4dddb9a20..dc9480ef6 100644 --- a/.github/workflows/source-vendor.yml +++ b/.github/workflows/source-vendor.yml @@ -10,6 +10,7 @@ jobs: uses: actions/checkout@v4 with: submodules: 'recursive' + persist-credentials: false - name: Create clean tarball run: | diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml index 95af300c9..ef8d0e09d 100644 --- a/.github/workflows/test-build.yml +++ b/.github/workflows/test-build.yml @@ -46,6 +46,7 @@ jobs: uses: actions/checkout@v4 with: submodules: true + persist-credentials: false - name: Setup environment uses: ./.github/actions/setup-build-env @@ -89,6 +90,8 @@ jobs: steps: - name: Checkout Yosys uses: actions/checkout@v4 + with: + persist-credentials: false - name: Setup environment uses: ./.github/actions/setup-build-env @@ -115,7 +118,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' @@ -167,6 +170,8 @@ jobs: steps: - name: Checkout Yosys uses: actions/checkout@v4 + with: + persist-credentials: false - name: Setup environment uses: ./.github/actions/setup-build-env @@ -188,7 +193,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 @@ -204,6 +209,7 @@ jobs: uses: actions/checkout@v4 with: submodules: true + persist-credentials: false - name: Runtime environment run: | @@ -213,7 +219,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 @@ -223,7 +229,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 diff --git a/.github/workflows/test-compile.yml b/.github/workflows/test-compile.yml index 74c3e2639..4f60af0f8 100644 --- a/.github/workflows/test-compile.yml +++ b/.github/workflows/test-compile.yml @@ -48,6 +48,7 @@ jobs: uses: actions/checkout@v4 with: submodules: true + persist-credentials: false - name: Setup environment uses: ./.github/actions/setup-build-env diff --git a/.github/workflows/test-verific.yml b/.github/workflows/test-verific.yml index 98b05e8dd..013c9f8ca 100644 --- a/.github/workflows/test-verific.yml +++ b/.github/workflows/test-verific.yml @@ -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: | diff --git a/.github/workflows/update-flake-lock.yml b/.github/workflows/update-flake-lock.yml index c7aa6ecab..de7ef04d6 100644 --- a/.github/workflows/update-flake-lock.yml +++ b/.github/workflows/update-flake-lock.yml @@ -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 diff --git a/.github/workflows/version.yml b/.github/workflows/version.yml index f73c68bdf..26dcba4a4 100644 --- a/.github/workflows/version.yml +++ b/.github/workflows/version.yml @@ -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 diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index d66239a16..79f971dac 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -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 From 91cd382f8bb06c19c89742f8c56eb6187ef28d19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Tue, 18 Mar 2025 13:25:10 +0100 Subject: [PATCH 02/44] macc: Rename 'ports' to 'terms' throughout codebase --- kernel/consteval.h | 2 +- kernel/macc.h | 56 ++++++++++++++++++------------------- kernel/satgen.cc | 2 +- passes/opt/share.cc | 58 +++++++++++++++++++-------------------- passes/techmap/alumacc.cc | 52 +++++++++++++++++------------------ passes/techmap/booth.cc | 6 ++-- passes/techmap/maccmap.cc | 54 ++++++++++++++++++------------------ passes/tests/test_cell.cc | 12 ++++---- 8 files changed, 121 insertions(+), 121 deletions(-) diff --git a/kernel/consteval.h b/kernel/consteval.h index 05e94ab86..844120ef0 100644 --- a/kernel/consteval.h +++ b/kernel/consteval.h @@ -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)) diff --git a/kernel/macc.h b/kernel/macc.h index 5fc6036ed..ceda1dceb 100644 --- a/kernel/macc.h +++ b/kernel/macc.h @@ -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 ports; + std::vector terms; void optimize(int width) { - std::vector new_ports; + std::vector 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) diff --git a/kernel/satgen.cc b/kernel/satgen.cc index 9e5fa9111..13f243b14 100644 --- a/kernel/satgen.cc +++ b/kernel/satgen.cc @@ -750,7 +750,7 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep) std::vector tmp(GetSize(y), ez->CONST_FALSE); - for (auto &port : macc.ports) + for (auto &port : macc.terms) { std::vector in_a = importDefSigSpec(port.in_a, timestep); std::vector in_b = importDefSigSpec(port.in_b, timestep); diff --git a/passes/opt/share.cc b/passes/opt/share.cc index 57a52969b..14e184a99 100644 --- a/passes/opt/share.cc +++ b/passes/opt/share.cc @@ -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 *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 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) diff --git a/passes/techmap/alumacc.cc b/passes/techmap/alumacc.cc index 591c51c74..3dc54e8bb 100644 --- a/passes/techmap/alumacc.cc +++ b/passes/techmap/alumacc.cc @@ -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 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) { diff --git a/passes/techmap/booth.cc b/passes/techmap/booth.cc index cd9012e6c..a692b99fe 100644 --- a/passes/techmap/booth.cc +++ b/passes/techmap/booth.cc @@ -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; diff --git a/passes/techmap/maccmap.cc b/passes/techmap/maccmap.cc index 3dde92438..42b615002 100644 --- a/passes/techmap/maccmap.cc +++ b/passes/techmap/maccmap.cc @@ -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 summand_t; std::vector 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()); diff --git a/passes/tests/test_cell.cc b/passes/tests/test_cell.cc index 39b7ccd3a..a34eafc2f 100644 --- a/passes/tests/test_cell.cc +++ b/passes/tests/test_cell.cc @@ -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); From 251285be4c086eba80cafe637029218bb2e8f2a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Tue, 18 Mar 2025 13:51:09 +0100 Subject: [PATCH 03/44] cost: Add `$mem_v2`, `$macc_v2` estimates --- kernel/cost.cc | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/kernel/cost.cc b/kernel/cost.cc index 5d897ab7a..985220f14 100644 --- a/kernel/cost.cc +++ b/kernel/cost.cc @@ -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; From 1113c8c95a568740497d2a5f5497d1d3b592a2c9 Mon Sep 17 00:00:00 2001 From: Kelvin Chung Date: Fri, 28 Feb 2025 19:35:47 +0000 Subject: [PATCH 04/44] feat: Allow full constant wrapping for hilomap --- passes/techmap/hilomap.cc | 53 ++++++++++++++++++++++++++++----------- 1 file changed, 38 insertions(+), 15 deletions(-) diff --git a/passes/techmap/hilomap.cc b/passes/techmap/hilomap.cc index c1b947221..f342db340 100644 --- a/passes/techmap/hilomap.cc +++ b/passes/techmap/hilomap.cc @@ -26,29 +26,41 @@ PRIVATE_NAMESPACE_BEGIN static std::string hicell_celltype, hicell_portname; static std::string locell_celltype, locell_portname; +static std::string fullcell_celltype, fullcell_portname, fullcell_paramname; static bool singleton_mode; +static bool multi_bit; static RTLIL::Module *module; static RTLIL::SigBit last_hi, last_lo; +static RTLIL::SigChunk value; void hilomap_worker(RTLIL::SigSpec &sig) { - for (auto &bit : sig) { - if (bit == RTLIL::State::S1 && !hicell_celltype.empty()) { - if (!singleton_mode || last_hi == RTLIL::State::Sm) { - last_hi = module->addWire(NEW_ID); - RTLIL::Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(hicell_celltype)); - cell->setPort(RTLIL::escape_id(hicell_portname), last_hi); + if (multi_bit && sig.is_fully_const()){ + value = module->addWire(NEW_ID, sig.size()); + RTLIL::Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(fullcell_celltype)); + cell->setParam(RTLIL::escape_id(fullcell_paramname), sig.as_const()); + cell->setPort(RTLIL::escape_id(fullcell_portname), value); + sig = value; + } + else{ + for (auto &bit : sig) { + if (bit == RTLIL::State::S1 && !hicell_celltype.empty()) { + if (!singleton_mode || last_hi == RTLIL::State::Sm) { + last_hi = module->addWire(NEW_ID); + RTLIL::Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(hicell_celltype)); + cell->setPort(RTLIL::escape_id(hicell_portname), last_hi); + } + bit = last_hi; } - bit = last_hi; - } - if (bit == RTLIL::State::S0 && !locell_celltype.empty()) { - if (!singleton_mode || last_lo == RTLIL::State::Sm) { - last_lo = module->addWire(NEW_ID); - RTLIL::Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(locell_celltype)); - cell->setPort(RTLIL::escape_id(locell_portname), last_lo); + if (bit == RTLIL::State::S0 && !locell_celltype.empty()) { + if (!singleton_mode || last_lo == RTLIL::State::Sm) { + last_lo = module->addWire(NEW_ID); + RTLIL::Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(locell_celltype)); + cell->setPort(RTLIL::escape_id(locell_portname), last_lo); + } + bit = last_lo; } - bit = last_lo; } } } @@ -68,6 +80,10 @@ struct HilomapPass : public Pass { log(" -locell \n"); log(" Replace constant lo bits with this cell.\n"); log("\n"); + log(" -wrap \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"); log(" -singleton\n"); log(" Create only one hi/lo cell and connect all constant bits\n"); log(" to that cell. Per default a separate cell is created for\n"); @@ -83,7 +99,7 @@ struct HilomapPass : public Pass { locell_celltype = std::string(); locell_portname = std::string(); singleton_mode = false; - + multi_bit = false; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { @@ -97,6 +113,13 @@ struct HilomapPass : public Pass { locell_portname = args[++argidx]; continue; } + if (args[argidx] == "-wrap" && argidx+3 < args.size()){ + fullcell_celltype = args[++argidx]; + fullcell_portname = args[++argidx]; + fullcell_paramname = args[++argidx]; + multi_bit = true; + continue; + } if (args[argidx] == "-singleton") { singleton_mode = true; continue; From 7bbdf6049aeced309a2fe7e10f2f60b6cd7dd596 Mon Sep 17 00:00:00 2001 From: Kelvin Chung Date: Wed, 26 Mar 2025 11:52:55 +0000 Subject: [PATCH 05/44] Move implementation to constmap and add test --- passes/techmap/Makefile.inc | 1 + passes/techmap/constmap.cc | 82 +++++++++++++++++++++++++++++++++++++ passes/techmap/hilomap.cc | 53 +++++++----------------- tests/techmap/constmap.ys | 31 ++++++++++++++ 4 files changed, 129 insertions(+), 38 deletions(-) create mode 100644 passes/techmap/constmap.cc create mode 100644 tests/techmap/constmap.ys diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc index 4e1d16744..bd18bd826 100644 --- a/passes/techmap/Makefile.inc +++ b/passes/techmap/Makefile.inc @@ -53,6 +53,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) diff --git a/passes/techmap/constmap.cc b/passes/techmap/constmap.cc new file mode 100644 index 000000000..59bffbeb6 --- /dev/null +++ b/passes/techmap/constmap.cc @@ -0,0 +1,82 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2025 King Lok Chung + * + * 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, RTLIL::escape_id(celltype)); + cell->setParam(RTLIL::escape_id(cell_paramname), sig.as_const()); + cell->setPort(RTLIL::escape_id(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 \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 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 = args[++argidx]; + cell_portname = args[++argidx]; + cell_paramname = args[++argidx]; + continue; + } + break; + } + extra_args(args, argidx, design); + + for (auto mod : design->selected_modules()) + { + module = mod; + module->rewrite_sigspecs(constmap_worker); + } + } +} HilomapPass; + +PRIVATE_NAMESPACE_END diff --git a/passes/techmap/hilomap.cc b/passes/techmap/hilomap.cc index f342db340..c1b947221 100644 --- a/passes/techmap/hilomap.cc +++ b/passes/techmap/hilomap.cc @@ -26,41 +26,29 @@ PRIVATE_NAMESPACE_BEGIN static std::string hicell_celltype, hicell_portname; static std::string locell_celltype, locell_portname; -static std::string fullcell_celltype, fullcell_portname, fullcell_paramname; static bool singleton_mode; -static bool multi_bit; static RTLIL::Module *module; static RTLIL::SigBit last_hi, last_lo; -static RTLIL::SigChunk value; void hilomap_worker(RTLIL::SigSpec &sig) { - if (multi_bit && sig.is_fully_const()){ - value = module->addWire(NEW_ID, sig.size()); - RTLIL::Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(fullcell_celltype)); - cell->setParam(RTLIL::escape_id(fullcell_paramname), sig.as_const()); - cell->setPort(RTLIL::escape_id(fullcell_portname), value); - sig = value; - } - else{ - for (auto &bit : sig) { - if (bit == RTLIL::State::S1 && !hicell_celltype.empty()) { - if (!singleton_mode || last_hi == RTLIL::State::Sm) { - last_hi = module->addWire(NEW_ID); - RTLIL::Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(hicell_celltype)); - cell->setPort(RTLIL::escape_id(hicell_portname), last_hi); - } - bit = last_hi; + for (auto &bit : sig) { + if (bit == RTLIL::State::S1 && !hicell_celltype.empty()) { + if (!singleton_mode || last_hi == RTLIL::State::Sm) { + last_hi = module->addWire(NEW_ID); + RTLIL::Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(hicell_celltype)); + cell->setPort(RTLIL::escape_id(hicell_portname), last_hi); } - if (bit == RTLIL::State::S0 && !locell_celltype.empty()) { - if (!singleton_mode || last_lo == RTLIL::State::Sm) { - last_lo = module->addWire(NEW_ID); - RTLIL::Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(locell_celltype)); - cell->setPort(RTLIL::escape_id(locell_portname), last_lo); - } - bit = last_lo; + bit = last_hi; + } + if (bit == RTLIL::State::S0 && !locell_celltype.empty()) { + if (!singleton_mode || last_lo == RTLIL::State::Sm) { + last_lo = module->addWire(NEW_ID); + RTLIL::Cell *cell = module->addCell(NEW_ID, RTLIL::escape_id(locell_celltype)); + cell->setPort(RTLIL::escape_id(locell_portname), last_lo); } + bit = last_lo; } } } @@ -80,10 +68,6 @@ struct HilomapPass : public Pass { log(" -locell \n"); log(" Replace constant lo bits with this cell.\n"); log("\n"); - log(" -wrap \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"); log(" -singleton\n"); log(" Create only one hi/lo cell and connect all constant bits\n"); log(" to that cell. Per default a separate cell is created for\n"); @@ -99,7 +83,7 @@ struct HilomapPass : public Pass { locell_celltype = std::string(); locell_portname = std::string(); singleton_mode = false; - multi_bit = false; + size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { @@ -113,13 +97,6 @@ struct HilomapPass : public Pass { locell_portname = args[++argidx]; continue; } - if (args[argidx] == "-wrap" && argidx+3 < args.size()){ - fullcell_celltype = args[++argidx]; - fullcell_portname = args[++argidx]; - fullcell_paramname = args[++argidx]; - multi_bit = true; - continue; - } if (args[argidx] == "-singleton") { singleton_mode = true; continue; diff --git a/tests/techmap/constmap.ys b/tests/techmap/constmap.ys new file mode 100644 index 000000000..ceac0e570 --- /dev/null +++ b/tests/techmap/constmap.ys @@ -0,0 +1,31 @@ +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 +select -assert-count 1 r:value=16 + +design -reset +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 From a0dabf9203139588e94e793cf17c2e8a2dfec51d Mon Sep 17 00:00:00 2001 From: Kelvin Chung Date: Wed, 26 Mar 2025 22:24:41 +0000 Subject: [PATCH 06/44] Add extra test --- tests/techmap/constmap.ys | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/techmap/constmap.ys b/tests/techmap/constmap.ys index ceac0e570..2854f2e57 100644 --- a/tests/techmap/constmap.ys +++ b/tests/techmap/constmap.ys @@ -13,6 +13,13 @@ select -assert-count 1 t:const_cell select -assert-count 1 r:value=16 design -reset + +read_verilog -lib << EOT +module const_cell(O); +output O; +endmodule +EOT + read_verilog << EOT module test(); @@ -29,3 +36,5 @@ 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 From 5a6b7e1e91ac1e7f2afda5e702adb705a0375c4e Mon Sep 17 00:00:00 2001 From: Akash Levy Date: Sun, 6 Apr 2025 22:54:14 -0700 Subject: [PATCH 07/44] Add NamedObject to py_wrap_generator --- misc/py_wrap_generator.py | 1 + 1 file changed, 1 insertion(+) diff --git a/misc/py_wrap_generator.py b/misc/py_wrap_generator.py index 03374c610..4857a9dc3 100644 --- a/misc/py_wrap_generator.py +++ b/misc/py_wrap_generator.py @@ -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), From 2bc2105d8287d43c629404914d3d7ac9d3c8b78a Mon Sep 17 00:00:00 2001 From: Donn Date: Wed, 9 Apr 2025 10:42:40 +0200 Subject: [PATCH 08/44] wheels: fix builds, add linux aarch64 to ci Essentially, something is attempting to build the Yosys EXE when you build libyosys.so now. With `ENABLE_PYTHON_CONFIG_EMBED=0`, the Yosys EXE will always fail to build. Furthermore, because `ENABLE_PYOSYS` now attempts to build a wheel, building a wheel has become recursive. This commit uses a supplementary set of libs for the EXE (EXE_LIBS) so it and libyosys.so can be built simultaneously, as well as a new Makefile flag, `ENABLE_WHEEL`, to prevent the aforementioned recursion. I also enabled aarch64 Linux in the CI because it's publicly available now. --- .github/workflows/wheels.yml | 16 ++++++---------- Makefile | 15 ++++++++++----- setup.py | 4 ++-- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index d66239a16..3a3d240c4 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -14,16 +14,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", diff --git a/Makefile b/Makefile index 89723e99d..74951b8cb 100644 --- a/Makefile +++ b/Makefile @@ -27,6 +27,7 @@ ENABLE_ZLIB := 1 # python wrappers ENABLE_PYOSYS := 0 +ENABLE_WHEEL := $(ENABLE_PYOSYS) # other configuration flags ENABLE_GCOV := 0 @@ -102,6 +103,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)" @@ -209,11 +211,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,8 +348,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 +ifeq ($(ENABLE_WHEEL),1) EXTRA_TARGETS += wheel +endif # Detect name of boost_python library. Some distros use boost_python-py, other boost_python, 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)") @@ -735,7 +740,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) diff --git a/setup.py b/setup.py index b39b579e0..8a37a91b3 100644 --- a/setup.py +++ b/setup.py @@ -40,8 +40,8 @@ class libyosys_so_ext(Extension): ) self.args = [ "ENABLE_PYOSYS=1", - # Wheel meant to be imported from interpreter - "ENABLE_PYTHON_CONFIG_EMBED=0", + # Prevent recursive wheel build + "ENABLE_WHEEL=0", # Would need to be installed separately by the user "ENABLE_TCL=0", "ENABLE_READLINE=0", From 414dc855730ce27b1b49bc50cc97ef4240b42ad4 Mon Sep 17 00:00:00 2001 From: Kelvin Chung Date: Thu, 10 Apr 2025 00:01:50 +0100 Subject: [PATCH 09/44] Correct and more test --- passes/techmap/constmap.cc | 2 +- tests/techmap/constmap.ys | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/passes/techmap/constmap.cc b/passes/techmap/constmap.cc index 59bffbeb6..8f3235991 100644 --- a/passes/techmap/constmap.cc +++ b/passes/techmap/constmap.cc @@ -77,6 +77,6 @@ struct ConstmapPass : public Pass { module->rewrite_sigspecs(constmap_worker); } } -} HilomapPass; +} ConstmapPass; PRIVATE_NAMESPACE_END diff --git a/tests/techmap/constmap.ys b/tests/techmap/constmap.ys index 2854f2e57..fbaca7662 100644 --- a/tests/techmap/constmap.ys +++ b/tests/techmap/constmap.ys @@ -16,6 +16,7 @@ design -reset read_verilog -lib << EOT module const_cell(O); +parameter value=0; output O; endmodule EOT @@ -33,8 +34,30 @@ 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 + +design -reset + +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 1 t:const_cell r:value=16 %i +select -assert-count 1 t:const_cell r:value=32 %i From 583771ef5b8fd847c012c60f165ed9e1b8aa2db3 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Fri, 11 Apr 2025 04:12:34 +1200 Subject: [PATCH 10/44] cutpoint: Add -blackbox option Replace the contents of all blackboxes in the design with a formal cut point. Includes test script. --- passes/sat/cutpoint.cc | 27 ++++++++++++++++++++++-- tests/various/cutpoint_blackbox.ys | 33 ++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 tests/various/cutpoint_blackbox.ys diff --git a/passes/sat/cutpoint.cc b/passes/sat/cutpoint.cc index 263a3a4c8..171ae060a 100644 --- a/passes/sat/cutpoint.cc +++ b/passes/sat/cutpoint.cc @@ -37,10 +37,15 @@ 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(" cutpoint -blackbox [options]\n"); + log("\n"); + log("Replace the contents of all blackboxes in the design with a formal cut point.\n"); + log("\n"); } void execute(std::vector args, RTLIL::Design *design) override { - bool flag_undef = false; + bool flag_undef = false; + bool flag_blackbox = false; log_header(design, "Executing CUTPOINT pass.\n"); @@ -51,11 +56,25 @@ struct CutpointPass : public Pass { flag_undef = true; continue; } + if (args[argidx] == "-blackbox") { + flag_blackbox = true; + continue; + } break; } extra_args(args, argidx, design); - for (auto module : design->selected_modules()) + if (flag_blackbox) { + if (!design->full_selection()) + log_cmd_error("This command only operates on fully selected designs!\n"); + RTLIL::Selection module_boxes(false); + for (auto module : design->modules()) + if (module->get_blackbox_attribute()) + module_boxes.select(module); + design->selection_stack.push_back(module_boxes); + } + + for (auto module : design->all_selected_modules()) { if (module->is_selected_whole()) { log("Making all outputs of module %s cut points, removing module contents.\n", log_id(module)); @@ -68,6 +87,10 @@ struct CutpointPass : public Pass { 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))); + if (module->get_blackbox_attribute()) { + module->set_bool_attribute(ID::blackbox, false); + module->set_bool_attribute(ID::whitebox, false); + } continue; } diff --git a/tests/various/cutpoint_blackbox.ys b/tests/various/cutpoint_blackbox.ys new file mode 100644 index 000000000..78ee46db6 --- /dev/null +++ b/tests/various/cutpoint_blackbox.ys @@ -0,0 +1,33 @@ +read_verilog -specify << EOT +module top(input a, b, output o); + wire c, d; + bb bb1 (.a (a), .b (b), .o (c)); + wb wb1 (.a (a), .b (b), .o (d)); + some_mod some_inst (.a (c), .b (d), .o (o)); +endmodule + +(* blackbox *) +module bb(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, output o); +assign o = a & b; +endmodule +EOT + +select top + +select -assert-count 0 t:$anyseq +select -assert-count 2 =t:?b +cutpoint -blackbox =* +select -assert-count 2 t:$anyseq +select -assert-count 2 t:?b From ca57df89277edb4394dd140cabb5937bc2dfada4 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Fri, 11 Apr 2025 04:12:34 +1200 Subject: [PATCH 11/44] cutpoint: Add $scopeinfo cell Also adds "blackbox" as a valid TYPE. --- kernel/rtlil.cc | 2 +- passes/sat/cutpoint.cc | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index f835dd269..dd78b202d 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -2140,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; } diff --git a/passes/sat/cutpoint.cc b/passes/sat/cutpoint.cc index 171ae060a..573dfbd0a 100644 --- a/passes/sat/cutpoint.cc +++ b/passes/sat/cutpoint.cc @@ -90,6 +90,8 @@ struct CutpointPass : public Pass { if (module->get_blackbox_attribute()) { module->set_bool_attribute(ID::blackbox, false); module->set_bool_attribute(ID::whitebox, false); + auto scopeinfo = module->addCell(NEW_ID, ID($scopeinfo)); + scopeinfo->setParam(ID::TYPE, RTLIL::Const("blackbox")); } continue; } From cf44a9124fdf4c674e8914dafbb31942fec371ac Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Fri, 11 Apr 2025 04:12:34 +1200 Subject: [PATCH 12/44] cutpoint: Test -blackbox with parameter Modify `cutpoint_blackbox.ys` to check that parameters on blackbox modules are maintained after the cutpoint. Also adjusts the test to check that each instance gets the `$anyseq` cell. --- tests/various/cutpoint_blackbox.ys | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/tests/various/cutpoint_blackbox.ys b/tests/various/cutpoint_blackbox.ys index 78ee46db6..ee7a18c6a 100644 --- a/tests/various/cutpoint_blackbox.ys +++ b/tests/various/cutpoint_blackbox.ys @@ -1,13 +1,14 @@ read_verilog -specify << EOT module top(input a, b, output o); - wire c, d; - bb bb1 (.a (a), .b (b), .o (c)); - wb wb1 (.a (a), .b (b), .o (d)); - some_mod some_inst (.a (c), .b (d), .o (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(input a, b, output o); +module bb #( parameter SOME_PARAM=0 ) (input a, b, output o); assign o = a | b; specify (a => o) = 1; @@ -19,15 +20,20 @@ module wb(input a, b, output o); assign o = a ^ b; endmodule -module some_mod(input a, b, output o); -assign o = a & b; +module some_mod(input a, b, c, output o); +assign o = a & (b | c); endmodule EOT -select top +hierarchy -top top select -assert-count 0 t:$anyseq -select -assert-count 2 =t:?b -cutpoint -blackbox =* -select -assert-count 2 t:$anyseq -select -assert-count 2 t:?b +select -assert-count 3 =t:?b +cutpoint -blackbox + +select -assert-count 3 =t:?b +select -assert-count 2 r:SOME_PARAM +select -assert-count 1 r:SOME_PARAM=1 + +flatten +select -assert-count 3 t:$anyseq From b705c546ea71e72906590578435d347144f84dff Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Fri, 11 Apr 2025 04:12:34 +1200 Subject: [PATCH 13/44] cutpoint: Add -blackbox -instances Replace module instances instead of module contents. This fixes parametrisable width mismatch with read_verilog frontend, but not verific frontend. --- passes/sat/cutpoint.cc | 49 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/passes/sat/cutpoint.cc b/passes/sat/cutpoint.cc index 573dfbd0a..58cb4a2aa 100644 --- a/passes/sat/cutpoint.cc +++ b/passes/sat/cutpoint.cc @@ -41,11 +41,15 @@ struct CutpointPass : public Pass { log("\n"); log("Replace the contents of all blackboxes in the design with a formal cut point.\n"); log("\n"); + log(" -instances\n"); + log(" replace instances of blackboxes instead of the modules\n"); + log("\n"); } void execute(std::vector args, RTLIL::Design *design) override { bool flag_undef = false; bool flag_blackbox = false; + bool flag_instances = false; log_header(design, "Executing CUTPOINT pass.\n"); @@ -60,23 +64,39 @@ struct CutpointPass : public Pass { flag_blackbox = true; continue; } + if (args[argidx] == "-instances") { + flag_instances = true; + continue; + } break; } extra_args(args, argidx, design); + if (flag_instances && !flag_blackbox) { + log_cmd_error("-instances flag only valid with -blackbox!\n"); + } + if (flag_blackbox) { if (!design->full_selection()) log_cmd_error("This command only operates on fully selected designs!\n"); - RTLIL::Selection module_boxes(false); + RTLIL::Selection boxes(false); for (auto module : design->modules()) - if (module->get_blackbox_attribute()) - module_boxes.select(module); - design->selection_stack.push_back(module_boxes); + if (flag_instances) { + for (auto cell : module->cells()) { + auto mod = design->module(cell->type); + if (mod != nullptr && mod->get_blackbox_attribute()) + boxes.select(module, cell); + } + } else { + if (module->get_blackbox_attribute()) + boxes.select(module); + } + design->selection_stack.push_back(boxes); } for (auto module : design->all_selected_modules()) { - if (module->is_selected_whole()) { + if (module->is_selected_whole() && !flag_instances) { log("Making all outputs of module %s cut points, removing module contents.\n", log_id(module)); module->new_connections(std::vector()); for (auto cell : vector(module->cells())) @@ -107,7 +127,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_instances && 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()) { From 44545653ef9313bc8edb28cd13a867b01a1aea12 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Fri, 11 Apr 2025 04:12:34 +1200 Subject: [PATCH 14/44] hierarchy: Ignore width mismatch from verific But only if it's also a blackbox module with parameters (i.e. it *could* be parametrizable width). --- passes/hierarchy/hierarchy.cc | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc index 8372c0339..d94b5cef6 100644 --- a/passes/hierarchy/hierarchy.cc +++ b/passes/hierarchy/hierarchy.cc @@ -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); From 8b1cc6e05e6316e7af63d4cf9c5b9dd70298ac0b Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Fri, 11 Apr 2025 04:12:34 +1200 Subject: [PATCH 15/44] cutpoint: Use new selection helpers --- passes/sat/cutpoint.cc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/passes/sat/cutpoint.cc b/passes/sat/cutpoint.cc index 58cb4a2aa..bac699dec 100644 --- a/passes/sat/cutpoint.cc +++ b/passes/sat/cutpoint.cc @@ -79,19 +79,18 @@ struct CutpointPass : public Pass { if (flag_blackbox) { if (!design->full_selection()) log_cmd_error("This command only operates on fully selected designs!\n"); - RTLIL::Selection boxes(false); + design->push_empty_selection(); for (auto module : design->modules()) if (flag_instances) { for (auto cell : module->cells()) { auto mod = design->module(cell->type); if (mod != nullptr && mod->get_blackbox_attribute()) - boxes.select(module, cell); + design->select(module, cell); } } else { if (module->get_blackbox_attribute()) - boxes.select(module); + design->select(module); } - design->selection_stack.push_back(boxes); } for (auto module : design->all_selected_modules()) From 779a1fddf675635a2dafbbbf453a0a68f12a84bb Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Fri, 11 Apr 2025 04:12:34 +1200 Subject: [PATCH 16/44] Testing cutpoint with boxed selections --- tests/various/.gitignore | 1 + tests/various/cutpoint_blackbox.ys | 56 ++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/tests/various/.gitignore b/tests/various/.gitignore index 83e634820..3dbd50843 100644 --- a/tests/various/.gitignore +++ b/tests/various/.gitignore @@ -1,5 +1,6 @@ /*.log /*.out +/*.sel /write_gzip.v /write_gzip.v.gz /run-test.mk diff --git a/tests/various/cutpoint_blackbox.ys b/tests/various/cutpoint_blackbox.ys index ee7a18c6a..d2d823477 100644 --- a/tests/various/cutpoint_blackbox.ys +++ b/tests/various/cutpoint_blackbox.ys @@ -26,6 +26,7 @@ endmodule EOT hierarchy -top top +design -save hier select -assert-count 0 t:$anyseq select -assert-count 3 =t:?b @@ -37,3 +38,58 @@ select -assert-count 1 r:SOME_PARAM=1 flatten select -assert-count 3 t:$anyseq +select -assert-count 3 t:$scopeinfo n:*cutpoint.cc* %i + +# cutpoint -blackbox === cutpoint =A:whitebox =A:blackbox %u +# (simplified to =A:*box) +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 +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 + +# cutpoint -blackbox -instances !== cutpoint =A:whitebox =A:blackbox %u %C +# (simplified to =A:*box %C) +# because cutpoint -blackbox -instances adds $scopeinfo cells +design -load hier +cutpoint -blackbox -instances +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 +# 3 $scopeinfo in gold but not gate +select -assert-count 3 % %n +select -assert-count 3 t:$scopeinfo From 87d3b09988a486646aeb72fbf233484ebc7ed580 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Fri, 11 Apr 2025 04:12:35 +1200 Subject: [PATCH 17/44] cutpoint.cc: Fold -instances into -blackbox Replace `cutpoint -blackbox` behaviour with `cutpoint -blackbox -instances` behaviour. Drop `-instances` flag. Add `-noscopeinfo` flag. Use `RTLIL::Selection::boxed_module()` helper to shortcut blackbox check. Update `cutpoint_blackbox.ys` tests to match. --- passes/sat/cutpoint.cc | 59 ++++++++---------------------- tests/various/cutpoint_blackbox.ys | 51 +++++++------------------- 2 files changed, 29 insertions(+), 81 deletions(-) diff --git a/passes/sat/cutpoint.cc b/passes/sat/cutpoint.cc index bac699dec..7f0dc2fcf 100644 --- a/passes/sat/cutpoint.cc +++ b/passes/sat/cutpoint.cc @@ -37,19 +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 the contents of all blackboxes in the design with a formal cut point.\n"); - log("\n"); - log(" -instances\n"); - log(" replace instances of blackboxes instead of the modules\n"); + log("Replace all instances of blackboxes in the design with a formal cut point.\n"); log("\n"); } void execute(std::vector args, RTLIL::Design *design) override { bool flag_undef = false; + bool flag_scopeinfo = true; bool flag_blackbox = false; - bool flag_instances = false; log_header(design, "Executing CUTPOINT pass.\n"); @@ -60,61 +61,31 @@ struct CutpointPass : public Pass { flag_undef = true; continue; } - if (args[argidx] == "-blackbox") { - flag_blackbox = true; + if (args[argidx] == "-noscopeinfo") { + flag_scopeinfo = false; continue; } - if (args[argidx] == "-instances") { - flag_instances = true; + if (args[argidx] == "-blackbox") { + flag_blackbox = true; continue; } break; } extra_args(args, argidx, design); - if (flag_instances && !flag_blackbox) { - log_cmd_error("-instances flag only valid with -blackbox!\n"); - } - 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()) - if (flag_instances) { - for (auto cell : module->cells()) { - auto mod = design->module(cell->type); - if (mod != nullptr && mod->get_blackbox_attribute()) - design->select(module, cell); - } - } else { - if (module->get_blackbox_attribute()) - design->select(module); - } + for (auto cell : module->cells()) + if (selection.boxed_module(cell->type)) + selection.select(module, cell); } for (auto module : design->all_selected_modules()) { - if (module->is_selected_whole() && !flag_instances) { - log("Making all outputs of module %s cut points, removing module contents.\n", log_id(module)); - module->new_connections(std::vector()); - for (auto cell : vector(module->cells())) - module->remove(cell); - vector 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))); - if (module->get_blackbox_attribute()) { - module->set_bool_attribute(ID::blackbox, false); - module->set_bool_attribute(ID::whitebox, false); - auto scopeinfo = module->addCell(NEW_ID, ID($scopeinfo)); - scopeinfo->setParam(ID::TYPE, RTLIL::Const("blackbox")); - } - continue; - } - SigMap sigmap(module); pool cutpoint_bits; @@ -129,7 +100,7 @@ struct CutpointPass : public Pass { RTLIL::Cell *scopeinfo = nullptr; auto cell_name = cell->name; - if (flag_instances && cell_name.isPublic()) { + if (flag_scopeinfo && cell_name.isPublic()) { auto scopeinfo = module->addCell(NEW_ID, ID($scopeinfo)); scopeinfo->setParam(ID::TYPE, RTLIL::Const("blackbox")); diff --git a/tests/various/cutpoint_blackbox.ys b/tests/various/cutpoint_blackbox.ys index d2d823477..ee479b968 100644 --- a/tests/various/cutpoint_blackbox.ys +++ b/tests/various/cutpoint_blackbox.ys @@ -28,20 +28,25 @@ EOT hierarchy -top top design -save hier -select -assert-count 0 t:$anyseq +select -assert-none t:$anyseq select -assert-count 3 =t:?b cutpoint -blackbox -select -assert-count 3 =t:?b -select -assert-count 2 r:SOME_PARAM -select -assert-count 1 r:SOME_PARAM=1 +select -assert-none =t:?b +select -assert-none r:SOME_PARAM -flatten 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 -# cutpoint -blackbox === cutpoint =A:whitebox =A:blackbox %u -# (simplified to =A:*box) +# -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 @@ -50,33 +55,6 @@ rename -enumerate -pattern C_% w:*Anyseq* design -save gold select -write cutpoint.gold.sel =* -design -load hier -cutpoint =A:*box -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 - -# cutpoint -blackbox -instances !== cutpoint =A:whitebox =A:blackbox %u %C -# (simplified to =A:*box %C) -# because cutpoint -blackbox -instances adds $scopeinfo cells -design -load hier -cutpoint -blackbox -instances -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 @@ -90,6 +68,5 @@ select -assert-none % %n design -load gold select -read cutpoint.gate.sel -# 3 $scopeinfo in gold but not gate -select -assert-count 3 % %n -select -assert-count 3 t:$scopeinfo +# nothing in gold but not gate +select -assert-none % %n From 9d3d0a4336e3d84a8ea98dca613293eba380962f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 12 Apr 2025 00:22:23 +0000 Subject: [PATCH 18/44] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index deedbe17b..842a70283 100644 --- a/Makefile +++ b/Makefile @@ -159,7 +159,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.52+10 +YOSYS_VER := 0.52+32 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) From 872a197e94c477727845c1f0518a554fbaaacbd5 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Mon, 14 Apr 2025 12:41:14 +0200 Subject: [PATCH 19/44] memory_libmap: fix MapWorker memory allocation --- passes/memory/memory_libmap.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/passes/memory/memory_libmap.cc b/passes/memory/memory_libmap.cc index b0d0498ea..a5b30c7ae 100644 --- a/passes/memory/memory_libmap.cc +++ b/passes/memory/memory_libmap.cc @@ -2232,11 +2232,11 @@ struct MemoryLibMapPass : public Pass { if (module->has_processes_warn()) continue; - MapWorker worker(module); + auto worker = std::make_unique(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(module); } } } From 81f3369f248f84eeb81aa3a4b32ef93f32937ca8 Mon Sep 17 00:00:00 2001 From: Kelvin Chung Date: Mon, 14 Apr 2025 11:44:52 +0100 Subject: [PATCH 20/44] Add check at constmap and merge test --- passes/techmap/constmap.cc | 36 ++++++++++++++++++++++++++++++------ tests/techmap/constmap.ys | 22 +--------------------- 2 files changed, 31 insertions(+), 27 deletions(-) diff --git a/passes/techmap/constmap.cc b/passes/techmap/constmap.cc index 8f3235991..f0757403d 100644 --- a/passes/techmap/constmap.cc +++ b/passes/techmap/constmap.cc @@ -33,9 +33,9 @@ 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, RTLIL::escape_id(celltype)); - cell->setParam(RTLIL::escape_id(cell_paramname), sig.as_const()); - cell->setPort(RTLIL::escape_id(cell_portname), value); + RTLIL::Cell *cell = module->addCell(NEW_ID, celltype); + cell->setParam(cell_paramname, sig.as_const()); + cell->setPort(cell_portname, value); sig = value; } } @@ -62,15 +62,39 @@ struct ConstmapPass : public Pass { for (argidx = 1; argidx < args.size(); argidx++) { if (args[argidx] == "-cell" && argidx+3 < args.size()){ - celltype = args[++argidx]; - cell_portname = args[++argidx]; - cell_paramname = args[++argidx]; + 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; diff --git a/tests/techmap/constmap.ys b/tests/techmap/constmap.ys index fbaca7662..6945cf514 100644 --- a/tests/techmap/constmap.ys +++ b/tests/techmap/constmap.ys @@ -9,8 +9,7 @@ endmodule EOT constmap -cell const_cell O value -select -assert-count 1 t:const_cell -select -assert-count 1 r:value=16 +select -assert-count 1 t:const_cell r:value=16 %i design -reset @@ -42,22 +41,3 @@ 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 - -design -reset - -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 1 t:const_cell r:value=16 %i -select -assert-count 1 t:const_cell r:value=32 %i From c18f1310a534e84db70b19ebce238c19cb9ac73e Mon Sep 17 00:00:00 2001 From: Donn Date: Mon, 14 Apr 2025 14:45:41 +0200 Subject: [PATCH 21/44] Revert #4901 Partially reverts commit 9c5bffcf93183df0756e01f3c4774d2f83688b8e. The reasoning behind this is that setup.py is intended to strictly consume the Makefile and not be consumed by it. The attempt at using them recursively has caused a number of issues and has rendered Pyosys unusable to some users: See https://github.com/YosysHQ/yosys/issues/5012 Additionally, unlike the previous pyosys installation target, the wheel installation does not respect PREFIX=, only venvs. For installation inside a venv, the intended method should remain a user manually executing `pip3 install .` instead of relying on the Makefile. --- Makefile | 30 ++++++++++-------------------- passes/techmap/Makefile.inc | 2 +- setup.py | 5 ----- 3 files changed, 11 insertions(+), 26 deletions(-) diff --git a/Makefile b/Makefile index 74951b8cb..977e1cf40 100644 --- a/Makefile +++ b/Makefile @@ -27,7 +27,6 @@ ENABLE_ZLIB := 1 # python wrappers ENABLE_PYOSYS := 0 -ENABLE_WHEEL := $(ENABLE_PYOSYS) # other configuration flags ENABLE_GCOV := 0 @@ -350,9 +349,6 @@ 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 -ifeq ($(ENABLE_WHEEL),1) -EXTRA_TARGETS += wheel -endif # Detect name of boost_python library. Some distros use boost_python-py, other boost_python, 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)") @@ -971,20 +967,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) @@ -1004,7 +986,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) @@ -1020,7 +1008,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 diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc index e6a910a0d..f34faf37c 100644 --- a/passes/techmap/Makefile.inc +++ b/passes/techmap/Makefile.inc @@ -62,5 +62,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 diff --git a/setup.py b/setup.py index 8a37a91b3..a199530d0 100644 --- a/setup.py +++ b/setup.py @@ -40,8 +40,6 @@ class libyosys_so_ext(Extension): ) self.args = [ "ENABLE_PYOSYS=1", - # Prevent recursive wheel build - "ENABLE_WHEEL=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"): From b7062143e1fa76d8adbbe6f6cea013e4f2fc807a Mon Sep 17 00:00:00 2001 From: Donn Date: Mon, 14 Apr 2025 14:54:38 +0200 Subject: [PATCH 22/44] hotfix: fix CHECK_BOOST_PYTHON missing libpython --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 977e1cf40..2c145edfc 100644 --- a/Makefile +++ b/Makefile @@ -351,7 +351,7 @@ EXE_LIBS += $(filter-out $(LIBS),$(shell $(PYTHON_CONFIG_FOR_EXE) --libs)) CXXFLAGS += $(shell $(PYTHON_CONFIG) --includes) -DWITH_PYTHON # Detect name of boost_python library. Some distros use boost_python-py, other boost_python, 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)) || \ From c79379db02b47c0c9b7c5bc8b79627a50122d1c3 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Mon, 14 Apr 2025 15:22:38 +0200 Subject: [PATCH 23/44] Run wheels each Sunday at 10AM --- .github/workflows/wheels.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 2e47bcfa9..b01ce6b3a 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -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: From ea2c1e7ac73b81c4aa2b5dd1ae4948db1d75b12e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 15 Apr 2025 00:23:32 +0000 Subject: [PATCH 24/44] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 7011ab537..c0fcdfe62 100644 --- a/Makefile +++ b/Makefile @@ -160,7 +160,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.52+32 +YOSYS_VER := 0.52+45 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) From 21b93ee1fb36c25d240ea1146c3f4b7d9239881c Mon Sep 17 00:00:00 2001 From: clemens Date: Tue, 15 Apr 2025 09:38:04 +0200 Subject: [PATCH 25/44] fix sequential area not being included in addition/multiplication Fixes a bug where the sequential area isn't part of the Stat_numeric_members that are used to automatically add/mul the statdata_t members. --- passes/cmds/stat.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc index 7e51b6cb1..d68eda70a 100644 --- a/passes/cmds/stat.cc +++ b/passes/cmds/stat.cc @@ -40,7 +40,7 @@ struct statdata_t X(num_ports) X(num_port_bits) X(num_memories) X(num_memory_bits) X(num_cells) \ X(num_processes) - #define STAT_NUMERIC_MEMBERS STAT_INT_MEMBERS X(area) + #define STAT_NUMERIC_MEMBERS STAT_INT_MEMBERS X(area) X(sequential_area) #define X(_name) unsigned int _name; STAT_INT_MEMBERS From f8e67c7a081f2eaf3500b13e6f071e463da5bf8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Tue, 15 Apr 2025 10:31:42 +0200 Subject: [PATCH 26/44] satgen: Fix $macc_v2 x-prop --- kernel/satgen.cc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/kernel/satgen.cc b/kernel/satgen.cc index 9e5fa9111..a161adb5b 100644 --- a/kernel/satgen.cc +++ b/kernel/satgen.cc @@ -788,12 +788,18 @@ bool SatGen::importCell(RTLIL::Cell *cell, int timestep) { std::vector undef_a = importUndefSigSpec(cell->getPort(ID::A), timestep); std::vector undef_b = importUndefSigSpec(cell->getPort(ID::B), timestep); + std::vector undef_c; + + if (cell->type == ID($macc_v2)) + undef_c = importUndefSigSpec(cell->getPort(ID::C), timestep); int undef_any_a = ez->expression(ezSAT::OpOr, undef_a); int undef_any_b = ez->expression(ezSAT::OpOr, undef_b); + int undef_any_c = ez->expression(ezSAT::OpOr, undef_c); + int undef_any = ez->OR(undef_any_a, ez->OR(undef_any_b, undef_any_c)); std::vector undef_y = importUndefSigSpec(cell->getPort(ID::Y), timestep); - ez->assume(ez->vec_eq(undef_y, std::vector(GetSize(y), ez->OR(undef_any_a, undef_any_b)))); + ez->assume(ez->vec_eq(undef_y, std::vector(GetSize(y), undef_any))); undefGating(y, tmp, undef_y); } From 30486079f9b2c395f33c6604c6d3ddb68269cd9f Mon Sep 17 00:00:00 2001 From: Emily Schmidt Date: Wed, 9 Apr 2025 10:18:25 +0100 Subject: [PATCH 27/44] add dft_tag documentation --- .../more_scripting/data_flow_tracking.rst | 71 +++++++++++++++++++ .../using_yosys/more_scripting/index.rst | 1 + 2 files changed, 72 insertions(+) create mode 100644 docs/source/using_yosys/more_scripting/data_flow_tracking.rst diff --git a/docs/source/using_yosys/more_scripting/data_flow_tracking.rst b/docs/source/using_yosys/more_scripting/data_flow_tracking.rst new file mode 100644 index 000000000..e13dfac7d --- /dev/null +++ b/docs/source/using_yosys/more_scripting/data_flow_tracking.rst @@ -0,0 +1,71 @@ +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 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. + +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 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. + It also does not try to determine whether the effect of a signal is cancelled 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. \ No newline at end of file diff --git a/docs/source/using_yosys/more_scripting/index.rst b/docs/source/using_yosys/more_scripting/index.rst index 090b9e0b9..6265e5d0e 100644 --- a/docs/source/using_yosys/more_scripting/index.rst +++ b/docs/source/using_yosys/more_scripting/index.rst @@ -12,5 +12,6 @@ More scripting selections interactive_investigation model_checking + data_flow_tracking .. troubleshooting From ea6e5b3c48c44ea17470803d21c4c8b83a09ace9 Mon Sep 17 00:00:00 2001 From: Emily Schmidt Date: Thu, 10 Apr 2025 08:23:07 +0100 Subject: [PATCH 28/44] add changes to dft docs suggested by Krystine --- .../using_yosys/more_scripting/data_flow_tracking.rst | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/source/using_yosys/more_scripting/data_flow_tracking.rst b/docs/source/using_yosys/more_scripting/data_flow_tracking.rst index e13dfac7d..0bf5e567c 100644 --- a/docs/source/using_yosys/more_scripting/data_flow_tracking.rst +++ b/docs/source/using_yosys/more_scripting/data_flow_tracking.rst @@ -1,8 +1,11 @@ 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 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. +For this, four special cells, `$get_tag`, `$set_tag``, `$overwrite_tag` and `$original_tag` are inserted into the design and then the `dft_tag` is run, which converts these cells into ordinary logic. +Typically, one would then use `SBY docs`_ to prove assertions involving these cells. + +.. _SBY docs: 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. @@ -20,6 +23,7 @@ For example, XOR, AND and OR cells propagate tags as follows: #. 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. It also does not try to determine whether the effect of a signal is cancelled out, for example ``A ^ A`` or ``A ^ (B ^ A)`` is independent of ``A``, but its tags would be propagated nonetheless. @@ -29,6 +33,7 @@ Because of this propagation behaviour, we can answer questions about what signal 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. @@ -58,6 +63,7 @@ The main purpose of ``$overwrite_tag`` is adding tags to signals produced within 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. From bfed96ad88a422408717cf6ea54dca377e1f9b86 Mon Sep 17 00:00:00 2001 From: Emily Schmidt Date: Thu, 10 Apr 2025 08:43:00 +0100 Subject: [PATCH 29/44] some fixes and rewordings of the dft docs --- .../more_scripting/data_flow_tracking.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/source/using_yosys/more_scripting/data_flow_tracking.rst b/docs/source/using_yosys/more_scripting/data_flow_tracking.rst index 0bf5e567c..e0714b7e2 100644 --- a/docs/source/using_yosys/more_scripting/data_flow_tracking.rst +++ b/docs/source/using_yosys/more_scripting/data_flow_tracking.rst @@ -2,10 +2,10 @@ 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 and then the `dft_tag` is run, which converts these cells into ordinary logic. -Typically, one would then use `SBY docs`_ to prove assertions involving these cells. +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 docs: https://yosyshq.readthedocs.io/projects/sby +.. _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. @@ -19,14 +19,14 @@ For this, tags are simply *forwarded* or *propagated* (i.e. copied) from 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 only if the other input is ``1``. Because if one input is ``0``, the other input can never 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. - It also does not try to determine whether the effect of a signal is cancelled out, for example ``A ^ A`` or ``A ^ (B ^ A)`` is independent of ``A``, but its tags would be propagated nonetheless. + 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. @@ -35,7 +35,7 @@ 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. +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. From 19845be85c1fd2385dcfc07cdc39c2c6aae26a7f Mon Sep 17 00:00:00 2001 From: Emily Schmidt Date: Thu, 10 Apr 2025 08:43:21 +0100 Subject: [PATCH 30/44] reflow dft docs to 80 cols --- .../more_scripting/data_flow_tracking.rst | 115 ++++++++++++------ 1 file changed, 76 insertions(+), 39 deletions(-) diff --git a/docs/source/using_yosys/more_scripting/data_flow_tracking.rst b/docs/source/using_yosys/more_scripting/data_flow_tracking.rst index e0714b7e2..aa13a2e69 100644 --- a/docs/source/using_yosys/more_scripting/data_flow_tracking.rst +++ b/docs/source/using_yosys/more_scripting/data_flow_tracking.rst @@ -1,77 +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. +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"``. +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: +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. + 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. +#. 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. +#. 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. +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 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. +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``. +``$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. +``$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. +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``. +``$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. +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. + 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. \ No newline at end of file +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. \ No newline at end of file From 6dff9e778744ad538c55946eb7b5ab97ee99d5fd Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Mon, 14 Apr 2025 15:41:30 +0200 Subject: [PATCH 31/44] share: Restrict activation patterns to potentially relevant signals In case the two sets of activation patterns are mutually exclusive without considering the logic feeding into the activation signals, an activation condition can only be relevant if present in both sets with opposite polarity. This detects pattern-only mutual exclusion by running an additional SAT query before importing the input cone logic. If that is already UNSAT, we remove all non-relevant condition and re-simplify the remaining patterns. In cases of pattern-only mutual exclusion, this will often produce much smaller selection logic and avoid the more costly SAT query that includes the input cones. --- passes/opt/share.cc | 95 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 77 insertions(+), 18 deletions(-) diff --git a/passes/opt/share.cc b/passes/opt/share.cc index 0820bad12..7ffe26b2b 100644 --- a/passes/opt/share.cc +++ b/passes/opt/share.cc @@ -1000,6 +1000,53 @@ struct ShareWorker } } + pool> pattern_bits(const pool &activation_patterns) + { + pool> 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; + } + + void onesided_restrict_activiation_patterns( + pool &activation_patterns, const pool> &other_bits) + { + pool new_activiation_patterns; + + 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); + } + } + new_activiation_patterns.emplace(std::move(new_pair)); + } + + activation_patterns = std::move(new_activiation_patterns); + } + + // Only valid if the patterns on their own (i.e. without considering their input cone) are mutually exclusive! + void restrict_activiation_patterns(pool &activation_patterns, pool &other_activation_patterns) + { + pool> bits = pattern_bits(activation_patterns); + pool> other_bits = pattern_bits(other_activation_patterns); + + onesided_restrict_activiation_patterns(activation_patterns, other_bits); + onesided_restrict_activiation_patterns(other_activation_patterns, bits); + + optimize_activation_patterns(activation_patterns); + optimize_activation_patterns(other_activation_patterns); + } + RTLIL::SigSpec make_cell_activation_logic(const pool &activation_patterns, pool &supercell_aux) { RTLIL::Wire *all_cases_wire = module->addWire(NEW_ID, 0); @@ -1299,17 +1346,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 +1365,39 @@ struct ShareWorker continue; } - qcsat.ez->non_incremental(); + if (pattern_only_solve) { + qcsat.ez->non_incremental(); - all_ctrl_signals.sort_and_unify(); - std::vector sat_model = qcsat.importSig(all_ctrl_signals); - std::vector sat_model_values; + all_ctrl_signals.sort_and_unify(); + std::vector sat_model = qcsat.importSig(all_ctrl_signals); + std::vector sat_model_values; - qcsat.ez->assume(qcsat.ez->AND(sub1, sub2)); + qcsat.ez->assume(qcsat.ez->AND(sub1, sub2)); - log(" Size of SAT problem: %zu cells, %d variables, %d clauses\n", - qcsat.imported_cells.size(), qcsat.ez->numCnfVariables(), qcsat.ez->numCnfClauses()); + 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; + 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"); + restrict_activiation_patterns(filtered_cell_activation_patterns, filtered_other_cell_activation_patterns); + + for (auto &p : filtered_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 : filtered_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; From 27ed77ea2428433e4efc1ff29d0ebc36753f9458 Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Tue, 15 Apr 2025 10:25:39 +0200 Subject: [PATCH 32/44] share: Keep filtered activation patterns for the supercell The previous commit introduced code that optimizes the activation patterns to be able to generate smaller activation logic. The resulting supercell was then enqueued as shareable using those optimized activation patterns. The condition represented by the optimized patterns is an over-approximation of the actual activiation condition. This means using it as activiation for the supercell loses precision and pessimises sharing of the supercell with further cells, breaking the sat/share test. This commit fixes that by using the optimized activiation patterns only for the generation of activation logic and using the original patterns for enqueuing the supercell. --- passes/opt/share.cc | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/passes/opt/share.cc b/passes/opt/share.cc index 7ffe26b2b..eb6476d57 100644 --- a/passes/opt/share.cc +++ b/passes/opt/share.cc @@ -1365,6 +1365,9 @@ struct ShareWorker continue; } + pool optimized_cell_activation_patterns = filtered_cell_activation_patterns; + pool optimized_other_cell_activation_patterns = filtered_other_cell_activation_patterns; + if (pattern_only_solve) { qcsat.ez->non_incremental(); @@ -1389,12 +1392,12 @@ struct ShareWorker 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"); - restrict_activiation_patterns(filtered_cell_activation_patterns, filtered_other_cell_activation_patterns); + restrict_activiation_patterns(optimized_cell_activation_patterns, optimized_other_cell_activation_patterns); - for (auto &p : filtered_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 : filtered_other_cell_activation_patterns) + 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)); } @@ -1413,20 +1416,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 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)); } From 7593b5b224e54c871d5c48484eceac315b82ea9b Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Tue, 15 Apr 2025 12:02:09 +0200 Subject: [PATCH 33/44] share: Only print optimized activation patterns when different This removes redundant information from the log and makes it easier to spot where the new optimization had an effect. --- passes/opt/share.cc | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/passes/opt/share.cc b/passes/opt/share.cc index eb6476d57..580549e4d 100644 --- a/passes/opt/share.cc +++ b/passes/opt/share.cc @@ -1013,11 +1013,13 @@ struct ShareWorker return bits; } - void onesided_restrict_activiation_patterns( + bool onesided_restrict_activiation_patterns( pool &activation_patterns, const pool> &other_bits) { pool new_activiation_patterns; + bool simplified = false; + for (auto const &pattern : activation_patterns) { ssc_pair_t new_pair; for (int i = 0; i < GetSize(pattern.second); ++i) { @@ -1026,25 +1028,31 @@ struct ShareWorker 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_activiation_patterns.emplace(std::move(new_pair)); } activation_patterns = std::move(new_activiation_patterns); + return simplified; } // Only valid if the patterns on their own (i.e. without considering their input cone) are mutually exclusive! - void restrict_activiation_patterns(pool &activation_patterns, pool &other_activation_patterns) + bool restrict_activiation_patterns(pool &activation_patterns, pool &other_activation_patterns) { pool> bits = pattern_bits(activation_patterns); pool> other_bits = pattern_bits(other_activation_patterns); - onesided_restrict_activiation_patterns(activation_patterns, other_bits); - onesided_restrict_activiation_patterns(other_activation_patterns, bits); + bool simplified = false; + simplified |= onesided_restrict_activiation_patterns(activation_patterns, other_bits); + simplified |= onesided_restrict_activiation_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 &activation_patterns, pool &supercell_aux) @@ -1392,13 +1400,14 @@ struct ShareWorker 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"); - restrict_activiation_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)); + if (restrict_activiation_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)); + 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)); + } } if (find_in_input_cone(cell, other_cell)) { From 4b273a4ae9e4fc43b9580de82015a56d4095c85b Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Tue, 15 Apr 2025 12:04:09 +0200 Subject: [PATCH 34/44] share: Cleanup and additional testing Fixes a typo and adds another test case that triggers the fallback behavior as the existing tests all trigger the new optimization. --- passes/opt/share.cc | 16 ++++++++-------- tests/sat/share.v | 23 +++++++++++++++++++++++ tests/sat/share.ys | 6 +++++- 3 files changed, 36 insertions(+), 9 deletions(-) diff --git a/passes/opt/share.cc b/passes/opt/share.cc index 580549e4d..1d7ba7d98 100644 --- a/passes/opt/share.cc +++ b/passes/opt/share.cc @@ -1013,10 +1013,10 @@ struct ShareWorker return bits; } - bool onesided_restrict_activiation_patterns( + bool onesided_restrict_activation_patterns( pool &activation_patterns, const pool> &other_bits) { - pool new_activiation_patterns; + pool new_activation_patterns; bool simplified = false; @@ -1032,22 +1032,22 @@ struct ShareWorker simplified = true; } } - new_activiation_patterns.emplace(std::move(new_pair)); + new_activation_patterns.emplace(std::move(new_pair)); } - activation_patterns = std::move(new_activiation_patterns); + 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_activiation_patterns(pool &activation_patterns, pool &other_activation_patterns) + bool restrict_activation_patterns(pool &activation_patterns, pool &other_activation_patterns) { pool> bits = pattern_bits(activation_patterns); pool> other_bits = pattern_bits(other_activation_patterns); bool simplified = false; - simplified |= onesided_restrict_activiation_patterns(activation_patterns, other_bits); - simplified |= onesided_restrict_activiation_patterns(other_activation_patterns, bits); + 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); @@ -1401,7 +1401,7 @@ struct ShareWorker } else { log(" According to the SAT solver this pair of cells can be shared. (Pattern only case)\n"); - if (restrict_activiation_patterns(optimized_cell_activation_patterns, optimized_other_cell_activation_patterns)) { + 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)); diff --git a/tests/sat/share.v b/tests/sat/share.v index e06fc8f1e..29e423137 100644 --- a/tests/sat/share.v +++ b/tests/sat/share.v @@ -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 + diff --git a/tests/sat/share.ys b/tests/sat/share.ys index f2f5d649d..ef88d55c3 100644 --- a/tests/sat/share.ys +++ b/tests/sat/share.ys @@ -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 From c894685f26850a7313dcbf800c306dbab8681517 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 16 Apr 2025 00:23:21 +0000 Subject: [PATCH 35/44] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index c0fcdfe62..3f7c8aa38 100644 --- a/Makefile +++ b/Makefile @@ -160,7 +160,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.52+45 +YOSYS_VER := 0.52+50 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) From 04098933c724075cf350a79c3dc1f0dda6ec546b Mon Sep 17 00:00:00 2001 From: David Sawatzke Date: Wed, 16 Apr 2025 13:26:50 +0200 Subject: [PATCH 36/44] cxxrtl: Add internal cell "bwmux" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mirrors the implementation for the smt2 backend Co-authored-by: Martin Povišer --- backends/cxxrtl/cxxrtl_backend.cc | 10 +++++++++- backends/cxxrtl/runtime/cxxrtl/cxxrtl.h | 5 +++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/backends/cxxrtl/cxxrtl_backend.cc b/backends/cxxrtl/cxxrtl_backend.cc index b9958c5fb..052699ad6 100644 --- a/backends/cxxrtl/cxxrtl_backend.cc +++ b/backends/cxxrtl/cxxrtl_backend.cc @@ -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); diff --git a/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h b/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h index 9634b833b..37c84895f 100644 --- a/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h +++ b/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h @@ -498,6 +498,11 @@ struct value : public expr_base> { return result; } + CXXRTL_ALWAYS_INLINE + value bwmux(const value &b, const value &s) const { + return (bit_and(s.bit_not())).bit_or(b.bit_and(s)); + } + template value demux(const value &sel) const { static_assert(Bits << SelBits == ResultBits, "invalid sizes used in demux()"); From 5101b9fcba8f892a45bb5371e6f25f4d2ae9a46d Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Wed, 16 Apr 2025 18:52:49 +0200 Subject: [PATCH 37/44] liberty: Fix handling of non-ascii characters Use an `unsigned char` buffer to ensure characters cast to an `int` are in the range 0 <= c <= 255. --- passes/techmap/libparse.cc | 2 +- passes/techmap/libparse.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/passes/techmap/libparse.cc b/passes/techmap/libparse.cc index bc7758cbd..97a94ece0 100644 --- a/passes/techmap/libparse.cc +++ b/passes/techmap/libparse.cc @@ -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; diff --git a/passes/techmap/libparse.h b/passes/techmap/libparse.h index 3ba381fdf..f834044ae 100644 --- a/passes/techmap/libparse.h +++ b/passes/techmap/libparse.h @@ -92,7 +92,7 @@ namespace Yosys class LibertyInputStream { std::istream &f; - std::vector buffer; + std::vector 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) From 418e795235a0b2b8ebd5a39d8b0fa32c8707f0e7 Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Wed, 16 Apr 2025 19:03:05 +0200 Subject: [PATCH 38/44] liberty: Error when a read liberty file has no nodes --- passes/techmap/libparse.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/passes/techmap/libparse.h b/passes/techmap/libparse.h index f834044ae..e52f91e77 100644 --- a/passes/techmap/libparse.h +++ b/passes/techmap/libparse.h @@ -176,6 +176,14 @@ namespace Yosys LibertyParser(std::istream &f) : f(f), line(1) { shared_ast.reset(parse()); 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 @@ -186,6 +194,9 @@ namespace Yosys 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 }; From ce74404890242d8a45bccb6ee2fefd302316efcf Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Wed, 16 Apr 2025 19:12:01 +0200 Subject: [PATCH 39/44] liberty: Error on unclosed curly braces This is an indication that the liberty file was truncated, which shouldn't be silently ignored. --- passes/techmap/libparse.cc | 23 +++++++++++++++++++---- passes/techmap/libparse.h | 6 +++--- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/passes/techmap/libparse.cc b/passes/techmap/libparse.cc index 97a94ece0..5594d5443 100644 --- a/passes/techmap/libparse.cc +++ b/passes/techmap/libparse.cc @@ -436,6 +436,9 @@ void LibertyParser::report_unexpected_token(int tok) eReport += "'."; error(eReport); break; + case EOF: + error("Unexpected end of file"); + break; default: eReport = "Unexpected token: "; eReport += static_cast(tok); @@ -484,7 +487,7 @@ void LibertyParser::parse_vector_range(int tok) } } -LibertyAst *LibertyParser::parse() +LibertyAst *LibertyParser::parse(bool top_level) { std::string str; @@ -498,7 +501,13 @@ 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') { @@ -571,12 +580,18 @@ 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; } diff --git a/passes/techmap/libparse.h b/passes/techmap/libparse.h index e52f91e77..61dc83867 100644 --- a/passes/techmap/libparse.h +++ b/passes/techmap/libparse.h @@ -165,7 +165,7 @@ namespace Yosys void report_unexpected_token(int tok); void parse_vector_range(int tok); - LibertyAst *parse(); + LibertyAst *parse(bool top_level); void error() const; void error(const std::string &str) const; @@ -174,7 +174,7 @@ 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 @@ -190,7 +190,7 @@ namespace Yosys 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(); From c555add2310db3556db09a2e1e15864917a93fc3 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Thu, 17 Apr 2025 00:17:06 +0200 Subject: [PATCH 40/44] liberty: Test non-ascii characters --- tests/liberty/non-ascii.lib | 14 ++++++++++++++ tests/liberty/non-ascii.lib.filtered.ok | 12 ++++++++++++ tests/liberty/non-ascii.lib.verilogsim.ok | 5 +++++ 3 files changed, 31 insertions(+) create mode 100644 tests/liberty/non-ascii.lib create mode 100644 tests/liberty/non-ascii.lib.filtered.ok create mode 100644 tests/liberty/non-ascii.lib.verilogsim.ok diff --git a/tests/liberty/non-ascii.lib b/tests/liberty/non-ascii.lib new file mode 100644 index 000000000..1ac636e34 --- /dev/null +++ b/tests/liberty/non-ascii.lib @@ -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" ; + } + } +} \ No newline at end of file diff --git a/tests/liberty/non-ascii.lib.filtered.ok b/tests/liberty/non-ascii.lib.filtered.ok new file mode 100644 index 000000000..f03f725f7 --- /dev/null +++ b/tests/liberty/non-ascii.lib.filtered.ok @@ -0,0 +1,12 @@ +library(dummy) { + cell(buffer) { + area : 1 ; + pin(A) { + direction : input ; + } + pin(Y) { + direction : output ; + function : "A" ; + } + } +} diff --git a/tests/liberty/non-ascii.lib.verilogsim.ok b/tests/liberty/non-ascii.lib.verilogsim.ok new file mode 100644 index 000000000..de5e2e5f3 --- /dev/null +++ b/tests/liberty/non-ascii.lib.verilogsim.ok @@ -0,0 +1,5 @@ +module buffer (A, Y); + input A; + output Y; + assign Y = A; // "A" +endmodule From 08b3a9fc7b21aa6b4ccce0faa4c6f666f7a426c9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 17 Apr 2025 00:22:57 +0000 Subject: [PATCH 41/44] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 3f7c8aa38..76ac4bb18 100644 --- a/Makefile +++ b/Makefile @@ -160,7 +160,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.52+50 +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) From 01d80c74038dfb727e2ee19af53b813c4de364ef Mon Sep 17 00:00:00 2001 From: clemens Date: Sat, 19 Apr 2025 20:41:10 +0200 Subject: [PATCH 42/44] add testcase --- tests/various/stat.ys | 49 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/tests/various/stat.ys b/tests/various/stat.ys index ad96fe8d4..7c8700494 100644 --- a/tests/various/stat.ys +++ b/tests/various/stat.ys @@ -1,4 +1,4 @@ -read_rtlil << EOF +read_rtlil << EOT module \top wire input 1 \A wire output 2 \Y @@ -8,7 +8,52 @@ module \top connect \Y \Y end end -EOF +EOT logger -expect log "Chip area for module '\\top': 9.072000" 1 logger -expect-no-warnings stat -liberty ../../tests/liberty/foundry_data/sg13g2_stdcell_typ_1p20V_25C.lib.filtered.gz + + +design -reset +read_rtlil < Date: Sun, 20 Apr 2025 16:44:22 +0200 Subject: [PATCH 43/44] create testcase to check correct addition of areas. --- tests/various/stat.ys | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/tests/various/stat.ys b/tests/various/stat.ys index 7c8700494..cf084a986 100644 --- a/tests/various/stat.ys +++ b/tests/various/stat.ys @@ -15,20 +15,35 @@ stat -liberty ../../tests/liberty/foundry_data/sg13g2_stdcell_typ_1p20V_25C.lib. design -reset -read_rtlil < Date: Tue, 22 Apr 2025 00:23:01 +0000 Subject: [PATCH 44/44] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 76ac4bb18..e1483dbfe 100644 --- a/Makefile +++ b/Makefile @@ -160,7 +160,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.52+63 +YOSYS_VER := 0.52+75 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)