From 73403ad8304ec5a94e7effa6f10bb35a0d167dd9 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 12 Aug 2025 12:05:23 +1200 Subject: [PATCH 01/47] ci: Adjust workflow triggers for tests In light of problems with concurrent skipping, disable it. Instead, limit the `push` trigger to just main, and enable `workflow_dispatch` for manual triggering. Don't cancel builds from main if a new commit is pushed. --- .github/workflows/extra-builds.yml | 16 ++++++++++++---- .github/workflows/test-build.yml | 23 ++++++++++++++++------- .github/workflows/test-compile.yml | 16 ++++++++++++---- .github/workflows/test-verific.yml | 16 ++++++++++++---- 4 files changed, 52 insertions(+), 19 deletions(-) diff --git a/.github/workflows/extra-builds.yml b/.github/workflows/extra-builds.yml index 8d64b2e0e..944bb9e09 100644 --- a/.github/workflows/extra-builds.yml +++ b/.github/workflows/extra-builds.yml @@ -1,6 +1,14 @@ name: Test extra build flows -on: [push, pull_request] +on: + # always test main + push: + branches: + - main + # test PRs + pull_request: + # allow triggering tests, ignores skip check + workflow_dispatch: jobs: pre_job: @@ -11,11 +19,11 @@ jobs: - id: skip_check uses: fkirc/skip-duplicate-actions@v5 with: + # don't run on documentation changes paths_ignore: '["**/README.md", "docs/**", "guidelines/**"]' # cancel previous builds if a new commit is pushed - cancel_others: 'true' - # only run on push *or* pull_request, not both - concurrent_skipping: 'same_content_newer' + # but never cancel main + cancel_others: ${{ github.ref != 'refs/heads/main' }} vs-prep: name: Prepare Visual Studio build diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml index bdd290189..4cfd64da3 100644 --- a/.github/workflows/test-build.yml +++ b/.github/workflows/test-build.yml @@ -1,6 +1,14 @@ name: Build and run tests -on: [push, pull_request] +on: + # always test main + push: + branches: + - main + # test PRs + pull_request: + # allow triggering tests, ignores skip check + workflow_dispatch: jobs: pre_job: @@ -11,11 +19,12 @@ jobs: - id: skip_check uses: fkirc/skip-duplicate-actions@v5 with: + # don't run on documentation changes paths_ignore: '["**/README.md", "docs/**", "guidelines/**"]' # cancel previous builds if a new commit is pushed - cancel_others: 'true' - # only run on push *or* pull_request, not both - concurrent_skipping: 'same_content_newer' + # but never cancel main + cancel_others: ${{ github.ref != 'refs/heads/main' }} + pre_docs_job: runs-on: ubuntu-latest outputs: @@ -24,11 +33,11 @@ jobs: - id: skip_check uses: fkirc/skip-duplicate-actions@v5 with: + # don't run on readme changes paths_ignore: '["**/README.md"]' # cancel previous builds if a new commit is pushed - cancel_others: 'true' - # only run on push *or* pull_request, not both - concurrent_skipping: 'same_content_newer' + # but never cancel main + cancel_others: ${{ github.ref != 'refs/heads/main' }} build-yosys: name: Reusable build diff --git a/.github/workflows/test-compile.yml b/.github/workflows/test-compile.yml index 7a706e69a..f208b911a 100644 --- a/.github/workflows/test-compile.yml +++ b/.github/workflows/test-compile.yml @@ -1,6 +1,14 @@ name: Compiler testing -on: [push, pull_request] +on: + # always test main + push: + branches: + - main + # test PRs + pull_request: + # allow triggering tests, ignores skip check + workflow_dispatch: jobs: pre_job: @@ -11,11 +19,11 @@ jobs: - id: skip_check uses: fkirc/skip-duplicate-actions@v5 with: + # don't run on documentation changes paths_ignore: '["**/README.md", "docs/**", "guidelines/**"]' # cancel previous builds if a new commit is pushed - cancel_others: 'true' - # only run on push *or* pull_request, not both - concurrent_skipping: 'same_content_newer' + # but never cancel main + cancel_others: ${{ github.ref != 'refs/heads/main' }} test-compile: runs-on: ${{ matrix.os }} diff --git a/.github/workflows/test-verific.yml b/.github/workflows/test-verific.yml index 013c9f8ca..9af07b920 100644 --- a/.github/workflows/test-verific.yml +++ b/.github/workflows/test-verific.yml @@ -1,6 +1,14 @@ name: Build and run tests with Verific (Linux) -on: [push, pull_request] +on: + # always test main + push: + branches: + - main + # test PRs + pull_request: + # allow triggering tests, ignores skip check + workflow_dispatch: jobs: pre-job: @@ -11,11 +19,11 @@ jobs: - id: skip_check uses: fkirc/skip-duplicate-actions@v5 with: + # don't run on documentation changes paths_ignore: '["**/README.md", "docs/**", "guidelines/**"]' # cancel previous builds if a new commit is pushed - cancel_others: 'true' - # only run on push *or* pull_request, not both - concurrent_skipping: 'same_content_newer' + # but never cancel main + cancel_others: ${{ github.ref != 'refs/heads/main' }} test-verific: needs: pre-job From 0f8c040371e7f1c8c10859e77882bdea0f7bfab9 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 12 Aug 2025 12:21:50 +1200 Subject: [PATCH 02/47] ci: Move SAN into a separate workflow --- .github/workflows/test-build.yml | 13 +--- .github/workflows/test-sanitizers.yml | 105 ++++++++++++++++++++++++++ 2 files changed, 109 insertions(+), 9 deletions(-) create mode 100644 .github/workflows/test-sanitizers.yml diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml index 4cfd64da3..b62973414 100644 --- a/.github/workflows/test-build.yml +++ b/.github/workflows/test-build.yml @@ -42,6 +42,7 @@ jobs: build-yosys: name: Reusable build runs-on: ${{ matrix.os }} + # pre_job is a subset of pre_docs_job, so we can always build for pre_docs_job needs: pre_docs_job if: needs.pre_docs_job.outputs.should_skip != 'true' env: @@ -49,7 +50,6 @@ jobs: strategy: matrix: os: [ubuntu-latest, macos-latest] - sanitizer: [undefined, address] fail-fast: false steps: - name: Checkout Yosys @@ -67,7 +67,6 @@ jobs: mkdir build cd build make -f ../Makefile config-$CC - echo 'SANITIZER = ${{ matrix.sanitizer }}' >> Makefile.conf make -f ../Makefile -j$procs ENABLE_LTO=1 - name: Log yosys-config output @@ -83,7 +82,7 @@ jobs: - name: Store build artifact uses: actions/upload-artifact@v4 with: - name: build-${{ matrix.os }}-${{ matrix.sanitizer }} + name: build-${{ matrix.os }} path: build.tar retention-days: 1 @@ -94,12 +93,9 @@ jobs: if: needs.pre_job.outputs.should_skip != 'true' env: CC: clang - ASAN_OPTIONS: halt_on_error=1 - UBSAN_OPTIONS: halt_on_error=1 strategy: matrix: os: [ubuntu-latest, macos-latest] - sanitizer: [undefined, address] fail-fast: false steps: - name: Checkout Yosys @@ -148,7 +144,7 @@ jobs: - name: Download build artifact uses: actions/download-artifact@v4 with: - name: build-${{ matrix.os }}-${{ matrix.sanitizer }} + name: build-${{ matrix.os }} - name: Uncompress build shell: bash @@ -180,7 +176,6 @@ jobs: strategy: matrix: os: [ubuntu-latest] - sanitizer: [undefined, address] fail-fast: false steps: - name: Checkout Yosys @@ -194,7 +189,7 @@ jobs: - name: Download build artifact uses: actions/download-artifact@v4 with: - name: build-${{ matrix.os }}-${{ matrix.sanitizer }} + name: build-${{ matrix.os }} - name: Uncompress build shell: bash diff --git a/.github/workflows/test-sanitizers.yml b/.github/workflows/test-sanitizers.yml new file mode 100644 index 000000000..fb76d1266 --- /dev/null +++ b/.github/workflows/test-sanitizers.yml @@ -0,0 +1,105 @@ +name: Check clang sanitizers + +on: + # always test main + push: + branches: + - main + # ignore PRs due to time needed + # allow triggering tests, ignores skip check + workflow_dispatch: + +jobs: + pre_job: + runs-on: ubuntu-latest + outputs: + should_skip: ${{ steps.skip_check.outputs.should_skip }} + steps: + - id: skip_check + uses: fkirc/skip-duplicate-actions@v5 + with: + # don't run on documentation changes + paths_ignore: '["**/README.md", "docs/**", "guidelines/**"]' + + run_san: + name: Build and run tests + runs-on: ${{ matrix.os }} + needs: pre_job + if: needs.pre_job.outputs.should_skip != 'true' + env: + CC: clang + ASAN_OPTIONS: halt_on_error=1 + UBSAN_OPTIONS: halt_on_error=1 + strategy: + matrix: + os: [ubuntu-latest, macos-latest] + sanitizer: ['undefined,address'] + fail-fast: false + steps: + - name: Checkout Yosys + uses: actions/checkout@v4 + with: + submodules: true + persist-credentials: false + + - name: Setup environment + uses: ./.github/actions/setup-build-env + + - name: Build + shell: bash + run: | + mkdir build + cd build + make -f ../Makefile config-$CC + echo 'SANITIZER = ${{ matrix.sanitizer }}' >> Makefile.conf + make -f ../Makefile -j$procs ENABLE_LTO=1 + + - name: Log yosys-config output + run: | + ./yosys-config || true + + - name: Get iverilog + shell: bash + run: | + git clone https://github.com/steveicarus/iverilog.git + cd iverilog + echo "IVERILOG_GIT=$(git rev-parse HEAD)" >> $GITHUB_ENV + + - name: Get vcd2fst + shell: bash + run: | + git clone https://github.com/mmicko/libwave.git + mkdir -p ${{ github.workspace }}/.local/ + cd libwave + cmake . -DCMAKE_INSTALL_PREFIX=${{ github.workspace }}/.local + make -j$procs + make install + + - name: Cache iverilog + id: cache-iverilog + uses: actions/cache@v4 + with: + path: .local/ + key: ${{ matrix.os }}-${IVERILOG_GIT} + + - name: Build iverilog + if: steps.cache-iverilog.outputs.cache-hit != 'true' + shell: bash + run: | + mkdir -p ${{ github.workspace }}/.local/ + cd iverilog + autoconf + CC=gcc CXX=g++ ./configure --prefix=${{ github.workspace }}/.local + make -j$procs + make install + + - name: Run tests + shell: bash + run: | + make -j$procs test TARGETS= EXTRA_TARGETS= CONFIG=$CC + + - name: Report errors + if: ${{ failure() }} + shell: bash + run: | + find tests/**/*.err -print -exec cat {} \; From a0dde68487da600c569c0b61b684dc845fd5c554 Mon Sep 17 00:00:00 2001 From: clemens Date: Tue, 15 Apr 2025 09:39:49 +0200 Subject: [PATCH 03/47] Improve STAT --- passes/cmds/stat.cc | 617 +++++++++++++++++++++++++++++++++----------- 1 file changed, 472 insertions(+), 145 deletions(-) diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc index af7023bdd..0d19849c3 100644 --- a/passes/cmds/stat.cc +++ b/passes/cmds/stat.cc @@ -19,13 +19,14 @@ #include -#include "kernel/yosys.h" #include "kernel/celltypes.h" -#include "passes/techmap/libparse.h" #include "kernel/cost.h" #include "kernel/gzip.h" +#include "kernel/yosys.h" #include "libs/json11/json11.hpp" #include "kernel/log_help.h" +#include "passes/techmap/libparse.h" +#include USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -35,137 +36,225 @@ struct cell_area_t { bool is_sequential; }; -struct statdata_t -{ - #define STAT_INT_MEMBERS X(num_wires) X(num_wire_bits) X(num_pub_wires) X(num_pub_wire_bits) \ - X(num_ports) X(num_port_bits) X(num_memories) X(num_memory_bits) X(num_cells) \ - X(num_processes) +struct statdata_t { +#define STAT_INT_MEMBERS \ + X(num_wires) \ + X(num_wire_bits) \ + X(num_pub_wires) X(num_pub_wire_bits) 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) X(sequential_area) +#define STAT_NUMERIC_MEMBERS STAT_INT_MEMBERS X(area) X(sequential_area) - #define X(_name) unsigned int _name; +#define X(_name) unsigned int _name; STAT_INT_MEMBERS - #undef X +#undef X +#define X(_name) unsigned int local_##_name; + STAT_INT_MEMBERS +#undef X double area = 0; double sequential_area = 0; + double local_area = 0; + double local_sequential_area = 0; + double submodule_area = 0; + int num_submodules = 0; + std::map num_submodules_by_type; + std::map submodules_area_by_type; + + std::map local_num_cells_by_type; + std::map local_area_cells_by_type; + std::map local_seq_area_cells_by_type; string tech; std::map num_cells_by_type; + std::map area_cells_by_type; + std::map seq_area_cells_by_type; std::set unknown_cell_area; statdata_t operator+(const statdata_t &other) const { statdata_t sum = other; - #define X(_name) sum._name += _name; +#define X(_name) sum._name += _name; STAT_NUMERIC_MEMBERS - #undef X +#undef X for (auto &it : num_cells_by_type) sum.num_cells_by_type[it.first] += it.second; return sum; } - statdata_t operator*(unsigned int other) const { statdata_t sum = *this; - #define X(_name) sum._name *= other; +#define X(_name) sum._name *= other; STAT_NUMERIC_MEMBERS - #undef X +#undef X for (auto &it : sum.num_cells_by_type) it.second *= other; return sum; } + statdata_t add(const statdata_t &other) + { +#define X(_name) _name += other._name; + STAT_NUMERIC_MEMBERS +#undef X + for (auto &it : other.num_cells_by_type) { + if (num_cells_by_type.count(it.first)) + num_cells_by_type[it.first] += it.second; + else + num_cells_by_type[it.first] = it.second; + } + for (auto &it : other.submodules_area_by_type) { + if (submodules_area_by_type.count(it.first)) + submodules_area_by_type[it.first] += it.second; + else + submodules_area_by_type[it.first] = it.second; + } + for (auto &it : other.area_cells_by_type) { + if (area_cells_by_type.count(it.first)) + area_cells_by_type[it.first] += it.second; + else + area_cells_by_type[it.first] = it.second; + } + for (auto &it : other.seq_area_cells_by_type) { + if (seq_area_cells_by_type.count(it.first)) + seq_area_cells_by_type[it.first] += it.second; + else + seq_area_cells_by_type[it.first] = it.second; + } + unknown_cell_area.insert(other.unknown_cell_area.begin(), other.unknown_cell_area.end()); + return *this; + } statdata_t() { - #define X(_name) _name = 0; +#define X(_name) _name = 0; STAT_NUMERIC_MEMBERS - #undef X +#undef X } - statdata_t(RTLIL::Design *design, RTLIL::Module *mod, bool width_mode, const dict &cell_area, string techname) + statdata_t(cell_area_t &cell_data, string techname) + { + tech = techname; + area = cell_data.area; + if (cell_data.is_sequential) { + sequential_area = cell_data.area; + } + } + + statdata_t(const RTLIL::Design *design, const RTLIL::Module *mod, bool width_mode, dict &cell_area, string techname) { tech = techname; - #define X(_name) _name = 0; +#define X(_name) _name = 0; STAT_NUMERIC_MEMBERS - #undef X +#undef X +#define X(_name) local_##_name = 0; + STAT_NUMERIC_MEMBERS +#undef X + // additional_cell_area - for (auto wire : mod->selected_wires()) - { + for (auto wire : mod->selected_wires()) { if (wire->port_input || wire->port_output) { num_ports++; + local_num_ports++; num_port_bits += wire->width; + local_num_port_bits += wire->width; } if (wire->name.isPublic()) { num_pub_wires++; + local_num_pub_wires++; num_pub_wire_bits += wire->width; + local_num_pub_wire_bits += wire->width; } num_wires++; + local_num_wires++; num_wire_bits += wire->width; + local_num_wire_bits += wire->width; } for (auto &it : mod->memories) { if (!design->selected(mod, it.second)) continue; num_memories++; + local_num_memories++; num_memory_bits += it.second->width * it.second->size; + local_num_memory_bits += it.second->width * it.second->size; } - - for (auto cell : mod->selected_cells()) - { + for (auto cell : mod->selected_cells()) { RTLIL::IdString cell_type = cell->type; - - if (width_mode) - { - if (cell_type.in(ID($not), ID($pos), ID($neg), - ID($logic_not), ID($logic_and), ID($logic_or), - ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_xnor), ID($reduce_bool), - ID($lut), ID($and), ID($or), ID($xor), ID($xnor), - ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx), - ID($lt), ID($le), ID($eq), ID($ne), ID($eqx), ID($nex), ID($ge), ID($gt), - ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($divfloor), ID($modfloor), ID($pow), ID($alu))) { + if (width_mode) { + if (cell_type.in(ID($not), ID($pos), ID($neg), ID($logic_not), ID($logic_and), ID($logic_or), ID($reduce_and), + ID($reduce_or), ID($reduce_xor), ID($reduce_xnor), ID($reduce_bool), ID($lut), ID($and), ID($or), + ID($xor), ID($xnor), ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx), ID($lt), + ID($le), ID($eq), ID($ne), ID($eqx), ID($nex), ID($ge), ID($gt), ID($add), ID($sub), ID($mul), + ID($div), ID($mod), ID($divfloor), ID($modfloor), ID($pow), ID($alu))) { int width_a = cell->hasPort(ID::A) ? GetSize(cell->getPort(ID::A)) : 0; int width_b = cell->hasPort(ID::B) ? GetSize(cell->getPort(ID::B)) : 0; int width_y = cell->hasPort(ID::Y) ? GetSize(cell->getPort(ID::Y)) : 0; cell_type = stringf("%s_%d", cell_type.c_str(), max({width_a, width_b, width_y})); - } - else if (cell_type.in(ID($mux), ID($pmux))) + } else if (cell_type.in(ID($mux))) cell_type = stringf("%s_%d", cell_type.c_str(), GetSize(cell->getPort(ID::Y))); - else if (cell_type == ID($bmux)) - cell_type = stringf("%s_%d_%d", cell_type.c_str(), GetSize(cell->getPort(ID::Y)), GetSize(cell->getPort(ID::S))); + else if (cell_type.in(ID($bmux), ID($pmux))) + cell_type = + stringf("%s_%d_%d", cell_type.c_str(), GetSize(cell->getPort(ID::Y)), GetSize(cell->getPort(ID::S))); else if (cell_type == ID($demux)) - cell_type = stringf("%s_%d_%d", cell_type.c_str(), GetSize(cell->getPort(ID::A)), GetSize(cell->getPort(ID::S))); - else if (cell_type.in( - ID($sr), ID($ff), ID($dff), ID($dffe), ID($dffsr), ID($dffsre), - ID($adff), ID($adffe), ID($sdff), ID($sdffe), ID($sdffce), - ID($aldff), ID($aldffe), ID($dlatch), ID($adlatch), ID($dlatchsr))) + cell_type = + stringf("%s_%d_%d", cell_type.c_str(), GetSize(cell->getPort(ID::A)), GetSize(cell->getPort(ID::S))); + else if (cell_type.in(ID($sr), ID($ff), ID($dff), ID($dffe), ID($dffsr), ID($dffsre), ID($adff), ID($adffe), + ID($sdff), ID($sdffe), ID($sdffce), ID($aldff), ID($aldffe), ID($dlatch), ID($adlatch), + ID($dlatchsr))) cell_type = stringf("%s_%d", cell_type.c_str(), GetSize(cell->getPort(ID::Q))); } if (!cell_area.empty()) { + if (cell_area.count(cell_type)) { cell_area_t cell_data = cell_area.at(cell_type); if (cell_data.is_sequential) { sequential_area += cell_data.area; + local_sequential_area += cell_data.area; } area += cell_data.area; - } - else { - unknown_cell_area.insert(cell_type); - } - } + num_cells++; + num_cells_by_type[cell_type]++; + area_cells_by_type[cell_type] += cell_data.area; + seq_area_cells_by_type[cell_type] += cell_data.is_sequential ? cell_data.area : 0; + local_area_cells_by_type[cell_type] += cell_data.area; + local_seq_area_cells_by_type[cell_type] += cell_data.is_sequential ? cell_data.area : 0; + local_area += cell_data.area; + local_num_cells++; + local_num_cells_by_type[cell_type]++; - num_cells++; - num_cells_by_type[cell_type]++; + } else { + unknown_cell_area.insert(cell_type); + num_cells++; + num_cells_by_type[cell_type]++; + local_num_cells++; + local_num_cells_by_type[cell_type]++; + area_cells_by_type[cell_type] = 0; + seq_area_cells_by_type[cell_type] = 0; + local_area_cells_by_type[cell_type] = 0; + local_seq_area_cells_by_type[cell_type] = 0; + } + } else { + num_cells++; + num_cells_by_type[cell_type]++; + area_cells_by_type[cell_type] = 0; + seq_area_cells_by_type[cell_type] = 0; + local_num_cells++; + local_num_cells_by_type[cell_type]++; + local_area_cells_by_type[cell_type] = 0; + local_seq_area_cells_by_type[cell_type] = 0; + } } for (auto &it : mod->processes) { if (!design->selected(mod, it.second)) continue; num_processes++; + local_num_processes++; } + RTLIL::IdString cell_name = mod->name; + auto s = cell_name.str(); } unsigned int estimate_xilinx_lc() @@ -238,22 +327,119 @@ struct statdata_t return tran_cnt; } - void log_data(RTLIL::IdString mod_name, bool top_mod) + /* + format a floating point value to a of 8 characters, with at most 7 digits or scientific notation + uses - to mark zero or very small values + */ + std::string f_val(double value) { - log(" Number of wires: %6u\n", num_wires); - log(" Number of wire bits: %6u\n", num_wire_bits); - log(" Number of public wires: %6u\n", num_pub_wires); - log(" Number of public wire bits: %6u\n", num_pub_wire_bits); - log(" Number of ports: %6u\n", num_ports); - log(" Number of port bits: %6u\n", num_port_bits); - log(" Number of memories: %6u\n", num_memories); - log(" Number of memory bits: %6u\n", num_memory_bits); - log(" Number of processes: %6u\n", num_processes); - log(" Number of cells: %6u\n", num_cells); - for (auto &it : num_cells_by_type) - if (it.second) - log(" %-26s %6u\n", log_id(it.first), it.second); + if (std::abs(value) < 1e-12) + return " -"; + char buf[16]; + + int len = std::snprintf(buf, sizeof(buf), "%.3f", value); + + while (len > 0 && buf[len - 1] == '0') + --len; + if (len > 0 && buf[len - 1] == '.') + --len; + buf[len] = '\0'; + + if (len <= 7) { + return std::string(8 - len, ' ') + std::string(buf); + } + + // use scientific notation, this should always fit in 8 characters + std::snprintf(buf, sizeof(buf), "%8.3G", value); + + return std::string(buf); + } + + void print_log_line(const std::string &name, unsigned int count_local, double area_local, unsigned int count_global, double area_global, + int spacer = 0, bool print_area = true, bool print_hierarchical = true) + { + const std::string indent(2 * spacer, ' '); + + std::string count_local_str = f_val(static_cast(count_local)); + std::string count_global_str = f_val(static_cast(count_global)); + std::string area_local_str = f_val(area_local); + std::string area_global_str = f_val(area_global); + + if (print_area) { + if (print_hierarchical) { + log(" %s %s %s %s %s%s\n", count_global_str.c_str(), area_global_str.c_str(), count_local_str.c_str(), + area_local_str.c_str(), indent.c_str(), name.c_str()); + } else { + if (count_local > 0) + log(" %s %s %s%s\n", count_local_str.c_str(), area_local_str.c_str(), indent.c_str(), name.c_str()); + } + } else { + if (print_hierarchical) { + log(" %s %s %s%s\n", count_global_str.c_str(), count_local_str.c_str(), indent.c_str(), name.c_str()); + } else { + if (count_local > 0) + log(" %s %s%s\n", count_local_str.c_str(), indent.c_str(), name.c_str()); + } + } + } + + void print_log_header(bool print_area = true, bool print_hierarchical = true) + { + if (print_area) { + if (print_hierarchical) { + log(" %8s-%8s-%8s-%8s-%s\n", "+", "--------", "--------", "--------", "Count including submodules."); + log(" %8s %8s-%8s-%8s-%s\n", "|", "+", "--------", "--------", "Area including submodules."); + log(" %8s %8s %8s-%8s-%s\n", "|", "|", "+", "--------", "Local count, excluding submodules."); + log(" %8s %8s %8s %8s-%s\n", "|", "|", "|", "+", "Local area, excluding submodules."); + log(" %8s %8s %8s %8s \n", "|", "|", "|", "|"); + } else { + log(" %8s-%8s-%s\n", "+", "--------", "Local Count including submodules."); + log(" %8s %8s-%s\n", "|", "+", "Local Area including submodules."); + log(" %8s %8s \n", "|", "|"); + } + } else { + if (print_hierarchical) { + log(" %8s-%8s-%8s-%s\n", "+", "--------", "--------", "Count including submodules."); + log(" %8s %8s-%8s-%s\n", "|", "+", "--------", "Local count, excluding submodules."); + log(" %8s %8s \n", "|", "|"); + } else { + log(" %8s-%8s-%s\n", "+", "--------", "Local Count including submodules."); + log(" %8s \n", "|"); + } + } + } + + void log_data(RTLIL::IdString mod_name, bool top_mod, bool print_area = true, bool print_hierarchical = true) + { + + print_log_header(print_area, print_hierarchical); + + print_log_line("wires", local_num_wires, 0, num_wires, 0, 0, print_area, print_hierarchical); + print_log_line("wire bits", local_num_wire_bits, 0, num_wire_bits, 0, 0, print_area, print_hierarchical); + print_log_line("public wires", local_num_pub_wires, 0, num_pub_wires, 0, 0, print_area, print_hierarchical); + print_log_line("public wire bits", local_num_pub_wire_bits, 0, num_pub_wire_bits, 0, 0, print_area, print_hierarchical); + print_log_line("ports", local_num_ports, 0, num_ports, 0, 0, print_area, print_hierarchical); + print_log_line("port bits", local_num_port_bits, 0, num_port_bits, 0, 0, print_area, print_hierarchical); + print_log_line("memories", local_num_memories, 0, num_memories, 0, 0, print_area, print_hierarchical); + print_log_line("memory bits", local_num_memory_bits, 0, num_memory_bits, 0, 0, print_area, print_hierarchical); + print_log_line("processes", local_num_processes, 0, num_processes, 0, 0, print_area, print_hierarchical); + print_log_line("cells", local_num_cells, local_area, num_cells, area, 0, print_area, print_hierarchical); + for (auto &it : num_cells_by_type) + if (it.second) { + auto name = string(log_id(it.first)); + print_log_line(name, local_num_cells_by_type.count(it.first) ? local_num_cells_by_type.at(it.first) : 0, + local_area_cells_by_type.count(it.first) ? local_area_cells_by_type.at(it.first) : 0, it.second, + area_cells_by_type.at(it.first), 1, print_area, print_hierarchical); + } + if (num_submodules > 0) { + print_log_line("submodules", num_submodules, 0, num_submodules, submodule_area, 0, print_area, print_hierarchical); + for (auto &it : num_submodules_by_type) + if (it.second) + print_log_line(string(log_id(it.first)), it.second, 0, it.second, + submodules_area_by_type.count(it.first) ? submodules_area_by_type.at(it.first) : 0, 1, + print_area, print_hierarchical); + } if (!unknown_cell_area.empty()) { log("\n"); for (auto cell_type : unknown_cell_area) @@ -263,17 +449,15 @@ struct statdata_t if (area != 0) { log("\n"); log(" Chip area for %smodule '%s': %f\n", (top_mod) ? "top " : "", mod_name.c_str(), area); - log(" of which used for sequential elements: %f (%.2f%%)\n", sequential_area, 100.0*sequential_area/area); + log(" of which used for sequential elements: %f (%.2f%%)\n", sequential_area, 100.0 * sequential_area / area); } - if (tech == "xilinx") - { + if (tech == "xilinx") { log("\n"); log(" Estimated number of LCs: %10u\n", estimate_xilinx_lc()); } - if (tech == "cmos") - { + if (tech == "cmos") { bool tran_cnt_exact = true; unsigned int tran_cnt = cmos_transistor_count(&tran_cnt_exact); @@ -282,87 +466,203 @@ struct statdata_t } } - void log_data_json(const char *mod_name, bool first_module) + string json_line(unsigned int count_local, double area_local, unsigned int count_global, double area_global) + { + + return stringf("{ \"count\": \"%u\", \"area\": \"%f\", \"local_count\": \"%u\", \"local_area\": \"%f\" }", count_global, area_global, + count_local, area_local); + } + + void log_data_json(const char *mod_name, bool first_module, bool hierarchical = false) { if (!first_module) log(",\n"); - log(" %s: {\n", json11::Json(mod_name).dump().c_str()); - log(" \"num_wires\": %u,\n", num_wires); - log(" \"num_wire_bits\": %u,\n", num_wire_bits); - log(" \"num_pub_wires\": %u,\n", num_pub_wires); - log(" \"num_pub_wire_bits\": %u,\n", num_pub_wire_bits); - log(" \"num_ports\": %u,\n", num_ports); - log(" \"num_port_bits\": %u,\n", num_port_bits); - log(" \"num_memories\": %u,\n", num_memories); - log(" \"num_memory_bits\": %u,\n", num_memory_bits); - log(" \"num_processes\": %u,\n", num_processes); - log(" \"num_cells\": %u,\n", num_cells); - if (area != 0) { - log(" \"area\": %f,\n", area); - } - log(" \"num_cells_by_type\": {\n"); - bool first_line = true; - for (auto &it : num_cells_by_type) - if (it.second) { - if (!first_line) - log(",\n"); - log(" %s: %u", json11::Json(log_id(it.first)).dump().c_str(), it.second); - first_line = false; + if (hierarchical) { + log(" %s: {\n", json11::Json(mod_name).dump().c_str()); + log(" \"num_wires\": %s,\n", json_line(local_num_wires, 0, num_wires, 0).c_str()); + log(" \"num_wire_bits\": %s,\n", json_line(local_num_wire_bits, 0, num_wire_bits, 0).c_str()); + log(" \"num_pub_wires\": %s,\n", json_line(local_num_pub_wires, 0, num_pub_wires, 0).c_str()); + log(" \"num_pub_wire_bits\": %s,\n", json_line(local_num_pub_wire_bits, 0, num_pub_wire_bits, 0).c_str()); + log(" \"num_ports\": %s,\n", json_line(local_num_ports, 0, num_ports, 0).c_str()); + log(" \"num_port_bits\": %s,\n", json_line(local_num_port_bits, 0, num_port_bits, 0).c_str()); + log(" \"num_memories\": %s,\n", json_line(local_num_memories, 0, num_memories, 0).c_str()); + log(" \"num_memory_bits\": %s,\n", json_line(local_num_memory_bits, 0, num_memory_bits, 0).c_str()); + log(" \"num_processes\": %s,\n", json_line(local_num_processes, 0, num_processes, 0).c_str()); + log(" \"num_cells\": %s,\n", json_line(local_num_cells, local_area, num_cells, area).c_str()); + log(" \"num_submodules\": %s,\n", json_line(0, 0, num_submodules, submodule_area).c_str()); + log(" \"sequential_area\": %s,\n", json_line(0, local_sequential_area, 0, sequential_area).c_str()); + + log(" \"num_cells_by_type\": {\n"); + bool first_line = true; + for (auto &it : num_cells_by_type) + if (it.second) { + if (!first_line) + log(",\n"); + log(" %s: %s", json11::Json(log_id(it.first)).dump().c_str(), + json_line(local_num_cells_by_type.count(it.first) ? local_num_cells_by_type.at(it.first) : 0, + local_area_cells_by_type.count(it.first) ? local_area_cells_by_type.at(it.first) : 0, it.second, + area_cells_by_type.at(it.first)) + .c_str()); + first_line = false; + } + log("\n },\n"); + log(" \"num_submodules_by_type\": {\n"); + first_line = true; + for (auto &it : num_submodules_by_type) + if (it.second) { + if (!first_line) + log(",\n"); + log(" %s: %s", json11::Json(log_id(it.first)).dump().c_str(), + json_line(0, 0, it.second, + submodules_area_by_type.count(it.first) ? submodules_area_by_type.at(it.first) : 0) + .c_str()); + first_line = false; + } + log("\n }\n"); + if (tech == "xilinx") { + log(" \"estimated_num_lc\": %u,\n", estimate_xilinx_lc()); } - log("\n"); - log(" }"); - if (tech == "xilinx") - { - log(",\n"); - log(" \"estimated_num_lc\": %u", estimate_xilinx_lc()); + if (tech == "cmos") { + bool tran_cnt_exact = true; + unsigned int tran_cnt = cmos_transistor_count(&tran_cnt_exact); + log(" \"estimated_num_transistors\": \"%u%s\"\n", tran_cnt, tran_cnt_exact ? "" : "+"); + } + log(" }"); + + } else { + + log(" %s: {\n", json11::Json(mod_name).dump().c_str()); + log(" \"num_wires\": %u,\n", num_wires); + log(" \"num_wire_bits\": %u,\n", num_wire_bits); + log(" \"num_pub_wires\": %u,\n", num_pub_wires); + log(" \"num_pub_wire_bits\": %u,\n", num_pub_wire_bits); + log(" \"num_ports\": %u,\n", num_ports); + log(" \"num_port_bits\": %u,\n", num_port_bits); + log(" \"num_memories\": %u,\n", num_memories); + log(" \"num_memory_bits\": %u,\n", num_memory_bits); + log(" \"num_processes\": %u,\n", num_processes); + log(" \"num_cells\": %u,\n", local_num_cells); + log(" \"num_submodules\": %u,\n", num_submodules); + if (area != 0) { + log(" \"area\": %f,\n", area); + log(" \"sequential_area\": %f,\n", sequential_area); + } + log(" \"num_cells_by_type\": {\n"); + bool first_line = true; + for (auto &it : local_num_cells_by_type) + if (it.second) { + if (!first_line) + log(",\n"); + log(" %s: %u", json11::Json(log_id(it.first)).dump().c_str(), it.second); + first_line = false; + } + for (auto &it : num_submodules_by_type) + if (it.second) { + if (!first_line) + log(",\n"); + log(" %s: %u", json11::Json(log_id(it.first)).dump().c_str(), it.second); + first_line = false; + } + log("\n"); + log(" }"); + if (tech == "xilinx") { + log(",\n"); + log(" \"estimated_num_lc\": %u", estimate_xilinx_lc()); + } + if (tech == "cmos") { + bool tran_cnt_exact = true; + unsigned int tran_cnt = cmos_transistor_count(&tran_cnt_exact); + log(",\n"); + log(" \"estimated_num_transistors\": \"%u%s\"", tran_cnt, tran_cnt_exact ? "" : "+"); + } + log("\n"); + log(" }"); } - if (tech == "cmos") - { - bool tran_cnt_exact = true; - unsigned int tran_cnt = cmos_transistor_count(&tran_cnt_exact); - log(",\n"); - log(" \"estimated_num_transistors\": \"%u%s\"", tran_cnt, tran_cnt_exact ? "" : "+"); - } - log("\n"); - log(" }"); } }; -statdata_t hierarchy_worker(std::map &mod_stat, RTLIL::IdString mod, int level, bool quiet = false) +statdata_t hierarchy_worker(std::map &mod_stat, RTLIL::IdString mod, int level, bool quiet = false, bool has_area = true, + bool hierarchy_mode = true) { statdata_t mod_data = mod_stat.at(mod); - std::map num_cells_by_type; - num_cells_by_type.swap(mod_data.num_cells_by_type); - for (auto &it : num_cells_by_type) + for (auto &it : mod_data.num_submodules_by_type) { if (mod_stat.count(it.first) > 0) { if (!quiet) - log(" %*s%-*s %6u\n", 2*level, "", 26-2*level, log_id(it.first), it.second); - mod_data = mod_data + hierarchy_worker(mod_stat, it.first, level+1, quiet) * it.second; - mod_data.num_cells -= it.second; - } else { - mod_data.num_cells_by_type[it.first] += it.second; + mod_data.print_log_line(string(log_id(it.first)), mod_stat.at(it.first).local_num_cells, + mod_stat.at(it.first).local_area, mod_stat.at(it.first).num_cells, mod_stat.at(it.first).area, + level, has_area, hierarchy_mode); + hierarchy_worker(mod_stat, it.first, level + 1, quiet, has_area, hierarchy_mode) * it.second; } + } return mod_data; } +statdata_t hierarchy_builder(const RTLIL::Design *design, const RTLIL::Module *top_mod, std::map &mod_stat, + bool width_mode, dict &cell_area, string techname) +{ + if (top_mod == nullptr) + top_mod = design->top_module(); + statdata_t mod_data(design, top_mod, width_mode, cell_area, techname); + for (auto cell : top_mod->selected_cells()) { + if (cell_area.count(cell->type) == 0) { + if (design->has(cell->type)) { + if (!(design->module(cell->type)->attributes.count(ID::blackbox))) { + // deal with modules + mod_data.add( + hierarchy_builder(design, design->module(cell->type), mod_stat, width_mode, cell_area, techname)); + mod_data.num_submodules_by_type[cell->type]++; + mod_data.submodules_area_by_type[cell->type] += mod_stat.at(cell->type).area; + mod_data.submodule_area += mod_stat.at(cell->type).area; + mod_data.num_submodules++; + mod_data.unknown_cell_area.erase(cell->type); + mod_data.num_cells -= mod_data.num_cells_by_type.erase(cell->type); + mod_data.area_cells_by_type.erase(cell->type); + mod_data.local_num_cells -= mod_data.local_num_cells_by_type.erase(cell->type); + mod_data.local_area_cells_by_type.erase(cell->type); + } else { + // deal with blackbox cells + if (design->module(cell->type)->attributes.count(ID::area) && + design->module(cell->type)->attributes.at(ID::area).size() == 0) { + mod_data.num_submodules_by_type[cell->type]++; + mod_data.num_submodules++; + mod_data.submodules_area_by_type[cell->type] += + double(design->module(cell->type)->attributes.at(ID::area).as_int()); + mod_data.area += double(design->module(cell->type)->attributes.at(ID::area).as_int()); + mod_data.unknown_cell_area.erase(cell->type); + } else { + mod_data.unknown_cell_area.insert(cell->type); + mod_data.num_submodules++; + mod_data.num_submodules_by_type[cell->type]++; + mod_data.submodules_area_by_type[cell->type] = 0; + mod_data.seq_area_cells_by_type[cell->type] = 0; + } + } + } + } + } + mod_stat[top_mod->name] = mod_data; + return mod_data; +} + void read_liberty_cellarea(dict &cell_area, string liberty_file) { - std::istream* f = uncompressed(liberty_file.c_str()); + std::istream *f = uncompressed(liberty_file.c_str()); yosys_input_files.insert(liberty_file); LibertyParser libparser(*f, liberty_file); delete f; - for (auto cell : libparser.ast->children) - { + for (auto cell : libparser.ast->children) { if (cell->id != "cell" || cell->args.size() != 1) continue; const LibertyAst *ar = cell->find("area"); bool is_flip_flop = cell->find("ff") != nullptr; - if (ar != nullptr && !ar->value.empty()) - cell_area["\\" + cell->args[0]] = {/*area=*/atof(ar->value.c_str()), is_flip_flop}; + if (ar != nullptr && !ar->value.empty()) { + string prefix = cell->args[0].substr(0, 1) == "$" ? "" : "\\"; + cell_area[prefix + cell->args[0]] = {atof(ar->value.c_str()), is_flip_flop}; + } } } @@ -381,6 +681,7 @@ struct StatPass : public Pass { log("\n"); log("Print some statistics (number of objects) on the selected portion of the\n"); log("design.\n"); + log("Extracts the area of cells from a liberty file, if provided.\n"); log("\n"); log(" -top \n"); log(" print design hierarchy with this module as top. if the design is fully\n"); @@ -402,35 +703,38 @@ struct StatPass : public Pass { log(" output the statistics in a machine-readable JSON format.\n"); log(" this is output to the console; use \"tee\" to output to a file.\n"); log("\n"); + log(" -hierarchy\n"); + log(" print hierarchical statistics, i.e. The area and number of cells include submodules.\n"); + log(" this changes the format of the json output.\n"); + log("\n"); } void execute(std::vector args, RTLIL::Design *design) override { - bool width_mode = false, json_mode = false; + bool width_mode = false, json_mode = false, hierarchy_mode = false; RTLIL::Module *top_mod = nullptr; std::map mod_stat; dict cell_area; string techname; size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) - { + for (argidx = 1; argidx < args.size(); argidx++) { if (args[argidx] == "-width") { width_mode = true; continue; } - if (args[argidx] == "-liberty" && argidx+1 < args.size()) { + if (args[argidx] == "-liberty" && argidx + 1 < args.size()) { string liberty_file = args[++argidx]; rewrite_filename(liberty_file); read_liberty_cellarea(cell_area, liberty_file); continue; } - if (args[argidx] == "-tech" && argidx+1 < args.size()) { + if (args[argidx] == "-tech" && argidx + 1 < args.size()) { techname = args[++argidx]; continue; } - if (args[argidx] == "-top" && argidx+1 < args.size()) { - if (design->module(RTLIL::escape_id(args[argidx+1])) == nullptr) - log_cmd_error("Can't find module %s.\n", args[argidx+1].c_str()); + if (args[argidx] == "-top" && argidx + 1 < args.size()) { + if (design->module(RTLIL::escape_id(args[argidx + 1])) == nullptr) + log_cmd_error("Can't find module %s.\n", args[argidx + 1].c_str()); top_mod = design->module(RTLIL::escape_id(args[++argidx])); continue; } @@ -438,11 +742,15 @@ struct StatPass : public Pass { json_mode = true; continue; } + if (args[argidx] == "-hierarchy") { + hierarchy_mode = true; + continue; + } break; } extra_args(args, argidx, design); - if(!json_mode) + if (!json_mode) log_header(design, "Printing statistics.\n"); if (techname != "" && techname != "xilinx" && techname != "cmos" && !json_mode) @@ -457,24 +765,40 @@ struct StatPass : public Pass { log(" \"modules\": {\n"); } + printf("building cell area\n"); + if (top_mod != nullptr) { + hierarchy_builder(design, top_mod, mod_stat, width_mode, cell_area, techname); + } else { + for (auto mod : design->selected_modules()) { + if (mod_stat.count(mod->name) == 0) { + hierarchy_builder(design, mod, mod_stat, width_mode, cell_area, techname); + } + } + } + + printf("built hierarchy\n"); bool first_module = true; - for (auto mod : design->selected_modules()) - { + // determine if anything has a area. + bool has_area = false; + for (auto &it : mod_stat) { + if (it.second.area > 0 || it.second.sequential_area > 0) { + has_area = true; + break; + } + } + for (auto mod : design->selected_modules()) { if (!top_mod && design->full_selection()) if (mod->get_bool_attribute(ID::top)) top_mod = mod; - - statdata_t data(design, mod, width_mode, cell_area, techname); - mod_stat[mod->name] = data; - + statdata_t data = mod_stat.at(mod->name); if (json_mode) { - data.log_data_json(mod->name.c_str(), first_module); + data.log_data_json(mod->name.c_str(), first_module, hierarchy_mode); first_module = false; } else { log("\n"); log("=== %s%s ===\n", log_id(mod->name), mod->is_selected_whole() ? "" : " (partially selected)"); log("\n"); - data.log_data(mod->name, false); + data.log_data(mod->name, false, has_area, hierarchy_mode); } } @@ -483,22 +807,24 @@ struct StatPass : public Pass { log(top_mod == nullptr ? " }\n" : " },\n"); } - if (top_mod != nullptr) - { + if (top_mod != nullptr) { if (!json_mode && GetSize(mod_stat) > 1) { log("\n"); log("=== design hierarchy ===\n"); log("\n"); - log(" %-28s %6d\n", log_id(top_mod->name), 1); + mod_stat[top_mod->name].print_log_header(has_area, hierarchy_mode); + mod_stat[top_mod->name].print_log_line(log_id(top_mod->name), mod_stat[top_mod->name].local_num_cells, + mod_stat[top_mod->name].local_area, mod_stat[top_mod->name].num_cells, + mod_stat[top_mod->name].area, 0, has_area, hierarchy_mode); } - statdata_t data = hierarchy_worker(mod_stat, top_mod->name, 0, /*quiet=*/json_mode); + statdata_t data = hierarchy_worker(mod_stat, top_mod->name, 0, /*quiet=*/json_mode, has_area, hierarchy_mode); if (json_mode) - data.log_data_json("design", true); + data.log_data_json("design", true, true); else if (GetSize(mod_stat) > 1) { log("\n"); - data.log_data(top_mod->name, true); + data.log_data(top_mod->name, true, has_area, hierarchy_mode); } design->scratchpad_set_int("stat.num_wires", data.num_wires); @@ -520,6 +846,7 @@ struct StatPass : public Pass { } log("\n"); + printf("processed statistics\n"); } } StatPass; From 2a97987cf208d353ff76f6c3964ea2ee689c0955 Mon Sep 17 00:00:00 2001 From: clemens Date: Tue, 12 Aug 2025 09:16:05 +0200 Subject: [PATCH 04/47] formatting and remove debug statements --- passes/cmds/stat.cc | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc index 0d19849c3..24b21d674 100644 --- a/passes/cmds/stat.cc +++ b/passes/cmds/stat.cc @@ -22,9 +22,9 @@ #include "kernel/celltypes.h" #include "kernel/cost.h" #include "kernel/gzip.h" +#include "kernel/log_help.h" #include "kernel/yosys.h" #include "libs/json11/json11.hpp" -#include "kernel/log_help.h" #include "passes/techmap/libparse.h" #include @@ -667,8 +667,9 @@ void read_liberty_cellarea(dict &cell_area, string libert } struct StatPass : public Pass { - StatPass() : Pass("stat", "print some statistics") { } - bool formatted_help() override { + StatPass() : Pass("stat", "print some statistics") {} + bool formatted_help() override + { auto *help = PrettyHelp::get_current(); help->set_group("passes/status"); return false; @@ -765,7 +766,6 @@ struct StatPass : public Pass { log(" \"modules\": {\n"); } - printf("building cell area\n"); if (top_mod != nullptr) { hierarchy_builder(design, top_mod, mod_stat, width_mode, cell_area, techname); } else { @@ -776,7 +776,6 @@ struct StatPass : public Pass { } } - printf("built hierarchy\n"); bool first_module = true; // determine if anything has a area. bool has_area = false; From 256aa3e389e325b925e554d1d3b52abaac2c7a11 Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Tue, 12 Aug 2025 14:38:20 +0200 Subject: [PATCH 05/47] check: Limit detailed cell edge checking for $pmux and $bmux While these cells can't have a quadratic number of edges between A, B and Y, they do have a quadratic number of edges between S and Y. --- passes/cmds/check.cc | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/passes/cmds/check.cc b/passes/cmds/check.cc index 8bbcb8da0..3017630a6 100644 --- a/passes/cmds/check.cc +++ b/passes/cmds/check.cc @@ -195,16 +195,23 @@ struct CheckPass : public Pass { // in port widths are those for us to check. if (!cell->type.in( ID($add), ID($sub), - ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx))) + ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx), + ID($pmux), ID($bmux))) return false; int in_widths = 0, out_widths = 0; - for (auto &conn : cell->connections()) { - if (cell->input(conn.first)) - in_widths += conn.second.size(); - if (cell->output(conn.first)) - out_widths += conn.second.size(); + if (cell->type.in(ID($pmux), ID($bmux))) { + // We're skipping inputs A and B, since each of their bits contributes only one edge + in_widths = GetSize(cell->getPort(ID::S)); + out_widths = GetSize(cell->getPort(ID::Y)); + } else { + for (auto &conn : cell->connections()) { + if (cell->input(conn.first)) + in_widths += conn.second.size(); + if (cell->output(conn.first)) + out_widths += conn.second.size(); + } } const int threshold = 1024; From 1f876f3a226ebb7b5e6227c915b868361a86ba37 Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Tue, 12 Aug 2025 15:26:36 +0200 Subject: [PATCH 06/47] abstract: Add -initstates option --- passes/cmds/abstract.cc | 65 +++++++++++++++++++++++----- tests/various/abstract_initstates.ys | 30 +++++++++++++ 2 files changed, 84 insertions(+), 11 deletions(-) create mode 100644 tests/various/abstract_initstates.ys diff --git a/passes/cmds/abstract.cc b/passes/cmds/abstract.cc index d4eb22ca5..907a16fe0 100644 --- a/passes/cmds/abstract.cc +++ b/passes/cmds/abstract.cc @@ -373,6 +373,12 @@ struct AbstractPass : public Pass { log(" abstractions performed by either mode. This option is not supported in\n"); log(" the -init mode.\n"); log("\n"); + log(" -initstates \n"); + log(" Perform conditional abstraction for the first time steps. See the\n"); + log(" description of the -state and -value modes for details on how the\n"); + log(" condition affects the abstractions performed by either mode. This option\n"); + log(" is not supported in the -init mode.\n"); + log("\n"); log(" -slice :\n"); log(" -slice \n"); log(" -rtlilslice :\n"); @@ -402,8 +408,10 @@ struct AbstractPass : public Pass { Always = -1, ActiveLow = false, // ensuring we can use bool(enable) ActiveHigh = true, + Initstates = 2, }; Enable enable = Enable::Always; + int initstates = 0; std::string enable_name; std::vector slices; for (argidx = 1; argidx < args.size(); argidx++) @@ -435,6 +443,13 @@ struct AbstractPass : public Pass { enable = Enable::ActiveLow; continue; } + if (arg == "-initstates" && argidx + 1 < args.size()) { + if (enable != Enable::Always) + log_cmd_error("Multiple enable condition are not supported\n"); + initstates = atoi(args[++argidx].c_str()); + enable = Enable::Initstates; + continue; + } if (arg == "-slice" && argidx + 1 < args.size()) { slices.emplace_back(SliceIndices::HdlSlice, args[++argidx]); continue; @@ -451,22 +466,50 @@ struct AbstractPass : public Pass { if (mode == Mode::Initial) log_cmd_error("Conditional initial value abstraction is not supported\n"); - if (enable_name.empty()) - log_cmd_error("Unspecified enable wire\n"); + switch (enable) { + case Enable::Always: + log_assert(false); + case Enable::ActiveLow: + case Enable::ActiveHigh: { + if (enable_name.empty()) + log_cmd_error("Unspecified enable wire\n"); + } break; + case Enable::Initstates: { + if (initstates <= 0) + log_cmd_error("Number of initial time steps must be positive\n"); + } break; + } } unsigned int changed = 0; if ((mode == State) || (mode == Value)) { for (auto mod : design->selected_modules()) { - EnableLogic enable_logic = { State::S1, true }; - if (enable != Enable::Always) { - Wire *enable_wire = mod->wire("\\" + enable_name); - if (!enable_wire) - log_cmd_error("Enable wire %s not found in module %s\n", enable_name.c_str(), mod->name.c_str()); - if (GetSize(enable_wire) != 1) - log_cmd_error("Enable wire %s must have width 1 but has width %d in module %s\n", - enable_name.c_str(), GetSize(enable_wire), mod->name.c_str()); - enable_logic = { enable_wire, enable == Enable::ActiveHigh }; + EnableLogic enable_logic; + + switch (enable) { + case Enable::Always: { + enable_logic = { State::S1, true }; + } break; + case Enable::ActiveLow: + case Enable::ActiveHigh: { + Wire *enable_wire = mod->wire("\\" + enable_name); + if (!enable_wire) + log_cmd_error("Enable wire %s not found in module %s\n", enable_name.c_str(), mod->name.c_str()); + if (GetSize(enable_wire) != 1) + log_cmd_error("Enable wire %s must have width 1 but has width %d in module %s\n", + enable_name.c_str(), GetSize(enable_wire), mod->name.c_str()); + enable_logic = { enable_wire, enable == Enable::ActiveHigh }; + } break; + case Enable::Initstates: { + SigBit in_init_states = mod->Initstate(NEW_ID); + for (int i = 1; i < initstates; i++) { + Wire *in_init_states_q = mod->addWire(NEW_ID); + mod->addFf(NEW_ID, in_init_states, in_init_states_q); + in_init_states_q->attributes[ID::init] = State::S1; + in_init_states = in_init_states_q; + } + enable_logic = { in_init_states, true }; + } break; } if (mode == State) changed += abstract_state(mod, enable_logic, slices); diff --git a/tests/various/abstract_initstates.ys b/tests/various/abstract_initstates.ys new file mode 100644 index 000000000..35d17cf62 --- /dev/null +++ b/tests/various/abstract_initstates.ys @@ -0,0 +1,30 @@ +read_verilog < Date: Tue, 15 Jul 2025 01:26:24 +0000 Subject: [PATCH 07/47] Move ABC pass state to a struct instead of storing it in global variables. --- passes/techmap/abc.cc | 124 +++++++++++++++++++++--------------------- 1 file changed, 62 insertions(+), 62 deletions(-) diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index cc37677ce..16d27a0e6 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -113,23 +113,42 @@ bool map_mux8; bool map_mux16; bool markgroups; -int map_autoidx; -SigMap assign_map; -RTLIL::Module *module; -std::vector signal_list; -dict signal_map; -FfInitVals initvals; + pool enabled_gates; bool cmos_cost; -bool had_init; -bool clk_polarity, en_polarity, arst_polarity, srst_polarity; -RTLIL::SigSpec clk_sig, en_sig, arst_sig, srst_sig; -dict pi_map, po_map; +struct AbcModuleState { + int map_autoidx = 0; + SigMap assign_map; + RTLIL::Module *module = nullptr; + std::vector signal_list; + dict signal_map; + FfInitVals initvals; + bool had_init = false; -int undef_bits_lost; + bool clk_polarity = false; + bool en_polarity = false; + bool arst_polarity = false; + bool srst_polarity = false; + RTLIL::SigSpec clk_sig, en_sig, arst_sig, srst_sig; + dict pi_map, po_map; -int map_signal(RTLIL::SigBit bit, gate_type_t gate_type = G(NONE), int in1 = -1, int in2 = -1, int in3 = -1, int in4 = -1) + int undef_bits_lost = 0; + + int map_signal(RTLIL::SigBit bit, gate_type_t gate_type = G(NONE), int in1 = -1, int in2 = -1, int in3 = -1, int in4 = -1); + void mark_port(RTLIL::SigSpec sig); + void extract_cell(RTLIL::Cell *cell, bool keepff); + std::string remap_name(RTLIL::IdString abc_name, RTLIL::Wire **orig_wire = nullptr); + void dump_loop_graph(FILE *f, int &nr, dict> &edges, pool &workpool, std::vector &in_counts); + void handle_loops(); + void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file, + std::vector &liberty_files, std::vector &genlib_files, std::string constr_file, + bool cleanup, vector lut_costs, bool dff_mode, std::string clk_str, bool keepff, std::string delay_target, + std::string sop_inputs, std::string sop_products, std::string lutin_shared, bool fast_mode, + const std::vector &cells, bool show_tempdir, bool sop_mode, bool abc_dress, std::vector &dont_use_cells); +}; + +int AbcModuleState::map_signal(RTLIL::SigBit bit, gate_type_t gate_type, int in1, int in2, int in3, int in4) { assign_map.apply(bit); @@ -167,14 +186,14 @@ int map_signal(RTLIL::SigBit bit, gate_type_t gate_type = G(NONE), int in1 = -1, return gate.id; } -void mark_port(RTLIL::SigSpec sig) +void AbcModuleState::mark_port(RTLIL::SigSpec sig) { for (auto &bit : assign_map(sig)) if (bit.wire != nullptr && signal_map.count(bit) > 0) signal_list[signal_map[bit]].is_port = true; } -void extract_cell(RTLIL::Cell *cell, bool keepff) +void AbcModuleState::extract_cell(RTLIL::Cell *cell, bool keepff) { if (RTLIL::builtin_ff_cell_types().count(cell->type)) { FfData ff(&initvals, cell); @@ -377,7 +396,7 @@ void extract_cell(RTLIL::Cell *cell, bool keepff) } } -std::string remap_name(RTLIL::IdString abc_name, RTLIL::Wire **orig_wire = nullptr) +std::string AbcModuleState::remap_name(RTLIL::IdString abc_name, RTLIL::Wire **orig_wire) { std::string abc_sname = abc_name.substr(1); bool isnew = false; @@ -416,7 +435,7 @@ std::string remap_name(RTLIL::IdString abc_name, RTLIL::Wire **orig_wire = nullp return stringf("$abc$%d$%s", map_autoidx, abc_name.c_str()+1); } -void dump_loop_graph(FILE *f, int &nr, dict> &edges, pool &workpool, std::vector &in_counts) +void AbcModuleState::dump_loop_graph(FILE *f, int &nr, dict> &edges, pool &workpool, std::vector &in_counts) { if (f == nullptr) return; @@ -445,7 +464,7 @@ void dump_loop_graph(FILE *f, int &nr, dict> &edges, pool &w fprintf(f, "}\n"); } -void handle_loops() +void AbcModuleState::handle_loops() { // http://en.wikipedia.org/wiki/Topological_sorting // (Kahn, Arthur B. (1962), "Topological sorting of large networks") @@ -646,13 +665,15 @@ std::string replace_tempdir(std::string text, std::string tempdir_name, bool sho struct abc_output_filter { + const AbcModuleState &state; bool got_cr; int escape_seq_state; std::string linebuf; std::string tempdir_name; bool show_tempdir; - abc_output_filter(std::string tempdir_name, bool show_tempdir) : tempdir_name(tempdir_name), show_tempdir(show_tempdir) + abc_output_filter(const AbcModuleState& state, std::string tempdir_name, bool show_tempdir) + : state(state), tempdir_name(tempdir_name), show_tempdir(show_tempdir) { got_cr = false; escape_seq_state = 0; @@ -693,8 +714,8 @@ struct abc_output_filter int pi, po; if (sscanf(line.c_str(), "Start-point = pi%d. End-point = po%d.", &pi, &po) == 2) { log("ABC: Start-point = pi%d (%s). End-point = po%d (%s).\n", - pi, pi_map.count(pi) ? pi_map.at(pi).c_str() : "???", - po, po_map.count(po) ? po_map.at(po).c_str() : "???"); + pi, state.pi_map.count(pi) ? state.pi_map.at(pi).c_str() : "???", + po, state.po_map.count(po) ? state.po_map.at(po).c_str() : "???"); return; } @@ -703,20 +724,16 @@ struct abc_output_filter } }; -void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file, +void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file, std::vector &liberty_files, std::vector &genlib_files, std::string constr_file, bool cleanup, vector lut_costs, bool dff_mode, std::string clk_str, bool keepff, std::string delay_target, std::string sop_inputs, std::string sop_products, std::string lutin_shared, bool fast_mode, const std::vector &cells, bool show_tempdir, bool sop_mode, bool abc_dress, std::vector &dont_use_cells) { module = current_module; + initvals.set(&assign_map, module); map_autoidx = autoidx++; - signal_map.clear(); - signal_list.clear(); - pi_map.clear(); - po_map.clear(); - if (clk_str != "$") { clk_polarity = true; @@ -1109,7 +1126,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin log("Running ABC command: %s\n", replace_tempdir(buffer, tempdir_name, show_tempdir).c_str()); #ifndef YOSYS_LINK_ABC - abc_output_filter filt(tempdir_name, show_tempdir); + abc_output_filter filt(*this, tempdir_name, show_tempdir); int ret = run_command(buffer, std::bind(&abc_output_filter::next_line, filt, std::placeholders::_1)); #else string temp_stdouterr_name = stringf("%s/stdouterr.txt", tempdir_name.c_str()); @@ -1652,13 +1669,6 @@ struct AbcPass : public Pass { log_header(design, "Executing ABC pass (technology mapping using ABC).\n"); log_push(); - assign_map.clear(); - signal_list.clear(); - signal_map.clear(); - initvals.clear(); - pi_map.clear(); - po_map.clear(); - std::string exe_file = yosys_abc_executable; std::string script_file, default_liberty_file, constr_file, clk_str; std::vector liberty_files, genlib_files, dont_use_cells; @@ -1667,13 +1677,6 @@ struct AbcPass : public Pass { bool show_tempdir = false, sop_mode = false; bool abc_dress = false; vector lut_costs; - markgroups = false; - - map_mux4 = false; - map_mux8 = false; - map_mux16 = false; - enabled_gates.clear(); - cmos_cost = false; // get arguments from scratchpad first, then override by command arguments std::string lut_arg, luts_arg, g_arg; @@ -2049,11 +2052,10 @@ struct AbcPass : public Pass { continue; } - assign_map.set(mod); - initvals.set(&assign_map, mod); - if (!dff_mode || !clk_str.empty()) { - abc_module(design, mod, script_file, exe_file, liberty_files, genlib_files, constr_file, cleanup, lut_costs, dff_mode, clk_str, keepff, + AbcModuleState state; + state.assign_map.set(mod); + state.abc_module(design, mod, script_file, exe_file, liberty_files, genlib_files, constr_file, cleanup, lut_costs, dff_mode, clk_str, keepff, delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, mod->selected_cells(), show_tempdir, sop_mode, abc_dress, dont_use_cells); continue; } @@ -2074,6 +2076,10 @@ struct AbcPass : public Pass { dict> cell_to_bit, cell_to_bit_up, cell_to_bit_down; dict> bit_to_cell, bit_to_cell_up, bit_to_cell_down; + SigMap assign_map; + assign_map.set(mod); + FfInitVals initvals; + initvals.set(&assign_map, mod); for (auto cell : all_cells) { clkdomain_t key; @@ -2207,27 +2213,21 @@ struct AbcPass : public Pass { std::get<6>(it.first) ? "" : "!", log_signal(std::get<7>(it.first))); for (auto &it : assigned_cells) { - clk_polarity = std::get<0>(it.first); - clk_sig = assign_map(std::get<1>(it.first)); - en_polarity = std::get<2>(it.first); - en_sig = assign_map(std::get<3>(it.first)); - arst_polarity = std::get<4>(it.first); - arst_sig = assign_map(std::get<5>(it.first)); - srst_polarity = std::get<6>(it.first); - srst_sig = assign_map(std::get<7>(it.first)); - abc_module(design, mod, script_file, exe_file, liberty_files, genlib_files, constr_file, cleanup, lut_costs, !clk_sig.empty(), "$", + AbcModuleState state; + state.assign_map.set(mod); + state.clk_polarity = std::get<0>(it.first); + state.clk_sig = assign_map(std::get<1>(it.first)); + state.en_polarity = std::get<2>(it.first); + state.en_sig = assign_map(std::get<3>(it.first)); + state.arst_polarity = std::get<4>(it.first); + state.arst_sig = assign_map(std::get<5>(it.first)); + state.srst_polarity = std::get<6>(it.first); + state.srst_sig = assign_map(std::get<7>(it.first)); + state.abc_module(design, mod, script_file, exe_file, liberty_files, genlib_files, constr_file, cleanup, lut_costs, !state.clk_sig.empty(), "$", keepff, delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, it.second, show_tempdir, sop_mode, abc_dress, dont_use_cells); - assign_map.set(mod); } } - assign_map.clear(); - signal_list.clear(); - signal_map.clear(); - initvals.clear(); - pi_map.clear(); - po_map.clear(); - log_pop(); } } AbcPass; From ceedcecfae4a2110f42f471f10ec8a901a73264e Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 15 Jul 2025 03:38:54 +0000 Subject: [PATCH 08/47] Move the input parameters to `abc_module` that are identical across modules to an `AbcConfig` struct. --- passes/techmap/abc.cc | 260 ++++++++++++++++++++++-------------------- 1 file changed, 137 insertions(+), 123 deletions(-) diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index 16d27a0e6..28e39998d 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -117,7 +117,30 @@ bool markgroups; pool enabled_gates; bool cmos_cost; +struct AbcConfig +{ + std::string script_file; + std::string exe_file; + std::vector liberty_files; + std::vector genlib_files; + std::string constr_file; + vector lut_costs; + std::string delay_target; + std::string sop_inputs; + std::string sop_products; + std::string lutin_shared; + std::vector dont_use_cells; + bool cleanup = true; + bool keepff = false; + bool fast_mode = false; + bool show_tempdir = false; + bool sop_mode = false; + bool abc_dress = false; +}; + struct AbcModuleState { + const AbcConfig &config; + int map_autoidx = 0; SigMap assign_map; RTLIL::Module *module = nullptr; @@ -135,17 +158,16 @@ struct AbcModuleState { int undef_bits_lost = 0; + AbcModuleState(const AbcConfig &config) : config(config) {} + int map_signal(RTLIL::SigBit bit, gate_type_t gate_type = G(NONE), int in1 = -1, int in2 = -1, int in3 = -1, int in4 = -1); void mark_port(RTLIL::SigSpec sig); void extract_cell(RTLIL::Cell *cell, bool keepff); std::string remap_name(RTLIL::IdString abc_name, RTLIL::Wire **orig_wire = nullptr); void dump_loop_graph(FILE *f, int &nr, dict> &edges, pool &workpool, std::vector &in_counts); void handle_loops(); - void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file, - std::vector &liberty_files, std::vector &genlib_files, std::string constr_file, - bool cleanup, vector lut_costs, bool dff_mode, std::string clk_str, bool keepff, std::string delay_target, - std::string sop_inputs, std::string sop_products, std::string lutin_shared, bool fast_mode, - const std::vector &cells, bool show_tempdir, bool sop_mode, bool abc_dress, std::vector &dont_use_cells); + void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, const std::vector &cells, + bool dff_mode, std::string clk_str); }; int AbcModuleState::map_signal(RTLIL::SigBit bit, gate_type_t gate_type, int in1, int in2, int in3, int in4) @@ -724,11 +746,8 @@ struct abc_output_filter } }; -void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::string script_file, std::string exe_file, - std::vector &liberty_files, std::vector &genlib_files, std::string constr_file, - bool cleanup, vector lut_costs, bool dff_mode, std::string clk_str, bool keepff, std::string delay_target, - std::string sop_inputs, std::string sop_products, std::string lutin_shared, bool fast_mode, - const std::vector &cells, bool show_tempdir, bool sop_mode, bool abc_dress, std::vector &dont_use_cells) +void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_module, const std::vector &cells, + bool dff_mode, std::string clk_str) { module = current_module; initvals.set(&assign_map, module); @@ -805,38 +824,39 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_mo log_cmd_error("Clock domain %s not found.\n", clk_str.c_str()); std::string tempdir_name; - if (cleanup) + if (config.cleanup) tempdir_name = get_base_tmpdir() + "/"; else tempdir_name = "_tmp_"; tempdir_name += proc_program_prefix() + "yosys-abc-XXXXXX"; tempdir_name = make_temp_dir(tempdir_name); log_header(design, "Extracting gate netlist of module `%s' to `%s/input.blif'..\n", - module->name.c_str(), replace_tempdir(tempdir_name, tempdir_name, show_tempdir).c_str()); + module->name.c_str(), replace_tempdir(tempdir_name, tempdir_name, config.show_tempdir).c_str()); std::string abc_script = stringf("read_blif \"%s/input.blif\"; ", tempdir_name.c_str()); - if (!liberty_files.empty() || !genlib_files.empty()) { + if (!config.liberty_files.empty() || !config.genlib_files.empty()) { std::string dont_use_args; - for (std::string dont_use_cell : dont_use_cells) { + for (std::string dont_use_cell : config.dont_use_cells) { dont_use_args += stringf("-X \"%s\" ", dont_use_cell.c_str()); } bool first_lib = true; - for (std::string liberty_file : liberty_files) { + for (std::string liberty_file : config.liberty_files) { abc_script += stringf("read_lib %s %s -w \"%s\" ; ", dont_use_args.c_str(), first_lib ? "" : "-m", liberty_file.c_str()); first_lib = false; } - for (std::string liberty_file : genlib_files) + for (std::string liberty_file : config.genlib_files) abc_script += stringf("read_library \"%s\"; ", liberty_file.c_str()); - if (!constr_file.empty()) - abc_script += stringf("read_constr -v \"%s\"; ", constr_file.c_str()); + if (!config.constr_file.empty()) + abc_script += stringf("read_constr -v \"%s\"; ", config.constr_file.c_str()); } else - if (!lut_costs.empty()) + if (!config.lut_costs.empty()) abc_script += stringf("read_lut %s/lutdefs.txt; ", tempdir_name.c_str()); else abc_script += stringf("read_library %s/stdcells.genlib; ", tempdir_name.c_str()); - if (!script_file.empty()) { + if (!config.script_file.empty()) { + const std::string &script_file = config.script_file; if (script_file[0] == '+') { for (size_t i = 1; i < script_file.size(); i++) if (script_file[i] == '\'') @@ -847,37 +867,38 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_mo abc_script += script_file[i]; } else abc_script += stringf("source %s", script_file.c_str()); - } else if (!lut_costs.empty()) { + } else if (!config.lut_costs.empty()) { bool all_luts_cost_same = true; - for (int this_cost : lut_costs) - if (this_cost != lut_costs.front()) + for (int this_cost : config.lut_costs) + if (this_cost != config.lut_costs.front()) all_luts_cost_same = false; - abc_script += fast_mode ? ABC_FAST_COMMAND_LUT : ABC_COMMAND_LUT; - if (all_luts_cost_same && !fast_mode) + abc_script += config.fast_mode ? ABC_FAST_COMMAND_LUT : ABC_COMMAND_LUT; + if (all_luts_cost_same && !config.fast_mode) abc_script += "; lutpack {S}"; - } else if (!liberty_files.empty() || !genlib_files.empty()) - abc_script += constr_file.empty() ? (fast_mode ? ABC_FAST_COMMAND_LIB : ABC_COMMAND_LIB) : (fast_mode ? ABC_FAST_COMMAND_CTR : ABC_COMMAND_CTR); - else if (sop_mode) - abc_script += fast_mode ? ABC_FAST_COMMAND_SOP : ABC_COMMAND_SOP; + } else if (!config.liberty_files.empty() || !config.genlib_files.empty()) + abc_script += config.constr_file.empty() ? + (config.fast_mode ? ABC_FAST_COMMAND_LIB : ABC_COMMAND_LIB) : (config.fast_mode ? ABC_FAST_COMMAND_CTR : ABC_COMMAND_CTR); + else if (config.sop_mode) + abc_script += config.fast_mode ? ABC_FAST_COMMAND_SOP : ABC_COMMAND_SOP; else - abc_script += fast_mode ? ABC_FAST_COMMAND_DFL : ABC_COMMAND_DFL; + abc_script += config.fast_mode ? ABC_FAST_COMMAND_DFL : ABC_COMMAND_DFL; - if (script_file.empty() && !delay_target.empty()) + if (config.script_file.empty() && !config.delay_target.empty()) for (size_t pos = abc_script.find("dretime;"); pos != std::string::npos; pos = abc_script.find("dretime;", pos+1)) abc_script = abc_script.substr(0, pos) + "dretime; retime -o {D};" + abc_script.substr(pos+8); for (size_t pos = abc_script.find("{D}"); pos != std::string::npos; pos = abc_script.find("{D}", pos)) - abc_script = abc_script.substr(0, pos) + delay_target + abc_script.substr(pos+3); + abc_script = abc_script.substr(0, pos) + config.delay_target + abc_script.substr(pos+3); for (size_t pos = abc_script.find("{I}"); pos != std::string::npos; pos = abc_script.find("{I}", pos)) - abc_script = abc_script.substr(0, pos) + sop_inputs + abc_script.substr(pos+3); + abc_script = abc_script.substr(0, pos) + config.sop_inputs + abc_script.substr(pos+3); for (size_t pos = abc_script.find("{P}"); pos != std::string::npos; pos = abc_script.find("{P}", pos)) - abc_script = abc_script.substr(0, pos) + sop_products + abc_script.substr(pos+3); + abc_script = abc_script.substr(0, pos) + config.sop_products + abc_script.substr(pos+3); for (size_t pos = abc_script.find("{S}"); pos != std::string::npos; pos = abc_script.find("{S}", pos)) - abc_script = abc_script.substr(0, pos) + lutin_shared + abc_script.substr(pos+3); - if (abc_dress) + abc_script = abc_script.substr(0, pos) + config.lutin_shared + abc_script.substr(pos+3); + if (config.abc_dress) abc_script += stringf("; dress \"%s/input.blif\"", tempdir_name.c_str()); abc_script += stringf("; write_blif %s/output.blif", tempdir_name.c_str()); abc_script = add_echos_to_abc_cmd(abc_script); @@ -913,7 +934,7 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_mo had_init = false; for (auto c : cells) - extract_cell(c, keepff); + extract_cell(c, config.keepff); if (undef_bits_lost) log("Replacing %d occurrences of constant undef bits with constant zero bits\n", undef_bits_lost); @@ -1112,21 +1133,21 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_mo fprintf(f, "GATE MUX16 %d Y=(!S*!T*!U*!V*A)+(S*!T*!U*!V*B)+(!S*T*!U*!V*C)+(S*T*!U*!V*D)+(!S*!T*U*!V*E)+(S*!T*U*!V*F)+(!S*T*U*!V*G)+(S*T*U*!V*H)+(!S*!T*!U*V*I)+(S*!T*!U*V*J)+(!S*T*!U*V*K)+(S*T*!U*V*L)+(!S*!T*U*V*M)+(S*!T*U*V*N)+(!S*T*U*V*O)+(S*T*U*V*P); PIN * UNKNOWN 1 999 1 0 1 0\n", 8*cell_cost.at(ID($_MUX_))); fclose(f); - if (!lut_costs.empty()) { + if (!config.lut_costs.empty()) { buffer = stringf("%s/lutdefs.txt", tempdir_name.c_str()); f = fopen(buffer.c_str(), "wt"); if (f == nullptr) log_error("Opening %s for writing failed: %s\n", buffer.c_str(), strerror(errno)); - for (int i = 0; i < GetSize(lut_costs); i++) - fprintf(f, "%d %d.00 1.00\n", i+1, lut_costs.at(i)); + for (int i = 0; i < GetSize(config.lut_costs); i++) + fprintf(f, "%d %d.00 1.00\n", i+1, config.lut_costs.at(i)); fclose(f); } - buffer = stringf("\"%s\" -s -f %s/abc.script 2>&1", exe_file.c_str(), tempdir_name.c_str()); - log("Running ABC command: %s\n", replace_tempdir(buffer, tempdir_name, show_tempdir).c_str()); + buffer = stringf("\"%s\" -s -f %s/abc.script 2>&1", config.exe_file.c_str(), tempdir_name.c_str()); + log("Running ABC command: %s\n", replace_tempdir(buffer, tempdir_name, config.show_tempdir).c_str()); #ifndef YOSYS_LINK_ABC - abc_output_filter filt(*this, tempdir_name, show_tempdir); + abc_output_filter filt(*this, tempdir_name, config.show_tempdir); int ret = run_command(buffer, std::bind(&abc_output_filter::next_line, filt, std::placeholders::_1)); #else string temp_stdouterr_name = stringf("%s/stdouterr.txt", tempdir_name.c_str()); @@ -1150,7 +1171,7 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_mo // These needs to be mutable, supposedly due to getopt char *abc_argv[5]; string tmp_script_name = stringf("%s/abc.script", tempdir_name.c_str()); - abc_argv[0] = strdup(exe_file.c_str()); + abc_argv[0] = strdup(config.exe_file.c_str()); abc_argv[1] = strdup("-s"); abc_argv[2] = strdup("-f"); abc_argv[3] = strdup(tmp_script_name.c_str()); @@ -1167,7 +1188,7 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_mo fclose(old_stdout); fclose(old_stderr); std::ifstream temp_stdouterr_r(temp_stdouterr_name); - abc_output_filter filt(tempdir_name, show_tempdir); + abc_output_filter filt(*this, tempdir_name, config.show_tempdir); for (std::string line; std::getline(temp_stdouterr_r, line); ) filt.next_line(line + "\n"); temp_stdouterr_r.close(); @@ -1181,9 +1202,9 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_mo if (ifs.fail()) log_error("Can't open ABC output file `%s'.\n", buffer.c_str()); - bool builtin_lib = liberty_files.empty() && genlib_files.empty(); + bool builtin_lib = config.liberty_files.empty() && config.genlib_files.empty(); RTLIL::Design *mapped_design = new RTLIL::Design; - parse_blif(mapped_design, ifs, builtin_lib ? ID(DFF) : ID(_dff_), false, sop_mode); + parse_blif(mapped_design, ifs, builtin_lib ? ID(DFF) : ID(_dff_), false, config.sop_mode); ifs.close(); @@ -1459,7 +1480,7 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_mo log("Don't call ABC as there is nothing to map.\n"); } - if (cleanup) + if (config.cleanup) { log("Removing temp directory.\n"); remove_directory(tempdir_name); @@ -1669,57 +1690,52 @@ struct AbcPass : public Pass { log_header(design, "Executing ABC pass (technology mapping using ABC).\n"); log_push(); - std::string exe_file = yosys_abc_executable; - std::string script_file, default_liberty_file, constr_file, clk_str; - std::vector liberty_files, genlib_files, dont_use_cells; - std::string delay_target, sop_inputs, sop_products, lutin_shared = "-S 1"; - bool fast_mode = false, dff_mode = false, keepff = false, cleanup = true; - bool show_tempdir = false, sop_mode = false; - bool abc_dress = false; - vector lut_costs; + AbcConfig config; // get arguments from scratchpad first, then override by command arguments std::string lut_arg, luts_arg, g_arg; - exe_file = design->scratchpad_get_string("abc.exe", exe_file /* inherit default value if not set */); - script_file = design->scratchpad_get_string("abc.script", script_file); - default_liberty_file = design->scratchpad_get_string("abc.liberty", default_liberty_file); - constr_file = design->scratchpad_get_string("abc.constr", constr_file); + config.exe_file = design->scratchpad_get_string("abc.exe", yosys_abc_executable /* inherit default value if not set */); + config.script_file = design->scratchpad_get_string("abc.script", ""); + std::string default_liberty_file = design->scratchpad_get_string("abc.liberty", ""); + config.constr_file = design->scratchpad_get_string("abc.constr", ""); if (design->scratchpad.count("abc.D")) { - delay_target = "-D " + design->scratchpad_get_string("abc.D"); + config.delay_target = "-D " + design->scratchpad_get_string("abc.D"); } if (design->scratchpad.count("abc.I")) { - sop_inputs = "-I " + design->scratchpad_get_string("abc.I"); + config.sop_inputs = "-I " + design->scratchpad_get_string("abc.I"); } if (design->scratchpad.count("abc.P")) { - sop_products = "-P " + design->scratchpad_get_string("abc.P"); + config.sop_products = "-P " + design->scratchpad_get_string("abc.P"); } if (design->scratchpad.count("abc.S")) { - lutin_shared = "-S " + design->scratchpad_get_string("abc.S"); + config.lutin_shared = "-S " + design->scratchpad_get_string("abc.S"); + } else { + config.lutin_shared = "-S 1"; } lut_arg = design->scratchpad_get_string("abc.lut", lut_arg); luts_arg = design->scratchpad_get_string("abc.luts", luts_arg); - sop_mode = design->scratchpad_get_bool("abc.sop", sop_mode); + config.sop_mode = design->scratchpad_get_bool("abc.sop", false); map_mux4 = design->scratchpad_get_bool("abc.mux4", map_mux4); map_mux8 = design->scratchpad_get_bool("abc.mux8", map_mux8); map_mux16 = design->scratchpad_get_bool("abc.mux16", map_mux16); - abc_dress = design->scratchpad_get_bool("abc.dress", abc_dress); + config.abc_dress = design->scratchpad_get_bool("abc.dress", false); g_arg = design->scratchpad_get_string("abc.g", g_arg); - fast_mode = design->scratchpad_get_bool("abc.fast", fast_mode); - dff_mode = design->scratchpad_get_bool("abc.dff", dff_mode); + config.fast_mode = design->scratchpad_get_bool("abc.fast", false); + bool dff_mode = design->scratchpad_get_bool("abc.dff", false); + std::string clk_str; if (design->scratchpad.count("abc.clk")) { clk_str = design->scratchpad_get_string("abc.clk"); dff_mode = true; } - keepff = design->scratchpad_get_bool("abc.keepff", keepff); - cleanup = !design->scratchpad_get_bool("abc.nocleanup", !cleanup); - keepff = design->scratchpad_get_bool("abc.keepff", keepff); - show_tempdir = design->scratchpad_get_bool("abc.showtmp", show_tempdir); + config.keepff = design->scratchpad_get_bool("abc.keepff", false); + config.cleanup = !design->scratchpad_get_bool("abc.nocleanup", false); + config.show_tempdir = design->scratchpad_get_bool("abc.showtmp", false); markgroups = design->scratchpad_get_bool("abc.markgroups", markgroups); if (design->scratchpad_get_bool("abc.debug")) { - cleanup = false; - show_tempdir = true; + config.cleanup = false; + config.show_tempdir = true; } size_t argidx, g_argidx = -1; @@ -1736,43 +1752,43 @@ struct AbcPass : public Pass { for (argidx = 1; argidx < args.size(); argidx++) { std::string arg = args[argidx]; if (arg == "-exe" && argidx+1 < args.size()) { - exe_file = args[++argidx]; + config.exe_file = args[++argidx]; continue; } if (arg == "-script" && argidx+1 < args.size()) { - script_file = args[++argidx]; + config.script_file = args[++argidx]; continue; } if (arg == "-liberty" && argidx+1 < args.size()) { - liberty_files.push_back(args[++argidx]); + config.liberty_files.push_back(args[++argidx]); continue; } if (arg == "-dont_use" && argidx+1 < args.size()) { - dont_use_cells.push_back(args[++argidx]); + config.dont_use_cells.push_back(args[++argidx]); continue; } if (arg == "-genlib" && argidx+1 < args.size()) { - genlib_files.push_back(args[++argidx]); + config.genlib_files.push_back(args[++argidx]); continue; } if (arg == "-constr" && argidx+1 < args.size()) { - constr_file = args[++argidx]; + config.constr_file = args[++argidx]; continue; } if (arg == "-D" && argidx+1 < args.size()) { - delay_target = "-D " + args[++argidx]; + config.delay_target = "-D " + args[++argidx]; continue; } if (arg == "-I" && argidx+1 < args.size()) { - sop_inputs = "-I " + args[++argidx]; + config.sop_inputs = "-I " + args[++argidx]; continue; } if (arg == "-P" && argidx+1 < args.size()) { - sop_products = "-P " + args[++argidx]; + config.sop_products = "-P " + args[++argidx]; continue; } if (arg == "-S" && argidx+1 < args.size()) { - lutin_shared = "-S " + args[++argidx]; + config.lutin_shared = "-S " + args[++argidx]; continue; } if (arg == "-lut" && argidx+1 < args.size()) { @@ -1784,7 +1800,7 @@ struct AbcPass : public Pass { continue; } if (arg == "-sop") { - sop_mode = true; + config.sop_mode = true; continue; } if (arg == "-mux4") { @@ -1800,7 +1816,7 @@ struct AbcPass : public Pass { continue; } if (arg == "-dress") { - abc_dress = true; + config.abc_dress = true; continue; } if (arg == "-g" && argidx+1 < args.size()) { @@ -1812,7 +1828,7 @@ struct AbcPass : public Pass { continue; } if (arg == "-fast") { - fast_mode = true; + config.fast_mode = true; continue; } if (arg == "-dff") { @@ -1825,15 +1841,15 @@ struct AbcPass : public Pass { continue; } if (arg == "-keepff") { - keepff = true; + config.keepff = true; continue; } if (arg == "-nocleanup") { - cleanup = false; + config.cleanup = false; continue; } if (arg == "-showtmp") { - show_tempdir = true; + config.show_tempdir = true; continue; } if (arg == "-markgroups") { @@ -1844,25 +1860,25 @@ struct AbcPass : public Pass { } extra_args(args, argidx, design); - if (genlib_files.empty() && liberty_files.empty() && !default_liberty_file.empty()) - liberty_files.push_back(default_liberty_file); + if (config.genlib_files.empty() && config.liberty_files.empty() && !default_liberty_file.empty()) + config.liberty_files.push_back(default_liberty_file); - rewrite_filename(script_file); - if (!script_file.empty() && !is_absolute_path(script_file) && script_file[0] != '+') - script_file = std::string(pwd) + "/" + script_file; - for (int i = 0; i < GetSize(liberty_files); i++) { - rewrite_filename(liberty_files[i]); - if (!liberty_files[i].empty() && !is_absolute_path(liberty_files[i])) - liberty_files[i] = std::string(pwd) + "/" + liberty_files[i]; + rewrite_filename(config.script_file); + if (!config.script_file.empty() && !is_absolute_path(config.script_file) && config.script_file[0] != '+') + config.script_file = std::string(pwd) + "/" + config.script_file; + for (int i = 0; i < GetSize(config.liberty_files); i++) { + rewrite_filename(config.liberty_files[i]); + if (!config.liberty_files[i].empty() && !is_absolute_path(config.liberty_files[i])) + config.liberty_files[i] = std::string(pwd) + "/" + config.liberty_files[i]; } - for (int i = 0; i < GetSize(genlib_files); i++) { - rewrite_filename(genlib_files[i]); - if (!genlib_files[i].empty() && !is_absolute_path(genlib_files[i])) - genlib_files[i] = std::string(pwd) + "/" + genlib_files[i]; + for (int i = 0; i < GetSize(config.genlib_files); i++) { + rewrite_filename(config.genlib_files[i]); + if (!config.genlib_files[i].empty() && !is_absolute_path(config.genlib_files[i])) + config.genlib_files[i] = std::string(pwd) + "/" + config.genlib_files[i]; } - rewrite_filename(constr_file); - if (!constr_file.empty() && !is_absolute_path(constr_file)) - constr_file = std::string(pwd) + "/" + constr_file; + rewrite_filename(config.constr_file); + if (!config.constr_file.empty() && !is_absolute_path(config.constr_file)) + config.constr_file = std::string(pwd) + "/" + config.constr_file; // handle -lut argument if (!lut_arg.empty()) { @@ -1875,24 +1891,24 @@ struct AbcPass : public Pass { lut_mode = atoi(lut_arg.c_str()); lut_mode2 = lut_mode; } - lut_costs.clear(); + config.lut_costs.clear(); for (int i = 0; i < lut_mode; i++) - lut_costs.push_back(1); + config.lut_costs.push_back(1); for (int i = lut_mode; i < lut_mode2; i++) - lut_costs.push_back(2 << (i - lut_mode)); + config.lut_costs.push_back(2 << (i - lut_mode)); } //handle -luts argument if (!luts_arg.empty()){ - lut_costs.clear(); + config.lut_costs.clear(); for (auto &tok : split_tokens(luts_arg, ",")) { auto parts = split_tokens(tok, ":"); - if (GetSize(parts) == 0 && !lut_costs.empty()) - lut_costs.push_back(lut_costs.back()); + if (GetSize(parts) == 0 && !config.lut_costs.empty()) + config.lut_costs.push_back(config.lut_costs.back()); else if (GetSize(parts) == 1) - lut_costs.push_back(atoi(parts.at(0).c_str())); + config.lut_costs.push_back(atoi(parts.at(0).c_str())); else if (GetSize(parts) == 2) - while (GetSize(lut_costs) < std::atoi(parts.at(0).c_str())) - lut_costs.push_back(atoi(parts.at(1).c_str())); + while (GetSize(config.lut_costs) < std::atoi(parts.at(0).c_str())) + config.lut_costs.push_back(atoi(parts.at(1).c_str())); else log_cmd_error("Invalid -luts syntax.\n"); } @@ -2023,9 +2039,9 @@ struct AbcPass : public Pass { } } - if (!lut_costs.empty() && !(liberty_files.empty() && genlib_files.empty())) + if (!config.lut_costs.empty() && !(config.liberty_files.empty() && config.genlib_files.empty())) log_cmd_error("Got -lut and -liberty/-genlib! These two options are exclusive.\n"); - if (!constr_file.empty() && (liberty_files.empty() && genlib_files.empty())) + if (!config.constr_file.empty() && (config.liberty_files.empty() && config.genlib_files.empty())) log_cmd_error("Got -constr but no -liberty/-genlib!\n"); if (enabled_gates.empty()) { @@ -2053,10 +2069,9 @@ struct AbcPass : public Pass { } if (!dff_mode || !clk_str.empty()) { - AbcModuleState state; + AbcModuleState state(config); state.assign_map.set(mod); - state.abc_module(design, mod, script_file, exe_file, liberty_files, genlib_files, constr_file, cleanup, lut_costs, dff_mode, clk_str, keepff, - delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, mod->selected_cells(), show_tempdir, sop_mode, abc_dress, dont_use_cells); + state.abc_module(design, mod, mod->selected_cells(), dff_mode, clk_str); continue; } @@ -2213,7 +2228,7 @@ struct AbcPass : public Pass { std::get<6>(it.first) ? "" : "!", log_signal(std::get<7>(it.first))); for (auto &it : assigned_cells) { - AbcModuleState state; + AbcModuleState state(config); state.assign_map.set(mod); state.clk_polarity = std::get<0>(it.first); state.clk_sig = assign_map(std::get<1>(it.first)); @@ -2223,8 +2238,7 @@ struct AbcPass : public Pass { state.arst_sig = assign_map(std::get<5>(it.first)); state.srst_polarity = std::get<6>(it.first); state.srst_sig = assign_map(std::get<7>(it.first)); - state.abc_module(design, mod, script_file, exe_file, liberty_files, genlib_files, constr_file, cleanup, lut_costs, !state.clk_sig.empty(), "$", - keepff, delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, it.second, show_tempdir, sop_mode, abc_dress, dont_use_cells); + state.abc_module(design, mod, it.second, !state.clk_sig.empty(), "$"); } } From 53c72c0d3944535e7d81d785d4c6f78c7cafcc33 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 15 Jul 2025 03:54:41 +0000 Subject: [PATCH 09/47] Move code in `abc_module()` that modifies the design into a new function `extract()` Splits up the big `abc_module()` function and isolates the code that modifies the design after running ABC. --- passes/techmap/abc.cc | 491 ++++++++++++++++++++++-------------------- 1 file changed, 255 insertions(+), 236 deletions(-) diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index 28e39998d..494494a49 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -148,6 +148,7 @@ struct AbcModuleState { dict signal_map; FfInitVals initvals; bool had_init = false; + bool did_run_abc = false; bool clk_polarity = false; bool en_polarity = false; @@ -158,6 +159,8 @@ struct AbcModuleState { int undef_bits_lost = 0; + std::string tempdir_name; + AbcModuleState(const AbcConfig &config) : config(config) {} int map_signal(RTLIL::SigBit bit, gate_type_t gate_type = G(NONE), int in1 = -1, int in2 = -1, int in3 = -1, int in4 = -1); @@ -168,6 +171,8 @@ struct AbcModuleState { void handle_loops(); void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, const std::vector &cells, bool dff_mode, std::string clk_str); + void extract(RTLIL::Design *design); + void finish(); }; int AbcModuleState::map_signal(RTLIL::SigBit bit, gate_type_t gate_type, int in1, int in2, int in3, int in4) @@ -823,7 +828,6 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_mo if (dff_mode && clk_sig.empty()) log_cmd_error("Clock domain %s not found.\n", clk_str.c_str()); - std::string tempdir_name; if (config.cleanup) tempdir_name = get_base_tmpdir() + "/"; else @@ -1193,194 +1197,155 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_mo filt.next_line(line + "\n"); temp_stdouterr_r.close(); #endif - if (ret != 0) + if (ret != 0) { log_error("ABC: execution of command \"%s\" failed: return code %d.\n", buffer.c_str(), ret); - - buffer = stringf("%s/%s", tempdir_name.c_str(), "output.blif"); - std::ifstream ifs; - ifs.open(buffer); - if (ifs.fail()) - log_error("Can't open ABC output file `%s'.\n", buffer.c_str()); - - bool builtin_lib = config.liberty_files.empty() && config.genlib_files.empty(); - RTLIL::Design *mapped_design = new RTLIL::Design; - parse_blif(mapped_design, ifs, builtin_lib ? ID(DFF) : ID(_dff_), false, config.sop_mode); - - ifs.close(); - - log_header(design, "Re-integrating ABC results.\n"); - RTLIL::Module *mapped_mod = mapped_design->module(ID(netlist)); - if (mapped_mod == nullptr) - log_error("ABC output file does not contain a module `netlist'.\n"); - for (auto w : mapped_mod->wires()) { - RTLIL::Wire *orig_wire = nullptr; - RTLIL::Wire *wire = module->addWire(remap_name(w->name, &orig_wire)); - if (orig_wire != nullptr && orig_wire->attributes.count(ID::src)) - wire->attributes[ID::src] = orig_wire->attributes[ID::src]; - if (markgroups) wire->attributes[ID::abcgroup] = map_autoidx; - design->select(module, wire); + return; } + did_run_abc = true; + return; + } + log("Don't call ABC as there is nothing to map.\n"); +} - SigMap mapped_sigmap(mapped_mod); - FfInitVals mapped_initvals(&mapped_sigmap, mapped_mod); +void AbcModuleState::extract(RTLIL::Design *design) +{ + if (!did_run_abc) { + return; + } - dict cell_stats; - for (auto c : mapped_mod->cells()) + std::string buffer = stringf("%s/%s", tempdir_name.c_str(), "output.blif"); + std::ifstream ifs; + ifs.open(buffer); + if (ifs.fail()) + log_error("Can't open ABC output file `%s'.\n", buffer.c_str()); + + bool builtin_lib = config.liberty_files.empty() && config.genlib_files.empty(); + RTLIL::Design *mapped_design = new RTLIL::Design; + parse_blif(mapped_design, ifs, builtin_lib ? ID(DFF) : ID(_dff_), false, config.sop_mode); + + ifs.close(); + + log_header(design, "Re-integrating ABC results.\n"); + RTLIL::Module *mapped_mod = mapped_design->module(ID(netlist)); + if (mapped_mod == nullptr) + log_error("ABC output file does not contain a module `netlist'.\n"); + for (auto w : mapped_mod->wires()) { + RTLIL::Wire *orig_wire = nullptr; + RTLIL::Wire *wire = module->addWire(remap_name(w->name, &orig_wire)); + if (orig_wire != nullptr && orig_wire->attributes.count(ID::src)) + wire->attributes[ID::src] = orig_wire->attributes[ID::src]; + if (markgroups) wire->attributes[ID::abcgroup] = map_autoidx; + design->select(module, wire); + } + + SigMap mapped_sigmap(mapped_mod); + FfInitVals mapped_initvals(&mapped_sigmap, mapped_mod); + + dict cell_stats; + for (auto c : mapped_mod->cells()) + { + if (builtin_lib) { - if (builtin_lib) - { - cell_stats[RTLIL::unescape_id(c->type)]++; - if (c->type.in(ID(ZERO), ID(ONE))) { - RTLIL::SigSig conn; - RTLIL::IdString name_y = remap_name(c->getPort(ID::Y).as_wire()->name); - conn.first = module->wire(name_y); - conn.second = RTLIL::SigSpec(c->type == ID(ZERO) ? 0 : 1, 1); - module->connect(conn); - continue; - } - if (c->type == ID(BUF)) { - RTLIL::SigSig conn; - RTLIL::IdString name_y = remap_name(c->getPort(ID::Y).as_wire()->name); - RTLIL::IdString name_a = remap_name(c->getPort(ID::A).as_wire()->name); - conn.first = module->wire(name_y); - conn.second = module->wire(name_a); - module->connect(conn); - continue; - } - if (c->type == ID(NOT)) { - RTLIL::Cell *cell = module->addCell(remap_name(c->name), ID($_NOT_)); - if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; - for (auto name : {ID::A, ID::Y}) { - RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name); - cell->setPort(name, module->wire(remapped_name)); - } - design->select(module, cell); - continue; - } - if (c->type.in(ID(AND), ID(OR), ID(XOR), ID(NAND), ID(NOR), ID(XNOR), ID(ANDNOT), ID(ORNOT))) { - RTLIL::Cell *cell = module->addCell(remap_name(c->name), stringf("$_%s_", c->type.c_str()+1)); - if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; - for (auto name : {ID::A, ID::B, ID::Y}) { - RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name); - cell->setPort(name, module->wire(remapped_name)); - } - design->select(module, cell); - continue; - } - if (c->type.in(ID(MUX), ID(NMUX))) { - RTLIL::Cell *cell = module->addCell(remap_name(c->name), stringf("$_%s_", c->type.c_str()+1)); - if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; - for (auto name : {ID::A, ID::B, ID::S, ID::Y}) { - RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name); - cell->setPort(name, module->wire(remapped_name)); - } - design->select(module, cell); - continue; - } - if (c->type == ID(MUX4)) { - RTLIL::Cell *cell = module->addCell(remap_name(c->name), ID($_MUX4_)); - if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; - for (auto name : {ID::A, ID::B, ID::C, ID::D, ID::S, ID::T, ID::Y}) { - RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name); - cell->setPort(name, module->wire(remapped_name)); - } - design->select(module, cell); - continue; - } - if (c->type == ID(MUX8)) { - RTLIL::Cell *cell = module->addCell(remap_name(c->name), ID($_MUX8_)); - if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; - for (auto name : {ID::A, ID::B, ID::C, ID::D, ID::E, ID::F, ID::G, ID::H, ID::S, ID::T, ID::U, ID::Y}) { - RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name); - cell->setPort(name, module->wire(remapped_name)); - } - design->select(module, cell); - continue; - } - if (c->type == ID(MUX16)) { - RTLIL::Cell *cell = module->addCell(remap_name(c->name), ID($_MUX16_)); - if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; - for (auto name : {ID::A, ID::B, ID::C, ID::D, ID::E, ID::F, ID::G, ID::H, ID::I, ID::J, ID::K, - ID::L, ID::M, ID::N, ID::O, ID::P, ID::S, ID::T, ID::U, ID::V, ID::Y}) { - RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name); - cell->setPort(name, module->wire(remapped_name)); - } - design->select(module, cell); - continue; - } - if (c->type.in(ID(AOI3), ID(OAI3))) { - RTLIL::Cell *cell = module->addCell(remap_name(c->name), stringf("$_%s_", c->type.c_str()+1)); - if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; - for (auto name : {ID::A, ID::B, ID::C, ID::Y}) { - RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name); - cell->setPort(name, module->wire(remapped_name)); - } - design->select(module, cell); - continue; - } - if (c->type.in(ID(AOI4), ID(OAI4))) { - RTLIL::Cell *cell = module->addCell(remap_name(c->name), stringf("$_%s_", c->type.c_str()+1)); - if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; - for (auto name : {ID::A, ID::B, ID::C, ID::D, ID::Y}) { - RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name); - cell->setPort(name, module->wire(remapped_name)); - } - design->select(module, cell); - continue; - } - if (c->type == ID(DFF)) { - log_assert(clk_sig.size() == 1); - FfData ff(module, &initvals, remap_name(c->name)); - ff.width = 1; - ff.is_fine = true; - ff.has_clk = true; - ff.pol_clk = clk_polarity; - ff.sig_clk = clk_sig; - if (en_sig.size() != 0) { - log_assert(en_sig.size() == 1); - ff.has_ce = true; - ff.pol_ce = en_polarity; - ff.sig_ce = en_sig; - } - RTLIL::Const init = mapped_initvals(c->getPort(ID::Q)); - if (had_init) - ff.val_init = init; - else - ff.val_init = State::Sx; - if (arst_sig.size() != 0) { - log_assert(arst_sig.size() == 1); - ff.has_arst = true; - ff.pol_arst = arst_polarity; - ff.sig_arst = arst_sig; - ff.val_arst = init; - } - if (srst_sig.size() != 0) { - log_assert(srst_sig.size() == 1); - ff.has_srst = true; - ff.pol_srst = srst_polarity; - ff.sig_srst = srst_sig; - ff.val_srst = init; - } - ff.sig_d = module->wire(remap_name(c->getPort(ID::D).as_wire()->name)); - ff.sig_q = module->wire(remap_name(c->getPort(ID::Q).as_wire()->name)); - RTLIL::Cell *cell = ff.emit(); - if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; - design->select(module, cell); - continue; - } - } - else - cell_stats[RTLIL::unescape_id(c->type)]++; - - if (c->type.in(ID(_const0_), ID(_const1_))) { + cell_stats[RTLIL::unescape_id(c->type)]++; + if (c->type.in(ID(ZERO), ID(ONE))) { RTLIL::SigSig conn; - conn.first = module->wire(remap_name(c->connections().begin()->second.as_wire()->name)); - conn.second = RTLIL::SigSpec(c->type == ID(_const0_) ? 0 : 1, 1); + RTLIL::IdString name_y = remap_name(c->getPort(ID::Y).as_wire()->name); + conn.first = module->wire(name_y); + conn.second = RTLIL::SigSpec(c->type == ID(ZERO) ? 0 : 1, 1); module->connect(conn); continue; } - - if (c->type == ID(_dff_)) { + if (c->type == ID(BUF)) { + RTLIL::SigSig conn; + RTLIL::IdString name_y = remap_name(c->getPort(ID::Y).as_wire()->name); + RTLIL::IdString name_a = remap_name(c->getPort(ID::A).as_wire()->name); + conn.first = module->wire(name_y); + conn.second = module->wire(name_a); + module->connect(conn); + continue; + } + if (c->type == ID(NOT)) { + RTLIL::Cell *cell = module->addCell(remap_name(c->name), ID($_NOT_)); + if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; + for (auto name : {ID::A, ID::Y}) { + RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name); + cell->setPort(name, module->wire(remapped_name)); + } + design->select(module, cell); + continue; + } + if (c->type.in(ID(AND), ID(OR), ID(XOR), ID(NAND), ID(NOR), ID(XNOR), ID(ANDNOT), ID(ORNOT))) { + RTLIL::Cell *cell = module->addCell(remap_name(c->name), stringf("$_%s_", c->type.c_str()+1)); + if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; + for (auto name : {ID::A, ID::B, ID::Y}) { + RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name); + cell->setPort(name, module->wire(remapped_name)); + } + design->select(module, cell); + continue; + } + if (c->type.in(ID(MUX), ID(NMUX))) { + RTLIL::Cell *cell = module->addCell(remap_name(c->name), stringf("$_%s_", c->type.c_str()+1)); + if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; + for (auto name : {ID::A, ID::B, ID::S, ID::Y}) { + RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name); + cell->setPort(name, module->wire(remapped_name)); + } + design->select(module, cell); + continue; + } + if (c->type == ID(MUX4)) { + RTLIL::Cell *cell = module->addCell(remap_name(c->name), ID($_MUX4_)); + if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; + for (auto name : {ID::A, ID::B, ID::C, ID::D, ID::S, ID::T, ID::Y}) { + RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name); + cell->setPort(name, module->wire(remapped_name)); + } + design->select(module, cell); + continue; + } + if (c->type == ID(MUX8)) { + RTLIL::Cell *cell = module->addCell(remap_name(c->name), ID($_MUX8_)); + if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; + for (auto name : {ID::A, ID::B, ID::C, ID::D, ID::E, ID::F, ID::G, ID::H, ID::S, ID::T, ID::U, ID::Y}) { + RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name); + cell->setPort(name, module->wire(remapped_name)); + } + design->select(module, cell); + continue; + } + if (c->type == ID(MUX16)) { + RTLIL::Cell *cell = module->addCell(remap_name(c->name), ID($_MUX16_)); + if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; + for (auto name : {ID::A, ID::B, ID::C, ID::D, ID::E, ID::F, ID::G, ID::H, ID::I, ID::J, ID::K, + ID::L, ID::M, ID::N, ID::O, ID::P, ID::S, ID::T, ID::U, ID::V, ID::Y}) { + RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name); + cell->setPort(name, module->wire(remapped_name)); + } + design->select(module, cell); + continue; + } + if (c->type.in(ID(AOI3), ID(OAI3))) { + RTLIL::Cell *cell = module->addCell(remap_name(c->name), stringf("$_%s_", c->type.c_str()+1)); + if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; + for (auto name : {ID::A, ID::B, ID::C, ID::Y}) { + RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name); + cell->setPort(name, module->wire(remapped_name)); + } + design->select(module, cell); + continue; + } + if (c->type.in(ID(AOI4), ID(OAI4))) { + RTLIL::Cell *cell = module->addCell(remap_name(c->name), stringf("$_%s_", c->type.c_str()+1)); + if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; + for (auto name : {ID::A, ID::B, ID::C, ID::D, ID::Y}) { + RTLIL::IdString remapped_name = remap_name(c->getPort(name).as_wire()->name); + cell->setPort(name, module->wire(remapped_name)); + } + design->select(module, cell); + continue; + } + if (c->type == ID(DFF)) { log_assert(clk_sig.size() == 1); FfData ff(module, &initvals, remap_name(c->name)); ff.width = 1; @@ -1390,6 +1355,7 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_mo ff.sig_clk = clk_sig; if (en_sig.size() != 0) { log_assert(en_sig.size() == 1); + ff.has_ce = true; ff.pol_ce = en_polarity; ff.sig_ce = en_sig; } @@ -1400,12 +1366,14 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_mo ff.val_init = State::Sx; if (arst_sig.size() != 0) { log_assert(arst_sig.size() == 1); + ff.has_arst = true; ff.pol_arst = arst_polarity; ff.sig_arst = arst_sig; ff.val_arst = init; } if (srst_sig.size() != 0) { log_assert(srst_sig.size() == 1); + ff.has_srst = true; ff.pol_srst = srst_polarity; ff.sig_srst = srst_sig; ff.val_srst = init; @@ -1417,69 +1385,116 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_mo design->select(module, cell); continue; } + } + else + cell_stats[RTLIL::unescape_id(c->type)]++; - if (c->type == ID($lut) && GetSize(c->getPort(ID::A)) == 1 && c->getParam(ID::LUT).as_int() == 2) { - SigSpec my_a = module->wire(remap_name(c->getPort(ID::A).as_wire()->name)); - SigSpec my_y = module->wire(remap_name(c->getPort(ID::Y).as_wire()->name)); - module->connect(my_y, my_a); - continue; - } - - RTLIL::Cell *cell = module->addCell(remap_name(c->name), c->type); - if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; - cell->parameters = c->parameters; - for (auto &conn : c->connections()) { - RTLIL::SigSpec newsig; - for (auto &c : conn.second.chunks()) { - if (c.width == 0) - continue; - log_assert(c.width == 1); - newsig.append(module->wire(remap_name(c.wire->name))); - } - cell->setPort(conn.first, newsig); - } - design->select(module, cell); + if (c->type.in(ID(_const0_), ID(_const1_))) { + RTLIL::SigSig conn; + conn.first = module->wire(remap_name(c->connections().begin()->second.as_wire()->name)); + conn.second = RTLIL::SigSpec(c->type == ID(_const0_) ? 0 : 1, 1); + module->connect(conn); + continue; } - for (auto conn : mapped_mod->connections()) { - if (!conn.first.is_fully_const()) - conn.first = module->wire(remap_name(conn.first.as_wire()->name)); - if (!conn.second.is_fully_const()) - conn.second = module->wire(remap_name(conn.second.as_wire()->name)); + if (c->type == ID(_dff_)) { + log_assert(clk_sig.size() == 1); + FfData ff(module, &initvals, remap_name(c->name)); + ff.width = 1; + ff.is_fine = true; + ff.has_clk = true; + ff.pol_clk = clk_polarity; + ff.sig_clk = clk_sig; + if (en_sig.size() != 0) { + log_assert(en_sig.size() == 1); + ff.pol_ce = en_polarity; + ff.sig_ce = en_sig; + } + RTLIL::Const init = mapped_initvals(c->getPort(ID::Q)); + if (had_init) + ff.val_init = init; + else + ff.val_init = State::Sx; + if (arst_sig.size() != 0) { + log_assert(arst_sig.size() == 1); + ff.pol_arst = arst_polarity; + ff.sig_arst = arst_sig; + ff.val_arst = init; + } + if (srst_sig.size() != 0) { + log_assert(srst_sig.size() == 1); + ff.pol_srst = srst_polarity; + ff.sig_srst = srst_sig; + ff.val_srst = init; + } + ff.sig_d = module->wire(remap_name(c->getPort(ID::D).as_wire()->name)); + ff.sig_q = module->wire(remap_name(c->getPort(ID::Q).as_wire()->name)); + RTLIL::Cell *cell = ff.emit(); + if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; + design->select(module, cell); + continue; + } + + if (c->type == ID($lut) && GetSize(c->getPort(ID::A)) == 1 && c->getParam(ID::LUT).as_int() == 2) { + SigSpec my_a = module->wire(remap_name(c->getPort(ID::A).as_wire()->name)); + SigSpec my_y = module->wire(remap_name(c->getPort(ID::Y).as_wire()->name)); + module->connect(my_y, my_a); + continue; + } + + RTLIL::Cell *cell = module->addCell(remap_name(c->name), c->type); + if (markgroups) cell->attributes[ID::abcgroup] = map_autoidx; + cell->parameters = c->parameters; + for (auto &conn : c->connections()) { + RTLIL::SigSpec newsig; + for (auto &c : conn.second.chunks()) { + if (c.width == 0) + continue; + log_assert(c.width == 1); + newsig.append(module->wire(remap_name(c.wire->name))); + } + cell->setPort(conn.first, newsig); + } + design->select(module, cell); + } + + for (auto conn : mapped_mod->connections()) { + if (!conn.first.is_fully_const()) + conn.first = module->wire(remap_name(conn.first.as_wire()->name)); + if (!conn.second.is_fully_const()) + conn.second = module->wire(remap_name(conn.second.as_wire()->name)); + module->connect(conn); + } + + cell_stats.sort(); + for (auto &it : cell_stats) + log("ABC RESULTS: %15s cells: %8d\n", it.first.c_str(), it.second); + int in_wires = 0, out_wires = 0; + for (auto &si : signal_list) + if (si.is_port) { + char buffer[100]; + snprintf(buffer, 100, "\\ys__n%d", si.id); + RTLIL::SigSig conn; + if (si.type != G(NONE)) { + conn.first = si.bit; + conn.second = module->wire(remap_name(buffer)); + out_wires++; + } else { + conn.first = module->wire(remap_name(buffer)); + conn.second = si.bit; + in_wires++; + } module->connect(conn); } + log("ABC RESULTS: internal signals: %8d\n", int(signal_list.size()) - in_wires - out_wires); + log("ABC RESULTS: input signals: %8d\n", in_wires); + log("ABC RESULTS: output signals: %8d\n", out_wires); - cell_stats.sort(); - for (auto &it : cell_stats) - log("ABC RESULTS: %15s cells: %8d\n", it.first.c_str(), it.second); - int in_wires = 0, out_wires = 0; - for (auto &si : signal_list) - if (si.is_port) { - char buffer[100]; - snprintf(buffer, 100, "\\ys__n%d", si.id); - RTLIL::SigSig conn; - if (si.type != G(NONE)) { - conn.first = si.bit; - conn.second = module->wire(remap_name(buffer)); - out_wires++; - } else { - conn.first = module->wire(remap_name(buffer)); - conn.second = si.bit; - in_wires++; - } - module->connect(conn); - } - log("ABC RESULTS: internal signals: %8d\n", int(signal_list.size()) - in_wires - out_wires); - log("ABC RESULTS: input signals: %8d\n", in_wires); - log("ABC RESULTS: output signals: %8d\n", out_wires); - - delete mapped_design; - } - else - { - log("Don't call ABC as there is nothing to map.\n"); - } + delete mapped_design; +} +void AbcModuleState::finish() +{ if (config.cleanup) { log("Removing temp directory.\n"); @@ -2072,6 +2087,8 @@ struct AbcPass : public Pass { AbcModuleState state(config); state.assign_map.set(mod); state.abc_module(design, mod, mod->selected_cells(), dff_mode, clk_str); + state.extract(design); + state.finish(); continue; } @@ -2239,6 +2256,8 @@ struct AbcPass : public Pass { state.srst_polarity = std::get<6>(it.first); state.srst_sig = assign_map(std::get<7>(it.first)); state.abc_module(design, mod, it.second, !state.clk_sig.empty(), "$"); + state.extract(design); + state.finish(); } } From 885bb744e3b7c25d684b9f8db2a4c5e970ce65d3 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 15 Jul 2025 04:17:48 +0000 Subject: [PATCH 10/47] Make `module` a parameter of the function so we can change its constness in context --- passes/techmap/abc.cc | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index 494494a49..fb889f530 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -143,7 +143,6 @@ struct AbcModuleState { int map_autoidx = 0; SigMap assign_map; - RTLIL::Module *module = nullptr; std::vector signal_list; dict signal_map; FfInitVals initvals; @@ -165,13 +164,13 @@ struct AbcModuleState { int map_signal(RTLIL::SigBit bit, gate_type_t gate_type = G(NONE), int in1 = -1, int in2 = -1, int in3 = -1, int in4 = -1); void mark_port(RTLIL::SigSpec sig); - void extract_cell(RTLIL::Cell *cell, bool keepff); + void extract_cell(RTLIL::Module *module, RTLIL::Cell *cell, bool keepff); std::string remap_name(RTLIL::IdString abc_name, RTLIL::Wire **orig_wire = nullptr); void dump_loop_graph(FILE *f, int &nr, dict> &edges, pool &workpool, std::vector &in_counts); - void handle_loops(); - void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, const std::vector &cells, + void handle_loops(RTLIL::Module *module); + void abc_module(RTLIL::Design *design, RTLIL::Module *module, const std::vector &cells, bool dff_mode, std::string clk_str); - void extract(RTLIL::Design *design); + void extract(RTLIL::Design *design, RTLIL::Module *module); void finish(); }; @@ -220,7 +219,7 @@ void AbcModuleState::mark_port(RTLIL::SigSpec sig) signal_list[signal_map[bit]].is_port = true; } -void AbcModuleState::extract_cell(RTLIL::Cell *cell, bool keepff) +void AbcModuleState::extract_cell(RTLIL::Module *module, RTLIL::Cell *cell, bool keepff) { if (RTLIL::builtin_ff_cell_types().count(cell->type)) { FfData ff(&initvals, cell); @@ -491,7 +490,7 @@ void AbcModuleState::dump_loop_graph(FILE *f, int &nr, dict> &edg fprintf(f, "}\n"); } -void AbcModuleState::handle_loops() +void AbcModuleState::handle_loops(RTLIL::Module *module) { // http://en.wikipedia.org/wiki/Topological_sorting // (Kahn, Arthur B. (1962), "Topological sorting of large networks") @@ -751,10 +750,9 @@ struct abc_output_filter } }; -void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_module, const std::vector &cells, +void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *module, const std::vector &cells, bool dff_mode, std::string clk_str) { - module = current_module; initvals.set(&assign_map, module); map_autoidx = autoidx++; @@ -938,7 +936,7 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_mo had_init = false; for (auto c : cells) - extract_cell(c, config.keepff); + extract_cell(module, c, config.keepff); if (undef_bits_lost) log("Replacing %d occurrences of constant undef bits with constant zero bits\n", undef_bits_lost); @@ -964,7 +962,7 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_mo if (srst_sig.size() != 0) mark_port(srst_sig); - handle_loops(); + handle_loops(module); buffer = stringf("%s/input.blif", tempdir_name.c_str()); f = fopen(buffer.c_str(), "wt"); @@ -1207,7 +1205,7 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *current_mo log("Don't call ABC as there is nothing to map.\n"); } -void AbcModuleState::extract(RTLIL::Design *design) +void AbcModuleState::extract(RTLIL::Design *design, RTLIL::Module *module) { if (!did_run_abc) { return; @@ -2087,7 +2085,7 @@ struct AbcPass : public Pass { AbcModuleState state(config); state.assign_map.set(mod); state.abc_module(design, mod, mod->selected_cells(), dff_mode, clk_str); - state.extract(design); + state.extract(design, mod); state.finish(); continue; } @@ -2256,7 +2254,7 @@ struct AbcPass : public Pass { state.srst_polarity = std::get<6>(it.first); state.srst_sig = assign_map(std::get<7>(it.first)); state.abc_module(design, mod, it.second, !state.clk_sig.empty(), "$"); - state.extract(design); + state.extract(design, mod); state.finish(); } } From ccb23ffc1a37d2227c759a4b8f9c9e096ef71982 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 15 Jul 2025 04:19:09 +0000 Subject: [PATCH 11/47] Fix indentation --- passes/techmap/abc.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index fb889f530..0c2576c1a 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -947,8 +947,8 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *module, co } for (auto cell : module->cells()) - for (auto &port_it : cell->connections()) - mark_port(port_it.second); + for (auto &port_it : cell->connections()) + mark_port(port_it.second); if (clk_sig.size() != 0) mark_port(clk_sig); From 1eb8844e38ce0dd88f797e26661cfd31007a1597 Mon Sep 17 00:00:00 2001 From: clemens Date: Wed, 13 Aug 2025 08:36:26 +0200 Subject: [PATCH 12/47] fix labeling in report fix design hierarchy containing wrong values. remove left over debug print. --- passes/cmds/stat.cc | 62 +++++++++++++++++++++++++++------------------ 1 file changed, 37 insertions(+), 25 deletions(-) diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc index 24b21d674..8ed4e5b93 100644 --- a/passes/cmds/stat.cc +++ b/passes/cmds/stat.cc @@ -338,7 +338,7 @@ struct statdata_t { char buf[16]; - int len = std::snprintf(buf, sizeof(buf), "%.3f", value); + int len = snprintf(buf, sizeof(buf), "%.3f", value); while (len > 0 && buf[len - 1] == '0') --len; @@ -351,13 +351,13 @@ struct statdata_t { } // use scientific notation, this should always fit in 8 characters - std::snprintf(buf, sizeof(buf), "%8.3G", value); + snprintf(buf, sizeof(buf), "%8.3G", value); return std::string(buf); } void print_log_line(const std::string &name, unsigned int count_local, double area_local, unsigned int count_global, double area_global, - int spacer = 0, bool print_area = true, bool print_hierarchical = true) + int spacer = 0, bool print_area = true, bool print_hierarchical = true, bool print_global_only = false) { const std::string indent(2 * spacer, ' '); @@ -370,6 +370,8 @@ struct statdata_t { if (print_hierarchical) { log(" %s %s %s %s %s%s\n", count_global_str.c_str(), area_global_str.c_str(), count_local_str.c_str(), area_local_str.c_str(), indent.c_str(), name.c_str()); + } else if (print_global_only) { + log(" %s %s %s%s\n", count_global_str.c_str(), area_global_str.c_str(), indent.c_str(), name.c_str()); } else { if (count_local > 0) log(" %s %s %s%s\n", count_local_str.c_str(), area_local_str.c_str(), indent.c_str(), name.c_str()); @@ -377,6 +379,8 @@ struct statdata_t { } else { if (print_hierarchical) { log(" %s %s %s%s\n", count_global_str.c_str(), count_local_str.c_str(), indent.c_str(), name.c_str()); + } else if (print_global_only) { + log(" %s %s%s\n", count_global_str.c_str(), indent.c_str(), name.c_str()); } else { if (count_local > 0) log(" %s %s%s\n", count_local_str.c_str(), indent.c_str(), name.c_str()); @@ -384,7 +388,7 @@ struct statdata_t { } } - void print_log_header(bool print_area = true, bool print_hierarchical = true) + void print_log_header(bool print_area = true, bool print_hierarchical = true, bool print_global_only = false) { if (print_area) { if (print_hierarchical) { @@ -393,9 +397,13 @@ struct statdata_t { log(" %8s %8s %8s-%8s-%s\n", "|", "|", "+", "--------", "Local count, excluding submodules."); log(" %8s %8s %8s %8s-%s\n", "|", "|", "|", "+", "Local area, excluding submodules."); log(" %8s %8s %8s %8s \n", "|", "|", "|", "|"); + } else if (print_global_only) { + log(" %8s-%8s-%s\n", "+", "--------", "Count including submodules."); + log(" %8s %8s-%s\n", "|", "+", "Area including submodules."); + log(" %8s %8s \n", "|", "|"); } else { - log(" %8s-%8s-%s\n", "+", "--------", "Local Count including submodules."); - log(" %8s %8s-%s\n", "|", "+", "Local Area including submodules."); + log(" %8s-%8s-%s\n", "+", "--------", "Local Count, excluding submodules."); + log(" %8s %8s-%s\n", "|", "+", "Local Area, excluding submodules."); log(" %8s %8s \n", "|", "|"); } } else { @@ -403,42 +411,47 @@ struct statdata_t { log(" %8s-%8s-%8s-%s\n", "+", "--------", "--------", "Count including submodules."); log(" %8s %8s-%8s-%s\n", "|", "+", "--------", "Local count, excluding submodules."); log(" %8s %8s \n", "|", "|"); + } else if (print_global_only) { + log(" %8s-%8s-%s\n", "+", "--------", "Count including submodules."); + log(" %8s %8s \n", "|", "|"); } else { - log(" %8s-%8s-%s\n", "+", "--------", "Local Count including submodules."); + log(" %8s-%8s-%s\n", "+", "--------", "Local Count, excluding submodules."); log(" %8s \n", "|"); } } } - void log_data(RTLIL::IdString mod_name, bool top_mod, bool print_area = true, bool print_hierarchical = true) + void log_data(RTLIL::IdString mod_name, bool top_mod, bool print_area = true, bool print_hierarchical = true, bool print_global_only = false) { - print_log_header(print_area, print_hierarchical); + print_log_header(print_area, print_hierarchical, print_global_only); - print_log_line("wires", local_num_wires, 0, num_wires, 0, 0, print_area, print_hierarchical); - print_log_line("wire bits", local_num_wire_bits, 0, num_wire_bits, 0, 0, print_area, print_hierarchical); - print_log_line("public wires", local_num_pub_wires, 0, num_pub_wires, 0, 0, print_area, print_hierarchical); - print_log_line("public wire bits", local_num_pub_wire_bits, 0, num_pub_wire_bits, 0, 0, print_area, print_hierarchical); - print_log_line("ports", local_num_ports, 0, num_ports, 0, 0, print_area, print_hierarchical); - print_log_line("port bits", local_num_port_bits, 0, num_port_bits, 0, 0, print_area, print_hierarchical); - print_log_line("memories", local_num_memories, 0, num_memories, 0, 0, print_area, print_hierarchical); - print_log_line("memory bits", local_num_memory_bits, 0, num_memory_bits, 0, 0, print_area, print_hierarchical); - print_log_line("processes", local_num_processes, 0, num_processes, 0, 0, print_area, print_hierarchical); - print_log_line("cells", local_num_cells, local_area, num_cells, area, 0, print_area, print_hierarchical); + print_log_line("wires", local_num_wires, 0, num_wires, 0, 0, print_area, print_hierarchical, print_global_only); + print_log_line("wire bits", local_num_wire_bits, 0, num_wire_bits, 0, 0, print_area, print_hierarchical, print_global_only); + print_log_line("public wires", local_num_pub_wires, 0, num_pub_wires, 0, 0, print_area, print_hierarchical, print_global_only); + print_log_line("public wire bits", local_num_pub_wire_bits, 0, num_pub_wire_bits, 0, 0, print_area, print_hierarchical, + print_global_only); + print_log_line("ports", local_num_ports, 0, num_ports, 0, 0, print_area, print_hierarchical, print_global_only); + print_log_line("port bits", local_num_port_bits, 0, num_port_bits, 0, 0, print_area, print_hierarchical, print_global_only); + print_log_line("memories", local_num_memories, 0, num_memories, 0, 0, print_area, print_hierarchical, print_global_only); + print_log_line("memory bits", local_num_memory_bits, 0, num_memory_bits, 0, 0, print_area, print_hierarchical, print_global_only); + print_log_line("processes", local_num_processes, 0, num_processes, 0, 0, print_area, print_hierarchical, print_global_only); + print_log_line("cells", local_num_cells, local_area, num_cells, area, 0, print_area, print_hierarchical, print_global_only); for (auto &it : num_cells_by_type) if (it.second) { auto name = string(log_id(it.first)); print_log_line(name, local_num_cells_by_type.count(it.first) ? local_num_cells_by_type.at(it.first) : 0, local_area_cells_by_type.count(it.first) ? local_area_cells_by_type.at(it.first) : 0, it.second, - area_cells_by_type.at(it.first), 1, print_area, print_hierarchical); + area_cells_by_type.at(it.first), 1, print_area, print_hierarchical, print_global_only); } if (num_submodules > 0) { - print_log_line("submodules", num_submodules, 0, num_submodules, submodule_area, 0, print_area, print_hierarchical); + print_log_line("submodules", num_submodules, 0, num_submodules, submodule_area, 0, print_area, print_hierarchical, + print_global_only); for (auto &it : num_submodules_by_type) if (it.second) print_log_line(string(log_id(it.first)), it.second, 0, it.second, submodules_area_by_type.count(it.first) ? submodules_area_by_type.at(it.first) : 0, 1, - print_area, print_hierarchical); + print_area, print_hierarchical, print_global_only); } if (!unknown_cell_area.empty()) { log("\n"); @@ -811,7 +824,7 @@ struct StatPass : public Pass { log("\n"); log("=== design hierarchy ===\n"); log("\n"); - mod_stat[top_mod->name].print_log_header(has_area, hierarchy_mode); + mod_stat[top_mod->name].print_log_header(has_area, hierarchy_mode, true); mod_stat[top_mod->name].print_log_line(log_id(top_mod->name), mod_stat[top_mod->name].local_num_cells, mod_stat[top_mod->name].local_area, mod_stat[top_mod->name].num_cells, mod_stat[top_mod->name].area, 0, has_area, hierarchy_mode); @@ -823,7 +836,7 @@ struct StatPass : public Pass { data.log_data_json("design", true, true); else if (GetSize(mod_stat) > 1) { log("\n"); - data.log_data(top_mod->name, true, has_area, hierarchy_mode); + data.log_data(top_mod->name, true, has_area, hierarchy_mode, true); } design->scratchpad_set_int("stat.num_wires", data.num_wires); @@ -845,7 +858,6 @@ struct StatPass : public Pass { } log("\n"); - printf("processed statistics\n"); } } StatPass; From 383d11c2ac9254836f8107e4a2fa6901b7bccd09 Mon Sep 17 00:00:00 2001 From: clemens Date: Wed, 13 Aug 2025 10:09:02 +0200 Subject: [PATCH 13/47] fix design overview in json. Fix some unknown cells apearing twice. --- passes/cmds/stat.cc | 118 ++++++++++++++++++++++++++++---------------- 1 file changed, 76 insertions(+), 42 deletions(-) diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc index 8ed4e5b93..ea9dfcd3c 100644 --- a/passes/cmds/stat.cc +++ b/passes/cmds/stat.cc @@ -486,7 +486,7 @@ struct statdata_t { count_local, area_local); } - void log_data_json(const char *mod_name, bool first_module, bool hierarchical = false) + void log_data_json(const char *mod_name, bool first_module, bool hierarchical = false, bool global_only = false) { if (!first_module) log(",\n"); @@ -543,41 +543,77 @@ struct statdata_t { log(" }"); } else { - - log(" %s: {\n", json11::Json(mod_name).dump().c_str()); - log(" \"num_wires\": %u,\n", num_wires); - log(" \"num_wire_bits\": %u,\n", num_wire_bits); - log(" \"num_pub_wires\": %u,\n", num_pub_wires); - log(" \"num_pub_wire_bits\": %u,\n", num_pub_wire_bits); - log(" \"num_ports\": %u,\n", num_ports); - log(" \"num_port_bits\": %u,\n", num_port_bits); - log(" \"num_memories\": %u,\n", num_memories); - log(" \"num_memory_bits\": %u,\n", num_memory_bits); - log(" \"num_processes\": %u,\n", num_processes); - log(" \"num_cells\": %u,\n", local_num_cells); - log(" \"num_submodules\": %u,\n", num_submodules); - if (area != 0) { - log(" \"area\": %f,\n", area); - log(" \"sequential_area\": %f,\n", sequential_area); + if (global_only) { + log(" %s: {\n", json11::Json(mod_name).dump().c_str()); + log(" \"num_wires\": %u,\n", num_wires); + log(" \"num_wire_bits\": %u,\n", num_wire_bits); + log(" \"num_pub_wires\": %u,\n", num_pub_wires); + log(" \"num_pub_wire_bits\": %u,\n", num_pub_wire_bits); + log(" \"num_ports\": %u,\n", num_ports); + log(" \"num_port_bits\": %u,\n", num_port_bits); + log(" \"num_memories\": %u,\n", num_memories); + log(" \"num_memory_bits\": %u,\n", num_memory_bits); + log(" \"num_processes\": %u,\n", num_processes); + log(" \"num_cells\": %u,\n", num_cells); + log(" \"num_submodules\": %u,\n", num_submodules); + if (area != 0) { + log(" \"area\": %f,\n", area); + log(" \"sequential_area\": %f,\n", sequential_area); + } + log(" \"num_cells_by_type\": {\n"); + bool first_line = true; + for (auto &it : num_cells_by_type) + if (it.second) { + if (!first_line) + log(",\n"); + log(" %s: %u", json11::Json(log_id(it.first)).dump().c_str(), it.second); + first_line = false; + } + for (auto &it : num_submodules_by_type) + if (it.second) { + if (!first_line) + log(",\n"); + log(" %s: %u", json11::Json(log_id(it.first)).dump().c_str(), it.second); + first_line = false; + } + log("\n"); + log(" }"); + } else { + log(" %s: {\n", json11::Json(mod_name).dump().c_str()); + log(" \"num_wires\": %u,\n", local_num_wires); + log(" \"num_wire_bits\": %u,\n", local_num_wire_bits); + log(" \"num_pub_wires\": %u,\n", local_num_pub_wires); + log(" \"num_pub_wire_bits\": %u,\n", local_num_pub_wire_bits); + log(" \"num_ports\": %u,\n", local_num_ports); + log(" \"num_port_bits\": %u,\n", local_num_port_bits); + log(" \"num_memories\": %u,\n", local_num_memories); + log(" \"num_memory_bits\": %u,\n", local_num_memory_bits); + log(" \"num_processes\": %u,\n", local_num_processes); + log(" \"num_cells\": %u,\n", local_num_cells); + log(" \"num_submodules\": %u,\n", num_submodules); + if (area != 0) { + log(" \"area\": %f,\n", area); + log(" \"sequential_area\": %f,\n", sequential_area); + } + log(" \"num_cells_by_type\": {\n"); + bool first_line = true; + for (auto &it : local_num_cells_by_type) + if (it.second) { + if (!first_line) + log(",\n"); + log(" %s: %u", json11::Json(log_id(it.first)).dump().c_str(), it.second); + first_line = false; + } + for (auto &it : num_submodules_by_type) + if (it.second) { + if (!first_line) + log(",\n"); + log(" %s: %u", json11::Json(log_id(it.first)).dump().c_str(), it.second); + first_line = false; + } + log("\n"); + log(" }"); } - log(" \"num_cells_by_type\": {\n"); - bool first_line = true; - for (auto &it : local_num_cells_by_type) - if (it.second) { - if (!first_line) - log(",\n"); - log(" %s: %u", json11::Json(log_id(it.first)).dump().c_str(), it.second); - first_line = false; - } - for (auto &it : num_submodules_by_type) - if (it.second) { - if (!first_line) - log(",\n"); - log(" %s: %u", json11::Json(log_id(it.first)).dump().c_str(), it.second); - first_line = false; - } - log("\n"); - log(" }"); if (tech == "xilinx") { log(",\n"); log(" \"estimated_num_lc\": %u", estimate_xilinx_lc()); @@ -644,12 +680,10 @@ statdata_t hierarchy_builder(const RTLIL::Design *design, const RTLIL::Module *t double(design->module(cell->type)->attributes.at(ID::area).as_int()); mod_data.area += double(design->module(cell->type)->attributes.at(ID::area).as_int()); mod_data.unknown_cell_area.erase(cell->type); - } else { - mod_data.unknown_cell_area.insert(cell->type); - mod_data.num_submodules++; - mod_data.num_submodules_by_type[cell->type]++; - mod_data.submodules_area_by_type[cell->type] = 0; - mod_data.seq_area_cells_by_type[cell->type] = 0; + mod_data.num_cells -= mod_data.num_cells_by_type.erase(cell->type); + mod_data.area_cells_by_type.erase(cell->type); + mod_data.local_num_cells -= mod_data.local_num_cells_by_type.erase(cell->type); + mod_data.local_area_cells_by_type.erase(cell->type); } } } @@ -833,7 +867,7 @@ struct StatPass : public Pass { statdata_t data = hierarchy_worker(mod_stat, top_mod->name, 0, /*quiet=*/json_mode, has_area, hierarchy_mode); if (json_mode) - data.log_data_json("design", true, true); + data.log_data_json("design", true, hierarchy_mode, true); else if (GetSize(mod_stat) > 1) { log("\n"); data.log_data(top_mod->name, true, has_area, hierarchy_mode, true); From 71307b4a519dbbe81fff5988987f69eec290e737 Mon Sep 17 00:00:00 2001 From: clemens Date: Wed, 13 Aug 2025 14:46:01 +0200 Subject: [PATCH 14/47] add Testcases Fix existing testcases Fix edgecase where modules where counted as cells. --- passes/cmds/stat.cc | 16 +++++---- tests/various/stat.ys | 7 +++- tests/various/stat_hierarchy.ys | 62 +++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 8 deletions(-) create mode 100644 tests/various/stat_hierarchy.ys diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc index ea9dfcd3c..5cb223ba8 100644 --- a/passes/cmds/stat.cc +++ b/passes/cmds/stat.cc @@ -666,9 +666,10 @@ statdata_t hierarchy_builder(const RTLIL::Design *design, const RTLIL::Module *t mod_data.submodule_area += mod_stat.at(cell->type).area; mod_data.num_submodules++; mod_data.unknown_cell_area.erase(cell->type); - mod_data.num_cells -= mod_data.num_cells_by_type.erase(cell->type); - mod_data.area_cells_by_type.erase(cell->type); - mod_data.local_num_cells -= mod_data.local_num_cells_by_type.erase(cell->type); + mod_data.num_cells -= (mod_data.num_cells_by_type.count(cell->type) != 0)? mod_data.num_cells_by_type.at(cell->type): 0; + mod_data.num_cells_by_type.erase(cell->type); + mod_data.local_num_cells -= (mod_data.local_num_cells_by_type.count(cell->type) != 0)? mod_data.local_num_cells_by_type.at(cell->type): 0; + mod_data.local_num_cells_by_type.erase(cell->type); mod_data.local_area_cells_by_type.erase(cell->type); } else { // deal with blackbox cells @@ -680,9 +681,10 @@ statdata_t hierarchy_builder(const RTLIL::Design *design, const RTLIL::Module *t double(design->module(cell->type)->attributes.at(ID::area).as_int()); mod_data.area += double(design->module(cell->type)->attributes.at(ID::area).as_int()); mod_data.unknown_cell_area.erase(cell->type); - mod_data.num_cells -= mod_data.num_cells_by_type.erase(cell->type); - mod_data.area_cells_by_type.erase(cell->type); - mod_data.local_num_cells -= mod_data.local_num_cells_by_type.erase(cell->type); + mod_data.num_cells -= (mod_data.num_cells_by_type.count(cell->type) != 0)? mod_data.num_cells_by_type.at(cell->type): 0; + mod_data.num_cells_by_type.erase(cell->type); + mod_data.local_num_cells -= (mod_data.local_num_cells_by_type.count(cell->type) != 0)? mod_data.local_num_cells_by_type.at(cell->type): 0; + mod_data.local_num_cells_by_type.erase(cell->type); mod_data.local_area_cells_by_type.erase(cell->type); } } @@ -861,7 +863,7 @@ struct StatPass : public Pass { mod_stat[top_mod->name].print_log_header(has_area, hierarchy_mode, true); mod_stat[top_mod->name].print_log_line(log_id(top_mod->name), mod_stat[top_mod->name].local_num_cells, mod_stat[top_mod->name].local_area, mod_stat[top_mod->name].num_cells, - mod_stat[top_mod->name].area, 0, has_area, hierarchy_mode); + mod_stat[top_mod->name].area, 0, has_area, hierarchy_mode, true); } statdata_t data = hierarchy_worker(mod_stat, top_mod->name, 0, /*quiet=*/json_mode, has_area, hierarchy_mode); diff --git a/tests/various/stat.ys b/tests/various/stat.ys index cf084a986..50e1a35d8 100644 --- a/tests/various/stat.ys +++ b/tests/various/stat.ys @@ -11,6 +11,8 @@ end EOT logger -expect log "Chip area for module '\\top': 9.072000" 1 logger -expect-no-warnings +logger -expect log " 1 9.072 cells" 1 +logger -expect log " 1 9.072 sg13g2_and2_1" 1 stat -liberty ../../tests/liberty/foundry_data/sg13g2_stdcell_typ_1p20V_25C.lib.filtered.gz @@ -69,6 +71,9 @@ module \child end EOT logger -expect log "Chip area for top module '\\top': 112.492800" 1 -logger -expect log "of which used for sequential elements: 94.348800" 1 +logger -expect log "of which used for sequential elements: 94.348800" 2 +logger -expect log "2 18.144 cells" 1 +logger -expect log "4 112.493 cells" 1 +logger -expect log "2 94.349 sg13g2_dfrbp_1" 1 logger -expect-no-warnings stat -liberty ../../tests/liberty/foundry_data/sg13g2_stdcell_typ_1p20V_25C.lib.filtered.gz -top \top diff --git a/tests/various/stat_hierarchy.ys b/tests/various/stat_hierarchy.ys new file mode 100644 index 000000000..f41165629 --- /dev/null +++ b/tests/various/stat_hierarchy.ys @@ -0,0 +1,62 @@ + +read_rtlil << EOT +module \top + wire input 1 \A + wire output 2 \Y + wire output 3 \N + + cell \sg13g2_and2_1 \sub1 + connect \A \A + connect \B 1'0 + connect \Y \Y + end + + cell \child \sequential + connect \A \A + connect \B 1'0 + connect \R 1'0 + connect \Y \Y + connect \N \N + end + + cell \child \sequential1 + connect \A \A + connect \B 1'0 + connect \R 1'0 + connect \Y \Y + connect \N \N + end + + cell \sg13g2_and2_1 \sub2 + connect \A \A + connect \B 1'0 + connect \Y \Y + end +end + +module \child + wire input 1 \A + wire input 2 \B + wire input 3 \R + + wire output 4 \Y + wire output 5 \N + + cell \sg13g2_dfrbp_1 \sequential_ff + connect \CLK \A + connect \D \B + connect \Q \Y + connect \Q_N \N + connect \RESET_B \R + end + +end +EOT +logger -expect log "4 112.493 2 18.144 cells" 2 +logger -expect log "2 18.144 2 18.144 sg13g2_and2_1" 2 +logger -expect log "2 94.349 - - sg13g2_dfrbp_1" 2 +logger -expect log "2 94.349 2 - submodules" 2 +logger -expect-no-warnings +stat -liberty ../../tests/liberty/foundry_data/sg13g2_stdcell_typ_1p20V_25C.lib.filtered.gz -top \top -hierarchy + + From 4de3ee093eecf4e766734fddb113187df36be31a Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Sat, 26 Jul 2025 09:34:37 +0000 Subject: [PATCH 15/47] Mark kept FF output wires as ports directly instead of via the 'keep' attribute --- passes/techmap/abc.cc | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index 0c2576c1a..dfaee9415 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -291,12 +291,15 @@ void AbcModuleState::extract_cell(RTLIL::Module *module, RTLIL::Cell *cell, bool return; } - if (keepff) - for (auto &c : ff.sig_q.chunks()) - if (c.wire != nullptr) - c.wire->attributes[ID::keep] = 1; - - map_signal(ff.sig_q, type, map_signal(ff.sig_d)); + int gate_id = map_signal(ff.sig_q, type, map_signal(ff.sig_d)); + if (keepff) { + SigBit bit = ff.sig_q; + if (assign_map(bit).wire != nullptr) { + signal_list[gate_id].is_port = true; + } + if (bit.wire != nullptr) + bit.wire->attributes[ID::keep] = 1; + } ff.remove(); return; From ac8259b02e6d2ac98fd903603d012c8180540aba Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Thu, 17 Jul 2025 06:16:54 +0000 Subject: [PATCH 16/47] Preserve `assign_map` across ABC invocations. Currently `assign_map` is rebuilt from the module from scratch every time we invoke ABC. That doesn't scale when we do thousands of ABC runs over large modules. Instead, create it once and then maintain incrementally it as we update the module. --- passes/techmap/abc.cc | 130 ++++++++++++++++++++++-------------------- 1 file changed, 68 insertions(+), 62 deletions(-) diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index dfaee9415..75f19f77b 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -142,7 +142,6 @@ struct AbcModuleState { const AbcConfig &config; int map_autoidx = 0; - SigMap assign_map; std::vector signal_list; dict signal_map; FfInitVals initvals; @@ -162,19 +161,19 @@ struct AbcModuleState { AbcModuleState(const AbcConfig &config) : config(config) {} - int map_signal(RTLIL::SigBit bit, gate_type_t gate_type = G(NONE), int in1 = -1, int in2 = -1, int in3 = -1, int in4 = -1); - void mark_port(RTLIL::SigSpec sig); - void extract_cell(RTLIL::Module *module, RTLIL::Cell *cell, bool keepff); + int map_signal(const SigMap &assign_map, RTLIL::SigBit bit, gate_type_t gate_type = G(NONE), int in1 = -1, int in2 = -1, int in3 = -1, int in4 = -1); + void mark_port(const SigMap &assign_map, RTLIL::SigSpec sig); + void extract_cell(const SigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell, bool keepff); std::string remap_name(RTLIL::IdString abc_name, RTLIL::Wire **orig_wire = nullptr); void dump_loop_graph(FILE *f, int &nr, dict> &edges, pool &workpool, std::vector &in_counts); - void handle_loops(RTLIL::Module *module); - void abc_module(RTLIL::Design *design, RTLIL::Module *module, const std::vector &cells, + void handle_loops(SigMap &assign_map, RTLIL::Module *module); + void abc_module(RTLIL::Design *design, RTLIL::Module *module, SigMap &assign_map, const std::vector &cells, bool dff_mode, std::string clk_str); - void extract(RTLIL::Design *design, RTLIL::Module *module); + void extract(SigMap &assign_map, RTLIL::Design *design, RTLIL::Module *module); void finish(); }; -int AbcModuleState::map_signal(RTLIL::SigBit bit, gate_type_t gate_type, int in1, int in2, int in3, int in4) +int AbcModuleState::map_signal(const SigMap &assign_map, RTLIL::SigBit bit, gate_type_t gate_type, int in1, int in2, int in3, int in4) { assign_map.apply(bit); @@ -212,14 +211,14 @@ int AbcModuleState::map_signal(RTLIL::SigBit bit, gate_type_t gate_type, int in1 return gate.id; } -void AbcModuleState::mark_port(RTLIL::SigSpec sig) +void AbcModuleState::mark_port(const SigMap &assign_map, RTLIL::SigSpec sig) { for (auto &bit : assign_map(sig)) if (bit.wire != nullptr && signal_map.count(bit) > 0) signal_list[signal_map[bit]].is_port = true; } -void AbcModuleState::extract_cell(RTLIL::Module *module, RTLIL::Cell *cell, bool keepff) +void AbcModuleState::extract_cell(const SigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell, bool keepff) { if (RTLIL::builtin_ff_cell_types().count(cell->type)) { FfData ff(&initvals, cell); @@ -291,7 +290,7 @@ void AbcModuleState::extract_cell(RTLIL::Module *module, RTLIL::Cell *cell, bool return; } - int gate_id = map_signal(ff.sig_q, type, map_signal(ff.sig_d)); + int gate_id = map_signal(assign_map, ff.sig_q, type, map_signal(assign_map, ff.sig_d)); if (keepff) { SigBit bit = ff.sig_q; if (assign_map(bit).wire != nullptr) { @@ -301,6 +300,8 @@ void AbcModuleState::extract_cell(RTLIL::Module *module, RTLIL::Cell *cell, bool bit.wire->attributes[ID::keep] = 1; } + map_signal(assign_map, ff.sig_q, type, map_signal(assign_map, ff.sig_d)); + ff.remove(); return; } @@ -313,7 +314,7 @@ void AbcModuleState::extract_cell(RTLIL::Module *module, RTLIL::Cell *cell, bool assign_map.apply(sig_a); assign_map.apply(sig_y); - map_signal(sig_y, cell->type == ID($_BUF_) ? G(BUF) : G(NOT), map_signal(sig_a)); + map_signal(assign_map, sig_y, cell->type == ID($_BUF_) ? G(BUF) : G(NOT), map_signal(assign_map, sig_a)); module->remove(cell); return; @@ -329,25 +330,25 @@ void AbcModuleState::extract_cell(RTLIL::Module *module, RTLIL::Cell *cell, bool assign_map.apply(sig_b); assign_map.apply(sig_y); - int mapped_a = map_signal(sig_a); - int mapped_b = map_signal(sig_b); + int mapped_a = map_signal(assign_map, sig_a); + int mapped_b = map_signal(assign_map, sig_b); if (cell->type == ID($_AND_)) - map_signal(sig_y, G(AND), mapped_a, mapped_b); + map_signal(assign_map, sig_y, G(AND), mapped_a, mapped_b); else if (cell->type == ID($_NAND_)) - map_signal(sig_y, G(NAND), mapped_a, mapped_b); + map_signal(assign_map, sig_y, G(NAND), mapped_a, mapped_b); else if (cell->type == ID($_OR_)) - map_signal(sig_y, G(OR), mapped_a, mapped_b); + map_signal(assign_map, sig_y, G(OR), mapped_a, mapped_b); else if (cell->type == ID($_NOR_)) - map_signal(sig_y, G(NOR), mapped_a, mapped_b); + map_signal(assign_map, sig_y, G(NOR), mapped_a, mapped_b); else if (cell->type == ID($_XOR_)) - map_signal(sig_y, G(XOR), mapped_a, mapped_b); + map_signal(assign_map, sig_y, G(XOR), mapped_a, mapped_b); else if (cell->type == ID($_XNOR_)) - map_signal(sig_y, G(XNOR), mapped_a, mapped_b); + map_signal(assign_map, sig_y, G(XNOR), mapped_a, mapped_b); else if (cell->type == ID($_ANDNOT_)) - map_signal(sig_y, G(ANDNOT), mapped_a, mapped_b); + map_signal(assign_map, sig_y, G(ANDNOT), mapped_a, mapped_b); else if (cell->type == ID($_ORNOT_)) - map_signal(sig_y, G(ORNOT), mapped_a, mapped_b); + map_signal(assign_map, sig_y, G(ORNOT), mapped_a, mapped_b); else log_abort(); @@ -367,11 +368,11 @@ void AbcModuleState::extract_cell(RTLIL::Module *module, RTLIL::Cell *cell, bool assign_map.apply(sig_s); assign_map.apply(sig_y); - int mapped_a = map_signal(sig_a); - int mapped_b = map_signal(sig_b); - int mapped_s = map_signal(sig_s); + int mapped_a = map_signal(assign_map, sig_a); + int mapped_b = map_signal(assign_map, sig_b); + int mapped_s = map_signal(assign_map, sig_s); - map_signal(sig_y, cell->type == ID($_MUX_) ? G(MUX) : G(NMUX), mapped_a, mapped_b, mapped_s); + map_signal(assign_map, sig_y, cell->type == ID($_MUX_) ? G(MUX) : G(NMUX), mapped_a, mapped_b, mapped_s); module->remove(cell); return; @@ -389,11 +390,11 @@ void AbcModuleState::extract_cell(RTLIL::Module *module, RTLIL::Cell *cell, bool assign_map.apply(sig_c); assign_map.apply(sig_y); - int mapped_a = map_signal(sig_a); - int mapped_b = map_signal(sig_b); - int mapped_c = map_signal(sig_c); + int mapped_a = map_signal(assign_map, sig_a); + int mapped_b = map_signal(assign_map, sig_b); + int mapped_c = map_signal(assign_map, sig_c); - map_signal(sig_y, cell->type == ID($_AOI3_) ? G(AOI3) : G(OAI3), mapped_a, mapped_b, mapped_c); + map_signal(assign_map, sig_y, cell->type == ID($_AOI3_) ? G(AOI3) : G(OAI3), mapped_a, mapped_b, mapped_c); module->remove(cell); return; @@ -413,12 +414,12 @@ void AbcModuleState::extract_cell(RTLIL::Module *module, RTLIL::Cell *cell, bool assign_map.apply(sig_d); assign_map.apply(sig_y); - int mapped_a = map_signal(sig_a); - int mapped_b = map_signal(sig_b); - int mapped_c = map_signal(sig_c); - int mapped_d = map_signal(sig_d); + int mapped_a = map_signal(assign_map, sig_a); + int mapped_b = map_signal(assign_map, sig_b); + int mapped_c = map_signal(assign_map, sig_c); + int mapped_d = map_signal(assign_map, sig_d); - map_signal(sig_y, cell->type == ID($_AOI4_) ? G(AOI4) : G(OAI4), mapped_a, mapped_b, mapped_c, mapped_d); + map_signal(assign_map, sig_y, cell->type == ID($_AOI4_) ? G(AOI4) : G(OAI4), mapped_a, mapped_b, mapped_c, mapped_d); module->remove(cell); return; @@ -493,7 +494,13 @@ void AbcModuleState::dump_loop_graph(FILE *f, int &nr, dict> &edg fprintf(f, "}\n"); } -void AbcModuleState::handle_loops(RTLIL::Module *module) +void connect(SigMap &assign_map, RTLIL::Module *module, const RTLIL::SigSig &conn) +{ + module->connect(conn); + assign_map.add(conn.first, conn.second); +} + +void AbcModuleState::handle_loops(SigMap &assign_map, RTLIL::Module *module) { // http://en.wikipedia.org/wiki/Topological_sorting // (Kahn, Arthur B. (1962), "Topological sorting of large networks") @@ -598,7 +605,7 @@ void AbcModuleState::handle_loops(RTLIL::Module *module) first_line = false; } - int id3 = map_signal(RTLIL::SigSpec(wire)); + int id3 = map_signal(assign_map, RTLIL::SigSpec(wire)); signal_list[id1].is_port = true; signal_list[id3].is_port = true; log_assert(id3 == int(in_edges_count.size())); @@ -617,7 +624,7 @@ void AbcModuleState::handle_loops(RTLIL::Module *module) } edges[id1].swap(edges[id3]); - module->connect(RTLIL::SigSig(signal_list[id3].bit, signal_list[id1].bit)); + connect(assign_map, module, RTLIL::SigSig(signal_list[id3].bit, signal_list[id1].bit)); dump_loop_graph(dot_f, dot_nr, edges, workpool, in_edges_count); } } @@ -753,7 +760,7 @@ struct abc_output_filter } }; -void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *module, const std::vector &cells, +void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *module, SigMap &assign_map, const std::vector &cells, bool dff_mode, std::string clk_str) { initvals.set(&assign_map, module); @@ -939,33 +946,33 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *module, co had_init = false; for (auto c : cells) - extract_cell(module, c, config.keepff); + extract_cell(assign_map, module, c, config.keepff); if (undef_bits_lost) log("Replacing %d occurrences of constant undef bits with constant zero bits\n", undef_bits_lost); for (auto wire : module->wires()) { if (wire->port_id > 0 || wire->get_bool_attribute(ID::keep)) - mark_port(wire); + mark_port(assign_map, wire); } for (auto cell : module->cells()) for (auto &port_it : cell->connections()) - mark_port(port_it.second); + mark_port(assign_map, port_it.second); if (clk_sig.size() != 0) - mark_port(clk_sig); + mark_port(assign_map, clk_sig); if (en_sig.size() != 0) - mark_port(en_sig); + mark_port(assign_map, en_sig); if (arst_sig.size() != 0) - mark_port(arst_sig); + mark_port(assign_map, arst_sig); if (srst_sig.size() != 0) - mark_port(srst_sig); + mark_port(assign_map, srst_sig); - handle_loops(module); + handle_loops(assign_map, module); buffer = stringf("%s/input.blif", tempdir_name.c_str()); f = fopen(buffer.c_str(), "wt"); @@ -1208,7 +1215,7 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *module, co log("Don't call ABC as there is nothing to map.\n"); } -void AbcModuleState::extract(RTLIL::Design *design, RTLIL::Module *module) +void AbcModuleState::extract(SigMap &assign_map, RTLIL::Design *design, RTLIL::Module *module) { if (!did_run_abc) { return; @@ -1253,7 +1260,7 @@ void AbcModuleState::extract(RTLIL::Design *design, RTLIL::Module *module) RTLIL::IdString name_y = remap_name(c->getPort(ID::Y).as_wire()->name); conn.first = module->wire(name_y); conn.second = RTLIL::SigSpec(c->type == ID(ZERO) ? 0 : 1, 1); - module->connect(conn); + connect(assign_map, module, conn); continue; } if (c->type == ID(BUF)) { @@ -1262,7 +1269,7 @@ void AbcModuleState::extract(RTLIL::Design *design, RTLIL::Module *module) RTLIL::IdString name_a = remap_name(c->getPort(ID::A).as_wire()->name); conn.first = module->wire(name_y); conn.second = module->wire(name_a); - module->connect(conn); + connect(assign_map, module, conn); continue; } if (c->type == ID(NOT)) { @@ -1394,7 +1401,7 @@ void AbcModuleState::extract(RTLIL::Design *design, RTLIL::Module *module) RTLIL::SigSig conn; conn.first = module->wire(remap_name(c->connections().begin()->second.as_wire()->name)); conn.second = RTLIL::SigSpec(c->type == ID(_const0_) ? 0 : 1, 1); - module->connect(conn); + connect(assign_map, module, conn); continue; } @@ -1439,7 +1446,7 @@ void AbcModuleState::extract(RTLIL::Design *design, RTLIL::Module *module) if (c->type == ID($lut) && GetSize(c->getPort(ID::A)) == 1 && c->getParam(ID::LUT).as_int() == 2) { SigSpec my_a = module->wire(remap_name(c->getPort(ID::A).as_wire()->name)); SigSpec my_y = module->wire(remap_name(c->getPort(ID::Y).as_wire()->name)); - module->connect(my_y, my_a); + connect(assign_map, module, RTLIL::SigSig(my_a, my_y)); continue; } @@ -1464,7 +1471,7 @@ void AbcModuleState::extract(RTLIL::Design *design, RTLIL::Module *module) conn.first = module->wire(remap_name(conn.first.as_wire()->name)); if (!conn.second.is_fully_const()) conn.second = module->wire(remap_name(conn.second.as_wire()->name)); - module->connect(conn); + connect(assign_map, module, conn); } cell_stats.sort(); @@ -1485,7 +1492,7 @@ void AbcModuleState::extract(RTLIL::Design *design, RTLIL::Module *module) conn.second = si.bit; in_wires++; } - module->connect(conn); + connect(assign_map, module, conn); } log("ABC RESULTS: internal signals: %8d\n", int(signal_list.size()) - in_wires - out_wires); log("ABC RESULTS: input signals: %8d\n", in_wires); @@ -2079,6 +2086,9 @@ struct AbcPass : public Pass { for (auto mod : design->selected_modules()) { + SigMap assign_map; + assign_map.set(mod); + if (mod->processes.size() > 0) { log("Skipping module %s as it contains processes.\n", log_id(mod)); continue; @@ -2086,9 +2096,8 @@ struct AbcPass : public Pass { if (!dff_mode || !clk_str.empty()) { AbcModuleState state(config); - state.assign_map.set(mod); - state.abc_module(design, mod, mod->selected_cells(), dff_mode, clk_str); - state.extract(design, mod); + state.abc_module(design, mod, assign_map, mod->selected_cells(), dff_mode, clk_str); + state.extract(assign_map, design, mod); state.finish(); continue; } @@ -2109,8 +2118,6 @@ struct AbcPass : public Pass { dict> cell_to_bit, cell_to_bit_up, cell_to_bit_down; dict> bit_to_cell, bit_to_cell_up, bit_to_cell_down; - SigMap assign_map; - assign_map.set(mod); FfInitVals initvals; initvals.set(&assign_map, mod); for (auto cell : all_cells) @@ -2247,7 +2254,6 @@ struct AbcPass : public Pass { for (auto &it : assigned_cells) { AbcModuleState state(config); - state.assign_map.set(mod); state.clk_polarity = std::get<0>(it.first); state.clk_sig = assign_map(std::get<1>(it.first)); state.en_polarity = std::get<2>(it.first); @@ -2256,8 +2262,8 @@ struct AbcPass : public Pass { state.arst_sig = assign_map(std::get<5>(it.first)); state.srst_polarity = std::get<6>(it.first); state.srst_sig = assign_map(std::get<7>(it.first)); - state.abc_module(design, mod, it.second, !state.clk_sig.empty(), "$"); - state.extract(design, mod); + state.abc_module(design, mod, assign_map, it.second, !state.clk_sig.empty(), "$"); + state.extract(assign_map, design, mod); state.finish(); } } From 2654bd53553b3502cd65f5e0fb0a6566fe1584be Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Sun, 27 Jul 2025 23:44:41 +0000 Subject: [PATCH 17/47] Compute `is_port` in AbcPass without iterating through all cells and wires in the module every time we run ABC. This does not scale when we run ABC thousands of times in a single AbcPass. --- kernel/ffinit.h | 6 +- kernel/ffmerge.h | 2 +- kernel/hashlib.h | 3 +- kernel/sigtools.h | 172 +++++++++++++++++++++++++++++++++--------- passes/techmap/abc.cc | 172 +++++++++++++++++++++++++++++------------- 5 files changed, 264 insertions(+), 91 deletions(-) diff --git a/kernel/ffinit.h b/kernel/ffinit.h index 6d4c97ac3..66c13b68f 100644 --- a/kernel/ffinit.h +++ b/kernel/ffinit.h @@ -27,10 +27,10 @@ YOSYS_NAMESPACE_BEGIN struct FfInitVals { - const SigMap *sigmap; + const SigMapView *sigmap; dict> initbits; - void set(const SigMap *sigmap_, RTLIL::Module *module) + void set(const SigMapView *sigmap_, RTLIL::Module *module) { sigmap = sigmap_; initbits.clear(); @@ -126,7 +126,7 @@ struct FfInitVals initbits.clear(); } - FfInitVals (const SigMap *sigmap, RTLIL::Module *module) + FfInitVals (const SigMapView *sigmap, RTLIL::Module *module) { set(sigmap, module); } diff --git a/kernel/ffmerge.h b/kernel/ffmerge.h index 5428da324..028987503 100644 --- a/kernel/ffmerge.h +++ b/kernel/ffmerge.h @@ -58,7 +58,7 @@ YOSYS_NAMESPACE_BEGIN struct FfMergeHelper { - const SigMap *sigmap; + const SigMapView *sigmap; RTLIL::Module *module; FfInitVals *initvals; diff --git a/kernel/hashlib.h b/kernel/hashlib.h index 52ff96028..7a5650fa3 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -1353,7 +1353,8 @@ public: return p; } - // Merge sets if the given indices belong to different sets + // Merge sets if the given indices belong to different sets. + // Makes ifind(j) the root of the merged set. void imerge(int i, int j) { i = ifind(i); diff --git a/kernel/sigtools.h b/kernel/sigtools.h index 3b0d7b40d..7962eaa70 100644 --- a/kernel/sigtools.h +++ b/kernel/sigtools.h @@ -237,6 +237,42 @@ using sort_by_name_id_guard = typename std::enable_if class SigSet> : public SigSet::type>> {}; +struct SigMapView +{ + mfp database; + + // Modify bit to its representative + void apply(RTLIL::SigBit &bit) const + { + bit = database.find(bit); + } + + void apply(RTLIL::SigSpec &sig) const + { + for (auto &bit : sig) + apply(bit); + } + + RTLIL::SigBit operator()(RTLIL::SigBit bit) const + { + apply(bit); + return bit; + } + + RTLIL::SigSpec operator()(RTLIL::SigSpec sig) const + { + apply(sig); + return sig; + } + + RTLIL::SigSpec operator()(RTLIL::Wire *wire) const + { + SigSpec sig(wire); + apply(sig); + return sig; + } +}; + /** * SigMap wraps a union-find "database" * to map SigBits of a module to canonical representative SigBits. @@ -244,10 +280,8 @@ class SigSet> : public SigSet database; - SigMap(RTLIL::Module *module = NULL) { if (module != NULL) @@ -320,37 +354,6 @@ struct SigMap inline void add(Wire *wire) { return add(RTLIL::SigSpec(wire)); } - // Modify bit to its representative - void apply(RTLIL::SigBit &bit) const - { - bit = database.find(bit); - } - - void apply(RTLIL::SigSpec &sig) const - { - for (auto &bit : sig) - apply(bit); - } - - RTLIL::SigBit operator()(RTLIL::SigBit bit) const - { - apply(bit); - return bit; - } - - RTLIL::SigSpec operator()(RTLIL::SigSpec sig) const - { - apply(sig); - return sig; - } - - RTLIL::SigSpec operator()(RTLIL::Wire *wire) const - { - SigSpec sig(wire); - apply(sig); - return sig; - } - // All non-const bits RTLIL::SigSpec allbits() const { @@ -362,6 +365,107 @@ struct SigMap } }; +/** + * SiValgMap wraps a union-find "database" to map SigBits of a module to + * canonical representative SigBits plus some optional Val value associated with the bits. + * Val has a commutative, associative, idempotent operator|=, a default constructor + * which constructs an identity element, and a copy constructor. + * SigBits that are connected share a set in the underlying database; + * the associated value is the "sum" of all the values associated with the contributing bits. + * If any of the SigBits in a set are a constant, the canonical SigBit is a constant. + */ +template +struct SigValMap final : public SigMapView +{ + dict values; + + void swap(SigValMap &other) + { + database.swap(other.database); + values.swap(other.values); + } + + void clear() + { + database.clear(); + values.clear(); + } + + // Rebuild SigMap for all connections in module + void set(RTLIL::Module *module) + { + int bitcount = 0; + for (auto &it : module->connections()) + bitcount += it.first.size(); + + database.clear(); + values.clear(); + database.reserve(bitcount); + + for (auto &it : module->connections()) + add(it.first, it.second); + } + + // Add connections from "from" to "to", bit-by-bit. + void add(const RTLIL::SigSpec& from, const RTLIL::SigSpec& to) + { + log_assert(GetSize(from) == GetSize(to)); + + for (int i = 0; i < GetSize(from); i++) + { + int bfi = database.lookup(from[i]); + int bti = database.lookup(to[i]); + if (bfi == bti) { + continue; + } + + const RTLIL::SigBit &bf = database[bfi]; + const RTLIL::SigBit &bt = database[bti]; + if (bf.wire == nullptr) { + // bf is constant so make it the canonical representative. + database.imerge(bti, bfi); + merge_value(bt, bf); + } else { + // Make bt the canonical representative. + database.imerge(bfi, bti); + merge_value(bf, bt); + } + } + } + + void addVal(const RTLIL::SigBit &bit, const Val &val) + { + values[database.find(bit)] |= val; + } + + void addVal(const RTLIL::SigSpec &sig, const Val &val) + { + for (const auto &bit : sig) + addVal(bit, val); + } + + Val apply_and_get_value(RTLIL::SigBit &bit) const + { + bit = database.find(bit); + auto it = values.find(bit); + return it == values.end() ? Val() : it->second; + } + +private: + void merge_value(const RTLIL::SigBit &from, const RTLIL::SigBit &to) + { + auto it = values.find(from); + if (it == values.end()) { + return; + } + // values[to] could resize the underlying `entries` so + // finish using `it` first. + Val v = it->second; + values.erase(it); + values[to] |= v; + } +}; + YOSYS_NAMESPACE_END #endif /* SIGTOOLS_H */ diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index 75f19f77b..f3d53d042 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -138,6 +138,18 @@ struct AbcConfig bool abc_dress = false; }; +struct AbcSigVal { + bool is_port; + + AbcSigVal(bool is_port = false) : is_port(is_port) {} + AbcSigVal &operator|=(const AbcSigVal &other) { + is_port |= other.is_port; + return *this; + } +}; + +using AbcSigMap = SigValMap; + struct AbcModuleState { const AbcConfig &config; @@ -161,21 +173,21 @@ struct AbcModuleState { AbcModuleState(const AbcConfig &config) : config(config) {} - int map_signal(const SigMap &assign_map, RTLIL::SigBit bit, gate_type_t gate_type = G(NONE), int in1 = -1, int in2 = -1, int in3 = -1, int in4 = -1); - void mark_port(const SigMap &assign_map, RTLIL::SigSpec sig); - void extract_cell(const SigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell, bool keepff); + int map_signal(const AbcSigMap &assign_map, RTLIL::SigBit bit, gate_type_t gate_type = G(NONE), int in1 = -1, int in2 = -1, int in3 = -1, int in4 = -1); + void mark_port(const AbcSigMap &assign_map, RTLIL::SigSpec sig); + bool extract_cell(const AbcSigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell, bool keepff); std::string remap_name(RTLIL::IdString abc_name, RTLIL::Wire **orig_wire = nullptr); void dump_loop_graph(FILE *f, int &nr, dict> &edges, pool &workpool, std::vector &in_counts); - void handle_loops(SigMap &assign_map, RTLIL::Module *module); - void abc_module(RTLIL::Design *design, RTLIL::Module *module, SigMap &assign_map, const std::vector &cells, + void handle_loops(AbcSigMap &assign_map, RTLIL::Module *module); + void abc_module(RTLIL::Design *design, RTLIL::Module *module, AbcSigMap &assign_map, const std::vector &cells, bool dff_mode, std::string clk_str); - void extract(SigMap &assign_map, RTLIL::Design *design, RTLIL::Module *module); + void extract(AbcSigMap &assign_map, RTLIL::Design *design, RTLIL::Module *module); void finish(); }; -int AbcModuleState::map_signal(const SigMap &assign_map, RTLIL::SigBit bit, gate_type_t gate_type, int in1, int in2, int in3, int in4) +int AbcModuleState::map_signal(const AbcSigMap &assign_map, RTLIL::SigBit bit, gate_type_t gate_type, int in1, int in2, int in3, int in4) { - assign_map.apply(bit); + AbcSigVal val = assign_map.apply_and_get_value(bit); if (bit == State::Sx) undef_bits_lost++; @@ -188,7 +200,7 @@ int AbcModuleState::map_signal(const SigMap &assign_map, RTLIL::SigBit bit, gate gate.in2 = -1; gate.in3 = -1; gate.in4 = -1; - gate.is_port = false; + gate.is_port = bit.wire != nullptr && val.is_port; gate.bit = bit; gate.init = initvals(bit); signal_list.push_back(gate); @@ -211,40 +223,40 @@ int AbcModuleState::map_signal(const SigMap &assign_map, RTLIL::SigBit bit, gate return gate.id; } -void AbcModuleState::mark_port(const SigMap &assign_map, RTLIL::SigSpec sig) +void AbcModuleState::mark_port(const AbcSigMap &assign_map, RTLIL::SigSpec sig) { for (auto &bit : assign_map(sig)) if (bit.wire != nullptr && signal_map.count(bit) > 0) signal_list[signal_map[bit]].is_port = true; } -void AbcModuleState::extract_cell(const SigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell, bool keepff) +bool AbcModuleState::extract_cell(const AbcSigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell, bool keepff) { if (RTLIL::builtin_ff_cell_types().count(cell->type)) { FfData ff(&initvals, cell); gate_type_t type = G(FF); if (!ff.has_clk) - return; + return false; if (ff.has_gclk) - return; + return false; if (ff.has_aload) - return; + return false; if (ff.has_sr) - return; + return false; if (!ff.is_fine) - return; + return false; if (clk_polarity != ff.pol_clk) - return; + return false; if (clk_sig != assign_map(ff.sig_clk)) - return; + return false; if (ff.has_ce) { if (en_polarity != ff.pol_ce) - return; + return false; if (en_sig != assign_map(ff.sig_ce)) - return; + return false; } else { if (GetSize(en_sig) != 0) - return; + return false; } if (ff.val_init == State::S1) { type = G(FF1); @@ -255,39 +267,39 @@ void AbcModuleState::extract_cell(const SigMap &assign_map, RTLIL::Module *modul } if (ff.has_arst) { if (arst_polarity != ff.pol_arst) - return; + return false; if (arst_sig != assign_map(ff.sig_arst)) - return; + return false; if (ff.val_arst == State::S1) { if (type == G(FF0)) - return; + return false; type = G(FF1); } else if (ff.val_arst == State::S0) { if (type == G(FF1)) - return; + return false; type = G(FF0); } } else { if (GetSize(arst_sig) != 0) - return; + return false; } if (ff.has_srst) { if (srst_polarity != ff.pol_srst) - return; + return false; if (srst_sig != assign_map(ff.sig_srst)) - return; + return false; if (ff.val_srst == State::S1) { if (type == G(FF0)) - return; + return false; type = G(FF1); } else if (ff.val_srst == State::S0) { if (type == G(FF1)) - return; + return false; type = G(FF0); } } else { if (GetSize(srst_sig) != 0) - return; + return false; } int gate_id = map_signal(assign_map, ff.sig_q, type, map_signal(assign_map, ff.sig_d)); @@ -303,7 +315,7 @@ void AbcModuleState::extract_cell(const SigMap &assign_map, RTLIL::Module *modul map_signal(assign_map, ff.sig_q, type, map_signal(assign_map, ff.sig_d)); ff.remove(); - return; + return true; } if (cell->type.in(ID($_BUF_), ID($_NOT_))) @@ -317,7 +329,7 @@ void AbcModuleState::extract_cell(const SigMap &assign_map, RTLIL::Module *modul map_signal(assign_map, sig_y, cell->type == ID($_BUF_) ? G(BUF) : G(NOT), map_signal(assign_map, sig_a)); module->remove(cell); - return; + return true; } if (cell->type.in(ID($_AND_), ID($_NAND_), ID($_OR_), ID($_NOR_), ID($_XOR_), ID($_XNOR_), ID($_ANDNOT_), ID($_ORNOT_))) @@ -353,7 +365,7 @@ void AbcModuleState::extract_cell(const SigMap &assign_map, RTLIL::Module *modul log_abort(); module->remove(cell); - return; + return true; } if (cell->type.in(ID($_MUX_), ID($_NMUX_))) @@ -375,7 +387,7 @@ void AbcModuleState::extract_cell(const SigMap &assign_map, RTLIL::Module *modul map_signal(assign_map, sig_y, cell->type == ID($_MUX_) ? G(MUX) : G(NMUX), mapped_a, mapped_b, mapped_s); module->remove(cell); - return; + return true; } if (cell->type.in(ID($_AOI3_), ID($_OAI3_))) @@ -397,7 +409,7 @@ void AbcModuleState::extract_cell(const SigMap &assign_map, RTLIL::Module *modul map_signal(assign_map, sig_y, cell->type == ID($_AOI3_) ? G(AOI3) : G(OAI3), mapped_a, mapped_b, mapped_c); module->remove(cell); - return; + return true; } if (cell->type.in(ID($_AOI4_), ID($_OAI4_))) @@ -422,8 +434,10 @@ void AbcModuleState::extract_cell(const SigMap &assign_map, RTLIL::Module *modul map_signal(assign_map, sig_y, cell->type == ID($_AOI4_) ? G(AOI4) : G(OAI4), mapped_a, mapped_b, mapped_c, mapped_d); module->remove(cell); - return; + return true; } + + return false; } std::string AbcModuleState::remap_name(RTLIL::IdString abc_name, RTLIL::Wire **orig_wire) @@ -494,13 +508,13 @@ void AbcModuleState::dump_loop_graph(FILE *f, int &nr, dict> &edg fprintf(f, "}\n"); } -void connect(SigMap &assign_map, RTLIL::Module *module, const RTLIL::SigSig &conn) +void connect(AbcSigMap &assign_map, RTLIL::Module *module, const RTLIL::SigSig &conn) { module->connect(conn); assign_map.add(conn.first, conn.second); } -void AbcModuleState::handle_loops(SigMap &assign_map, RTLIL::Module *module) +void AbcModuleState::handle_loops(AbcSigMap &assign_map, RTLIL::Module *module) { // http://en.wikipedia.org/wiki/Topological_sorting // (Kahn, Arthur B. (1962), "Topological sorting of large networks") @@ -760,7 +774,7 @@ struct abc_output_filter } }; -void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *module, SigMap &assign_map, const std::vector &cells, +void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *module, AbcSigMap &assign_map, const std::vector &cells, bool dff_mode, std::string clk_str) { initvals.set(&assign_map, module); @@ -945,18 +959,18 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *module, Si undef_bits_lost = 0; had_init = false; + std::vector kept_cells; for (auto c : cells) - extract_cell(assign_map, module, c, config.keepff); + if (!extract_cell(assign_map, module, c, config.keepff)) + kept_cells.push_back(c); if (undef_bits_lost) log("Replacing %d occurrences of constant undef bits with constant zero bits\n", undef_bits_lost); - for (auto wire : module->wires()) { - if (wire->port_id > 0 || wire->get_bool_attribute(ID::keep)) - mark_port(assign_map, wire); - } - - for (auto cell : module->cells()) + // Wires with port_id > 0, ID::keep, and connections to cells outside our cell set have already + // been accounted for via AbcSigVal::is_port. Now we just need to account for + // connections to cells inside our cell set that weren't removed by extract_cell(). + for (auto cell : kept_cells) for (auto &port_it : cell->connections()) mark_port(assign_map, port_it.second); @@ -1215,7 +1229,7 @@ void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *module, Si log("Don't call ABC as there is nothing to map.\n"); } -void AbcModuleState::extract(SigMap &assign_map, RTLIL::Design *design, RTLIL::Module *module) +void AbcModuleState::extract(AbcSigMap &assign_map, RTLIL::Design *design, RTLIL::Module *module) { if (!did_run_abc) { return; @@ -1512,6 +1526,47 @@ void AbcModuleState::finish() log_pop(); } +// For every signal that connects cells from different sets, or a cell in a set to a cell not in any set, +// mark it as a port in `assign_map`. +void assign_cell_connection_ports(RTLIL::Module *module, const std::vector *> &cell_sets, + AbcSigMap &assign_map) +{ + pool cells_in_no_set; + for (RTLIL::Cell *cell : module->cells()) { + cells_in_no_set.insert(cell); + } + // For every canonical signal in `assign_map`, the index of the set it is connected to, + // or -1 if it connects a cell in one set to a cell in another set or not in any set. + dict signal_cell_set; + for (int i = 0; i < int(cell_sets.size()); ++i) { + for (RTLIL::Cell *cell : *cell_sets[i]) { + cells_in_no_set.erase(cell); + for (auto &port_it : cell->connections()) { + for (SigBit bit : port_it.second) { + assign_map.apply(bit); + auto it = signal_cell_set.find(bit); + if (it == signal_cell_set.end()) + signal_cell_set[bit] = i; + else if (it->second >= 0 && it->second != i) { + it->second = -1; + assign_map.addVal(bit, AbcSigVal(true)); + } + } + } + } + } + for (RTLIL::Cell *cell : cells_in_no_set) { + for (auto &port_it : cell->connections()) { + for (SigBit bit : port_it.second) { + assign_map.apply(bit); + auto it = signal_cell_set.find(bit); + if (it != signal_cell_set.end() && it->second >= 0) + assign_map.addVal(bit, AbcSigVal(true)); + } + } + } +} + struct AbcPass : public Pass { AbcPass() : Pass("abc", "use ABC for technology mapping") { } void help() override @@ -2086,17 +2141,24 @@ struct AbcPass : public Pass { for (auto mod : design->selected_modules()) { - SigMap assign_map; - assign_map.set(mod); - if (mod->processes.size() > 0) { log("Skipping module %s as it contains processes.\n", log_id(mod)); continue; } + AbcSigMap assign_map; + assign_map.set(mod); + + for (auto wire : mod->wires()) + if (wire->port_id > 0 || wire->get_bool_attribute(ID::keep)) + assign_map.addVal(SigSpec(wire), AbcSigVal(true)); + if (!dff_mode || !clk_str.empty()) { + std::vector cells = mod->selected_cells(); + assign_cell_connection_ports(mod, {&cells}, assign_map); + AbcModuleState state(config); - state.abc_module(design, mod, assign_map, mod->selected_cells(), dff_mode, clk_str); + state.abc_module(design, mod, assign_map, cells, dff_mode, clk_str); state.extract(assign_map, design, mod); state.finish(); continue; @@ -2252,6 +2314,12 @@ struct AbcPass : public Pass { std::get<4>(it.first) ? "" : "!", log_signal(std::get<5>(it.first)), std::get<6>(it.first) ? "" : "!", log_signal(std::get<7>(it.first))); + { + std::vector*> cell_sets; + for (auto &it : assigned_cells) + cell_sets.push_back(&it.second); + assign_cell_connection_ports(mod, cell_sets, assign_map); + } for (auto &it : assigned_cells) { AbcModuleState state(config); state.clk_polarity = std::get<0>(it.first); From 62c441107dfdf7eac04ebbdc74d5693da69988a9 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 5 Aug 2025 22:21:30 +0000 Subject: [PATCH 18/47] Build FfInitVals for the entire module once and use it for every ABC run. --- passes/techmap/abc.cc | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index f3d53d042..9aaac84e9 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -156,7 +156,7 @@ struct AbcModuleState { int map_autoidx = 0; std::vector signal_list; dict signal_map; - FfInitVals initvals; + FfInitVals &initvals; bool had_init = false; bool did_run_abc = false; @@ -171,7 +171,8 @@ struct AbcModuleState { std::string tempdir_name; - AbcModuleState(const AbcConfig &config) : config(config) {} + AbcModuleState(const AbcConfig &config, FfInitVals &initvals) + : config(config), initvals(initvals) {} int map_signal(const AbcSigMap &assign_map, RTLIL::SigBit bit, gate_type_t gate_type = G(NONE), int in1 = -1, int in2 = -1, int in3 = -1, int in4 = -1); void mark_port(const AbcSigMap &assign_map, RTLIL::SigSpec sig); @@ -777,7 +778,6 @@ struct abc_output_filter void AbcModuleState::abc_module(RTLIL::Design *design, RTLIL::Module *module, AbcSigMap &assign_map, const std::vector &cells, bool dff_mode, std::string clk_str) { - initvals.set(&assign_map, module); map_autoidx = autoidx++; if (clk_str != "$") @@ -2148,6 +2148,11 @@ struct AbcPass : public Pass { AbcSigMap assign_map; assign_map.set(mod); + // Create an FfInitVals and use it for all ABC runs. FfInitVals only cares about + // wires with the ID::init attribute and we don't add or remove any such wires + // in this pass. + FfInitVals initvals; + initvals.set(&assign_map, mod); for (auto wire : mod->wires()) if (wire->port_id > 0 || wire->get_bool_attribute(ID::keep)) @@ -2157,7 +2162,7 @@ struct AbcPass : public Pass { std::vector cells = mod->selected_cells(); assign_cell_connection_ports(mod, {&cells}, assign_map); - AbcModuleState state(config); + AbcModuleState state(config, initvals); state.abc_module(design, mod, assign_map, cells, dff_mode, clk_str); state.extract(assign_map, design, mod); state.finish(); @@ -2180,8 +2185,6 @@ struct AbcPass : public Pass { dict> cell_to_bit, cell_to_bit_up, cell_to_bit_down; dict> bit_to_cell, bit_to_cell_up, bit_to_cell_down; - FfInitVals initvals; - initvals.set(&assign_map, mod); for (auto cell : all_cells) { clkdomain_t key; @@ -2321,7 +2324,7 @@ struct AbcPass : public Pass { assign_cell_connection_ports(mod, cell_sets, assign_map); } for (auto &it : assigned_cells) { - AbcModuleState state(config); + AbcModuleState state(config, initvals); state.clk_polarity = std::get<0>(it.first); state.clk_sig = assign_map(std::get<1>(it.first)); state.en_polarity = std::get<2>(it.first); From ec18d1aede7cfcc6415e19be635a86bc09c88c4f Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Fri, 15 Aug 2025 10:48:32 +1200 Subject: [PATCH 19/47] rename.cc: Fixup ports after -unescape --- passes/cmds/rename.cc | 2 ++ tests/various/rename_unescape.ys | 15 +++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/passes/cmds/rename.cc b/passes/cmds/rename.cc index 7e3f87147..167997dc0 100644 --- a/passes/cmds/rename.cc +++ b/passes/cmds/rename.cc @@ -598,6 +598,8 @@ struct RenamePass : public Pass { for (auto &it : new_cell_names) module->rename(it.first, it.second); + + module->fixup_ports(); } } else diff --git a/tests/various/rename_unescape.ys b/tests/various/rename_unescape.ys index 546d97357..2bb5286cc 100644 --- a/tests/various/rename_unescape.ys +++ b/tests/various/rename_unescape.ys @@ -39,3 +39,18 @@ select -assert-count 1 w:d__1 select -assert-count 1 w:_e select -assert-count 1 w:wire_ select -assert-count 1 w:$add$< Date: Wed, 13 Aug 2025 21:22:45 +0000 Subject: [PATCH 20/47] Make OptMuxtree int-indexed vectors into hashtables For one of our large circuits, this reduced the time for an OPT_MUXTREE pass from 169s to 5s. --- passes/opt/opt_muxtree.cc | 48 +++++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/passes/opt/opt_muxtree.cc b/passes/opt/opt_muxtree.cc index 100b1b495..e1ed5da08 100644 --- a/passes/opt/opt_muxtree.cc +++ b/passes/opt/opt_muxtree.cc @@ -23,6 +23,8 @@ #include "kernel/celltypes.h" #include #include +#include +#include #include USING_YOSYS_NAMESPACE @@ -291,14 +293,14 @@ struct OptMuxtreeWorker // database of known inactive signals // the payload is a reference counter used to manage the // list. when it is non-zero the signal in known to be inactive - vector known_inactive; + std::unordered_map known_inactive; // database of known active signals - vector known_active; + std::unordered_map known_active; // this is just used to keep track of visited muxes in order to prohibit // endless recursion in mux loops - vector visited_muxes; + std::unordered_set visited_muxes; }; void eval_mux_port(knowledge_t &knowledge, int mux_idx, int port_idx, bool do_replace_known, bool do_enable_ports, int abort_count) @@ -315,17 +317,18 @@ struct OptMuxtreeWorker if (i == port_idx) continue; if (muxinfo.ports[i].ctrl_sig >= 0) - knowledge.known_inactive.at(muxinfo.ports[i].ctrl_sig)++; + ++knowledge.known_inactive[muxinfo.ports[i].ctrl_sig]; } if (port_idx < GetSize(muxinfo.ports)-1 && !muxinfo.ports[port_idx].const_activated) - knowledge.known_active.at(muxinfo.ports[port_idx].ctrl_sig)++; + ++knowledge.known_active[muxinfo.ports[port_idx].ctrl_sig]; vector parent_muxes; for (int m : muxinfo.ports[port_idx].input_muxes) { - if (knowledge.visited_muxes[m]) + auto it = knowledge.visited_muxes.find(m); + if (it != knowledge.visited_muxes.end()) continue; - knowledge.visited_muxes[m] = true; + knowledge.visited_muxes.insert(it, m); parent_muxes.push_back(m); } for (int m : parent_muxes) { @@ -344,16 +347,24 @@ struct OptMuxtreeWorker return; } for (int m : parent_muxes) - knowledge.visited_muxes[m] = false; + knowledge.visited_muxes.erase(m); - if (port_idx < GetSize(muxinfo.ports)-1 && !muxinfo.ports[port_idx].const_activated) - knowledge.known_active.at(muxinfo.ports[port_idx].ctrl_sig)--; + if (port_idx < GetSize(muxinfo.ports)-1 && !muxinfo.ports[port_idx].const_activated) { + auto it = knowledge.known_active.find(muxinfo.ports[port_idx].ctrl_sig); + if (it != knowledge.known_active.end()) + if (--it->second == 0) + knowledge.known_active.erase(it); + } for (int i = 0; i < GetSize(muxinfo.ports); i++) { if (i == port_idx) continue; - if (muxinfo.ports[i].ctrl_sig >= 0) - knowledge.known_inactive.at(muxinfo.ports[i].ctrl_sig)--; + if (muxinfo.ports[i].ctrl_sig >= 0) { + auto it = knowledge.known_inactive.find(muxinfo.ports[i].ctrl_sig); + if (it != knowledge.known_inactive.end()) + if (--it->second == 0) + knowledge.known_inactive.erase(it); + } } } @@ -373,11 +384,11 @@ struct OptMuxtreeWorker vector bits = sig2bits(sig, false); for (int i = 0; i < GetSize(bits); i++) { if (bits[i] >= 0) { - if (knowledge.known_inactive.at(bits[i])) { + if (knowledge.known_inactive.count(bits[i]) > 0) { sig[i] = State::S0; did_something = true; } else - if (knowledge.known_active.at(bits[i])) { + if (knowledge.known_active.count(bits[i]) > 0) { sig[i] = State::S1; did_something = true; } @@ -435,7 +446,7 @@ struct OptMuxtreeWorker portinfo_t &portinfo = muxinfo.ports[port_idx]; if (portinfo.const_deactivated) continue; - if (knowledge.known_active.at(portinfo.ctrl_sig)) { + if (knowledge.known_active.count(portinfo.ctrl_sig) > 0) { eval_mux_port(knowledge, mux_idx, port_idx, do_replace_known, do_enable_ports, abort_count); return; } @@ -449,7 +460,7 @@ struct OptMuxtreeWorker if (portinfo.const_deactivated) continue; if (port_idx < GetSize(muxinfo.ports)-1) - if (knowledge.known_inactive.at(portinfo.ctrl_sig)) + if (knowledge.known_inactive.count(portinfo.ctrl_sig) > 0) continue; eval_mux_port(knowledge, mux_idx, port_idx, do_replace_known, do_enable_ports, abort_count); @@ -462,10 +473,7 @@ struct OptMuxtreeWorker { log_assert(glob_abort_cnt > 0); knowledge_t knowledge; - knowledge.known_inactive.resize(GetSize(bit2info)); - knowledge.known_active.resize(GetSize(bit2info)); - knowledge.visited_muxes.resize(GetSize(mux2info)); - knowledge.visited_muxes[mux_idx] = true; + knowledge.visited_muxes.insert(mux_idx); eval_mux(knowledge, mux_idx, true, root_enable_muxes.at(mux_idx), 3); } }; From bf625951d774d2747fa606f923ba5cf34b935a4a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 15 Aug 2025 00:26:03 +0000 Subject: [PATCH 21/47] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 8ec8715d3..ed9b10d79 100644 --- a/Makefile +++ b/Makefile @@ -159,7 +159,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.56+105 +YOSYS_VER := 0.56+110 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 6d62a1fff72c38c2c7b38b86c75d7b3043a27def Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Fri, 15 Aug 2025 05:43:53 +0000 Subject: [PATCH 22/47] Fix vararg alignment --- kernel/io.cc | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 78 insertions(+), 2 deletions(-) diff --git a/kernel/io.cc b/kernel/io.cc index 9811919ba..ef73a3b3d 100644 --- a/kernel/io.cc +++ b/kernel/io.cc @@ -412,6 +412,70 @@ static std::string string_view_stringf(std::string_view spec, ...) return result; } +static int spec_parameter_size(std::string_view spec) +{ + // Every valid spec starts with '%' which means the code below + // won't look before the spec start. + switch (spec[spec.size() - 1]) { + case 'd': + case 'i': + case 'o': + case 'u': + case 'x': + case 'X': + switch (spec[spec.size() - 2]) { + case 'h': + if (spec[spec.size() - 3] == 'h') + return sizeof(char); + return sizeof(short); + case 'l': + if (spec[spec.size() - 3] == 'l') + return sizeof(long long); + return sizeof(long); + case 'L': + case 'q': + return sizeof(long long); + case 'j': + return sizeof(intmax_t); + case 'z': + case 'Z': + return sizeof(size_t); + case 't': + return sizeof(ptrdiff_t); + } + return sizeof(int); + case 'e': + case 'E': + case 'f': + case 'F': + case 'g': + case 'G': + case 'a': + case 'A': + if (spec[spec.size() - 2] == 'L') + return sizeof(long double); + if (spec[spec.size() - 2] == 'l' && spec[spec.size() - 3] == 'l') + return sizeof(long double); + return sizeof(double); + case 'c': + if (spec[spec.size() - 2] == 'l') { + return sizeof(wchar_t); + } + return sizeof(unsigned char); + case 'C': + return sizeof(wchar_t); + case 's': + case 'p': + case 'S': + case 'n': + return sizeof(void *); + case 'm': + return sizeof(int); + default: + return -1; + } +} + template static void format_emit_stringf(std::string &result, std::string_view spec, int *dynamic_ints, DynamicIntCount num_dynamic_ints, Arg arg) @@ -439,7 +503,13 @@ void format_emit_long_long(std::string &result, std::string_view spec, int *dyna result += std::to_string(static_cast(arg)); return; } - format_emit_stringf(result, spec, dynamic_ints, num_dynamic_ints, arg); + if (spec_parameter_size(spec) <= 4) { + // On some platforms (Wasm) we must ensure that the arg is properly aligned + // after the dynamic `int` parameters. + format_emit_stringf(result, spec, dynamic_ints, num_dynamic_ints, (int)arg); + } else { + format_emit_stringf(result, spec, dynamic_ints, num_dynamic_ints, arg); + } } void format_emit_unsigned_long_long(std::string &result, std::string_view spec, int *dynamic_ints, @@ -454,7 +524,13 @@ void format_emit_unsigned_long_long(std::string &result, std::string_view spec, result += static_cast(arg); return; } - format_emit_stringf(result, spec, dynamic_ints, num_dynamic_ints, arg); + if (spec_parameter_size(spec) <= 4) { + // On some platforms (Wasm) we must ensure that the arg is properly aligned + // after the dynamic `int` parameters. + format_emit_stringf(result, spec, dynamic_ints, num_dynamic_ints, (unsigned int)arg); + } else { + format_emit_stringf(result, spec, dynamic_ints, num_dynamic_ints, arg); + } } void format_emit_double(std::string &result, std::string_view spec, int *dynamic_ints, From e906ea3f1ba4e9097bb763d188ba7e15399c7f6c Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Fri, 15 Aug 2025 23:58:58 +0000 Subject: [PATCH 23/47] Add tests for dynamic precision and with with an int parameter --- tests/unit/kernel/ioTest.cc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/unit/kernel/ioTest.cc b/tests/unit/kernel/ioTest.cc index 7cb8498cb..43a71eb79 100644 --- a/tests/unit/kernel/ioTest.cc +++ b/tests/unit/kernel/ioTest.cc @@ -69,4 +69,14 @@ TEST(KernelStringfTest, dynamicWidthAndPrecision) EXPECT_EQ(stringf("%*.*f", 8, 4, 1.0), " 1.0000"); } +TEST(KernelStringfTest, dynamicPrecisionInt) +{ + EXPECT_EQ(stringf("%.*d", 4, 7), "0007"); +} + +TEST(KernelStringfTest, dynamicWidthAndPrecisionInt) +{ + EXPECT_EQ(stringf("%*.*d", 8, 4, 7), " 0007"); +} + YOSYS_NAMESPACE_END From d10fdc0ec5ee17e5fb5d6e1f12c081fffc719750 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 16 Aug 2025 00:24:02 +0000 Subject: [PATCH 24/47] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index ed9b10d79..e83d32ac2 100644 --- a/Makefile +++ b/Makefile @@ -159,7 +159,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.56+110 +YOSYS_VER := 0.56+125 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 f5b219f59eb02fb0d8a4a9fad731cf0cc96368ab Mon Sep 17 00:00:00 2001 From: suisseWalter <42143099+suisseWalter@users.noreply.github.com> Date: Sat, 16 Aug 2025 08:36:06 +0200 Subject: [PATCH 25/47] Update passes/cmds/stat.cc Co-authored-by: KrystalDelusion <93062060+KrystalDelusion@users.noreply.github.com> --- 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 5cb223ba8..6d8d3105f 100644 --- a/passes/cmds/stat.cc +++ b/passes/cmds/stat.cc @@ -413,7 +413,7 @@ struct statdata_t { log(" %8s %8s \n", "|", "|"); } else if (print_global_only) { log(" %8s-%8s-%s\n", "+", "--------", "Count including submodules."); - log(" %8s %8s \n", "|", "|"); + log(" %8s \n", "|"); } else { log(" %8s-%8s-%s\n", "+", "--------", "Local Count, excluding submodules."); log(" %8s \n", "|"); From a6e0ab5ea5b6938f3ff67e5b36ecdf8797ce852c Mon Sep 17 00:00:00 2001 From: clemens Date: Sat, 16 Aug 2025 09:09:57 +0200 Subject: [PATCH 26/47] Update (sequential) area to be only local without -hierarchy --- passes/cmds/stat.cc | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc index 6d8d3105f..c41b8831f 100644 --- a/passes/cmds/stat.cc +++ b/passes/cmds/stat.cc @@ -461,8 +461,20 @@ struct statdata_t { if (area != 0) { log("\n"); - log(" Chip area for %smodule '%s': %f\n", (top_mod) ? "top " : "", mod_name.c_str(), area); - log(" of which used for sequential elements: %f (%.2f%%)\n", sequential_area, 100.0 * sequential_area / area); + if (print_hierarchical || print_global_only) { + log(" Chip area for %smodule '%s': %f\n", (top_mod) ? "top " : "", mod_name.c_str(), area); + log(" of which used for sequential elements: %f (%.2f%%)\n", sequential_area, 100.0 * sequential_area / area); + } else { + double local_area = 0; + for (auto &it : local_area_cells_by_type) + local_area += it.second; + double local_sequential_area = 0; + for (auto &it : local_seq_area_cells_by_type) + local_sequential_area += it.second; + log(" Chip area for %smodule '%s': %f\n", (top_mod) ? "top " : "", mod_name.c_str(), local_area); + log(" of which used for sequential elements: %f (%.2f%%)\n", local_sequential_area, + 100.0 * local_sequential_area / local_area); + } } if (tech == "xilinx") { @@ -666,9 +678,12 @@ statdata_t hierarchy_builder(const RTLIL::Design *design, const RTLIL::Module *t mod_data.submodule_area += mod_stat.at(cell->type).area; mod_data.num_submodules++; mod_data.unknown_cell_area.erase(cell->type); - mod_data.num_cells -= (mod_data.num_cells_by_type.count(cell->type) != 0)? mod_data.num_cells_by_type.at(cell->type): 0; + mod_data.num_cells -= + (mod_data.num_cells_by_type.count(cell->type) != 0) ? mod_data.num_cells_by_type.at(cell->type) : 0; mod_data.num_cells_by_type.erase(cell->type); - mod_data.local_num_cells -= (mod_data.local_num_cells_by_type.count(cell->type) != 0)? mod_data.local_num_cells_by_type.at(cell->type): 0; + mod_data.local_num_cells -= (mod_data.local_num_cells_by_type.count(cell->type) != 0) + ? mod_data.local_num_cells_by_type.at(cell->type) + : 0; mod_data.local_num_cells_by_type.erase(cell->type); mod_data.local_area_cells_by_type.erase(cell->type); } else { @@ -681,9 +696,12 @@ statdata_t hierarchy_builder(const RTLIL::Design *design, const RTLIL::Module *t double(design->module(cell->type)->attributes.at(ID::area).as_int()); mod_data.area += double(design->module(cell->type)->attributes.at(ID::area).as_int()); mod_data.unknown_cell_area.erase(cell->type); - mod_data.num_cells -= (mod_data.num_cells_by_type.count(cell->type) != 0)? mod_data.num_cells_by_type.at(cell->type): 0; + mod_data.num_cells -= + (mod_data.num_cells_by_type.count(cell->type) != 0) ? mod_data.num_cells_by_type.at(cell->type) : 0; mod_data.num_cells_by_type.erase(cell->type); - mod_data.local_num_cells -= (mod_data.local_num_cells_by_type.count(cell->type) != 0)? mod_data.local_num_cells_by_type.at(cell->type): 0; + mod_data.local_num_cells -= (mod_data.local_num_cells_by_type.count(cell->type) != 0) + ? mod_data.local_num_cells_by_type.at(cell->type) + : 0; mod_data.local_num_cells_by_type.erase(cell->type); mod_data.local_area_cells_by_type.erase(cell->type); } From d8fb4da437b9fc1b4e818f8bfac10ded3a1cee15 Mon Sep 17 00:00:00 2001 From: clemens Date: Sat, 16 Aug 2025 09:32:08 +0200 Subject: [PATCH 27/47] updated testcase --- tests/various/stat.ys | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/various/stat.ys b/tests/various/stat.ys index 50e1a35d8..1644f63e3 100644 --- a/tests/various/stat.ys +++ b/tests/various/stat.ys @@ -71,7 +71,7 @@ module \child end EOT logger -expect log "Chip area for top module '\\top': 112.492800" 1 -logger -expect log "of which used for sequential elements: 94.348800" 2 +logger -expect log "of which used for sequential elements: 94.348800" 1 logger -expect log "2 18.144 cells" 1 logger -expect log "4 112.493 cells" 1 logger -expect log "2 94.349 sg13g2_dfrbp_1" 1 From 5fc0e77c3d8d954594ef933d6270b5864f410661 Mon Sep 17 00:00:00 2001 From: clemens Date: Tue, 12 Aug 2025 08:56:05 +0200 Subject: [PATCH 28/47] add functionality to be able to use parameterised cells. cells can have their area as a function of the input port width. --- passes/cmds/stat.cc | 143 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 142 insertions(+), 1 deletion(-) diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc index c41b8831f..827ee0f05 100644 --- a/passes/cmds/stat.cc +++ b/passes/cmds/stat.cc @@ -34,6 +34,9 @@ PRIVATE_NAMESPACE_BEGIN struct cell_area_t { double area; bool is_sequential; + vector single_parameter_area; + vector> double_parameter_area; + vector parameter_names; }; struct statdata_t { @@ -206,6 +209,89 @@ struct statdata_t { } if (!cell_area.empty()) { + // check if cell_area provides a area calculator + if (cell_area.count(cell->type)) { + cell_area_t cell_data = cell_area.at(cell->type); + if (cell_data.single_parameter_area.size() > 0) { + // assume that we just take the max of the A,B,Y ports + + int width_a = cell->hasPort(ID::A) ? GetSize(cell->getPort(ID::A)) : 0; + int width_b = cell->hasPort(ID::B) ? GetSize(cell->getPort(ID::B)) : 0; + int width_y = cell->hasPort(ID::Y) ? GetSize(cell->getPort(ID::Y)) : 0; + int width_q = cell->hasPort(ID::Q) ? GetSize(cell->getPort(ID::Q)) : 0; + int max_width = max({width_a, width_b, width_y, width_q}); + if (!cell_area.count(cell_type)) { + cell_area[cell_type] = cell_data; + } + if (cell_data.single_parameter_area.size() > max_width - 1u) { + cell_area.at(cell_type).area = cell_data.single_parameter_area.at(max_width - 1); + cell_area.at(cell_type).is_sequential = cell_data.is_sequential; + + } else { + printf("too small single_parameter_area %s %d %f\n", cell_type.c_str(), max_width, + cell_data.single_parameter_area.back()); + cell_area.at(cell_type).area = cell_data.single_parameter_area.back(); + cell_area.at(cell_type).is_sequential = cell_data.is_sequential; + } + // printf("single_paramter_extraction %s %d %f\n", cell_type.c_str(), max_width, + // cell_area.at(cell_type).area); + } + vector widths; + if (cell_data.parameter_names.size() > 0) { + for (auto &it : cell_data.parameter_names) { + RTLIL::IdString port_name; + // TODO: there has to be a better way to do this + if (it == "A") { + port_name = ID::A; + } else if (it == "B") { + port_name = ID::B; + } else if (it == "Y") { + port_name = ID::Y; + } else if (it == "Q") { + port_name = ID::Q; + } else if (it == "S") { + port_name = ID::S; + } else { + port_name = ID(it); + } + if (cell->hasPort(port_name)) { + int width = GetSize(cell->getPort(port_name)); + widths.push_back(width); + } else { + widths.push_back(0); + } + } + } + + if (cell_data.double_parameter_area.size() > 0) { + if (!cell_area.count(cell_type)) { + cell_area[cell_type] = cell_data; + } + if (widths.size() == 2) { + unsigned int width_a = widths.at(0); + unsigned int width_b = widths.at(1); + if (width_a > 0 && width_b > 0) { + if (cell_data.double_parameter_area.size() > width_a - 1 && + cell_data.double_parameter_area.at(width_a - 1).size() > width_b - 1) { + cell_area.at(cell_type).area = + cell_data.double_parameter_area.at(width_a - 1).at(width_b - 1); + cell_area.at(cell_type).is_sequential = cell_data.is_sequential; + } else { + printf("too small double_parameter_area %s %d %d %f\n", cell_type.c_str(), + width_a, width_b, cell_data.double_parameter_area.back().back()); + cell_area.at(cell_type).area = cell_data.double_parameter_area.back().back(); + cell_area.at(cell_type).is_sequential = cell_data.is_sequential; + } + } else { + cell_area.at(cell_type).area = cell_data.area; + cell_area.at(cell_type).is_sequential = cell_data.is_sequential; + } + } else { + printf("double_paramter_extraction %s %zu %f\n", cell_type.c_str(), widths.size(), + cell_area.at(cell_type).area); + } + } + } if (cell_area.count(cell_type)) { cell_area_t cell_data = cell_area.at(cell_type); @@ -726,9 +812,64 @@ void read_liberty_cellarea(dict &cell_area, string libert const LibertyAst *ar = cell->find("area"); bool is_flip_flop = cell->find("ff") != nullptr; + vector single_parameter_area; + vector> double_parameter_area; + vector port_names; + const LibertyAst *sar = cell->find("single_area_parameterised"); + if (sar != nullptr) { + for (const auto &s : sar->args) { + double value = 0; + auto [ptr, ec] = std::from_chars(s.data(), s.data() + s.size(), value); + // ec != std::errc() means parse error, or ptr didn't consume entire string + if (ec != std::errc() || ptr != s.data() + s.size()) + break; + single_parameter_area.push_back(value); + } + if (single_parameter_area.size() == 0) + printf("error: %s\n", sar->args[single_parameter_area.size() - 1].c_str()); + // check if it is a double parameterised area + } + const LibertyAst *dar = cell->find("double_area_parameterised"); + if (dar != nullptr) { + for (const auto &s : dar->args) { + + // printf("value: %s\n",sar->value.c_str()); + // printf("args1: %s\n",dar->args[0].c_str()); + + vector sub_array; + std::string::size_type start = 0; + std::string::size_type end = s.find_first_of(",", start); + while (end != std::string::npos) { + sub_array.push_back(s.substr(start, end - start)); + start = end + 1; + end = s.find_first_of(",", start); + } + sub_array.push_back(s.substr(start, end)); + + vector cast_sub_array; + for (const auto &s : sub_array) { + double value = 0; + auto [ptr, ec] = std::from_chars(s.data() + 1, s.data() + s.size(), value); + if (ec != std::errc() || ptr != s.data() + s.size()) + break; + cast_sub_array.push_back(value); + } + double_parameter_area.push_back(cast_sub_array); + if (cast_sub_array.size() == 0) + printf("error: %s\n", s.c_str()); + } + } + const LibertyAst *par = cell->find("port_names"); + if (par != nullptr) { + for (const auto &s : par->args) { + port_names.push_back(s); + } + } + if (ar != nullptr && !ar->value.empty()) { string prefix = cell->args[0].substr(0, 1) == "$" ? "" : "\\"; - cell_area[prefix + cell->args[0]] = {atof(ar->value.c_str()), is_flip_flop}; + cell_area[prefix + cell->args[0]] = {atof(ar->value.c_str()), is_flip_flop, single_parameter_area, double_parameter_area, + port_names}; } } } From 50fe9dd7f26615c8e90d01bb443644096e9f6185 Mon Sep 17 00:00:00 2001 From: clemens Date: Tue, 12 Aug 2025 09:37:55 +0200 Subject: [PATCH 29/47] clean parsing code --- passes/cmds/stat.cc | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc index 827ee0f05..a036b1930 100644 --- a/passes/cmds/stat.cc +++ b/passes/cmds/stat.cc @@ -818,12 +818,12 @@ void read_liberty_cellarea(dict &cell_area, string libert const LibertyAst *sar = cell->find("single_area_parameterised"); if (sar != nullptr) { for (const auto &s : sar->args) { - double value = 0; - auto [ptr, ec] = std::from_chars(s.data(), s.data() + s.size(), value); - // ec != std::errc() means parse error, or ptr didn't consume entire string - if (ec != std::errc() || ptr != s.data() + s.size()) - break; - single_parameter_area.push_back(value); + try { + double value = std::stod(s); + single_parameter_area.push_back(value); + } catch (const std::exception &e) { + log_error("Failed to parse single parameter area value '%s': %s\n", s.c_str(), e.what()); + } } if (single_parameter_area.size() == 0) printf("error: %s\n", sar->args[single_parameter_area.size() - 1].c_str()); @@ -849,10 +849,12 @@ void read_liberty_cellarea(dict &cell_area, string libert vector cast_sub_array; for (const auto &s : sub_array) { double value = 0; - auto [ptr, ec] = std::from_chars(s.data() + 1, s.data() + s.size(), value); - if (ec != std::errc() || ptr != s.data() + s.size()) - break; - cast_sub_array.push_back(value); + try { + value = std::stod(s); + cast_sub_array.push_back(value); + } catch (const std::exception &e) { + log_error("Failed to parse double parameter area value '%s': %s\n", s.c_str(), e.what()); + } } double_parameter_area.push_back(cast_sub_array); if (cast_sub_array.size() == 0) From 8b1f77ebd297ab312af81be0661f44f09b0edb43 Mon Sep 17 00:00:00 2001 From: clemens Date: Wed, 13 Aug 2025 15:16:15 +0200 Subject: [PATCH 30/47] cleanup. printf to errors or warnings --- passes/cmds/stat.cc | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc index a036b1930..4d01b8535 100644 --- a/passes/cmds/stat.cc +++ b/passes/cmds/stat.cc @@ -228,19 +228,16 @@ struct statdata_t { cell_area.at(cell_type).is_sequential = cell_data.is_sequential; } else { - printf("too small single_parameter_area %s %d %f\n", cell_type.c_str(), max_width, - cell_data.single_parameter_area.back()); + log_warning("too small single_parameter_area %s width: %d size: %d\n", cell_type.c_str(), max_width, + (int)cell_data.single_parameter_area.size()); cell_area.at(cell_type).area = cell_data.single_parameter_area.back(); cell_area.at(cell_type).is_sequential = cell_data.is_sequential; } - // printf("single_paramter_extraction %s %d %f\n", cell_type.c_str(), max_width, - // cell_area.at(cell_type).area); } vector widths; if (cell_data.parameter_names.size() > 0) { for (auto &it : cell_data.parameter_names) { RTLIL::IdString port_name; - // TODO: there has to be a better way to do this if (it == "A") { port_name = ID::A; } else if (it == "B") { @@ -277,8 +274,9 @@ struct statdata_t { cell_data.double_parameter_area.at(width_a - 1).at(width_b - 1); cell_area.at(cell_type).is_sequential = cell_data.is_sequential; } else { - printf("too small double_parameter_area %s %d %d %f\n", cell_type.c_str(), - width_a, width_b, cell_data.double_parameter_area.back().back()); + log_warning("too small double_parameter_area %s, width_a: %d, width_b: %d, size_a: %d, size_b: %d\n", cell_type.c_str(), + (int)width_a, width_b, cell_data.double_parameter_area.size(), + (int)cell_data.double_parameter_area.at(width_a - 1).size()); cell_area.at(cell_type).area = cell_data.double_parameter_area.back().back(); cell_area.at(cell_type).is_sequential = cell_data.is_sequential; } @@ -287,8 +285,8 @@ struct statdata_t { cell_area.at(cell_type).is_sequential = cell_data.is_sequential; } } else { - printf("double_paramter_extraction %s %zu %f\n", cell_type.c_str(), widths.size(), - cell_area.at(cell_type).area); + log_error("double_parameter_area for %s has %d parameters, but only 2 are expected.\n", cell_type.c_str(), + (int)cell_data.double_parameter_area.size()); } } } @@ -826,15 +824,13 @@ void read_liberty_cellarea(dict &cell_area, string libert } } if (single_parameter_area.size() == 0) - printf("error: %s\n", sar->args[single_parameter_area.size() - 1].c_str()); + log_error("single parameter area has size 0: %s\n", sar->args[single_parameter_area.size() - 1].c_str()); // check if it is a double parameterised area } const LibertyAst *dar = cell->find("double_area_parameterised"); if (dar != nullptr) { for (const auto &s : dar->args) { - // printf("value: %s\n",sar->value.c_str()); - // printf("args1: %s\n",dar->args[0].c_str()); vector sub_array; std::string::size_type start = 0; @@ -858,7 +854,7 @@ void read_liberty_cellarea(dict &cell_area, string libert } double_parameter_area.push_back(cast_sub_array); if (cast_sub_array.size() == 0) - printf("error: %s\n", s.c_str()); + log_error("double paramter array has size 0: %s\n", s.c_str()); } } const LibertyAst *par = cell->find("port_names"); From 73d1177665815012981f439138f97937c4a90373 Mon Sep 17 00:00:00 2001 From: clemens Date: Thu, 14 Aug 2025 09:57:44 +0200 Subject: [PATCH 31/47] testcases one testcase for single parameter cells. one testcase for double parameter cells. --- tests/various/stat_area_by_width.lib | 42 +++++++++++++ tests/various/stat_high_level.ys | 92 ++++++++++++++++++++++++++++ tests/various/stat_high_level2.ys | 91 +++++++++++++++++++++++++++ 3 files changed, 225 insertions(+) create mode 100644 tests/various/stat_area_by_width.lib create mode 100644 tests/various/stat_high_level.ys create mode 100644 tests/various/stat_high_level2.ys diff --git a/tests/various/stat_area_by_width.lib b/tests/various/stat_area_by_width.lib new file mode 100644 index 000000000..73e266472 --- /dev/null +++ b/tests/various/stat_area_by_width.lib @@ -0,0 +1,42 @@ + +/************************************************************************ + + Copyright 2025 Clemens Walter, + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +************************************************************************/ +//Mock library for Yosys pre techmap +library (mock) { +cell ( "$reduce_xor" ) { + area : 3.0 ; + delay : 2.5 ; + single_area_parameterised ( 3.0, 5.5, 8.0, 10.5, 13.0, 15.5, 18.0, 20.5, 23.0, 25.5, 28.0, 30.5, 33.0, 35.5, 38.0, 40.5, 43.0, 45.5, 48.0, 50.5, 53.0, 55.5, 58.0, 60.5, 63.0, 65.5, 68.0, 70.5, 73.0, 75.5, 78.0, 80.5, 83.0, 85.5, 88.0, 90.5, 93.0, 95.5, 98.0, 100.5, 103.0, 105.5, 108.0, 110.5, 113.0, 115.5, 118.0, 120.5, ) ; + +} + +cell ( "$xor" ) { + area : 5.0 ; + delay : 2.0 ; + single_area_parameterised ( 5.0, 7.5, 10.0, 12.5, 15.0, 17.5, 20.0, 22.5, 25.0, 27.5, 30.0, 32.5, 35.0, 37.5, 40.0, 42.5, 45.0, 47.5, 50.0, 52.5, 55.0, ) ; + +} + +cell ( "$bmux" ) { + area : 3.0 ; + delay : 2.0 ; + port_names ( "Y", "S" ) ; + double_area_parameterised ( " 3.0, 6.0, 9.0, 12.0, 15.0, 18.0, 21.0, 24.0, 27.0, 30.0, 33.0, 36.0, 39.0, 42.0, 45.0, 48.0, 51.0, 54.0, 57.0, 60.0, 63.0, 66.0, 69.0, 72.0, 75.0, 78.0, 81.0, 84.0, 87.0, 90.0, 93.0, 96.0, 99.0, 102.0, 105.0, 108.0, 111.0, 114.0, 117.0, 120.0, 123.0, 126.0, 129.0, 132.0, 135.0, 138.0, 141.0, 144.0, 147.0, 150.0, 153.0, 156.0, 159.0, 162.0, 165.0, 168.0, 171.0, 174.0, 177.0, 180.0, 183.0, 186.0, 189.0, 192.0, 195.0, 198.0, 201.0, 204.0, 207.0, 210.0, 213.0, 216.0, 219.0, 222.0, 225.0, 228.0, 231.0, 234.0, 237.0, 240.0, 243.0, 246.0, 249.0, 252.0, 255.0, 258.0, 261.0, 264.0, 267.0, 270.0, 273.0, 276.0, 279.0, 282.0, 285.0, 288.0, 291.0, 294.0, 297.0, 300.0, 303.0, 306.0, 309.0, 312.0, 315.0, 318.0, 321.0, 324.0, 327.0, 330.0, 333.0, 336.0, 339.0, 342.0, 345.0, 348.0, 351.0, 354.0, 357.0, 360.0, 363.0, 366.0, 369.0, 372.0, 375.0, 378.0, 381.0, 384.0,", " 6.0, 12.0, 18.0, 24.0, 30.0, 36.0, 42.0, 48.0, 54.0, 60.0, 66.0, 72.0, 78.0, 84.0, 90.0, 96.0, 102.0, 108.0, 114.0, 120.0, 126.0, 132.0, 138.0, 144.0, 150.0, 156.0, 162.0, 168.0, 174.0, 180.0, 186.0, 192.0, 198.0, 204.0, 210.0, 216.0, 222.0, 228.0, 234.0, 240.0, 246.0, 252.0, 258.0, 264.0, 270.0, 276.0, 282.0, 288.0, 294.0, 300.0, 306.0, 312.0, 318.0, 324.0, 330.0, 336.0, 342.0, 348.0, 354.0, 360.0, 366.0, 372.0, 378.0, 384.0, 390.0, 396.0, 402.0, 408.0, 414.0, 420.0, 426.0, 432.0, 438.0, 444.0, 450.0, 456.0, 462.0, 468.0, 474.0, 480.0, 486.0, 492.0, 498.0, 504.0, 510.0, 516.0, 522.0, 528.0, 534.0, 540.0, 546.0, 552.0, 558.0, 564.0, 570.0, 576.0, 582.0, 588.0, 594.0, 600.0, 606.0, 612.0, 618.0, 624.0, 630.0, 636.0, 642.0, 648.0, 654.0, 660.0, 666.0, 672.0, 678.0, 684.0, 690.0, 696.0, 702.0, 708.0, 714.0, 720.0, 726.0, 732.0, 738.0, 744.0, 750.0, 756.0, 762.0, 768.0,", " 9.0, 18.0, 27.0, 36.0, 45.0, 54.0, 63.0, 72.0, 81.0, 90.0, 99.0, 108.0, 117.0, 126.0, 135.0, 144.0, 153.0, 162.0, 171.0, 180.0, 189.0, 198.0, 207.0, 216.0, 225.0, 234.0, 243.0, 252.0, 261.0, 270.0, 279.0, 288.0, 297.0, 306.0, 315.0, 324.0, 333.0, 342.0, 351.0, 360.0, 369.0, 378.0, 387.0, 396.0, 405.0, 414.0, 423.0, 432.0, 441.0, 450.0, 459.0, 468.0, 477.0, 486.0, 495.0, 504.0, 513.0, 522.0, 531.0, 540.0, 549.0, 558.0, 567.0, 576.0, 585.0, 594.0, 603.0, 612.0, 621.0, 630.0, 639.0, 648.0, 657.0, 666.0, 675.0, 684.0, 693.0, 702.0, 711.0, 720.0, 729.0, 738.0, 747.0, 756.0, 765.0, 774.0, 783.0, 792.0, 801.0, 810.0, 819.0, 828.0, 837.0, 846.0, 855.0, 864.0, 873.0, 882.0, 891.0, 900.0, 909.0, 918.0, 927.0, 936.0, 945.0, 954.0, 963.0, 972.0, 981.0, 990.0, 999.0, 1008.0, 1017.0, 1026.0, 1035.0, 1044.0, 1053.0, 1062.0, 1071.0, 1080.0, 1089.0, 1098.0, 1107.0, 1116.0, 1125.0, 1134.0, 1143.0, 1152.0,", " 12.0, 24.0, 36.0, 48.0, 60.0, 72.0, 84.0, 96.0, 108.0, 120.0, 132.0, 144.0, 156.0, 168.0, 180.0, 192.0, 204.0, 216.0, 228.0, 240.0, 252.0, 264.0, 276.0, 288.0, 300.0, 312.0, 324.0, 336.0, 348.0, 360.0, 372.0, 384.0, 396.0, 408.0, 420.0, 432.0, 444.0, 456.0, 468.0, 480.0, 492.0, 504.0, 516.0, 528.0, 540.0, 552.0, 564.0, 576.0, 588.0, 600.0, 612.0, 624.0, 636.0, 648.0, 660.0, 672.0, 684.0, 696.0, 708.0, 720.0, 732.0, 744.0, 756.0, 768.0, 780.0, 792.0, 804.0, 816.0, 828.0, 840.0, 852.0, 864.0, 876.0, 888.0, 900.0, 912.0, 924.0, 936.0, 948.0, 960.0, 972.0, 984.0, 996.0, 1008.0, 1020.0, 1032.0, 1044.0, 1056.0, 1068.0, 1080.0, 1092.0, 1104.0, 1116.0, 1128.0, 1140.0, 1152.0, 1164.0, 1176.0, 1188.0, 1200.0, 1212.0, 1224.0, 1236.0, 1248.0, 1260.0, 1272.0, 1284.0, 1296.0, 1308.0, 1320.0, 1332.0, 1344.0, 1356.0, 1368.0, 1380.0, 1392.0, 1404.0, 1416.0, 1428.0, 1440.0, 1452.0, 1464.0, 1476.0, 1488.0, 1500.0, 1512.0, 1524.0, 1536.0,", " 15.0, 30.0, 45.0, 60.0, 75.0, 90.0, 105.0, 120.0, 135.0, 150.0, 165.0, 180.0, 195.0, 210.0, 225.0, 240.0, 255.0, 270.0, 285.0, 300.0, 315.0, 330.0, 345.0, 360.0, 375.0, 390.0, 405.0, 420.0, 435.0, 450.0, 465.0, 480.0, 495.0, 510.0, 525.0, 540.0, 555.0, 570.0, 585.0, 600.0, 615.0, 630.0, 645.0, 660.0, 675.0, 690.0, 705.0, 720.0, 735.0, 750.0, 765.0, 780.0, 795.0, 810.0, 825.0, 840.0, 855.0, 870.0, 885.0, 900.0, 915.0, 930.0, 945.0, 960.0, 975.0, 990.0, 1005.0, 1020.0, 1035.0, 1050.0, 1065.0, 1080.0, 1095.0, 1110.0, 1125.0, 1140.0, 1155.0, 1170.0, 1185.0, 1200.0, 1215.0, 1230.0, 1245.0, 1260.0, 1275.0, 1290.0, 1305.0, 1320.0, 1335.0, 1350.0, 1365.0, 1380.0, 1395.0, 1410.0, 1425.0, 1440.0, 1455.0, 1470.0, 1485.0, 1500.0, 1515.0, 1530.0, 1545.0, 1560.0, 1575.0, 1590.0, 1605.0, 1620.0, 1635.0, 1650.0, 1665.0, 1680.0, 1695.0, 1710.0, 1725.0, 1740.0, 1755.0, 1770.0, 1785.0, 1800.0, 1815.0, 1830.0, 1845.0, 1860.0, 1875.0, 1890.0, 1905.0, 1920.0,", " 18.0, 36.0, 54.0, 72.0, 90.0, 108.0, 126.0, 144.0, 162.0, 180.0, 198.0, 216.0, 234.0, 252.0, 270.0, 288.0, 306.0, 324.0, 342.0, 360.0, 378.0, 396.0, 414.0, 432.0, 450.0, 468.0, 486.0, 504.0, 522.0, 540.0, 558.0, 576.0, 594.0, 612.0, 630.0, 648.0, 666.0, 684.0, 702.0, 720.0, 738.0, 756.0, 774.0, 792.0, 810.0, 828.0, 846.0, 864.0, 882.0, 900.0, 918.0, 936.0, 954.0, 972.0, 990.0, 1008.0, 1026.0, 1044.0, 1062.0, 1080.0, 1098.0, 1116.0, 1134.0, 1152.0, 1170.0, 1188.0, 1206.0, 1224.0, 1242.0, 1260.0, 1278.0, 1296.0, 1314.0, 1332.0, 1350.0, 1368.0, 1386.0, 1404.0, 1422.0, 1440.0, 1458.0, 1476.0, 1494.0, 1512.0, 1530.0, 1548.0, 1566.0, 1584.0, 1602.0, 1620.0, 1638.0, 1656.0, 1674.0, 1692.0, 1710.0, 1728.0, 1746.0, 1764.0, 1782.0, 1800.0, 1818.0, 1836.0, 1854.0, 1872.0, 1890.0, 1908.0, 1926.0, 1944.0, 1962.0, 1980.0, 1998.0, 2016.0, 2034.0, 2052.0, 2070.0, 2088.0, 2106.0, 2124.0, 2142.0, 2160.0, 2178.0, 2196.0, 2214.0, 2232.0, 2250.0, 2268.0, 2286.0, 2304.0,", " 21.0, 42.0, 63.0, 84.0, 105.0, 126.0, 147.0, 168.0, 189.0, 210.0, 231.0, 252.0, 273.0, 294.0, 315.0, 336.0, 357.0, 378.0, 399.0, 420.0, 441.0, 462.0, 483.0, 504.0, 525.0, 546.0, 567.0, 588.0, 609.0, 630.0, 651.0, 672.0, 693.0, 714.0, 735.0, 756.0, 777.0, 798.0, 819.0, 840.0, 861.0, 882.0, 903.0, 924.0, 945.0, 966.0, 987.0, 1008.0, 1029.0, 1050.0, 1071.0, 1092.0, 1113.0, 1134.0, 1155.0, 1176.0, 1197.0, 1218.0, 1239.0, 1260.0, 1281.0, 1302.0, 1323.0, 1344.0, 1365.0, 1386.0, 1407.0, 1428.0, 1449.0, 1470.0, 1491.0, 1512.0, 1533.0, 1554.0, 1575.0, 1596.0, 1617.0, 1638.0, 1659.0, 1680.0, 1701.0, 1722.0, 1743.0, 1764.0, 1785.0, 1806.0, 1827.0, 1848.0, 1869.0, 1890.0, 1911.0, 1932.0, 1953.0, 1974.0, 1995.0, 2016.0, 2037.0, 2058.0, 2079.0, 2100.0, 2121.0, 2142.0, 2163.0, 2184.0, 2205.0, 2226.0, 2247.0, 2268.0, 2289.0, 2310.0, 2331.0, 2352.0, 2373.0, 2394.0, 2415.0, 2436.0, 2457.0, 2478.0, 2499.0, 2520.0, 2541.0, 2562.0, 2583.0, 2604.0, 2625.0, 2646.0, 2667.0, 2688.0,", " 24.0, 48.0, 72.0, 96.0, 120.0, 144.0, 168.0, 192.0, 216.0, 240.0, 264.0, 288.0, 312.0, 336.0, 360.0, 384.0, 408.0, 432.0, 456.0, 480.0, 504.0, 528.0, 552.0, 576.0, 600.0, 624.0, 648.0, 672.0, 696.0, 720.0, 744.0, 768.0, 792.0, 816.0, 840.0, 864.0, 888.0, 912.0, 936.0, 960.0, 984.0, 1008.0, 1032.0, 1056.0, 1080.0, 1104.0, 1128.0, 1152.0, 1176.0, 1200.0, 1224.0, 1248.0, 1272.0, 1296.0, 1320.0, 1344.0, 1368.0, 1392.0, 1416.0, 1440.0, 1464.0, 1488.0, 1512.0, 1536.0, 1560.0, 1584.0, 1608.0, 1632.0, 1656.0, 1680.0, 1704.0, 1728.0, 1752.0, 1776.0, 1800.0, 1824.0, 1848.0, 1872.0, 1896.0, 1920.0, 1944.0, 1968.0, 1992.0, 2016.0, 2040.0, 2064.0, 2088.0, 2112.0, 2136.0, 2160.0, 2184.0, 2208.0, 2232.0, 2256.0, 2280.0, 2304.0, 2328.0, 2352.0, 2376.0, 2400.0, 2424.0, 2448.0, 2472.0, 2496.0, 2520.0, 2544.0, 2568.0, 2592.0, 2616.0, 2640.0, 2664.0, 2688.0, 2712.0, 2736.0, 2760.0, 2784.0, 2808.0, 2832.0, 2856.0, 2880.0, 2904.0, 2928.0, 2952.0, 2976.0, 3000.0, 3024.0, 3048.0, 3072.0,", " 27.0, 54.0, 81.0, 108.0, 135.0, 162.0, 189.0, 216.0, 243.0, 270.0, 297.0, 324.0, 351.0, 378.0, 405.0, 432.0, 459.0, 486.0, 513.0, 540.0, 567.0, 594.0, 621.0, 648.0, 675.0, 702.0, 729.0, 756.0, 783.0, 810.0, 837.0, 864.0, 891.0, 918.0, 945.0, 972.0, 999.0, 1026.0, 1053.0, 1080.0, 1107.0, 1134.0, 1161.0, 1188.0, 1215.0, 1242.0, 1269.0, 1296.0, 1323.0, 1350.0, 1377.0, 1404.0, 1431.0, 1458.0, 1485.0, 1512.0, 1539.0, 1566.0, 1593.0, 1620.0, 1647.0, 1674.0, 1701.0, 1728.0, 1755.0, 1782.0, 1809.0, 1836.0, 1863.0, 1890.0, 1917.0, 1944.0, 1971.0, 1998.0, 2025.0, 2052.0, 2079.0, 2106.0, 2133.0, 2160.0, 2187.0, 2214.0, 2241.0, 2268.0, 2295.0, 2322.0, 2349.0, 2376.0, 2403.0, 2430.0, 2457.0, 2484.0, 2511.0, 2538.0, 2565.0, 2592.0, 2619.0, 2646.0, 2673.0, 2700.0, 2727.0, 2754.0, 2781.0, 2808.0, 2835.0, 2862.0, 2889.0, 2916.0, 2943.0, 2970.0, 2997.0, 3024.0, 3051.0, 3078.0, 3105.0, 3132.0, 3159.0, 3186.0, 3213.0, 3240.0, 3267.0, 3294.0, 3321.0, 3348.0, 3375.0, 3402.0, 3429.0, 3456.0,", " 30.0, 60.0, 90.0, 120.0, 150.0, 180.0, 210.0, 240.0, 270.0, 300.0, 330.0, 360.0, 390.0, 420.0, 450.0, 480.0, 510.0, 540.0, 570.0, 600.0, 630.0, 660.0, 690.0, 720.0, 750.0, 780.0, 810.0, 840.0, 870.0, 900.0, 930.0, 960.0, 990.0, 1020.0, 1050.0, 1080.0, 1110.0, 1140.0, 1170.0, 1200.0, 1230.0, 1260.0, 1290.0, 1320.0, 1350.0, 1380.0, 1410.0, 1440.0, 1470.0, 1500.0, 1530.0, 1560.0, 1590.0, 1620.0, 1650.0, 1680.0, 1710.0, 1740.0, 1770.0, 1800.0, 1830.0, 1860.0, 1890.0, 1920.0, 1950.0, 1980.0, 2010.0, 2040.0, 2070.0, 2100.0, 2130.0, 2160.0, 2190.0, 2220.0, 2250.0, 2280.0, 2310.0, 2340.0, 2370.0, 2400.0, 2430.0, 2460.0, 2490.0, 2520.0, 2550.0, 2580.0, 2610.0, 2640.0, 2670.0, 2700.0, 2730.0, 2760.0, 2790.0, 2820.0, 2850.0, 2880.0, 2910.0, 2940.0, 2970.0, 3000.0, 3030.0, 3060.0, 3090.0, 3120.0, 3150.0, 3180.0, 3210.0, 3240.0, 3270.0, 3300.0, 3330.0, 3360.0, 3390.0, 3420.0, 3450.0, 3480.0, 3510.0, 3540.0, 3570.0, 3600.0, 3630.0, 3660.0, 3690.0, 3720.0, 3750.0, 3780.0, 3810.0, 3840.0,", " 33.0, 66.0, 99.0, 132.0, 165.0, 198.0, 231.0, 264.0, 297.0, 330.0, 363.0, 396.0, 429.0, 462.0, 495.0, 528.0, 561.0, 594.0, 627.0, 660.0, 693.0, 726.0, 759.0, 792.0, 825.0, 858.0, 891.0, 924.0, 957.0, 990.0, 1023.0, 1056.0, 1089.0, 1122.0, 1155.0, 1188.0, 1221.0, 1254.0, 1287.0, 1320.0, 1353.0, 1386.0, 1419.0, 1452.0, 1485.0, 1518.0, 1551.0, 1584.0, 1617.0, 1650.0, 1683.0, 1716.0, 1749.0, 1782.0, 1815.0, 1848.0, 1881.0, 1914.0, 1947.0, 1980.0, 2013.0, 2046.0, 2079.0, 2112.0, 2145.0, 2178.0, 2211.0, 2244.0, 2277.0, 2310.0, 2343.0, 2376.0, 2409.0, 2442.0, 2475.0, 2508.0, 2541.0, 2574.0, 2607.0, 2640.0, 2673.0, 2706.0, 2739.0, 2772.0, 2805.0, 2838.0, 2871.0, 2904.0, 2937.0, 2970.0, 3003.0, 3036.0, 3069.0, 3102.0, 3135.0, 3168.0, 3201.0, 3234.0, 3267.0, 3300.0, 3333.0, 3366.0, 3399.0, 3432.0, 3465.0, 3498.0, 3531.0, 3564.0, 3597.0, 3630.0, 3663.0, 3696.0, 3729.0, 3762.0, 3795.0, 3828.0, 3861.0, 3894.0, 3927.0, 3960.0, 3993.0, 4026.0, 4059.0, 4092.0, 4125.0, 4158.0, 4191.0, 4224.0,", " 36.0, 72.0, 108.0, 144.0, 180.0, 216.0, 252.0, 288.0, 324.0, 360.0, 396.0, 432.0, 468.0, 504.0, 540.0, 576.0, 612.0, 648.0, 684.0, 720.0, 756.0, 792.0, 828.0, 864.0, 900.0, 936.0, 972.0, 1008.0, 1044.0, 1080.0, 1116.0, 1152.0, 1188.0, 1224.0, 1260.0, 1296.0, 1332.0, 1368.0, 1404.0, 1440.0, 1476.0, 1512.0, 1548.0, 1584.0, 1620.0, 1656.0, 1692.0, 1728.0, 1764.0, 1800.0, 1836.0, 1872.0, 1908.0, 1944.0, 1980.0, 2016.0, 2052.0, 2088.0, 2124.0, 2160.0, 2196.0, 2232.0, 2268.0, 2304.0, 2340.0, 2376.0, 2412.0, 2448.0, 2484.0, 2520.0, 2556.0, 2592.0, 2628.0, 2664.0, 2700.0, 2736.0, 2772.0, 2808.0, 2844.0, 2880.0, 2916.0, 2952.0, 2988.0, 3024.0, 3060.0, 3096.0, 3132.0, 3168.0, 3204.0, 3240.0, 3276.0, 3312.0, 3348.0, 3384.0, 3420.0, 3456.0, 3492.0, 3528.0, 3564.0, 3600.0, 3636.0, 3672.0, 3708.0, 3744.0, 3780.0, 3816.0, 3852.0, 3888.0, 3924.0, 3960.0, 3996.0, 4032.0, 4068.0, 4104.0, 4140.0, 4176.0, 4212.0, 4248.0, 4284.0, 4320.0, 4356.0, 4392.0, 4428.0, 4464.0, 4500.0, 4536.0, 4572.0, 4608.0,", " 39.0, 78.0, 117.0, 156.0, 195.0, 234.0, 273.0, 312.0, 351.0, 390.0, 429.0, 468.0, 507.0, 546.0, 585.0, 624.0, 663.0, 702.0, 741.0, 780.0, 819.0, 858.0, 897.0, 936.0, 975.0, 1014.0, 1053.0, 1092.0, 1131.0, 1170.0, 1209.0, 1248.0, 1287.0, 1326.0, 1365.0, 1404.0, 1443.0, 1482.0, 1521.0, 1560.0, 1599.0, 1638.0, 1677.0, 1716.0, 1755.0, 1794.0, 1833.0, 1872.0, 1911.0, 1950.0, 1989.0, 2028.0, 2067.0, 2106.0, 2145.0, 2184.0, 2223.0, 2262.0, 2301.0, 2340.0, 2379.0, 2418.0, 2457.0, 2496.0, 2535.0, 2574.0, 2613.0, 2652.0, 2691.0, 2730.0, 2769.0, 2808.0, 2847.0, 2886.0, 2925.0, 2964.0, 3003.0, 3042.0, 3081.0, 3120.0, 3159.0, 3198.0, 3237.0, 3276.0, 3315.0, 3354.0, 3393.0, 3432.0, 3471.0, 3510.0, 3549.0, 3588.0, 3627.0, 3666.0, 3705.0, 3744.0, 3783.0, 3822.0, 3861.0, 3900.0, 3939.0, 3978.0, 4017.0, 4056.0, 4095.0, 4134.0, 4173.0, 4212.0, 4251.0, 4290.0, 4329.0, 4368.0, 4407.0, 4446.0, 4485.0, 4524.0, 4563.0, 4602.0, 4641.0, 4680.0, 4719.0, 4758.0, 4797.0, 4836.0, 4875.0, 4914.0, 4953.0, 4992.0,", ) ; + +} +} \ No newline at end of file diff --git a/tests/various/stat_high_level.ys b/tests/various/stat_high_level.ys new file mode 100644 index 000000000..03e5e957e --- /dev/null +++ b/tests/various/stat_high_level.ys @@ -0,0 +1,92 @@ + +read_rtlil << EOT +module \top + wire input 1 \A + wire output 2 \Y + wire output 3 \N + + cell $and \sub1 + parameter \A_SIGNED 0 + parameter \A_WIDTH 1 + parameter \B_SIGNED 0 + parameter \B_WIDTH 1 + parameter \Y_WIDTH 1 + connect \A \A + connect \B 1'0 + connect \Y \Y + end + + cell \child \sequential + connect \A \A + connect \B 1'0 + connect \R 1'0 + connect \Y \Y + connect \N \N + end + + cell \child \sequential1 + connect \A \A + connect \B 1'0 + connect \R 1'0 + connect \Y \Y + connect \N \N + end + + cell $xor \sub2 + parameter \A_SIGNED 0 + parameter \A_WIDTH 1 + parameter \B_SIGNED 0 + parameter \B_WIDTH 1 + parameter \Y_WIDTH 1 + connect \A \A + connect \B 1'0 + connect \Y \Y + end +end + +module \child + wire input 1 \A + wire input 2 \B + wire input 3 \R + + wire output 4 \Y + wire output 5 \N + wire \Y1 + wire \Y2 + cell \sg13g2_dfrbp_1 \sequential_ff + connect \CLK \A + connect \D \Y2 + connect \Q \Y + connect \Q_N \N + connect \RESET_B \R + end + + cell $xor \sub2 + parameter \A_SIGNED 0 + parameter \A_WIDTH 1 + parameter \B_SIGNED 0 + parameter \B_WIDTH 1 + parameter \Y_WIDTH 1 + connect \A \B + connect \B 1'0 + connect \Y \Y1 + end + + cell $reduce_xor \sub3 + parameter \A_SIGNED 0 + parameter \A_WIDTH 10 + parameter \Y_WIDTH 1 + connect \A 10'0000000000 + connect \Y \Y2 + end + +end +EOT +logger -expect log "Chip area for top module '\\top': 66.000000" 1 +logger -expect log "3 30.5 3 30.5 cells" 1 +logger -expect log "2 51 - - \$reduce_xor" 2 +logger -expect log "8 66 2 5 cells" 2 +logger -expect-no-warnings +stat -liberty ./stat_area_by_width.lib -top \top -hierarchy + + diff --git a/tests/various/stat_high_level2.ys b/tests/various/stat_high_level2.ys new file mode 100644 index 000000000..63d59da95 --- /dev/null +++ b/tests/various/stat_high_level2.ys @@ -0,0 +1,91 @@ + +read_rtlil << EOT +module \top + wire input 1 \A + wire output 2 \Y + wire output 3 \N + + cell $and \sub1 + parameter \A_SIGNED 0 + parameter \A_WIDTH 1 + parameter \B_SIGNED 0 + parameter \B_WIDTH 1 + parameter \Y_WIDTH 1 + connect \A \A + connect \B 1'0 + connect \Y \Y + end + + cell \child \sequential + connect \A \A + connect \B 1'0 + connect \R 1'0 + connect \Y \Y + connect \N \N + end + + cell \child \sequential1 + connect \A \A + connect \B 1'0 + connect \R 1'0 + connect \Y \Y + connect \N \N + end + + cell $xor \sub2 + parameter \A_SIGNED 0 + parameter \A_WIDTH 1 + parameter \B_SIGNED 0 + parameter \B_WIDTH 1 + parameter \Y_WIDTH 1 + connect \A \A + connect \B 1'0 + connect \Y \Y + end +end + +module \child + wire input 1 \A + wire input 2 \B + wire input 3 \R + + wire output 4 \Y + wire output 5 \N + wire \Y1 + wire \Y2 + wire width 2 \A2 + cell \sg13g2_dfrbp_1 \sequential_ff + connect \CLK \A + connect \D \Y2 + connect \Q \Y + connect \Q_N \N + connect \RESET_B \R + end + + cell $bmux \bmux1 + parameter \WIDTH 2 + parameter \S_WIDTH 2 + connect \A 8'00000000 + connect \S 2'00 + connect \Y \A2 + end + + cell $reduce_xor \sub3 + parameter \A_SIGNED 0 + parameter \A_WIDTH 10 + parameter \Y_WIDTH 1 + connect \A 10'0000000000 + connect \Y \Y2 + end + +end +EOT + +logger -expect log "Chip area for top module '\\top': 80.000000" 1 +logger -expect log "1 12 1 12 \$bmux" 1 +logger -expect log "3 37.5 3 37.5 cells" 1 +logger -expect log "8 80 2 5 cells" 2 +logger -expect-no-warnings +stat -liberty ./stat_area_by_width.lib -top \top -hierarchy + + From 4e45b5e1bb26a7c742b7abab7c4f78d80be0c052 Mon Sep 17 00:00:00 2001 From: clemens Date: Thu, 14 Aug 2025 11:13:40 +0200 Subject: [PATCH 32/47] permit trailing comma --- passes/cmds/stat.cc | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/passes/cmds/stat.cc b/passes/cmds/stat.cc index 4d01b8535..07b1e5228 100644 --- a/passes/cmds/stat.cc +++ b/passes/cmds/stat.cc @@ -275,7 +275,7 @@ struct statdata_t { cell_area.at(cell_type).is_sequential = cell_data.is_sequential; } else { log_warning("too small double_parameter_area %s, width_a: %d, width_b: %d, size_a: %d, size_b: %d\n", cell_type.c_str(), - (int)width_a, width_b, cell_data.double_parameter_area.size(), + width_a, width_b, (int)cell_data.double_parameter_area.size(), (int)cell_data.double_parameter_area.at(width_a - 1).size()); cell_area.at(cell_type).area = cell_data.double_parameter_area.back().back(); cell_area.at(cell_type).is_sequential = cell_data.is_sequential; @@ -816,6 +816,10 @@ void read_liberty_cellarea(dict &cell_area, string libert const LibertyAst *sar = cell->find("single_area_parameterised"); if (sar != nullptr) { for (const auto &s : sar->args) { + if (s.empty()) { + //catches trailing commas + continue; + } try { double value = std::stod(s); single_parameter_area.push_back(value); @@ -845,11 +849,15 @@ void read_liberty_cellarea(dict &cell_area, string libert vector cast_sub_array; for (const auto &s : sub_array) { double value = 0; + if (s.empty()) { + //catches trailing commas + continue; + } try { value = std::stod(s); cast_sub_array.push_back(value); } catch (const std::exception &e) { - log_error("Failed to parse double parameter area value '%s': %s\n", s.c_str(), e.what()); + log_error("Failed to parse double parameter area value for '%s': %s\n", s.c_str(), e.what()); } } double_parameter_area.push_back(cast_sub_array); From 9278bed853e0e391d42a646bb1633da9ae5f7597 Mon Sep 17 00:00:00 2001 From: clemens Date: Thu, 14 Aug 2025 16:33:59 +0200 Subject: [PATCH 33/47] removed copyright notice on lib file. Should be covered by the yosys license not anything else. --- tests/various/stat_area_by_width.lib | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/tests/various/stat_area_by_width.lib b/tests/various/stat_area_by_width.lib index 73e266472..1e98aa488 100644 --- a/tests/various/stat_area_by_width.lib +++ b/tests/various/stat_area_by_width.lib @@ -1,22 +1,5 @@ -/************************************************************************ - - Copyright 2025 Clemens Walter, - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - https://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - -************************************************************************/ -//Mock library for Yosys pre techmap +//library for testcases, can also be used as a template for new libraries library (mock) { cell ( "$reduce_xor" ) { area : 3.0 ; From 3f2c4f6f83b699c02fdad90aef8afdc0052531b4 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Sun, 17 Aug 2025 23:34:11 +0000 Subject: [PATCH 34/47] Remove redundant construction of `assign_map`. We call 'assign_map.set()' below which wipes the `SigMap` and reconstructs it. This operation is expensive because it scans the whole module. I think it's better to make heavyweight operations more visible so I'm removing the less obvious operation. --- passes/opt/opt_merge.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/opt/opt_merge.cc b/passes/opt/opt_merge.cc index b519d33d6..5ca19bc2f 100644 --- a/passes/opt/opt_merge.cc +++ b/passes/opt/opt_merge.cc @@ -227,7 +227,7 @@ struct OptMergeWorker } OptMergeWorker(RTLIL::Design *design, RTLIL::Module *module, bool mode_nomux, bool mode_share_all, bool mode_keepdc) : - design(design), module(module), assign_map(module), mode_share_all(mode_share_all) + design(design), module(module), mode_share_all(mode_share_all) { total_count = 0; ct.setup_internals(); From d73cd78001a4ea2d3279f7533b3f443128f63bad Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 18 Aug 2025 00:27:23 +0000 Subject: [PATCH 35/47] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index e83d32ac2..d9f9f432b 100644 --- a/Makefile +++ b/Makefile @@ -159,7 +159,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.56+125 +YOSYS_VER := 0.56+141 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 e0e70d11580df9743acf8fac2c91e8a305bcbf35 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Mon, 18 Aug 2025 03:07:45 +0000 Subject: [PATCH 36/47] Remove some `c_str()` calls where they're no longer needed as parameters to `stringf()`. --- backends/btor/btor.cc | 6 +-- backends/firrtl/firrtl.cc | 66 ++++++++++++++--------------- backends/intersynth/intersynth.cc | 8 ++-- backends/simplec/simplec.cc | 70 +++++++++++++++---------------- backends/spice/spice.cc | 22 +++++----- 5 files changed, 86 insertions(+), 86 deletions(-) diff --git a/backends/btor/btor.cc b/backends/btor/btor.cc index bfd293557..1daf68c9d 100644 --- a/backends/btor/btor.cc +++ b/backends/btor/btor.cc @@ -129,7 +129,7 @@ struct BtorWorker std::replace(src.begin(), src.end(), ' ', '_'); if (srcsymbols.count(src) || module->count_id("\\" + src)) { for (int i = 1;; i++) { - string s = stringf("%s-%d", src.c_str(), i); + string s = stringf("%s-%d", src, i); if (!srcsymbols.count(s) && !module->count_id("\\" + s)) { src = s; break; @@ -192,7 +192,7 @@ struct BtorWorker void btorf_push(const string &id) { if (verbose) { - f << indent << stringf(" ; begin %s\n", id.c_str()); + f << indent << stringf(" ; begin %s\n", id); indent += " "; } } @@ -201,7 +201,7 @@ struct BtorWorker { if (verbose) { indent = indent.substr(4); - f << indent << stringf(" ; end %s\n", id.c_str()); + f << indent << stringf(" ; end %s\n", id); } } diff --git a/backends/firrtl/firrtl.cc b/backends/firrtl/firrtl.cc index e4254f85a..7c9feebb1 100644 --- a/backends/firrtl/firrtl.cc +++ b/backends/firrtl/firrtl.cc @@ -253,7 +253,7 @@ void emit_extmodule(RTLIL::Cell *cell, RTLIL::Module *mod_instance, std::ostream const std::string extmoduleFileinfo = getFileinfo(cell); // Emit extmodule header. - f << stringf(" extmodule %s: %s\n", exported_name.c_str(), extmoduleFileinfo.c_str()); + f << stringf(" extmodule %s: %s\n", exported_name, extmoduleFileinfo); // Emit extmodule ports. for (auto wire : mod_instance->wires()) @@ -280,7 +280,7 @@ void emit_extmodule(RTLIL::Cell *cell, RTLIL::Module *mod_instance, std::ostream // Emit extmodule "defname" field. This is the name of the verilog blackbox // that is used when verilog is emitted, so we use the name of mod_instance // here. - f << stringf("%sdefname = %s\n", indent.c_str(), blackbox_name.c_str()); + f << stringf("%sdefname = %s\n", indent, blackbox_name); // Emit extmodule generic parameters. for (const auto &p : cell->parameters) @@ -301,7 +301,7 @@ void emit_extmodule(RTLIL::Cell *cell, RTLIL::Module *mod_instance, std::ostream param_name.end() ); - f << stringf("%sparameter %s = %s\n", indent.c_str(), param_name.c_str(), param_value.c_str()); + f << stringf("%sparameter %s = %s\n", indent, param_name, param_value); } f << "\n"; @@ -417,7 +417,7 @@ struct FirrtlWorker else { string wire_id = make_id(chunk.wire->name); - new_expr = stringf("bits(%s, %d, %d)", wire_id.c_str(), chunk.offset + chunk.width - 1, chunk.offset); + new_expr = stringf("bits(%s, %d, %d)", wire_id, chunk.offset + chunk.width - 1, chunk.offset); } if (expr.empty()) @@ -477,7 +477,7 @@ struct FirrtlWorker instanceOf; std::string cellFileinfo = getFileinfo(cell); - wire_exprs.push_back(stringf("%s" "inst %s%s of %s %s", indent.c_str(), cell_name.c_str(), cell_name_comment.c_str(), instanceName.c_str(), cellFileinfo.c_str())); + wire_exprs.push_back(stringf("%s" "inst %s%s of %s %s", indent, cell_name, cell_name_comment, instanceName, cellFileinfo)); for (auto it = cell->connections().begin(); it != cell->connections().end(); ++it) { if (it->second.size() > 0) { @@ -518,7 +518,7 @@ struct FirrtlWorker // as part of the coalesced subfield assignments for this wire. register_reverse_wire_map(sourceExpr, *sinkSig); } else { - wire_exprs.push_back(stringf("\n%s%s <= %s %s", indent.c_str(), sinkExpr.c_str(), sourceExpr.c_str(), cellFileinfo.c_str())); + wire_exprs.push_back(stringf("\n%s%s <= %s %s", indent, sinkExpr, sourceExpr, cellFileinfo)); } } } @@ -535,7 +535,7 @@ struct FirrtlWorker int max_shift_width_bits = FIRRTL_MAX_DSH_WIDTH_ERROR - 1; string max_shift_string = stringf("UInt<%d>(%d)", max_shift_width_bits, (1<name), moduleFileinfo.c_str()); + f << stringf(" module %s: %s\n", make_id(module->name), moduleFileinfo); vector port_decls, wire_decls, mem_exprs, cell_exprs, wire_exprs; std::vector memories = Mem::get_all_memories(module); @@ -602,7 +602,7 @@ struct FirrtlWorker if (cell->type.in(ID($not), ID($logic_not), ID($_NOT_), ID($neg), ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_bool), ID($reduce_xnor))) { string a_expr = make_expr(cell->getPort(ID::A)); - wire_decls.push_back(stringf("%swire %s: UInt<%d> %s\n", indent.c_str(), y_id.c_str(), y_width, cellFileinfo.c_str())); + wire_decls.push_back(stringf("%swire %s: UInt<%d> %s\n", indent, y_id, y_width, cellFileinfo)); if (a_signed) { a_expr = "asSInt(" + a_expr + ")"; @@ -610,7 +610,7 @@ struct FirrtlWorker // Don't use the results of logical operations (a single bit) to control padding if (!(cell->type.in(ID($eq), ID($eqx), ID($gt), ID($ge), ID($lt), ID($le), ID($ne), ID($nex), ID($reduce_bool), ID($logic_not)) && y_width == 1) ) { - a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width); + a_expr = stringf("pad(%s, %d)", a_expr, y_width); } // Assume the FIRRTL width is a single bit. @@ -622,27 +622,27 @@ struct FirrtlWorker firrtl_width = a_width; } else if (cell->type == ID($logic_not)) { primop = "eq"; - a_expr = stringf("%s, UInt(0)", a_expr.c_str()); + a_expr = stringf("%s, UInt(0)", a_expr); } else if (cell->type == ID($reduce_and)) primop = "andr"; else if (cell->type == ID($reduce_or)) primop = "orr"; else if (cell->type == ID($reduce_xor)) primop = "xorr"; else if (cell->type == ID($reduce_xnor)) { primop = "not"; - a_expr = stringf("xorr(%s)", a_expr.c_str()); + a_expr = stringf("xorr(%s)", a_expr); } else if (cell->type == ID($reduce_bool)) { primop = "neq"; // Use the sign of the a_expr and its width as the type (UInt/SInt) and width of the comparand. - a_expr = stringf("%s, %cInt<%d>(0)", a_expr.c_str(), a_signed ? 'S' : 'U', a_width); + a_expr = stringf("%s, %cInt<%d>(0)", a_expr, a_signed ? 'S' : 'U', a_width); } - string expr = stringf("%s(%s)", primop.c_str(), a_expr.c_str()); + string expr = stringf("%s(%s)", primop, a_expr); if ((firrtl_is_signed && !always_uint)) - expr = stringf("asUInt(%s)", expr.c_str()); + expr = stringf("asUInt(%s)", expr); - cell_exprs.push_back(stringf("%s%s <= %s %s\n", indent.c_str(), y_id.c_str(), expr.c_str(), cellFileinfo.c_str())); + cell_exprs.push_back(stringf("%s%s <= %s %s\n", indent, y_id, expr, cellFileinfo)); register_reverse_wire_map(y_id, cell->getPort(ID::Y)); continue; @@ -654,13 +654,13 @@ struct FirrtlWorker string a_expr = make_expr(cell->getPort(ID::A)); string b_expr = make_expr(cell->getPort(ID::B)); std::string cellFileinfo = getFileinfo(cell); - wire_decls.push_back(stringf("%swire %s: UInt<%d> %s\n", indent.c_str(), y_id.c_str(), y_width, cellFileinfo.c_str())); + wire_decls.push_back(stringf("%swire %s: UInt<%d> %s\n", indent, y_id, y_width, cellFileinfo)); if (a_signed) { a_expr = "asSInt(" + a_expr + ")"; // Expand the "A" operand to the result width if (a_width < y_width) { - a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width); + a_expr = stringf("pad(%s, %d)", a_expr, y_width); a_width = y_width; } } @@ -670,7 +670,7 @@ struct FirrtlWorker b_expr = "asSInt(" + b_expr + ")"; // Expand the "B" operand to the result width if (b_width < y_width) { - b_expr = stringf("pad(%s, %d)", b_expr.c_str(), y_width); + b_expr = stringf("pad(%s, %d)", b_expr, y_width); b_width = y_width; } } @@ -680,11 +680,11 @@ struct FirrtlWorker if (cell->type.in(ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($xor), ID($_XOR_), ID($xnor), ID($and), ID($_AND_), ID($or), ID($_OR_))) { if (a_width < y_width) { - a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width); + a_expr = stringf("pad(%s, %d)", a_expr, y_width); a_width = y_width; } if (b_width < y_width) { - b_expr = stringf("pad(%s, %d)", b_expr.c_str(), y_width); + b_expr = stringf("pad(%s, %d)", b_expr, y_width); b_width = y_width; } } @@ -856,23 +856,23 @@ struct FirrtlWorker string expr; // Deal with $xnor == ~^ (not xor) if (primop == "xnor") { - expr = stringf("not(xor(%s, %s))", a_expr.c_str(), b_expr.c_str()); + expr = stringf("not(xor(%s, %s))", a_expr, b_expr); } else { - expr = stringf("%s(%s, %s)", primop.c_str(), a_expr.c_str(), b_expr.c_str()); + expr = stringf("%s(%s, %s)", primop, a_expr, b_expr); } // Deal with FIRRTL's "shift widens" semantics, or the need to widen the FIRRTL result. // If the operation is signed, the FIRRTL width will be 1 one bit larger. if (extract_y_bits) { - expr = stringf("bits(%s, %d, 0)", expr.c_str(), y_width - 1); + expr = stringf("bits(%s, %d, 0)", expr, y_width - 1); } else if (firrtl_is_signed && (firrtl_width + 1) < y_width) { - expr = stringf("pad(%s, %d)", expr.c_str(), y_width); + expr = stringf("pad(%s, %d)", expr, y_width); } if ((firrtl_is_signed && !always_uint)) - expr = stringf("asUInt(%s)", expr.c_str()); + expr = stringf("asUInt(%s)", expr); - cell_exprs.push_back(stringf("%s%s <= %s %s\n", indent.c_str(), y_id.c_str(), expr.c_str(), cellFileinfo.c_str())); + cell_exprs.push_back(stringf("%s%s <= %s %s\n", indent, y_id, expr, cellFileinfo)); register_reverse_wire_map(y_id, cell->getPort(ID::Y)); continue; @@ -887,9 +887,9 @@ struct FirrtlWorker string s_expr = make_expr(cell->getPort(ID::S)); wire_decls.push_back(stringf("%swire %s: UInt<%d> %s\n", indent.c_str(), y_id.c_str(), width, cellFileinfo.c_str())); - string expr = stringf("mux(%s, %s, %s)", s_expr.c_str(), b_expr.c_str(), a_expr.c_str()); + string expr = stringf("mux(%s, %s, %s)", s_expr, b_expr, a_expr); - cell_exprs.push_back(stringf("%s%s <= %s %s\n", indent.c_str(), y_id.c_str(), expr.c_str(), cellFileinfo.c_str())); + cell_exprs.push_back(stringf("%s%s <= %s %s\n", indent, y_id, expr, cellFileinfo)); register_reverse_wire_map(y_id, cell->getPort(ID::Y)); continue; @@ -911,9 +911,9 @@ struct FirrtlWorker string expr = make_expr(cell->getPort(ID::D)); string clk_expr = "asClock(" + make_expr(cell->getPort(ID::CLK)) + ")"; - wire_decls.push_back(stringf("%sreg %s: UInt<%d>, %s %s\n", indent.c_str(), y_id.c_str(), width, clk_expr.c_str(), cellFileinfo.c_str())); + wire_decls.push_back(stringf("%sreg %s: UInt<%d>, %s %s\n", indent, y_id, width, clk_expr, cellFileinfo)); - cell_exprs.push_back(stringf("%s%s <= %s %s\n", indent.c_str(), y_id.c_str(), expr.c_str(), cellFileinfo.c_str())); + cell_exprs.push_back(stringf("%s%s <= %s %s\n", indent, y_id, expr, cellFileinfo)); register_reverse_wire_map(y_id, cell->getPort(ID::Q)); continue; @@ -934,7 +934,7 @@ struct FirrtlWorker int b_sign = cell->parameters.at(ID::B_WIDTH).as_int() - 1; b_expr = stringf("validif(not(bits(%s, %d, %d)), %s)", b_string, b_sign, b_sign, b_string); } - string expr = stringf("dshr(%s, %s)", a_expr.c_str(), b_expr.c_str()); + string expr = stringf("dshr(%s, %s)", a_expr, b_expr); cell_exprs.push_back(stringf("%s%s <= %s\n", indent.c_str(), y_id.c_str(), expr.c_str())); register_reverse_wire_map(y_id, cell->getPort(ID::Y)); @@ -973,7 +973,7 @@ struct FirrtlWorker // Verilog appears to treat the result as signed, so if the result is wider than "A", // we need to pad. if (a_width < y_width) { - a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width); + a_expr = stringf("pad(%s, %d)", a_expr, y_width); } wire_decls.push_back(stringf("%swire %s: UInt<%d>\n", indent.c_str(), y_id.c_str(), y_width)); cell_exprs.push_back(stringf("%s%s <= %s\n", indent.c_str(), y_id.c_str(), a_expr.c_str())); diff --git a/backends/intersynth/intersynth.cc b/backends/intersynth/intersynth.cc index dcf107de3..4c098e019 100644 --- a/backends/intersynth/intersynth.cc +++ b/backends/intersynth/intersynth.cc @@ -172,7 +172,7 @@ struct IntersynthBackend : public Backend { if (sig.size() != 0) { conntypes_code.insert(stringf("conntype b%d %d 2 %d\n", sig.size(), sig.size(), sig.size())); celltype_code += stringf(" b%d %s%s", sig.size(), ct.cell_output(cell->type, port.first) ? "*" : "", log_id(port.first)); - node_code += stringf(" %s %s", log_id(port.first), netname(conntypes_code, celltypes_code, constcells_code, sig).c_str()); + node_code += stringf(" %s %s", log_id(port.first), netname(conntypes_code, celltypes_code, constcells_code, sig)); } } for (auto ¶m : cell->parameters) { @@ -199,13 +199,13 @@ struct IntersynthBackend : public Backend { if (!flag_notypes) { *f << stringf("### Connection Types\n"); for (auto code : conntypes_code) - *f << stringf("%s", code.c_str()); + *f << stringf("%s", code); *f << stringf("\n### Cell Types\n"); for (auto code : celltypes_code) - *f << stringf("%s", code.c_str()); + *f << stringf("%s", code); } *f << stringf("\n### Netlists\n"); - *f << stringf("%s", netlists_code.c_str()); + *f << stringf("%s", netlists_code); for (auto lib : libs) delete lib; diff --git a/backends/simplec/simplec.cc b/backends/simplec/simplec.cc index e70c62a71..1ab586e43 100644 --- a/backends/simplec/simplec.cc +++ b/backends/simplec/simplec.cc @@ -218,8 +218,8 @@ struct SimplecWorker s[i] -= 'a' - 'A'; util_declarations.push_back(""); - util_declarations.push_back(stringf("#ifndef %s", s.c_str())); - util_declarations.push_back(stringf("#define %s", s.c_str())); + util_declarations.push_back(stringf("#ifndef %s", s)); + util_declarations.push_back(stringf("#define %s", s)); } string util_get_bit(const string &signame, int n, int idx) @@ -232,33 +232,33 @@ struct SimplecWorker if (generated_utils.count(util_name) == 0) { util_ifdef_guard(util_name); - util_declarations.push_back(stringf("static inline bool %s(const %s *sig)", util_name.c_str(), sigtype(n).c_str())); + util_declarations.push_back(stringf("static inline bool %s(const %s *sig)", util_name, sigtype(n))); util_declarations.push_back(stringf("{")); int word_idx = idx / max_uintsize, word_offset = idx % max_uintsize; string value_name = stringf("value_%d_%d", std::min(n-1, (word_idx+1)*max_uintsize-1), word_idx*max_uintsize); - util_declarations.push_back(stringf(" return (sig->%s >> %d) & 1;", value_name.c_str(), word_offset)); + util_declarations.push_back(stringf(" return (sig->%s >> %d) & 1;", value_name, word_offset)); util_declarations.push_back(stringf("}")); util_declarations.push_back(stringf("#endif")); generated_utils.insert(util_name); } - return stringf("%s(&%s)", util_name.c_str(), signame.c_str()); + return stringf("%s(&%s)", util_name, signame); } string util_set_bit(const string &signame, int n, int idx, const string &expr) { if (n == 1 && idx == 0) - return stringf(" %s.value_0_0 = %s;", signame.c_str(), expr.c_str()); + return stringf(" %s.value_0_0 = %s;", signame, expr); string util_name = stringf("yosys_simplec_set_bit_%d_of_%d", idx, n); if (generated_utils.count(util_name) == 0) { util_ifdef_guard(util_name); - util_declarations.push_back(stringf("static inline void %s(%s *sig, bool value)", util_name.c_str(), sigtype(n).c_str())); + util_declarations.push_back(stringf("static inline void %s(%s *sig, bool value)", util_name, sigtype(n))); util_declarations.push_back(stringf("{")); int word_idx = idx / max_uintsize, word_offset = idx % max_uintsize; @@ -266,9 +266,9 @@ struct SimplecWorker #if 0 util_declarations.push_back(stringf(" if (value)")); - util_declarations.push_back(stringf(" sig->%s |= 1UL << %d;", value_name.c_str(), word_offset)); + util_declarations.push_back(stringf(" sig->%s |= 1UL << %d;", value_name, word_offset)); util_declarations.push_back(stringf(" else")); - util_declarations.push_back(stringf(" sig->%s &= ~(1UL << %d);", value_name.c_str(), word_offset)); + util_declarations.push_back(stringf(" sig->%s &= ~(1UL << %d);", value_name, word_offset)); #else util_declarations.push_back(stringf(" sig->%s = (sig->%s & ~((uint%d_t)1 << %d)) | ((uint%d_t)value << %d);", value_name.c_str(), value_name.c_str(), max_uintsize, word_offset, max_uintsize, word_offset)); @@ -279,7 +279,7 @@ struct SimplecWorker generated_utils.insert(util_name); } - return stringf(" %s(&%s, %s);", util_name.c_str(), signame.c_str(), expr.c_str()); + return stringf(" %s(&%s, %s);", util_name, signame, expr); } void create_module_struct(Module *mod) @@ -339,38 +339,38 @@ struct SimplecWorker for (int i = 0; i < GetSize(topo.sorted); i++) topoidx[mod->cell(topo.sorted[i])] = i; - string ifdef_name = stringf("yosys_simplec_%s_state_t", cid(mod->name).c_str()); + string ifdef_name = stringf("yosys_simplec_%s_state_t", cid(mod->name)); for (int i = 0; i < GetSize(ifdef_name); i++) if ('a' <= ifdef_name[i] && ifdef_name[i] <= 'z') ifdef_name[i] -= 'a' - 'A'; struct_declarations.push_back(""); - struct_declarations.push_back(stringf("#ifndef %s", ifdef_name.c_str())); - struct_declarations.push_back(stringf("#define %s", ifdef_name.c_str())); - struct_declarations.push_back(stringf("struct %s_state_t", cid(mod->name).c_str())); + struct_declarations.push_back(stringf("#ifndef %s", ifdef_name)); + struct_declarations.push_back(stringf("#define %s", ifdef_name)); + struct_declarations.push_back(stringf("struct %s_state_t", cid(mod->name))); struct_declarations.push_back("{"); struct_declarations.push_back(" // Input Ports"); for (Wire *w : mod->wires()) if (w->port_input) - struct_declarations.push_back(stringf(" %s %s; // %s", sigtype(w->width).c_str(), cid(w->name).c_str(), log_id(w))); + struct_declarations.push_back(stringf(" %s %s; // %s", sigtype(w->width), cid(w->name), log_id(w))); struct_declarations.push_back(""); struct_declarations.push_back(" // Output Ports"); for (Wire *w : mod->wires()) if (!w->port_input && w->port_output) - struct_declarations.push_back(stringf(" %s %s; // %s", sigtype(w->width).c_str(), cid(w->name).c_str(), log_id(w))); + struct_declarations.push_back(stringf(" %s %s; // %s", sigtype(w->width), cid(w->name), log_id(w))); struct_declarations.push_back(""); struct_declarations.push_back(" // Internal Wires"); for (Wire *w : mod->wires()) if (!w->port_input && !w->port_output) - struct_declarations.push_back(stringf(" %s %s; // %s", sigtype(w->width).c_str(), cid(w->name).c_str(), log_id(w))); + struct_declarations.push_back(stringf(" %s %s; // %s", sigtype(w->width), cid(w->name), log_id(w))); for (Cell *c : mod->cells()) if (design->module(c->type)) - struct_declarations.push_back(stringf(" struct %s_state_t %s; // %s", cid(c->type).c_str(), cid(c->name).c_str(), log_id(c))); + struct_declarations.push_back(stringf(" struct %s_state_t %s; // %s", cid(c->type), cid(c->name), log_id(c))); struct_declarations.push_back(stringf("};")); struct_declarations.push_back("#endif"); @@ -407,14 +407,14 @@ struct SimplecWorker string b_expr = b.wire ? util_get_bit(work->prefix + cid(b.wire->name), b.wire->width, b.offset) : b.data ? "1" : "0"; string expr; - if (cell->type == ID($_AND_)) expr = stringf("%s & %s", a_expr.c_str(), b_expr.c_str()); - if (cell->type == ID($_NAND_)) expr = stringf("!(%s & %s)", a_expr.c_str(), b_expr.c_str()); - if (cell->type == ID($_OR_)) expr = stringf("%s | %s", a_expr.c_str(), b_expr.c_str()); - if (cell->type == ID($_NOR_)) expr = stringf("!(%s | %s)", a_expr.c_str(), b_expr.c_str()); - if (cell->type == ID($_XOR_)) expr = stringf("%s ^ %s", a_expr.c_str(), b_expr.c_str()); - if (cell->type == ID($_XNOR_)) expr = stringf("!(%s ^ %s)", a_expr.c_str(), b_expr.c_str()); - if (cell->type == ID($_ANDNOT_)) expr = stringf("%s & (!%s)", a_expr.c_str(), b_expr.c_str()); - if (cell->type == ID($_ORNOT_)) expr = stringf("%s | (!%s)", a_expr.c_str(), b_expr.c_str()); + if (cell->type == ID($_AND_)) expr = stringf("%s & %s", a_expr, b_expr); + if (cell->type == ID($_NAND_)) expr = stringf("!(%s & %s)", a_expr, b_expr); + if (cell->type == ID($_OR_)) expr = stringf("%s | %s", a_expr, b_expr); + if (cell->type == ID($_NOR_)) expr = stringf("!(%s | %s)", a_expr, b_expr); + if (cell->type == ID($_XOR_)) expr = stringf("%s ^ %s", a_expr, b_expr); + if (cell->type == ID($_XNOR_)) expr = stringf("!(%s ^ %s)", a_expr, b_expr); + if (cell->type == ID($_ANDNOT_)) expr = stringf("%s & (!%s)", a_expr, b_expr); + if (cell->type == ID($_ORNOT_)) expr = stringf("%s | (!%s)", a_expr, b_expr); log_assert(y.wire); funct_declarations.push_back(util_set_bit(work->prefix + cid(y.wire->name), y.wire->width, y.offset, expr) + @@ -436,8 +436,8 @@ struct SimplecWorker string c_expr = c.wire ? util_get_bit(work->prefix + cid(c.wire->name), c.wire->width, c.offset) : c.data ? "1" : "0"; string expr; - if (cell->type == ID($_AOI3_)) expr = stringf("!((%s & %s) | %s)", a_expr.c_str(), b_expr.c_str(), c_expr.c_str()); - if (cell->type == ID($_OAI3_)) expr = stringf("!((%s | %s) & %s)", a_expr.c_str(), b_expr.c_str(), c_expr.c_str()); + if (cell->type == ID($_AOI3_)) expr = stringf("!((%s & %s) | %s)", a_expr, b_expr, c_expr); + if (cell->type == ID($_OAI3_)) expr = stringf("!((%s | %s) & %s)", a_expr, b_expr, c_expr); log_assert(y.wire); funct_declarations.push_back(util_set_bit(work->prefix + cid(y.wire->name), y.wire->width, y.offset, expr) + @@ -461,8 +461,8 @@ struct SimplecWorker string d_expr = d.wire ? util_get_bit(work->prefix + cid(d.wire->name), d.wire->width, d.offset) : d.data ? "1" : "0"; string expr; - if (cell->type == ID($_AOI4_)) expr = stringf("!((%s & %s) | (%s & %s))", a_expr.c_str(), b_expr.c_str(), c_expr.c_str(), d_expr.c_str()); - if (cell->type == ID($_OAI4_)) expr = stringf("!((%s | %s) & (%s | %s))", a_expr.c_str(), b_expr.c_str(), c_expr.c_str(), d_expr.c_str()); + if (cell->type == ID($_AOI4_)) expr = stringf("!((%s & %s) | (%s & %s))", a_expr, b_expr, c_expr, d_expr); + if (cell->type == ID($_OAI4_)) expr = stringf("!((%s | %s) & (%s | %s))", a_expr, b_expr, c_expr, d_expr); log_assert(y.wire); funct_declarations.push_back(util_set_bit(work->prefix + cid(y.wire->name), y.wire->width, y.offset, expr) + @@ -484,9 +484,9 @@ struct SimplecWorker string s_expr = s.wire ? util_get_bit(work->prefix + cid(s.wire->name), s.wire->width, s.offset) : s.data ? "1" : "0"; // casts to bool are a workaround for CBMC bug (https://github.com/diffblue/cbmc/issues/933) - string expr = stringf("%s ? %s(bool)%s : %s(bool)%s", s_expr.c_str(), - cell->type == ID($_NMUX_) ? "!" : "", b_expr.c_str(), - cell->type == ID($_NMUX_) ? "!" : "", a_expr.c_str()); + string expr = stringf("%s ? %s(bool)%s : %s(bool)%s", s_expr, + cell->type == ID($_NMUX_) ? "!" : "", b_expr, + cell->type == ID($_NMUX_) ? "!" : "", a_expr); log_assert(y.wire); funct_declarations.push_back(util_set_bit(work->prefix + cid(y.wire->name), y.wire->width, y.offset, expr) + @@ -518,7 +518,7 @@ struct SimplecWorker continue; if (verbose) log(" Propagating %s.%s[%d:%d].\n", work->log_prefix.c_str(), log_id(chunk.wire), chunk.offset+chunk.width-1, chunk.offset); - funct_declarations.push_back(stringf(" // Updated signal in %s: %s", work->log_prefix.c_str(), log_signal(chunk))); + funct_declarations.push_back(stringf(" // Updated signal in %s: %s", work->log_prefix, log_signal(chunk))); } for (SigBit bit : dirtysig) @@ -636,7 +636,7 @@ struct SimplecWorker reactivated_cells.clear(); funct_declarations.push_back(""); - funct_declarations.push_back(stringf("static void %s(struct %s_state_t *state)", func_name.c_str(), cid(work->module->name).c_str())); + funct_declarations.push_back(stringf("static void %s(struct %s_state_t *state)", func_name, cid(work->module->name))); funct_declarations.push_back("{"); for (auto &line : preamble) funct_declarations.push_back(line); diff --git a/backends/spice/spice.cc b/backends/spice/spice.cc index e55db95e1..573093ff7 100644 --- a/backends/spice/spice.cc +++ b/backends/spice/spice.cc @@ -51,16 +51,16 @@ static void print_spice_net(std::ostream &f, RTLIL::SigBit s, std::string &neg, if (s.wire->port_id) use_inames = true; if (s.wire->width > 1) - f << stringf(" %s.%d", spice_id2str(s.wire->name, use_inames, inums).c_str(), s.offset); + f << stringf(" %s.%d", spice_id2str(s.wire->name, use_inames, inums), s.offset); else - f << stringf(" %s", spice_id2str(s.wire->name, use_inames, inums).c_str()); + f << stringf(" %s", spice_id2str(s.wire->name, use_inames, inums)); } else { if (s == RTLIL::State::S0) - f << stringf(" %s", neg.c_str()); + f << stringf(" %s", neg); else if (s == RTLIL::State::S1) - f << stringf(" %s", pos.c_str()); + f << stringf(" %s", pos); else - f << stringf(" %s%d", ncpf.c_str(), nc_counter++); + f << stringf(" %s%d", ncpf, nc_counter++); } } @@ -119,7 +119,7 @@ static void print_spice_module(std::ostream &f, RTLIL::Module *module, RTLIL::De } } - f << stringf(" %s\n", spice_id2str(cell->type).c_str()); + f << stringf(" %s\n", spice_id2str(cell->type)); } for (auto &conn : module->connections()) @@ -127,7 +127,7 @@ static void print_spice_module(std::ostream &f, RTLIL::Module *module, RTLIL::De f << (buf == "DC" ? stringf("V%d", conn_counter++) : stringf("X%d", cell_counter++)); print_spice_net(f, conn.second.extract(i, 1), neg, pos, ncpf, nc_counter, use_inames, inums); print_spice_net(f, conn.first.extract(i, 1), neg, pos, ncpf, nc_counter, use_inames, inums); - f << (buf == "DC" ? " DC 0\n" : stringf(" %s\n", buf.c_str())); + f << (buf == "DC" ? " DC 0\n" : stringf(" %s\n", buf)); } } @@ -242,18 +242,18 @@ struct SpiceBackend : public Backend { ports.at(wire->port_id-1) = wire; } - *f << stringf(".SUBCKT %s", spice_id2str(module->name).c_str()); + *f << stringf(".SUBCKT %s", spice_id2str(module->name)); for (RTLIL::Wire *wire : ports) { log_assert(wire != NULL); if (wire->width > 1) { for (int i = 0; i < wire->width; i++) - *f << stringf(" %s.%d", spice_id2str(wire->name).c_str(), big_endian ? wire->width - 1 - i : i); + *f << stringf(" %s.%d", spice_id2str(wire->name), big_endian ? wire->width - 1 - i : i); } else - *f << stringf(" %s", spice_id2str(wire->name).c_str()); + *f << stringf(" %s", spice_id2str(wire->name)); } *f << stringf("\n"); print_spice_module(*f, module, design, neg, pos, buf, ncpf, big_endian, use_inames); - *f << stringf(".ENDS %s\n\n", spice_id2str(module->name).c_str()); + *f << stringf(".ENDS %s\n\n", spice_id2str(module->name)); } if (!top_module_name.empty()) { From b640a16b07ec7c313ee3d97a4a84b0eccd3d59f9 Mon Sep 17 00:00:00 2001 From: Jannis Harder Date: Mon, 18 Aug 2025 20:39:00 +0200 Subject: [PATCH 37/47] Revert "Workflow adjustments" --- .github/workflows/extra-builds.yml | 16 +--- .github/workflows/test-build.yml | 36 ++++----- .github/workflows/test-compile.yml | 16 +--- .github/workflows/test-sanitizers.yml | 105 -------------------------- .github/workflows/test-verific.yml | 16 +--- 5 files changed, 28 insertions(+), 161 deletions(-) delete mode 100644 .github/workflows/test-sanitizers.yml diff --git a/.github/workflows/extra-builds.yml b/.github/workflows/extra-builds.yml index 11fd42a6c..458eb76a6 100644 --- a/.github/workflows/extra-builds.yml +++ b/.github/workflows/extra-builds.yml @@ -1,14 +1,6 @@ name: Test extra build flows -on: - # always test main - push: - branches: - - main - # test PRs - pull_request: - # allow triggering tests, ignores skip check - workflow_dispatch: +on: [push, pull_request] jobs: pre_job: @@ -19,11 +11,11 @@ jobs: - id: skip_check uses: fkirc/skip-duplicate-actions@v5 with: - # don't run on documentation changes paths_ignore: '["**/README.md", "docs/**", "guidelines/**"]' # cancel previous builds if a new commit is pushed - # but never cancel main - cancel_others: ${{ github.ref != 'refs/heads/main' }} + cancel_others: 'true' + # only run on push *or* pull_request, not both + concurrent_skipping: 'same_content_newer' vs-prep: name: Prepare Visual Studio build diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml index f44dee1ba..f9574594a 100644 --- a/.github/workflows/test-build.yml +++ b/.github/workflows/test-build.yml @@ -1,14 +1,6 @@ name: Build and run tests -on: - # always test main - push: - branches: - - main - # test PRs - pull_request: - # allow triggering tests, ignores skip check - workflow_dispatch: +on: [push, pull_request] jobs: pre_job: @@ -19,12 +11,11 @@ jobs: - id: skip_check uses: fkirc/skip-duplicate-actions@v5 with: - # don't run on documentation changes paths_ignore: '["**/README.md", "docs/**", "guidelines/**"]' # cancel previous builds if a new commit is pushed - # but never cancel main - cancel_others: ${{ github.ref != 'refs/heads/main' }} - + cancel_others: 'true' + # only run on push *or* pull_request, not both + concurrent_skipping: 'same_content_newer' pre_docs_job: runs-on: ubuntu-latest outputs: @@ -33,16 +24,15 @@ jobs: - id: skip_check uses: fkirc/skip-duplicate-actions@v5 with: - # don't run on readme changes paths_ignore: '["**/README.md"]' # cancel previous builds if a new commit is pushed - # but never cancel main - cancel_others: ${{ github.ref != 'refs/heads/main' }} + cancel_others: 'true' + # only run on push *or* pull_request, not both + concurrent_skipping: 'same_content_newer' build-yosys: name: Reusable build runs-on: ${{ matrix.os }} - # pre_job is a subset of pre_docs_job, so we can always build for pre_docs_job needs: pre_docs_job if: needs.pre_docs_job.outputs.should_skip != 'true' env: @@ -50,6 +40,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, macos-latest] + sanitizer: [undefined, address] fail-fast: false steps: - name: Checkout Yosys @@ -67,6 +58,7 @@ jobs: mkdir build cd build make -f ../Makefile config-$CC + echo 'SANITIZER = ${{ matrix.sanitizer }}' >> Makefile.conf make -f ../Makefile -j$procs ENABLE_LTO=1 - name: Log yosys-config output @@ -82,7 +74,7 @@ jobs: - name: Store build artifact uses: actions/upload-artifact@v4 with: - name: build-${{ matrix.os }} + name: build-${{ matrix.os }}-${{ matrix.sanitizer }} path: build.tar retention-days: 1 @@ -93,9 +85,12 @@ jobs: if: needs.pre_job.outputs.should_skip != 'true' env: CC: clang + ASAN_OPTIONS: halt_on_error=1 + UBSAN_OPTIONS: halt_on_error=1 strategy: matrix: os: [ubuntu-latest, macos-latest] + sanitizer: [undefined, address] fail-fast: false steps: - name: Checkout Yosys @@ -144,7 +139,7 @@ jobs: - name: Download build artifact uses: actions/download-artifact@v4 with: - name: build-${{ matrix.os }} + name: build-${{ matrix.os }}-${{ matrix.sanitizer }} - name: Uncompress build shell: bash @@ -214,6 +209,7 @@ jobs: strategy: matrix: os: [ubuntu-latest] + sanitizer: [undefined, address] fail-fast: false steps: - name: Checkout Yosys @@ -227,7 +223,7 @@ jobs: - name: Download build artifact uses: actions/download-artifact@v4 with: - name: build-${{ matrix.os }} + name: build-${{ matrix.os }}-${{ matrix.sanitizer }} - name: Uncompress build shell: bash diff --git a/.github/workflows/test-compile.yml b/.github/workflows/test-compile.yml index f208b911a..7a706e69a 100644 --- a/.github/workflows/test-compile.yml +++ b/.github/workflows/test-compile.yml @@ -1,14 +1,6 @@ name: Compiler testing -on: - # always test main - push: - branches: - - main - # test PRs - pull_request: - # allow triggering tests, ignores skip check - workflow_dispatch: +on: [push, pull_request] jobs: pre_job: @@ -19,11 +11,11 @@ jobs: - id: skip_check uses: fkirc/skip-duplicate-actions@v5 with: - # don't run on documentation changes paths_ignore: '["**/README.md", "docs/**", "guidelines/**"]' # cancel previous builds if a new commit is pushed - # but never cancel main - cancel_others: ${{ github.ref != 'refs/heads/main' }} + cancel_others: 'true' + # only run on push *or* pull_request, not both + concurrent_skipping: 'same_content_newer' test-compile: runs-on: ${{ matrix.os }} diff --git a/.github/workflows/test-sanitizers.yml b/.github/workflows/test-sanitizers.yml deleted file mode 100644 index fb76d1266..000000000 --- a/.github/workflows/test-sanitizers.yml +++ /dev/null @@ -1,105 +0,0 @@ -name: Check clang sanitizers - -on: - # always test main - push: - branches: - - main - # ignore PRs due to time needed - # allow triggering tests, ignores skip check - workflow_dispatch: - -jobs: - pre_job: - runs-on: ubuntu-latest - outputs: - should_skip: ${{ steps.skip_check.outputs.should_skip }} - steps: - - id: skip_check - uses: fkirc/skip-duplicate-actions@v5 - with: - # don't run on documentation changes - paths_ignore: '["**/README.md", "docs/**", "guidelines/**"]' - - run_san: - name: Build and run tests - runs-on: ${{ matrix.os }} - needs: pre_job - if: needs.pre_job.outputs.should_skip != 'true' - env: - CC: clang - ASAN_OPTIONS: halt_on_error=1 - UBSAN_OPTIONS: halt_on_error=1 - strategy: - matrix: - os: [ubuntu-latest, macos-latest] - sanitizer: ['undefined,address'] - fail-fast: false - steps: - - name: Checkout Yosys - uses: actions/checkout@v4 - with: - submodules: true - persist-credentials: false - - - name: Setup environment - uses: ./.github/actions/setup-build-env - - - name: Build - shell: bash - run: | - mkdir build - cd build - make -f ../Makefile config-$CC - echo 'SANITIZER = ${{ matrix.sanitizer }}' >> Makefile.conf - make -f ../Makefile -j$procs ENABLE_LTO=1 - - - name: Log yosys-config output - run: | - ./yosys-config || true - - - name: Get iverilog - shell: bash - run: | - git clone https://github.com/steveicarus/iverilog.git - cd iverilog - echo "IVERILOG_GIT=$(git rev-parse HEAD)" >> $GITHUB_ENV - - - name: Get vcd2fst - shell: bash - run: | - git clone https://github.com/mmicko/libwave.git - mkdir -p ${{ github.workspace }}/.local/ - cd libwave - cmake . -DCMAKE_INSTALL_PREFIX=${{ github.workspace }}/.local - make -j$procs - make install - - - name: Cache iverilog - id: cache-iverilog - uses: actions/cache@v4 - with: - path: .local/ - key: ${{ matrix.os }}-${IVERILOG_GIT} - - - name: Build iverilog - if: steps.cache-iverilog.outputs.cache-hit != 'true' - shell: bash - run: | - mkdir -p ${{ github.workspace }}/.local/ - cd iverilog - autoconf - CC=gcc CXX=g++ ./configure --prefix=${{ github.workspace }}/.local - make -j$procs - make install - - - name: Run tests - shell: bash - run: | - make -j$procs test TARGETS= EXTRA_TARGETS= CONFIG=$CC - - - name: Report errors - if: ${{ failure() }} - shell: bash - run: | - find tests/**/*.err -print -exec cat {} \; diff --git a/.github/workflows/test-verific.yml b/.github/workflows/test-verific.yml index 9af07b920..013c9f8ca 100644 --- a/.github/workflows/test-verific.yml +++ b/.github/workflows/test-verific.yml @@ -1,14 +1,6 @@ name: Build and run tests with Verific (Linux) -on: - # always test main - push: - branches: - - main - # test PRs - pull_request: - # allow triggering tests, ignores skip check - workflow_dispatch: +on: [push, pull_request] jobs: pre-job: @@ -19,11 +11,11 @@ jobs: - id: skip_check uses: fkirc/skip-duplicate-actions@v5 with: - # don't run on documentation changes paths_ignore: '["**/README.md", "docs/**", "guidelines/**"]' # cancel previous builds if a new commit is pushed - # but never cancel main - cancel_others: ${{ github.ref != 'refs/heads/main' }} + cancel_others: 'true' + # only run on push *or* pull_request, not both + concurrent_skipping: 'same_content_newer' test-verific: needs: pre-job From 6cbd44daa5362b87a084809f6f3b6808815a08ba Mon Sep 17 00:00:00 2001 From: Mohamed Gaber Date: Mon, 18 Aug 2025 22:34:15 +0300 Subject: [PATCH 38/47] wheels: bison 3.8 on almalinux + memory pressure easing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - cibw now builds and uses bison 3.8.2 explicitly on platforms with no or out-of-date bison — AlmaLinux 8 only goes up to Bison 3.0 - cibw environment now includes `OPTFLAGS=-O3` to avoid generating debug info for abc, saving space in memory during linking - setup.py attempts to build `yosys-abc` independently first to avoid memory pressure from gigantic abc link step running in parallel with something else --- .github/workflows/wheels.yml | 15 ++++++--- .github/workflows/wheels/_run_cibw_linux.py | 14 ++++++-- .github/workflows/wheels/cibw_before_all.sh | 36 ++++++++++++++------- .gitignore | 1 + setup.py | 20 +++++++++--- 5 files changed, 64 insertions(+), 22 deletions(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index d81e340aa..b48b981a8 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -4,7 +4,7 @@ name: Build Wheels for PyPI on: workflow_dispatch: schedule: - - cron: '0 10 * * 0' + - cron: "0 10 * * 0" jobs: build_wheels: @@ -54,9 +54,6 @@ jobs: fetch-depth: 0 submodules: true persist-credentials: false - - if: ${{ matrix.os.family == 'linux' }} - name: "[Linux] Set up QEMU" - uses: docker/setup-qemu-action@v3 - uses: actions/setup-python@v5 - name: Get Boost Source shell: bash @@ -68,6 +65,12 @@ jobs: run: | mkdir -p ffi curl -L https://github.com/libffi/libffi/releases/download/v3.4.6/libffi-3.4.6.tar.gz | tar --strip-components=1 -xzC ffi + - if: ${{ matrix.os.family == 'linux' }} + name: "[Linux] Bison 3.8.2" + shell: bash + run: | + mkdir -p bison + curl -L https://ftpmirror.gnu.org/gnu/bison/bison-3.8.2.tar.gz | tar --strip-components=1 -xzC bison ## Software installed by default in GitHub Action Runner VMs: ## https://github.com/actions/runner-images - if: ${{ matrix.os.family == 'macos' }} @@ -100,16 +103,20 @@ jobs: CIBW_MANYLINUX_AARCH64_IMAGE: manylinux_2_28 CIBW_BEFORE_ALL: bash ./.github/workflows/wheels/cibw_before_all.sh CIBW_ENVIRONMENT: > + OPTFLAGS=-O3 CXXFLAGS=-I./boost/pfx/include LINKFLAGS=-L./boost/pfx/lib PKG_CONFIG_PATH=./ffi/pfx/lib/pkgconfig makeFlags='BOOST_PYTHON_LIB=./boost/pfx/lib/libboost_python*.a' + PATH=$PWD/bison/src:$PATH CIBW_ENVIRONMENT_MACOS: > + OPTFLAGS=-O3 CXXFLAGS=-I./boost/pfx/include LINKFLAGS=-L./boost/pfx/lib PKG_CONFIG_PATH=./ffi/pfx/lib/pkgconfig MACOSX_DEPLOYMENT_TARGET=11 makeFlags='BOOST_PYTHON_LIB=./boost/pfx/lib/libboost_python*.a CONFIG=clang' + PATH=$PWD/bison/src:$PATH CIBW_BEFORE_BUILD: bash ./.github/workflows/wheels/cibw_before_build.sh CIBW_TEST_COMMAND: python3 {project}/tests/arch/ecp5/add_sub.py - uses: actions/upload-artifact@v4 diff --git a/.github/workflows/wheels/_run_cibw_linux.py b/.github/workflows/wheels/_run_cibw_linux.py index 894470a5a..fb4e0b839 100644 --- a/.github/workflows/wheels/_run_cibw_linux.py +++ b/.github/workflows/wheels/_run_cibw_linux.py @@ -20,11 +20,19 @@ import os import yaml import platform import subprocess +from pathlib import Path -__dir__ = os.path.dirname(os.path.abspath(__file__)) +__yosys_root__ = Path(__file__).absolute().parents[3] +for source in ["boost", "ffi", "bison"]: + if not (__yosys_root__ / source).is_dir(): + print( + "You need to download boost, ffi and bison in a similar manner to wheels.yml first." + ) + exit(-1) -workflow = yaml.safe_load(open(os.path.join(os.path.dirname(__dir__), "wheels.yml"))) +with open(__yosys_root__ / ".github" / "workflows" / "wheels.yml") as f: + workflow = yaml.safe_load(f) env = os.environ.copy() @@ -40,5 +48,5 @@ for key, value in cibw_step["env"].items(): continue env[key] = value -env["CIBW_ARCHS"] = os.getenv("CIBW_ARCHS") or platform.machine() +env["CIBW_ARCHS"] = os.getenv("CIBW_ARCHS", platform.machine()) subprocess.check_call(["cibuildwheel"], env=env) diff --git a/.github/workflows/wheels/cibw_before_all.sh b/.github/workflows/wheels/cibw_before_all.sh index fbb8dcad8..1aef650d7 100644 --- a/.github/workflows/wheels/cibw_before_all.sh +++ b/.github/workflows/wheels/cibw_before_all.sh @@ -1,23 +1,37 @@ -set -e -set -x +#!/bin/bash +set -e -x # Build-time dependencies ## Linux Docker Images if command -v yum &> /dev/null; then - yum install -y flex bison + yum install -y flex # manylinux's bison versions are hopelessly out of date fi if command -v apk &> /dev/null; then apk add flex bison fi +if ! printf '%s\n' '%require "3.8"' '%%' 'start: ;' | bison -o /dev/null /dev/stdin ; then + ( + set -e -x + cd bison + ./configure + make clean + make install -j$(getconf _NPROCESSORS_ONLN 2>/dev/null || sysctl -n hw.ncpu) + ) +fi + ## macOS/Windows -- installed in GitHub Action itself, not container -# Build Static FFI (platform-dependent but not Python version dependent) -cd ffi -## Ultimate libyosys.so will be shared, so we need fPIC for the static libraries -CFLAGS=-fPIC CXXFLAGS=-fPIC ./configure --prefix=$PWD/pfx -## Without this, SHELL has a space in its path which breaks the makefile -make install -j$(getconf _NPROCESSORS_ONLN 2>/dev/null || sysctl -n hw.ncpu) -## Forces static library to be used in all situations -sed -i.bak 's@-L${toolexeclibdir} -lffi@${toolexeclibdir}/libffi.a@' ./pfx/lib/pkgconfig/libffi.pc +# Runtime Dependencies +## Build Static FFI (platform-dependent but not Python version dependent) +( + set -e -x + cd ffi + ## Ultimate libyosys.so will be shared, so we need fPIC for the static libraries + CFLAGS=-fPIC CXXFLAGS=-fPIC ./configure --prefix=$PWD/pfx + make clean + make install -j$(getconf _NPROCESSORS_ONLN 2>/dev/null || sysctl -n hw.ncpu) + ## Forces static library to be used in all situations + sed -i.bak 's@-L${toolexeclibdir} -lffi@${toolexeclibdir}/libffi.a@' ./pfx/lib/pkgconfig/libffi.pc +) diff --git a/.gitignore b/.gitignore index 3b77edf1f..cac630d7c 100644 --- a/.gitignore +++ b/.gitignore @@ -47,6 +47,7 @@ /kernel/python_wrappers.cc /boost /ffi +/bison /venv /*.whl /*.egg-info diff --git a/setup.py b/setup.py index a199530d0..4a6ef5af9 100644 --- a/setup.py +++ b/setup.py @@ -51,16 +51,27 @@ class libyosys_so_ext(Extension): ] def custom_build(self, bext: build_ext): + make_flags_split = shlex.split(os.getenv("makeFlags", "")) + # abc linking takes a lot of memory, best get it out of the way first + bext.spawn( + [ + "make", + f"-j{os.cpu_count() or 1}", + "yosys-abc", + *make_flags_split, + *self.args, + ] + ) + # build libyosys and share with abc out of the way bext.spawn( [ "make", f"-j{os.cpu_count() or 1}", self.name, - "yosys-abc", "share", + *make_flags_split, + *self.args, ] - + shlex.split(os.getenv("makeFlags", "")) - + self.args ) build_path = os.path.dirname(os.path.dirname(bext.get_ext_fullpath(self.name))) pyosys_path = os.path.join(build_path, "pyosys") @@ -85,6 +96,7 @@ class libyosys_so_ext(Extension): shutil.copytree("share", share_target) + class custom_build_ext(build_ext): def build_extension(self, ext) -> None: if not hasattr(ext, "custom_build"): @@ -100,8 +112,8 @@ setup( long_description=open(os.path.join(__dir__, "README.md")).read(), long_description_content_type="text/markdown", install_requires=["wheel", "setuptools"], + license="MIT", classifiers=[ - "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3", "Intended Audience :: Developers", "Operating System :: POSIX :: Linux", From 2ed7a7aac92a8f2fc9148a11b2f536f7f7468792 Mon Sep 17 00:00:00 2001 From: Mohamed Gaber Date: Tue, 19 Aug 2025 01:28:46 +0300 Subject: [PATCH 39/47] wheels: fix PATH variables --- .github/workflows/wheels.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index b48b981a8..41d9183fc 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -77,8 +77,7 @@ jobs: name: "[macOS] Flex/Bison" run: | brew install flex bison - echo "PATH=$(brew --prefix flex)/bin:$PATH" >> $GITHUB_ENV - echo "PATH=$(brew --prefix bison)/bin:$PATH" >> $GITHUB_ENV + echo "PATH=$(brew --prefix flex)/bin:$(brew --prefix bison)/bin:$PATH" >> $GITHUB_ENV - if: ${{ matrix.os.family == 'windows' }} name: "[Windows] Flex/Bison" run: | @@ -108,7 +107,7 @@ jobs: LINKFLAGS=-L./boost/pfx/lib PKG_CONFIG_PATH=./ffi/pfx/lib/pkgconfig makeFlags='BOOST_PYTHON_LIB=./boost/pfx/lib/libboost_python*.a' - PATH=$PWD/bison/src:$PATH + PATH="$PWD/bison/src:$PATH" CIBW_ENVIRONMENT_MACOS: > OPTFLAGS=-O3 CXXFLAGS=-I./boost/pfx/include @@ -116,7 +115,7 @@ jobs: PKG_CONFIG_PATH=./ffi/pfx/lib/pkgconfig MACOSX_DEPLOYMENT_TARGET=11 makeFlags='BOOST_PYTHON_LIB=./boost/pfx/lib/libboost_python*.a CONFIG=clang' - PATH=$PWD/bison/src:$PATH + PATH="$PWD/bison/src:$PATH" CIBW_BEFORE_BUILD: bash ./.github/workflows/wheels/cibw_before_build.sh CIBW_TEST_COMMAND: python3 {project}/tests/arch/ecp5/add_sub.py - uses: actions/upload-artifact@v4 From bfc9a322e2a854418e6679e141be3d482dde808c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 19 Aug 2025 00:24:35 +0000 Subject: [PATCH 40/47] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index d9f9f432b..5165db4a0 100644 --- a/Makefile +++ b/Makefile @@ -159,7 +159,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.56+141 +YOSYS_VER := 0.56+152 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 3a5742ffd2e9a34b10af9a87748a7f1a7e94e62d Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 19 Aug 2025 03:21:54 +0000 Subject: [PATCH 41/47] Improve commutative hashing. The simple XOR `commutative_eat()` implementation produces a lot of collisions. https://www.preprints.org/manuscript/201710.0192/v1/download is a useful reference on this topic. Running the included `hashTest.cc` without the hashlib changes, I get 49,580,349 collisions. The 49,995,000 (i,j) pairs (0 <= i < 10000, i < j < 10000) hash into only 414,651 unique hash values. We get simple collisions like (0,1) colliding with (2,3). With the hashlib changes, we get only 707,099 collisions and 49,287,901 unique hash values. Much better! The `commutative_hash` implementation corresponds to `Sum(4)` in the paper mentioned above. --- kernel/hashlib.h | 39 ++++++++++++++++++++++++------ kernel/yosys_common.h | 1 + tests/unit/kernel/hashTest.cc | 45 +++++++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+), 7 deletions(-) create mode 100644 tests/unit/kernel/hashTest.cc diff --git a/kernel/hashlib.h b/kernel/hashlib.h index 7a5650fa3..b43b7302e 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -12,6 +12,7 @@ #ifndef HASHLIB_H #define HASHLIB_H +#include #include #include #include @@ -100,7 +101,7 @@ private: uint32_t hash = ((a << 5) + a) ^ b; return hash; } - public: +public: void hash32(uint32_t i) { state = djb2_xor(i, state); state = mkhash_xorshift(fudge ^ state); @@ -127,6 +128,7 @@ private: *this = hash_ops::hash_into(t, *this); } + [[deprecated]] void commutative_eat(hash_t t) { state ^= t; } @@ -356,6 +358,29 @@ template> class idict; template> class pool; template> class mfp; +// Computes the hash value of an unordered set of elements. +// See https://www.preprints.org/manuscript/201710.0192/v1/download. +// This is the Sum(4) algorithm from that paper, which has good collision resistance, +// much better than Sum(1) or Xor(1) (and somewhat better than Xor(4)). +class commutative_hash { +public: + commutative_hash() { + buckets.fill(0); + } + void eat(Hasher h) { + Hasher::hash_t v = h.yield(); + size_t index = v & (buckets.size() - 1); + buckets[index] += v; + } + [[nodiscard]] Hasher hash_into(Hasher h) const { + for (auto b : buckets) + h.eat(b); + return h; + } +private: + std::array buckets; +}; + template class dict { struct entry_t @@ -801,14 +826,14 @@ public: } [[nodiscard]] Hasher hash_into(Hasher h) const { + commutative_hash comm; for (auto &it : entries) { Hasher entry_hash; entry_hash.eat(it.udata.first); entry_hash.eat(it.udata.second); - h.commutative_eat(entry_hash.yield()); + comm.eat(entry_hash); } - h.eat(entries.size()); - return h; + return comm.hash_into(h); } void reserve(size_t n) { entries.reserve(n); } @@ -1184,11 +1209,11 @@ public: } [[nodiscard]] Hasher hash_into(Hasher h) const { + commutative_hash comm; for (auto &it : entries) { - h.commutative_eat(ops.hash(it.udata).yield()); + comm.eat(ops.hash(it.udata)); } - h.eat(entries.size()); - return h; + return comm.hash_into(h); } void reserve(size_t n) { entries.reserve(n); } diff --git a/kernel/yosys_common.h b/kernel/yosys_common.h index ecc8ce623..bc92e7869 100644 --- a/kernel/yosys_common.h +++ b/kernel/yosys_common.h @@ -20,6 +20,7 @@ #ifndef YOSYS_COMMON_H #define YOSYS_COMMON_H +#include #include #include #include diff --git a/tests/unit/kernel/hashTest.cc b/tests/unit/kernel/hashTest.cc new file mode 100644 index 000000000..6e4610ec8 --- /dev/null +++ b/tests/unit/kernel/hashTest.cc @@ -0,0 +1,45 @@ +#include +#include "kernel/yosys_common.h" + +#include + +YOSYS_NAMESPACE_BEGIN + +static Hasher hash(int x) +{ + Hasher h; + h.eat(x); + return h; +} + +TEST(CommutativeTest, basic) +{ + hashlib::commutative_hash comm1; + comm1.eat(hash(1)); + comm1.eat(hash(2)); + hashlib::commutative_hash comm2; + comm2.eat(hash(2)); + comm2.eat(hash(1)); + EXPECT_EQ(comm1.hash_into(Hasher()).yield(), comm2.hash_into(Hasher()).yield()); +} + +TEST(PoolHashTest, collisions) +{ + uint64_t collisions = 0; + std::unordered_set hashes; + for (int i = 0; i < 10000; ++i) { + for (int j = i + 1; j < 10000; ++j) { + pool p1; + p1.insert(i); + p1.insert(j); + auto h = p1.hash_into(Hasher()).yield(); + if (!hashes.insert(h).second) { + ++collisions; + } + } + } + std::cout << "pool collisions: " << collisions << std::endl; + EXPECT_LT(collisions, 1000000); +} + +YOSYS_NAMESPACE_END From 01de9fb453f8fadc23067d5c7e2442fcd1013d97 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Tue, 19 Aug 2025 16:35:34 +0200 Subject: [PATCH 42/47] hashlib: extend unit test with subset collisions, shorten runtime --- tests/unit/kernel/hashTest.cc | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/tests/unit/kernel/hashTest.cc b/tests/unit/kernel/hashTest.cc index 6e4610ec8..319d064a7 100644 --- a/tests/unit/kernel/hashTest.cc +++ b/tests/unit/kernel/hashTest.cc @@ -27,8 +27,8 @@ TEST(PoolHashTest, collisions) { uint64_t collisions = 0; std::unordered_set hashes; - for (int i = 0; i < 10000; ++i) { - for (int j = i + 1; j < 10000; ++j) { + for (int i = 0; i < 1000; ++i) { + for (int j = i + 1; j < 1000; ++j) { pool p1; p1.insert(i); p1.insert(j); @@ -39,7 +39,29 @@ TEST(PoolHashTest, collisions) } } std::cout << "pool collisions: " << collisions << std::endl; - EXPECT_LT(collisions, 1000000); + EXPECT_LT(collisions, 10'000); +} + +TEST(PoolHashTest, subset_collisions) +{ + uint64_t collisions = 0; + std::unordered_set hashes; + for (int i = 0; i < 1000 * 1000; ++i) { + + pool p1; + for (int b = 0; i >> b; ++b) { + if ((i >> b) & 1) { + p1.insert(b); + } + } + auto h = p1.hash_into(Hasher()).yield(); + if (!hashes.insert(h).second) { + ++collisions; + } + + } + std::cout << "pool subset collisions: " << collisions << std::endl; + EXPECT_LT(collisions, 100); } YOSYS_NAMESPACE_END From 7d0ea0d64f4e5845d78d9dc6c1757e909b0c4ada Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 19 Aug 2025 05:41:08 +0000 Subject: [PATCH 43/47] Refactor call to sorted_pmux_in to avoid copying the connection dictionary --- passes/opt/opt_merge.cc | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/passes/opt/opt_merge.cc b/passes/opt/opt_merge.cc index 5ca19bc2f..f9ee7ba40 100644 --- a/passes/opt/opt_merge.cc +++ b/passes/opt/opt_merge.cc @@ -44,11 +44,8 @@ struct OptMergeWorker CellTypes ct; int total_count; - static vector> sorted_pmux_in(const dict &conn) + static vector> sorted_pmux_in(const SigSpec& sig_s, const SigSpec& sig_b) { - SigSpec sig_s = conn.at(ID::S); - SigSpec sig_b = conn.at(ID::B); - int s_width = GetSize(sig_s); int width = GetSize(sig_b) / s_width; @@ -104,11 +101,9 @@ struct OptMergeWorker a.sort_and_unify(); h = a.hash_into(h); } else if (cell->type == ID($pmux)) { - dict conn = cell->connections(); - assign_map.apply(conn.at(ID::A)); - assign_map.apply(conn.at(ID::B)); - assign_map.apply(conn.at(ID::S)); - for (const auto& [s_bit, b_chunk] : sorted_pmux_in(conn)) { + SigSpec sig_s = assign_map(cell->getPort(ID::S)); + SigSpec sig_b = assign_map(cell->getPort(ID::B)); + for (const auto& [s_bit, b_chunk] : sorted_pmux_in(sig_s, sig_b)) { h = s_bit.hash_into(h); h = b_chunk.hash_into(h); } From 8c04e5266c1819b21e2656dd2083948ecf914082 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 19 Aug 2025 05:09:16 +0000 Subject: [PATCH 44/47] Use commutative hashing instead of expensive allocation and sorting For one of our large circuits, this improves the `OptMergePass` runtime from about 150s to about 130s. It's also simpler code. --- passes/opt/opt_merge.cc | 50 +++++++++++++++-------------------------- 1 file changed, 18 insertions(+), 32 deletions(-) diff --git a/passes/opt/opt_merge.cc b/passes/opt/opt_merge.cc index f9ee7ba40..ba8168e74 100644 --- a/passes/opt/opt_merge.cc +++ b/passes/opt/opt_merge.cc @@ -44,17 +44,16 @@ struct OptMergeWorker CellTypes ct; int total_count; - static vector> sorted_pmux_in(const SigSpec& sig_s, const SigSpec& sig_b) + static Hasher hash_pmux_in(const SigSpec& sig_s, const SigSpec& sig_b, Hasher h) { int s_width = GetSize(sig_s); int width = GetSize(sig_b) / s_width; - vector> sb_pairs; + hashlib::commutative_hash comm; for (int i = 0; i < s_width; i++) - sb_pairs.push_back(pair(sig_s[i], sig_b.extract(i*width, width))); + comm.eat(hash_ops>::hash({sig_s[i], sig_b.extract(i*width, width)})); - std::sort(sb_pairs.begin(), sb_pairs.end()); - return sb_pairs; + return comm.hash_into(h); } static void sort_pmux_conn(dict &conn) @@ -86,12 +85,10 @@ struct OptMergeWorker // (builtin || stdcell) && (unary || binary) && symmetrical if (cell->type.in(ID($and), ID($or), ID($xor), ID($xnor), ID($add), ID($mul), ID($logic_and), ID($logic_or), ID($_AND_), ID($_OR_), ID($_XOR_))) { - std::array inputs = { - assign_map(cell->getPort(ID::A)), - assign_map(cell->getPort(ID::B)) - }; - std::sort(inputs.begin(), inputs.end()); - h = hash_ops>::hash_into(inputs, h); + hashlib::commutative_hash comm; + comm.eat(hash_ops::hash(assign_map(cell->getPort(ID::A)))); + comm.eat(hash_ops::hash(assign_map(cell->getPort(ID::B)))); + h = comm.hash_into(h); } else if (cell->type.in(ID($reduce_xor), ID($reduce_xnor))) { SigSpec a = assign_map(cell->getPort(ID::A)); a.sort(); @@ -103,40 +100,29 @@ struct OptMergeWorker } else if (cell->type == ID($pmux)) { SigSpec sig_s = assign_map(cell->getPort(ID::S)); SigSpec sig_b = assign_map(cell->getPort(ID::B)); - for (const auto& [s_bit, b_chunk] : sorted_pmux_in(sig_s, sig_b)) { - h = s_bit.hash_into(h); - h = b_chunk.hash_into(h); - } + h = hash_pmux_in(sig_s, sig_b, h); h = assign_map(cell->getPort(ID::A)).hash_into(h); } else { - std::vector> conns; - for (const auto& conn : cell->connections()) { - conns.push_back(conn); + hashlib::commutative_hash comm; + for (const auto& [port, sig] : cell->connections()) { + if (cell->output(port)) + continue; + comm.eat(hash_ops>::hash({port, assign_map(sig)})); } - std::sort(conns.begin(), conns.end()); - for (const auto& [port, sig] : conns) { - if (!cell->output(port)) { - h = port.hash_into(h); - h = assign_map(sig).hash_into(h); - } - } - + h = comm.hash_into(h); if (RTLIL::builtin_ff_cell_types().count(cell->type)) h = initvals(cell->getPort(ID::Q)).hash_into(h); - } return h; } static Hasher hash_cell_parameters(const RTLIL::Cell *cell, Hasher h) { - using Paramvec = std::vector>; - Paramvec params; + hashlib::commutative_hash comm; for (const auto& param : cell->parameters) { - params.push_back(param); + comm.eat(hash_ops>::hash(param)); } - std::sort(params.begin(), params.end()); - return hash_ops::hash_into(params, h); + return comm.hash_into(h); } Hasher hash_cell_function(const RTLIL::Cell *cell, Hasher h) const From 4926e846f6a81de2a98c1df6ccde4e6c72cd2815 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 21 Aug 2025 00:22:37 +0000 Subject: [PATCH 45/47] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 5165db4a0..19fab9780 100644 --- a/Makefile +++ b/Makefile @@ -159,7 +159,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.56+152 +YOSYS_VER := 0.56+165 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 7f0130efce1ac96a0f4b4a30326ab98541258bd1 Mon Sep 17 00:00:00 2001 From: Ethan Mahintorabi Date: Wed, 20 Aug 2025 22:56:26 +0000 Subject: [PATCH 46/47] verilog: Fix missing sstream include Signed-off-by: Ethan Mahintorabi --- frontends/verilog/verilog_location.h | 1 + 1 file changed, 1 insertion(+) diff --git a/frontends/verilog/verilog_location.h b/frontends/verilog/verilog_location.h index 9b530fbeb..8ffe0552d 100644 --- a/frontends/verilog/verilog_location.h +++ b/frontends/verilog/verilog_location.h @@ -5,6 +5,7 @@ #include #include #include +#include /** * Provide frontend-wide location tracking like what bison generates From d10190606c34cc0d3b53679d32f5dd9448044dd4 Mon Sep 17 00:00:00 2001 From: Ethan Mahintorabi Date: Wed, 20 Aug 2025 22:58:51 +0000 Subject: [PATCH 47/47] verilog: Lower required bison version to 3.6 We're currently on version 3.6 of bison at Google, and Yosys still correctly builds with it. This should better reflect the actual requirements rather than an overly restrictive check. If features from 3.8 are required it seems like bumping would be appropriate. Signed-off-by: Ethan Mahintorabi --- frontends/verilog/verilog_parser.y | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index e299d3148..392d8921a 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -33,7 +33,7 @@ * */ -%require "3.8" +%require "3.6" %language "c++" %define api.value.type variant %define api.prefix {frontend_verilog_yy}