From bbceaa6b5e50aecc5bf8e4ab0cc03ad4abccd966 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 14 Oct 2025 14:59:32 +1300 Subject: [PATCH 01/97] docs: Note partial support of modports --- docs/source/using_yosys/verilog.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/source/using_yosys/verilog.rst b/docs/source/using_yosys/verilog.rst index 92f223e49..95c0168ba 100644 --- a/docs/source/using_yosys/verilog.rst +++ b/docs/source/using_yosys/verilog.rst @@ -370,7 +370,10 @@ from SystemVerilog: - array literals are currently not supported - SystemVerilog interfaces (SVIs) are supported. Modports for specifying whether - ports are inputs or outputs are supported. + ports are inputs or outputs are supported when used with named arguments, but + not positional arguments. i.e. ``driver_mod d0(.intf(intf0), + .in(inputs[0]));`` is supported but ``driver_mod d0(intf0, inputs[0]);`` is + not. - Assignments within expressions are supported. From 5cfe6a9c1ee66d810a5f40bedc57442dafd4b40d Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Fri, 8 Nov 2024 19:29:56 +0100 Subject: [PATCH 02/97] reduce OS ifdefs, refactor getting dirs and filenames from paths to files --- backends/cxxrtl/cxxrtl_backend.cc | 16 +--------------- frontends/ast/simplify.cc | 8 ++------ frontends/verilog/preproc.cc | 6 +----- kernel/io.cc | 19 +++++++++++++++++++ kernel/io.h | 2 ++ 5 files changed, 25 insertions(+), 26 deletions(-) diff --git a/backends/cxxrtl/cxxrtl_backend.cc b/backends/cxxrtl/cxxrtl_backend.cc index 48710aff8..d575b5879 100644 --- a/backends/cxxrtl/cxxrtl_backend.cc +++ b/backends/cxxrtl/cxxrtl_backend.cc @@ -637,20 +637,6 @@ std::string escape_cxx_string(const std::string &input) return output; } -std::string basename(const std::string &filepath) -{ -#ifdef _WIN32 - const std::string dir_seps = "\\/"; -#else - const std::string dir_seps = "/"; -#endif - size_t sep_pos = filepath.find_last_of(dir_seps); - if (sep_pos != std::string::npos) - return filepath.substr(sep_pos + 1); - else - return filepath; -} - template std::string get_hdl_name(T *object) { @@ -2858,7 +2844,7 @@ struct CxxrtlWorker { } if (split_intf) - f << "#include \"" << basename(intf_filename) << "\"\n"; + f << "#include \"" << name_from_file_path(intf_filename) << "\"\n"; else f << "#include \n"; f << "\n"; diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 81018e137..97abf7452 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -30,6 +30,7 @@ #include "libs/sha1/sha1.h" #include "frontends/verilog/verilog_frontend.h" #include "ast.h" +#include "kernel/io.h" #include #include @@ -4474,12 +4475,7 @@ std::unique_ptr AstNode::readmem(bool is_readmemh, std::string mem_file std::ifstream f; f.open(mem_filename.c_str()); if (f.fail()) { -#ifdef _WIN32 - char slash = '\\'; -#else - char slash = '/'; -#endif - std::string path = location.begin.filename->substr(0, location.begin.filename->find_last_of(slash)+1); + std::string path = parent_from_file_path(*location.begin.filename); f.open(path + mem_filename.c_str()); yosys_input_files.insert(path + mem_filename); } else { diff --git a/frontends/verilog/preproc.cc b/frontends/verilog/preproc.cc index 1858edc97..7675bab62 100644 --- a/frontends/verilog/preproc.cc +++ b/frontends/verilog/preproc.cc @@ -895,11 +895,7 @@ frontend_verilog_preproc(std::istream &f, // if the include file was not found, it is not given with an absolute path, and the // currently read file is given with a path, then try again relative to its directory ff.clear(); -#ifdef _WIN32 - fixed_fn = filename.substr(0, filename.find_last_of("/\\")+1) + fn; -#else - fixed_fn = filename.substr(0, filename.rfind('/')+1) + fn; -#endif + fixed_fn = parent_from_file_path(filename) + fn; ff.open(fixed_fn); } if (ff.fail() && fn.size() > 0 && fn_relative) { diff --git a/kernel/io.cc b/kernel/io.cc index 9e9eb9fb0..dfdb56d16 100644 --- a/kernel/io.cc +++ b/kernel/io.cc @@ -391,6 +391,25 @@ void append_globbed(std::vector& paths, std::string pattern) copy(globbed.begin(), globbed.end(), back_inserter(paths)); } +#ifdef _WIN32 +const char* const OS_PATH_SEP = "/\\"; +#else +const char* const OS_PATH_SEP = "/"; +#endif + +std::string name_from_file_path(std::string path) { + size_t sep_pos = path.find_last_of(OS_PATH_SEP); + if (sep_pos != std::string::npos) + return path.substr(sep_pos + 1); + else + return path; +} + +// Includes OS_PATH_SEP at the end if present +std::string parent_from_file_path(std::string path) { + return path.substr(0, path.find_last_of(OS_PATH_SEP)+1); +} + void format_emit_unescaped(std::string &result, std::string_view fmt) { result.reserve(result.size() + fmt.size()); diff --git a/kernel/io.h b/kernel/io.h index b3922bef0..171f47a80 100644 --- a/kernel/io.h +++ b/kernel/io.h @@ -470,6 +470,8 @@ void remove_directory(std::string dirname); bool create_directory(const std::string& dirname); std::string escape_filename_spaces(const std::string& filename); void append_globbed(std::vector& paths, std::string pattern); +std::string name_from_file_path(std::string path); +std::string parent_from_file_path(std::string path); YOSYS_NAMESPACE_END From 79cd4e08c4dc1828e697da722973c1be4c3d69ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emil=20Ji=C5=99=C3=AD=20Tywoniak?= Date: Tue, 23 Sep 2025 17:38:14 +0200 Subject: [PATCH 03/97] io: use std::filesystem --- kernel/io.cc | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/kernel/io.cc b/kernel/io.cc index dfdb56d16..45aa496b0 100644 --- a/kernel/io.cc +++ b/kernel/io.cc @@ -2,6 +2,7 @@ #include "kernel/log.h" #include #include +#include #if !defined(WIN32) #include @@ -398,16 +399,21 @@ const char* const OS_PATH_SEP = "/"; #endif std::string name_from_file_path(std::string path) { - size_t sep_pos = path.find_last_of(OS_PATH_SEP); - if (sep_pos != std::string::npos) - return path.substr(sep_pos + 1); - else - return path; + return std::filesystem::path(path).filename().string(); } // Includes OS_PATH_SEP at the end if present std::string parent_from_file_path(std::string path) { - return path.substr(0, path.find_last_of(OS_PATH_SEP)+1); + auto parent = std::filesystem::path(path).parent_path(); + if (parent.empty()) { + return ""; + } + // Add trailing separator to match original behavior + std::string result = parent.string(); + if (!result.empty() && result.back() != std::filesystem::path::preferred_separator) { + result += std::filesystem::path::preferred_separator; + } + return result; } void format_emit_unescaped(std::string &result, std::string_view fmt) From d1a628ab2664accf6cb58189c75e05c91c198695 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emil=20Ji=C5=99=C3=AD=20Tywoniak?= Date: Tue, 23 Sep 2025 17:38:32 +0200 Subject: [PATCH 04/97] CI: bump WASI SDK from 19 to 27 --- .github/workflows/extra-builds.yml | 4 ++-- Makefile | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/extra-builds.yml b/.github/workflows/extra-builds.yml index 503145e97..b22a399db 100644 --- a/.github/workflows/extra-builds.yml +++ b/.github/workflows/extra-builds.yml @@ -73,8 +73,8 @@ jobs: persist-credentials: false - name: Build run: | - WASI_SDK=wasi-sdk-19.0 - WASI_SDK_URL=https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-19/wasi-sdk-19.0-linux.tar.gz + WASI_SDK=wasi-sdk-27.0-x86_64-linux + WASI_SDK_URL=https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-27/wasi-sdk-27.0-x86_64-linux.tar.gz if ! [ -d ${WASI_SDK} ]; then curl -L ${WASI_SDK_URL} | tar xzf -; fi FLEX_VER=2.6.4 diff --git a/Makefile b/Makefile index b744763c8..04395a5a0 100644 --- a/Makefile +++ b/Makefile @@ -282,12 +282,11 @@ ifeq ($(WASI_SDK),) CXX = clang++ AR = llvm-ar RANLIB = llvm-ranlib -WASIFLAGS := -target wasm32-wasi --sysroot $(WASI_SYSROOT) $(WASIFLAGS) +WASIFLAGS := -target wasm32-wasi $(WASIFLAGS) else CXX = $(WASI_SDK)/bin/clang++ AR = $(WASI_SDK)/bin/ar RANLIB = $(WASI_SDK)/bin/ranlib -WASIFLAGS := --sysroot $(WASI_SDK)/share/wasi-sysroot $(WASIFLAGS) endif CXXFLAGS := $(WASIFLAGS) -std=$(CXXSTD) $(OPT_LEVEL) -D_WASI_EMULATED_PROCESS_CLOCKS $(filter-out -fPIC,$(CXXFLAGS)) LINKFLAGS := $(WASIFLAGS) -Wl,-z,stack-size=1048576 $(filter-out -rdynamic,$(LINKFLAGS)) From 1eb5181700e980a9a10c7c607e06c98755f8bc10 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 14 Oct 2025 14:12:24 +1300 Subject: [PATCH 05/97] Add tests/verilog/local_include.* `read_verilog` supports checking both the current directory and the source directory for relative includes. Make sure we aren't regressing that. --- tests/verilog/.gitignore | 2 ++ tests/verilog/local_include.sh | 30 ++++++++++++++++++++++++++++++ tests/verilog/local_include.v | 4 ++++ 3 files changed, 36 insertions(+) create mode 100755 tests/verilog/local_include.sh create mode 100644 tests/verilog/local_include.v diff --git a/tests/verilog/.gitignore b/tests/verilog/.gitignore index 3702f10cf..d3e8690d5 100644 --- a/tests/verilog/.gitignore +++ b/tests/verilog/.gitignore @@ -4,3 +4,5 @@ /roundtrip_proc_1.v /roundtrip_proc_2.v /assign_to_reg.v +/subdir +/temp_foo.v diff --git a/tests/verilog/local_include.sh b/tests/verilog/local_include.sh new file mode 100755 index 000000000..c10c7411b --- /dev/null +++ b/tests/verilog/local_include.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash + +set -eu + +# only works with read_verilog +yosys='../../yosys -f verilog' +test='-p hierarchy' +subdir=subdir +source=local_include.v +include=temp_foo.v + +# no include file should fail +rm -f $include +echo "logger -expect error $include 1; read_verilog $source" | $yosys + +# both files local +echo 'module foo (input a, output b); assign b = a; endmodule' > $include +$yosys $test $source + +# include local to cwd +mkdir -p $subdir +cp -t $subdir $source +$yosys $test $subdir/$source + +# include local to source +mv -t $subdir $include +$yosys $test $subdir/$source + +# include local to source, and source is given as an absolute path +$yosys $test $(pwd)/$subdir/$source diff --git a/tests/verilog/local_include.v b/tests/verilog/local_include.v new file mode 100644 index 000000000..a677e888e --- /dev/null +++ b/tests/verilog/local_include.v @@ -0,0 +1,4 @@ +`include "temp_foo.v" +module top (input x, output y); + foo bar (.a(x), .b(y)); +endmodule From 7bb0a1913e46cc205e89e1fda88eb31c85da4d86 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Wed, 15 Oct 2025 09:10:33 +1300 Subject: [PATCH 06/97] hierarchy.cc: Raise error on positional interface Add test to check that it does error. --- passes/hierarchy/hierarchy.cc | 69 +++++++++++++++++++-------- tests/svinterfaces/positional_args.ys | 33 +++++++++++++ tests/svinterfaces/run-test.sh | 1 + 3 files changed, 82 insertions(+), 21 deletions(-) create mode 100644 tests/svinterfaces/positional_args.ys mode change 100755 => 100644 tests/svinterfaces/run-test.sh diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc index ea68add18..c0e6a9104 100644 --- a/passes/hierarchy/hierarchy.cc +++ b/passes/hierarchy/hierarchy.cc @@ -156,6 +156,21 @@ std::string basic_cell_type(const std::string celltype, int pos[3] = nullptr) { return basicType; } +// Try to read an IdString as a numbered connection name ("$123" or similar), +// writing the result to dst. If the string isn't of the right format, ignore +// dst and return false. +bool read_id_num(RTLIL::IdString str, int *dst) +{ + log_assert(dst); + + const char *c_str = str.c_str(); + if (c_str[0] != '$' || !('0' <= c_str[1] && c_str[1] <= '9')) + return false; + + *dst = atoi(c_str + 1); + return true; +} + // A helper struct for expanding a module's interface connections in expand_module struct IFExpander { @@ -283,15 +298,42 @@ struct IFExpander RTLIL::IdString conn_name, const RTLIL::SigSpec &conn_signals) { - // Check if the connection is present as an interface in the sub-module's port list - const RTLIL::Wire *wire = submodule.wire(conn_name); - if (!wire || !wire->get_bool_attribute(ID::is_interface)) + // Does the connection look like an interface + const auto &bits = conn_signals; + if ( + bits.size() != 1 || + !bits[0].wire->get_bool_attribute(ID::is_interface) || + conn_signals[0].wire->name.str().find("$dummywireforinterface") != 0 + ) return; + // Check if the connection is present as an interface in the sub-module's port list + int id; + if (read_id_num(conn_name, &id)) { + /* Interface expansion is incompatible with positional arguments + * during expansion, the port list gets each interface signal + * inserted after the interface itself which means that the argument + * positions in the parent module no longer match. + * + * Supporting this would require expanding the interfaces in the + * parent module, renumbering the arguments to match, and then + * iterating over the ports list to find the matching interface + * (refactoring on_interface to accept different conn_names on the + * parent and child). + */ + log_error("Unable to connect `%s' to submodule `%s' with positional interface argument `%s'!\n", + module.name, + submodule.name, + conn_signals[0].wire->name.str().substr(23) + ); + } else { + // Lookup connection by name + const RTLIL::Wire *wire = submodule.wire(conn_name); + if (!wire || !wire->get_bool_attribute(ID::is_interface)) + return; + } // If the connection looks like an interface, handle it. - const auto &bits = conn_signals; - if (bits.size() == 1 && bits[0].wire->get_bool_attribute(ID::is_interface)) - on_interface(submodule, conn_name, conn_signals); + on_interface(submodule, conn_name, conn_signals); } // Iterate over the connections in a cell, tracking any interface @@ -376,21 +418,6 @@ RTLIL::Module *get_module(RTLIL::Design &design, return nullptr; } -// Try to read an IdString as a numbered connection name ("$123" or similar), -// writing the result to dst. If the string isn't of the right format, ignore -// dst and return false. -bool read_id_num(RTLIL::IdString str, int *dst) -{ - log_assert(dst); - - const char *c_str = str.c_str(); - if (c_str[0] != '$' || !('0' <= c_str[1] && c_str[1] <= '9')) - return false; - - *dst = atoi(c_str + 1); - return true; -} - // Check that the connections on the cell match those that are defined // on the type: each named connection should match the name of a port // and each positional connection should have an index smaller than diff --git a/tests/svinterfaces/positional_args.ys b/tests/svinterfaces/positional_args.ys new file mode 100644 index 000000000..6017a1c25 --- /dev/null +++ b/tests/svinterfaces/positional_args.ys @@ -0,0 +1,33 @@ +read_verilog -sv << EOF +interface simple_if; + logic receiver; + logic driver; +endinterface + +module driver_mod(simple_if intf, input in); + assign intf.driver = in; +endmodule + +module receiver_mod(simple_if intf); + assign intf.receiver = intf.driver; +endmodule + +module top( + input logic [1:0] inputs, + output logic [1:0] outputs +); + simple_if intf0(); + simple_if intf1(); + + driver_mod d0(intf0, inputs[0]); + driver_mod d1(intf1, inputs[1]); + + receiver_mod r0(intf0); + receiver_mod r1(intf1); + + assign outputs = {intf0.receiver, intf1.receiver}; +endmodule +EOF + +logger -expect error "Unable to connect.* with positional interface" 1 +hierarchy -top top diff --git a/tests/svinterfaces/run-test.sh b/tests/svinterfaces/run-test.sh old mode 100755 new mode 100644 index afa222766..71bdcd67a --- a/tests/svinterfaces/run-test.sh +++ b/tests/svinterfaces/run-test.sh @@ -5,3 +5,4 @@ ./run_simple.sh load_and_derive ./run_simple.sh resolve_types +./run_simple.sh positional_args From 37ba29482ef98c11ffea81185d5b869a6986f280 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Wed, 15 Oct 2025 09:17:52 +1300 Subject: [PATCH 07/97] docs: Amend modports support to all SVI Also some formatting fixes. --- docs/source/using_yosys/verilog.rst | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/docs/source/using_yosys/verilog.rst b/docs/source/using_yosys/verilog.rst index 95c0168ba..a557360b7 100644 --- a/docs/source/using_yosys/verilog.rst +++ b/docs/source/using_yosys/verilog.rst @@ -9,7 +9,7 @@ Yosys and there are currently no plans to add support for them: - Non-synthesizable language features as defined in - IEC 62142(E):2005 / IEEE Std. 1364.1(E):2002 + IEC 62142(E):2005 / IEEE Std. 1364.1(E):2002 - The ``tri``, ``triand`` and ``trior`` net types @@ -356,24 +356,29 @@ from SystemVerilog: files being read into the same design afterwards. - typedefs are supported (including inside packages) - - type casts are currently not supported + + - type casts are currently not supported - enums are supported (including inside packages) - - but are currently not strongly typed + + - but are currently not strongly typed - packed structs and unions are supported - - arrays of packed structs/unions are currently not supported - - structure literals are currently not supported + + - arrays of packed structs/unions are currently not supported + - structure literals are currently not supported - multidimensional arrays are supported - - array assignment of unpacked arrays is currently not supported - - array literals are currently not supported -- SystemVerilog interfaces (SVIs) are supported. Modports for specifying whether - ports are inputs or outputs are supported when used with named arguments, but - not positional arguments. i.e. ``driver_mod d0(.intf(intf0), - .in(inputs[0]));`` is supported but ``driver_mod d0(intf0, inputs[0]);`` is - not. + - array assignment of unpacked arrays is currently not supported + - array literals are currently not supported + +- SystemVerilog interfaces (SVIs), including modports for specifying whether + ports are inputs or outputs, are partially supported. + + - interfaces must be provided as *named* arguments, not positional arguments. + i.e. ``foo bar(.intf(intf0), .x(x));`` is supported but ``foo bar(intf0, + x);`` is not. - Assignments within expressions are supported. From 5d2d5441090c0621a7288735027af93f8e616899 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Wed, 15 Oct 2025 09:38:43 +1300 Subject: [PATCH 08/97] hierarchy.cc: Don't segfault --- passes/hierarchy/hierarchy.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc index c0e6a9104..bfdb80459 100644 --- a/passes/hierarchy/hierarchy.cc +++ b/passes/hierarchy/hierarchy.cc @@ -302,7 +302,9 @@ struct IFExpander const auto &bits = conn_signals; if ( bits.size() != 1 || + bits[0].wire == nullptr || !bits[0].wire->get_bool_attribute(ID::is_interface) || + conn_signals[0].wire == nullptr || conn_signals[0].wire->name.str().find("$dummywireforinterface") != 0 ) return; From 10a55119a9b1008b52f18c499a406dc9d3e25ec7 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Wed, 15 Oct 2025 09:42:47 +1300 Subject: [PATCH 09/97] hierarchy.cc: Tidying --- passes/hierarchy/hierarchy.cc | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc index bfdb80459..416997bee 100644 --- a/passes/hierarchy/hierarchy.cc +++ b/passes/hierarchy/hierarchy.cc @@ -299,12 +299,10 @@ struct IFExpander const RTLIL::SigSpec &conn_signals) { // Does the connection look like an interface - const auto &bits = conn_signals; if ( - bits.size() != 1 || - bits[0].wire == nullptr || - !bits[0].wire->get_bool_attribute(ID::is_interface) || + conn_signals.size() != 1 || conn_signals[0].wire == nullptr || + conn_signals[0].wire->get_bool_attribute(ID::is_interface) == false || conn_signals[0].wire->name.str().find("$dummywireforinterface") != 0 ) return; From c599d6a67e1ddd54afd503cdc245cb0234d1c54c Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Wed, 15 Oct 2025 09:49:53 +1300 Subject: [PATCH 10/97] tests/svinterfaces: re-chmod test script --- tests/svinterfaces/run-test.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 tests/svinterfaces/run-test.sh diff --git a/tests/svinterfaces/run-test.sh b/tests/svinterfaces/run-test.sh old mode 100644 new mode 100755 From 25aafab86b6c22f711fdd45cdd14f7721cfcffe1 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Thu, 23 Oct 2025 20:46:11 +0000 Subject: [PATCH 11/97] Set `port_id` for Verific PortBus wires --- frontends/verific/verific.cc | 1 + tests/verific/port_bus_order.ys | 13 +++++++++++++ 2 files changed, 14 insertions(+) create mode 100644 tests/verific/port_bus_order.ys diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index ff8932dac..5790e92f0 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -1576,6 +1576,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma SetIter si ; Port *port ; FOREACH_PORT_OF_PORTBUS(portbus, si, port) { + wire->port_id = nl->IndexOf(port) + 1; import_attributes(wire->attributes, port->GetNet(), nl, portbus->Size()); break; } diff --git a/tests/verific/port_bus_order.ys b/tests/verific/port_bus_order.ys new file mode 100644 index 000000000..8732582a2 --- /dev/null +++ b/tests/verific/port_bus_order.ys @@ -0,0 +1,13 @@ +verific -sv < Date: Wed, 22 Oct 2025 00:02:40 +0300 Subject: [PATCH 12/97] pyosys: fix regressions from 0.58 - consistently use value semantics for objects passed along FFI boundary (not ideal but matches previous behavior) - add new overload of RTLIL::Module: addMemory that does not require a "donor" object - the idea is `Module`, `Memory`, `Wire`, `Cell` and `Process` cannot be directly constructed in Python and can only be added to the existing memory hierarchy in `Design` using the `add` methods - `Memory` requiring a donor object was the odd one out here - fix superclass member wrapping only looking at direct superclass for inheritance instead of recursively checking superclasses - fix superclass member wrapping not using superclass's denylists - fix Design's `__str__` function not returning a string - fix the generator crashing if there's any `std::function` in a header - misc: add a crude `__repr__` based on `__str__` --- kernel/rtlil.cc | 8 ++ kernel/rtlil.h | 1 + pyosys/generator.py | 107 +++++++++++++++------- pyosys/wrappers_tpl.cc | 8 +- tests/pyosys/test_idstring_lifetime.py | 28 ++++++ tests/pyosys/test_indirect_inheritance.py | 15 +++ tests/pyosys/test_monitor.py | 2 +- 7 files changed, 135 insertions(+), 34 deletions(-) create mode 100644 tests/pyosys/test_idstring_lifetime.py create mode 100644 tests/pyosys/test_indirect_inheritance.py diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index aa4743a87..adfda7d5f 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -3088,6 +3088,14 @@ RTLIL::Cell *RTLIL::Module::addCell(RTLIL::IdString name, const RTLIL::Cell *oth return cell; } +RTLIL::Memory *RTLIL::Module::addMemory(RTLIL::IdString name) +{ + RTLIL::Memory *mem = new RTLIL::Memory; + mem->name = std::move(name); + memories[mem->name] = mem; + return mem; +} + RTLIL::Memory *RTLIL::Module::addMemory(RTLIL::IdString name, const RTLIL::Memory *other) { RTLIL::Memory *mem = new RTLIL::Memory; diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 394c6f25d..c68af4161 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1827,6 +1827,7 @@ public: RTLIL::Cell *addCell(RTLIL::IdString name, RTLIL::IdString type); RTLIL::Cell *addCell(RTLIL::IdString name, const RTLIL::Cell *other); + RTLIL::Memory *addMemory(RTLIL::IdString name); RTLIL::Memory *addMemory(RTLIL::IdString name, const RTLIL::Memory *other); RTLIL::Process *addProcess(RTLIL::IdString name); diff --git a/pyosys/generator.py b/pyosys/generator.py index 15b40a79e..65d886cf0 100644 --- a/pyosys/generator.py +++ b/pyosys/generator.py @@ -56,6 +56,7 @@ from cxxheaderparser.types import ( Variable, Array, FundamentalSpecifier, + FunctionType, ) __file_dir__ = Path(__file__).absolute().parent @@ -177,11 +178,11 @@ pyosys_headers = [ denylist=frozenset({"bits", "bitvectorize"}), ), PyosysClass("AttrObject", denylist=frozenset({"get_blackbox_attribute"})), - PyosysClass("NamedObject", denylist=frozenset({"get_blackbox_attribute"})), + PyosysClass("NamedObject"), PyosysClass("Selection"), # PyosysClass("Monitor"), # Virtual methods, manually bridged - PyosysClass("CaseRule", denylist=frozenset({"get_blackbox_attribute"})), - PyosysClass("SwitchRule", denylist=frozenset({"get_blackbox_attribute"})), + PyosysClass("CaseRule"), + PyosysClass("SwitchRule"), PyosysClass("SyncRule"), PyosysClass( "Process", @@ -219,7 +220,7 @@ pyosys_headers = [ ), PyosysClass( "Design", - string_expr="s.hashidx_", + string_expr="std::to_string(s.hashidx_)", hash_expr="s", denylist=frozenset({"selected_whole_modules"}), # deprecated ), @@ -241,13 +242,17 @@ class PyosysType: @classmethod def from_type(Self, type_obj, drop_const=False) -> "PyosysType": - const = type_obj.const and not drop_const + const = hasattr(type_obj, "const") and type_obj.const and not drop_const if isinstance(type_obj, Pointer): ptr_to = Self.from_type(type_obj.ptr_to) return Self("ptr", (ptr_to,), const) elif isinstance(type_obj, Reference): ref_to = Self.from_type(type_obj.ref_to) return Self("ref", (ref_to,), const) + elif isinstance(type_obj, FunctionType): + ret_type = Self.from_type(type_obj.return_type) + param_types = (Self.from_type(p.type) for p in type_obj.parameters) + return Self("fn", (ret_type, *param_types), False) assert isinstance( type_obj, Type ), f"unexpected c++ type object of type {type(type_obj)}" @@ -270,6 +275,16 @@ class PyosysType: if title == "Dict": key, value = self.specialization return f"{key.generate_identifier()}To{value.generate_identifier()}{title}" + elif title == "Fn": + identifier = self.specialization[0].generate_identifier() + if identifier == "Void": + identifier = "" + else: + identifier += "From" + identifier += "And".join( + p.generate_identifier() for p in self.specialization[1:] + ) + return identifier return ( "".join(spec.generate_identifier() for spec in self.specialization) + title @@ -283,6 +298,9 @@ class PyosysType: return const_prefix + f"{self.specialization[0].generate_cpp_name()} *" elif self.base == "ref": return const_prefix + f"{self.specialization[0].generate_cpp_name()} &" + elif self.base == "fn": + param_cpp_names = (s.generate_cpp_name() for s in self.specialization[1:]) + return f"{self.specialization[0].generate_cpp_name()}({','.join(param_cpp_names)})" else: return ( const_prefix @@ -301,7 +319,7 @@ class PyosysWrapperGenerator(object): self.f = wrapper_stream self.f_inc = header_stream self.found_containers: Dict[PyosysType, Any] = {} - self.class_registry: Dict[str, ClassScope] = {} + self.class_registry: Dict[str, Tuple[ClassScope, PyosysClass]] = {} # entry point def generate(self): @@ -380,7 +398,7 @@ class PyosysWrapperGenerator(object): if isinstance(type_info, Reference): return PyosysWrapperGenerator.find_containers(containers, type_info.ref_to) if not isinstance(type_info, Type): - return () + return {} segments = type_info.typename.segments containers_found = {} for segment in segments: @@ -411,19 +429,23 @@ class PyosysWrapperGenerator(object): def get_parameter_types(function: Function) -> str: return ", ".join(p.type.format() for p in function.parameters) - def register_containers(self, target: Union[Function, Field, Variable]): + def register_containers(self, target: Union[Function, Field, Variable]) -> bool: supported = ("dict", "idict", "pool", "set", "vector") + found = False if isinstance(target, Function): - self.found_containers.update( - self.find_containers(supported, target.return_type) - ) + return_type_containers = self.find_containers(supported, target.return_type) + found = found or len(return_type_containers) + self.found_containers.update(return_type_containers) for parameter in target.parameters: - self.found_containers.update( - self.find_containers(supported, parameter.type) - ) + parameter_containers = self.find_containers(supported, parameter.type) + found = found or len(parameter_containers) + self.found_containers.update(parameter_containers) else: - self.found_containers.update(self.find_containers(supported, target.type)) + variable_containers = self.find_containers(supported, target.type) + found = found or len(variable_containers) + self.found_containers.update(variable_containers) + return found # processors def get_overload_cast( @@ -470,9 +492,9 @@ class PyosysWrapperGenerator(object): def_args = [f'"{python_function_basename}"'] def_args.append(self.get_overload_cast(function, class_basename)) - for parameter in function.parameters: - # ASSUMPTION: there are no unnamed parameters in the yosys codebase - parameter_arg = f'py::arg("{parameter.name}")' + for i, parameter in enumerate(function.parameters): + name = parameter.name or f"arg{i}" + parameter_arg = f'py::arg("{name}")' if parameter.default is not None: parameter_arg += f" = {parameter.default.format()}" def_args.append(parameter_arg) @@ -525,8 +547,12 @@ class PyosysWrapperGenerator(object): if function.static: definition_fn = "def_static" + definition_args = self.get_definition_args( + function, metadata.name, python_name_override + ) + print( - f"\t\t\t.{definition_fn}({', '.join(self.get_definition_args(function, metadata.name, python_name_override))})", + f"\t\t\t.{definition_fn}({', '.join(definition_args)})", file=self.f, ) @@ -565,7 +591,7 @@ class PyosysWrapperGenerator(object): # care return - self.register_containers(field) + has_containers = self.register_containers(field) definition_fn = f"def_{'readonly' if field.type.const else 'readwrite'}" if field.static: @@ -573,8 +599,13 @@ class PyosysWrapperGenerator(object): field_python_basename = keyword_aliases.get(field.name, field.name) + def_args = [ + f'"{field_python_basename}"', + f"&{metadata.name}::{field.name}", + ] + def_args.append("py::return_value_policy::copy") print( - f'\t\t\t.{definition_fn}("{field_python_basename}", &{metadata.name}::{field.name})', + f"\t\t\t.{definition_fn}({', '.join(def_args)})", file=self.f, ) @@ -603,16 +634,20 @@ class PyosysWrapperGenerator(object): ) def process_class_members( - self, metadata: PyosysClass, cls: ClassScope, basename: str + self, + metadata: PyosysClass, + base_metadata: PyosysClass, + cls: ClassScope, + basename: str, ): for method in cls.methods: - if method.name.segments[-1].name in metadata.denylist: + if method.name.segments[-1].name in base_metadata.denylist: continue self.process_method(metadata, method) visited_anonymous_unions = set() for field_ in cls.fields: - if field_.name in metadata.denylist: + if field_.name in base_metadata.denylist: continue self.process_field(metadata, field_) @@ -627,6 +662,16 @@ class PyosysWrapperGenerator(object): for subfield in subclass.fields: self.process_field(metadata, subfield) + for base in cls.class_decl.bases: + if base.access != "public": + continue + name = base.typename.segments[-1].format() + if processed := self.class_registry.get(name): + base_scope, base_metadata = processed + self.process_class_members( + metadata, base_metadata, base_scope, basename + ) + def process_class( self, metadata: PyosysClass, @@ -638,7 +683,7 @@ class PyosysWrapperGenerator(object): segment.format() for segment in pqname.segments ] basename = full_path.pop() - self.class_registry[basename] = cls + self.class_registry[basename] = (cls, metadata) declaration_namespace = "::".join(full_path) tpl_args = [basename] @@ -649,19 +694,17 @@ class PyosysWrapperGenerator(object): file=self.f, ) - self.process_class_members(metadata, cls, basename) - for base in cls.class_decl.bases: - if base.access != "public": - continue - name = base.typename.segments[-1].format() - if base_scope := self.class_registry.get(name): - self.process_class_members(metadata, base_scope, basename) + self.process_class_members(metadata, metadata, cls, basename) if expr := metadata.string_expr: print( f'\t\t.def("__str__", [](const {basename} &s) {{ return {expr}; }})', file=self.f, ) + print( + f'\t\t.def("__repr__", [](const {basename} &s) {{ std::stringstream ss; ss << "<{basename} " << {expr} << ">"; return ss.str(); }})', + file=self.f, + ) if expr := metadata.hash_expr: print( diff --git a/pyosys/wrappers_tpl.cc b/pyosys/wrappers_tpl.cc index 5e77fef21..aa257e1b6 100644 --- a/pyosys/wrappers_tpl.cc +++ b/pyosys/wrappers_tpl.cc @@ -21,6 +21,12 @@ // #include #include +#include + +// duplicates for LSPs +#include "kernel/register.h" +#include "kernel/yosys_common.h" + #include "pyosys/hashlib.h" namespace py = pybind11; @@ -28,7 +34,7 @@ namespace py = pybind11; USING_YOSYS_NAMESPACE using std::set; -using std::regex; +using std::function; using std::ostream; using namespace RTLIL; diff --git a/tests/pyosys/test_idstring_lifetime.py b/tests/pyosys/test_idstring_lifetime.py new file mode 100644 index 000000000..4e6984474 --- /dev/null +++ b/tests/pyosys/test_idstring_lifetime.py @@ -0,0 +1,28 @@ + +from pyosys import libyosys as ys +from pathlib import Path + +__file_dir__ = Path(__file__).absolute().parent + +d = ys.Design() +ys.run_pass(f"read_verilog {__file_dir__ / 'spm.cut.v.gz'}", d) +ys.run_pass("hierarchy -top spm", d) + +external_idstring_holder_0 = None +external_idstring_holder_1 = None + +def get_top_module_idstring(): + global external_idstring_holder_0, external_idstring_holder_1 + d = ys.Design() + ys.run_pass(f"read_verilog {__file_dir__ / 'spm.cut.v.gz'}", d) + ys.run_pass("hierarchy -top spm", d) + external_idstring_holder_0 = d.top_module().name + for cell in d.top_module().cells_: + print(f"TARGETED: {cell}", flush=True) + external_idstring_holder_1 = cell + break + # d deallocates + +get_top_module_idstring() +print(external_idstring_holder_0, flush=True) +print(external_idstring_holder_1, flush=True) diff --git a/tests/pyosys/test_indirect_inheritance.py b/tests/pyosys/test_indirect_inheritance.py new file mode 100644 index 000000000..e29737e32 --- /dev/null +++ b/tests/pyosys/test_indirect_inheritance.py @@ -0,0 +1,15 @@ + +from pyosys import libyosys as ys +from pathlib import Path + +__file_dir__ = Path(__file__).absolute().parent + + +d = ys.Design() +ys.run_pass(f"read_verilog {__file_dir__ / 'spm.cut.v.gz'}", d) +ys.run_pass("hierarchy -top spm", d) + +for idstr, cell in d.top_module().cells_.items(): + cell.set_bool_attribute("\\set") + print(cell.attributes) + break diff --git a/tests/pyosys/test_monitor.py b/tests/pyosys/test_monitor.py index 2eefdad60..f9e435faa 100644 --- a/tests/pyosys/test_monitor.py +++ b/tests/pyosys/test_monitor.py @@ -14,7 +14,7 @@ class Monitor(ys.Monitor): self.mods.append(mod.name.str()) m = Monitor() -d.monitors.add(m) +d.monitors = [m] ys.run_pass(f"read_verilog {__file_dir__ / 'spm.cut.v.gz'}", d) ys.run_pass("hierarchy -top spm", d) From a27b1a83ae3d568994e2b898ea67513251b14a32 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Mon, 27 Oct 2025 20:32:12 +0000 Subject: [PATCH 13/97] Don't recompute hash using moved-out-of value --- kernel/hashlib.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/hashlib.h b/kernel/hashlib.h index ee27c85d6..ca600231a 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -1021,7 +1021,7 @@ protected: if (hashtable.empty()) { entries.emplace_back(std::forward(rvalue), -1); do_rehash(); - hash = do_hash(rvalue); + hash = do_hash(entries.back().udata); } else { entries.emplace_back(std::forward(rvalue), hashtable[hash]); hashtable[hash] = entries.size() - 1; From b2fe335b2d3270a565d5b46d7a64d4c8b88800bb Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Tue, 28 Oct 2025 13:01:26 +0100 Subject: [PATCH 14/97] dfflibmap: fix next_state inversion propagation for DFF flops by inverting reset value polarity --- passes/techmap/dfflibmap.cc | 7 ++++++ tests/techmap/dfflibmap_dff_not_next.lib | 24 ++++++++++++++++++ tests/techmap/dfflibmap_formal.ys | 31 ++++++++++++++++++++++++ 3 files changed, 62 insertions(+) create mode 100644 tests/techmap/dfflibmap_dff_not_next.lib diff --git a/passes/techmap/dfflibmap.cc b/passes/techmap/dfflibmap.cc index f2bd16082..6d55d1b43 100644 --- a/passes/techmap/dfflibmap.cc +++ b/passes/techmap/dfflibmap.cc @@ -271,6 +271,13 @@ static void find_cell(std::vector cells, IdString cell_type, continue; if (!parse_next_state(cell, ff->find("next_state"), cell_next_pin, cell_next_pol, cell_enable_pin, cell_enable_pol) || (has_enable && (cell_enable_pin.empty() || cell_enable_pol != enapol))) continue; + + if (has_reset && !cell_next_pol) { + // next_state is negated + // we later propagate this inversion to the output, + // which requires the negation of the reset value + rstval = !rstval; + } if (has_reset && rstval == false) { if (!parse_pin(cell, ff->find("clear"), cell_rst_pin, cell_rst_pol) || cell_rst_pol != rstpol) continue; diff --git a/tests/techmap/dfflibmap_dff_not_next.lib b/tests/techmap/dfflibmap_dff_not_next.lib new file mode 100644 index 000000000..0a0b011de --- /dev/null +++ b/tests/techmap/dfflibmap_dff_not_next.lib @@ -0,0 +1,24 @@ +library (test_not_next) { + cell (dff_not_next) { + area: 1.0; + pin (QN) { + direction : output; + function : "STATE"; + } + pin (CLK) { + direction : input; + clock : true; + } + pin (D) { + direction : input; + } + pin (RN) { + direction : input; + } + ff (STATE, STATEN) { + clocked_on: "CLK"; + next_state: "!D"; + preset : "!RN"; + } + } +} diff --git a/tests/techmap/dfflibmap_formal.ys b/tests/techmap/dfflibmap_formal.ys index 11c90ea6c..71a52a261 100644 --- a/tests/techmap/dfflibmap_formal.ys +++ b/tests/techmap/dfflibmap_formal.ys @@ -108,6 +108,37 @@ copy top top_unmapped simplemap top dfflibmap -liberty dfflibmap_dffn_dffe.lib -liberty dfflibmap_dffsr_not_next.lib top +async2sync +flatten +opt_clean -purge +equiv_make top top_unmapped equiv +equiv_induct equiv +equiv_status -assert equiv + +################################################################## + +design -reset +read_verilog < Date: Wed, 29 Oct 2025 12:48:21 +1000 Subject: [PATCH 15/97] Gowin. Fix GW5A ADCs. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For these primitives, Gowin decided to use a different option for describing ports—directly in the module header, i.e. ``` verilog module ADC(input CLK); ``` instead of ``` verilog module ADC(CLK); input CLK; ``` Since this one-time parser becomes too confusing, it is easier to simply add ADC descriptions as they are from a separate file, especially since these primitives are only available in the GW5A series. Test: ``` shell yosys -p "read_verilog top.v; synth_gowin -json top-synth.json -family gw5a" ``` The old version of Yosys simply won't compile the design due to the lack of port descriptions, while the new version will compile without errors. Signed-off-by: YRabbit --- techlibs/gowin/adc.v | 260 +++++++++++++++++++++++ techlibs/gowin/cells_xtra.py | 10 + techlibs/gowin/cells_xtra_gw5a.v | 346 +++++++++++++++++++++++-------- 3 files changed, 533 insertions(+), 83 deletions(-) create mode 100644 techlibs/gowin/adc.v diff --git a/techlibs/gowin/adc.v b/techlibs/gowin/adc.v new file mode 100644 index 000000000..a5bb13bde --- /dev/null +++ b/techlibs/gowin/adc.v @@ -0,0 +1,260 @@ +/********ADC***********/ +//ADC for LRC,GW5AT-138K +module ADCLRC ( +//Voltage signal source, /mV + input ADCINBK2A, //input from bank2 IO, adc_in_b is the reference + input ADCINBK2B, //input from bank2 IO, adc_in_b is the reference + input ADCINBK3A, //input from bank3 IO, adc_in_b is the reference + input ADCINBK3B, //input from bank3 IO, adc_in_b is the reference + input ADCINBK4A, //input from bank4 IO, adc_in_b is the reference + input ADCINBK4B, //input from bank4 IO, adc_in_b is the reference + input ADCINBK5A, //input from bank5 IO, adc_in_b is the reference + input ADCINBK5B, //input from bank5 IO, adc_in_b is the reference + +//control signal + input [2:0] VSENCTL, //Input source selection (ciu), from 0 to 7: adcv, adct, vdd09_0, vdd09_1, vdd18_0, vdd18_1, vdd33_0, vdd33_1 + + input [9:0] FSCAL_VALUE, // temperature mode 510~948, typical value 730; Voltage mode 452~840, typical value 653 + input [11:0] OFFSET_VALUE, //signed number, temperature mode - 1560~- 760, typical value - 1180; Voltage mode - 410~410, typical value 0 + + input ADCEN, //Enable signal, active high + input CLK, //clk input,1/2 shared + input DRSTN, //0/1 shared, Digital part reset signal, active low + input ADCREQI, //Measurement request signal, valid rising edge, asynchronous signal + + //output + output ADCRDY, //The measurement completion signal, active high + output [13:0] ADCVALUE //The measurement result output, signed number. In voltage mode,/2048 is the actual measured value; In temperature mode,/4 is the actual measured value + +); + + parameter DYN_BKEN = "FALSE";//"FALSE","TRUE"."TRUE",BUF_BK2_EN[0]&BUF_BK3_EN[0]=1 +//Input source selection,1/2 shared + parameter BUF_SERDES_Q1_EN = 3'b000; //[1:0] does not support "11" + parameter BUF_BK2_EN = 6'b000000; //[3:0] Only one bit can be 1 at the same time + parameter BUF_BK3_EN = 6'b000000; //[3:0] Only one bit can be 1 at the same time + parameter BUF_BK4_EN = 6'b000000; //[3:0] Only one bit can be 1 at the same time + parameter BUF_BK5_EN = 6'b000000; //[3:0] Only one bit can be 1 at the same time + parameter BUF_BK10_EN = 5'b00000; //[3:1] Only one bit can be 1 at the same time + parameter BUF_BK11_EN = 5'b00000; //[3:1] Only one bit can be 1 at the same time +//Analog terminal option + parameter CLK_SEL = 1'b0; //Clock source selection. 0,PIOCLK_SEL,1,ciu_clk + parameter PIOCLK_SEL = 1'b0; //Clock source selection. 1/2 shared,0,mck_adc_clk_osc,1,io_clk + parameter VSEN_CTL = 3'b000; //Input source selection + parameter VSEN_CTL_SEL = 1'b0; //vsen_ctl source selection,0,VSEN_CTL,1,ciu_vsen_ctl + parameter ADC_MODE = 1'b0; //Mode selection + parameter DIV_CTL = 2'd0; //clock division,0:/1,1:/2,2:/4,3:/8,Clock after frequency division, 500kHz~8MHz + + //Digital terminal options + parameter SAMPLE_CNT_SEL = 3'd4; //total samples configuration, 0~4:64, 128, 256, 512, 1024 sampling points, and the other values are 2048 sampling points.The total number of samples shall be greater than 7 * sampling period, i.e. SAMPLR_CNT_SEL >= RATE_CHANGE_CTRL-1 + parameter RATE_CHANGE_CTRL = 3'd4; //Sampling period configuration, 0~4:4、8、16、32、64,other values are 128 + + +endmodule + +//ADCULC,GW5AT-138K +module ADCULC ( + + //Voltage signal source, /mV + input ADCINBK6A, //input from bank6 IO, adc_in_b is the reference + input ADCINBK6B, //input from bank6 IO, adc_in_b is the reference + input ADCINBK7A, //input from bank7 IO, adc_in_b is the reference + input ADCINBK7B, //input from bank7 IO, adc_in_b is the reference + + //control signal + input [2:0] VSENCTL, //Input source selection(cib),0~7: vtest, vdd09_0, vdd09_1, vdd09_2, vdd18_0, vdd18_1, reserved, vdd33 + + input [9:0] FSCAL_VALUE, // temperature mode 510~948, typical value 730; Voltage mode 452~840, typical value 653 + input [11:0] OFFSET_VALUE, //signed number, temperature mode - 1560~- 760, typical value - 1180; Voltage mode - 410~410, typical value 0 + + input ADCEN, //Enable signal, active high + input CLK, //clk input + input DRSTN, //0/1 shared, Digital part reset signal, active low + input ADCREQI, //Measurement request signal, valid rising edge, asynchronous signal + output ADCRDY, //The measurement completion signal, active high + output [13:0] ADCVALUE //The measurement result output, signed number. In voltage mode,/2048 is the actual measured value; In temperature mode,/4 is the actual measured value + +); + parameter DYN_BKEN = "FALSE";//"FALSE","TRUE"."TRUE",BUF_BK6_EN[0]&BUF_BK7_EN[0]=1 + +//Input source selection + parameter BUF_VCC_EN = 1'b0; //ulc + parameter BUF_VCCM_EN = 1'b0; //ulc + parameter BUF_MIPI_M0_EN = 3'b000; //ulc,[1:0] Only one bit can be 1 at the same time + parameter BUF_MIPI_M1_EN = 3'b000; //ulc,[1:0] Only one bit can be 1 at the same time + parameter BUF_SERDES_Q0_EN = 3'b000; //ulc,[1:0] Only one bit can be 1 at the same time + parameter BUF_BK6_EN = 6'b000000; //bk6,[3:0] Only one bit can be 1 at the same time + parameter BUF_BK7_EN = 6'b000000; //bk7,[3:0] Only one bit can be 1 at the same time +//Analog terminal option + parameter CLK_SEL = 1'b0; //Clock source selection. 0,PIOCLK_SEL,1,ciu_clk + parameter PIOCLK_SEL = 1'b0; //Clock source selection. 1/2 shared,0,mck_adc_clk_osc,1,io_clk + parameter VSEN_CTL = 3'b000; //Input source selection + parameter VSEN_CTL_SEL = 1'b0; //vsen_ctl source selection,0,VSEN_CTL,1,ciu_vsen_ctl + parameter ADC_MODE = 1'b0; //Mode selection + parameter DIV_CTL = 2'd0; //clock division,0:/1,1:/2,2:/4,3:/8,Clock after frequency division, 500kHz~8MHz + +//Digital terminal options + parameter SAMPLE_CNT_SEL = 3'd4; //total samples configuration, 0~4:64, 128, 256, 512, 1024 sampling points, and the other values are 2048 sampling points.The total number of samples shall be greater than 7 * sampling period, i.e. SAMPLR_CNT_SEL >= RATE_CHANGE_CTRL-1 + parameter RATE_CHANGE_CTRL = 3'd4; //Sampling period configuration, 0~4:4、8、16、32、64,other values are 128 + +endmodule + + +//ADC,GW5A-25 +module ADC ( + + //control signal + input CLK, //clk input + input [2:0] VSENCTL, //Input source selection (ciu), from 0 to 7: glo_left,glo_right,loc_left,vtest,vcc_rt,vccc_rt,vccm_rt,vccx_buf + input ADCMODE, //Mode selection,0:temperature mode,1:voltage mode + input DRSTN, //Digital part reset signal, active low + input ADCREQI, //Measurement request signal, valid rising edge, asynchronous signal + output ADCRDY, //The measurement completion signal, active high + output [13:0] ADCVALUE, //The measurement result output, signed number. In voltage mode,/2048 is the actual measured value; In temperature mode,/4 is the actual measured value + //mdrp + input MDRP_CLK, //mdrp clock + input [7:0] MDRP_WDATA, //mdrp write data + input MDRP_A_INC, //mdrp self-increased address + input [1:0] MDRP_OPCODE, //mdrp opcode + output [7:0] MDRP_RDATA, //mdrp read data + input ADCEN //Enable signal, active high + +); + + //Analog terminal option + parameter CLK_SEL = 1'b0; //时钟源选择,0:osc(2.5MHz),1:CLK + parameter DIV_CTL = 2'd0; //clock division,0:/1,1:/2,2:/4,3:/8,Clock after frequency division, 500kHz~8MHz + + //Input source selection + parameter BUF_EN = 12'b000000000000; // + parameter BUF_BK0_VREF_EN = 1'b0; // + parameter BUF_BK1_VREF_EN = 1'b0; // + parameter BUF_BK2_VREF_EN = 1'b0; // + parameter BUF_BK3_VREF_EN = 1'b0; // + parameter BUF_BK4_VREF_EN = 1'b0; // + parameter BUF_BK5_VREF_EN = 1'b0; // + parameter BUF_BK6_VREF_EN = 1'b0; // + parameter BUF_BK7_VREF_EN = 1'b0; // + + //Digital terminal options + parameter CSR_ADC_MODE = 1'b1; // Mode selection + parameter CSR_VSEN_CTRL = 3'd0; // signal source:vccx/vccio_*/vcc_reg -> 7, signal source:vcc_ext -> 4, others -> 0 + parameter CSR_SAMPLE_CNT_SEL = 3'd4; // total samples configuration, 0~4:64, 128, 256, 512, 1024 sampling points, and the other values are 2048 sampling points.The total number of samples shall be greater than 7 * sampling period, i.e. SAMPLR_CNT_SEL >= RATE_CHANGE_CTRL-1 + parameter CSR_RATE_CHANGE_CTRL = 3'd4; // Sampling period configuration, 0~4:4、8、16、32、64,other values are 128 + parameter CSR_FSCAL = 10'd730; // Parameter 1: temperature mode 510~948, typical value 730; Voltage mode 452~840, typical value 653 + parameter CSR_OFFSET = -12'd1180; // Parameter 2, signed number, temperature mode - 1560~- 760, typical value - 1180; Voltage mode - 410~410, typical value 0 + + +endmodule + + +//ADC_SAR,integrated saradc and adc functions. +module ADC_SAR ( +//`ifdef ADC + input ADCMODE, //Mode selection + input [2:0] VSENCTL, //Input source selection + input CLK, //clk input + //Digital + output ADCENO, //Enable signal, active high + input DRSTN, //Digital part reset signal, active low + input ADCREQI, //Measurement request signal + output ADCRDY, //The measurement completion signal, active high + output [13:0] ADCVALUE, //The measurement result output + input MDRP_CLK, //mdrp clock + input [7:0] MDRP_WDATA, //mdrp write data + input MDRP_A_INC, //mdrp self-increased address + input [1:0] MDRP_OPCODE,//mdrp opcode + output [7:0] MDRP_RDATA, //mdrp read data + //Analog + output ADC1BIT, //Analog data output + output ADCCLKO, //Analog clock output + input ADCENI, //fabric adc enable input +//`endif +// SAR +//`ifdef SARADC + output [12:0] ADCBIT, //Measurement result output + output CLKO, //output clk + output EOC, //The measurement completion signal + input CLKI, //fabric input clk + input [6:0] CHEN, //channel select + input RSTN, //resetn,active low + input SOC //Measurement request signal +//`endif +); + + parameter BUF_EN = 29'b0; // signal source selecor switch +// Δ-Σ +//`ifdef ADC + parameter CLK_SEL = 1'b1; // clk source select + parameter DIV_CTL = 2'd0; // clock division.0:/1,1:/2,2:/4,3:/8 + parameter ADC_EN_SEL = 1'b0; // adc_en source select + parameter PHASE_SEL = 1'b0; // adc internal data phase select + + //Digital terminal options + parameter CSR_ADC_MODE = 1'b1; // Mode selection + parameter CSR_VSEN_CTRL = 3'd0; // signal source:vccx/vccio_*/vcc_reg -> 7, signal source:vcc_ext -> 4, others -> 0 + parameter CSR_SAMPLE_CNT_SEL = 3'd4; // total samples configuration, 0~4:64, 128, 256, 512, 1024 sampling points, and the other values are 2048 sampling points.The total number of samples shall be greater than 7 * sampling period, i.e. SAMPLR_CNT_SEL >= RATE_CHANGE_CTRL-1 + parameter CSR_RATE_CHANGE_CTRL = 3'd4; // Sampling period configuration, 0~4:4、8、16、32、64,other values are 128 + parameter CSR_FSCAL = 10'd730; // Parameter 1: temperature mode 510~948, typical value 730; Voltage mode 452~840, typical value 653 + parameter CSR_OFFSET = -12'd1180; // Parameter 2, signed number, temperature mode - 1560~- 760, typical value - 1180; Voltage mode - 410~410, typical value 0 + +//`endif +// SAR +//`ifdef SARADC + parameter ADC_CLK_DIV = 2'b00; // clock division.00:/1,01:/2,10:/4,11:/8 + parameter ADC_CLKDIV_EN = 1'b0; // clock division enable + parameter CLK_SRC_SEL = 1'b1; // source clock sel + parameter VREF_BUF_EN = 1'b1; // BGR vref buffer enable + parameter COUNT_LEN = 5'b10100; // ADC counter length + parameter DAC_SAMPLE_END = 5'b10010; // DAC sample end point + parameter DAC_SAMPLE_START = 5'b01101; // DAC sample start point + parameter SH_SAMPLE_END = 5'b01011; // SH sample start point + parameter SH_SAMPLE_START = 5'b00001; // SH sample end point + parameter AUTO_CHOP_EN = 1'b0; // auto chop + parameter CHOP_CLK_DIV = 4'b0; // chop clock divider + +//`endif + +endmodule + + +//ADCA,15k +module ADCA ( +// analog + input ADCMODE, //Mode selection + input [2:0] VSENCTL, //Input source selection 0-7: vglo_left, vglo_right, vcc2, vccc3, vccb4, vcc5, vccm6, vccc7 + input CLK, //clk input + input ADCENI, //fabric adc enable input + input PWRON_DYN, //power enable. 1:on 0:off + // digital + input DRSTN, //Digital part reset signal, active low + input ADCREQI, //Measurement request signal + output ADCRDY, //The measurement completion signal, active high + output [13:0] ADCVALUE, //The measurement result output + input MDRP_CLK, //mdrp clock + input [7:0] MDRP_WDATA, //mdrp write data + input MDRP_A_INC, //mdrp self-increased address + input [1:0] MDRP_OPCODE,//mdrp opcode + output [7:0] MDRP_RDATA //mdrp read data +); + + parameter BUF_EN = 20'b0; // signal source selecor switch //[8:0] one-hot; [19:15] one-hot. BUF_EN[6] must be 0 + parameter CLK_SEL = 1'b1; // clk source select + parameter DIV_CTL = 2'd0; // clock division + parameter ADC_EN_SEL = 1'b0; // adc_en source select + parameter PHASE_SEL = 1'b0; // adc internal data phase select + + parameter PWRON_SEL = 1'b0; // power enbale source select. 0:PWRON 1:PWRON_DYN + parameter PWRON = 1'b1; // as PWRON_DYN + parameter LDO_MODE = 1'b0; // LDO mode 0:on(2.5/3.3V) 1:off(1.8V) + + //Digital terminal options + parameter CSR_ADC_MODE = 1'b1; // Mode selection + parameter CSR_VSEN_CTRL = 3'd0; // signal source:vccx/vccio_*/vcc_reg -> 7, signal source:vcc_ext -> 4, others -> 0 + parameter CSR_SAMPLE_CNT_SEL = 3'd4; // total samples configuration, 0~4:64, 128, 256, 512, 1024 sampling points, and the other values are 2048 sampling points.The total number of samples shall be greater than 7 * sampling period, i.e. SAMPLR_CNT_SEL >= RATE_CHANGE_CTRL-1 + parameter CSR_RATE_CHANGE_CTRL = 3'd4; // Sampling period configuration, 0~4:4、8、16、32、64,other values are 128 + parameter CSR_FSCAL = 10'd730; // Parameter 1: temperature mode 510~948, typical value 730; Voltage mode 452~840, typical value 653 + parameter CSR_OFFSET = -12'd1180; // Parameter 2, signed number, temperature mode - 1560~- 760, typical value - 1180; Voltage mode - 410~410, typical value 0 + +endmodule + diff --git a/techlibs/gowin/cells_xtra.py b/techlibs/gowin/cells_xtra.py index 01416268a..7e8253a6b 100644 --- a/techlibs/gowin/cells_xtra.py +++ b/techlibs/gowin/cells_xtra.py @@ -32,6 +32,8 @@ _skip = { # These are already described, no need to extract them from the vendor 'DLNC', 'DLNCE', 'DLNP', 'DLNPE', 'rSDP', 'rSDPX9', 'rROM', 'rROMX9', 'TLVDS_OEN_BK', 'DLL', 'DCC', 'I3C', 'IODELAYA', 'IODELAYC', 'IODELAYB', 'SPMI', 'PLLO', 'DCCG', 'MIPI_DPHY_RX', 'CLKDIVG', 'PWRGRD', 'FLASH96KA', + # ADCs are in a separate file + 'ADCLRC', 'ADCULC', 'ADC', 'ADC_SAR', 'ADCA', } def xtract_cells_decl(dir, fout): fname = os.path.join(dir, 'prim_sim.v') @@ -94,3 +96,11 @@ if __name__ == '__main__': fout.write('// Created by cells_xtra.py\n') fout.write('\n') xtract_cells_decl(dir, fout) + if family == 'gw5a': + fout.write('\n') + fout.write('// Added from adc.v\n') + fout.write('\n') + with open(f'adc.v', 'r') as fin: + for l in fin: + fout.write(l); + diff --git a/techlibs/gowin/cells_xtra_gw5a.v b/techlibs/gowin/cells_xtra_gw5a.v index b4df1f33e..b2dc06236 100644 --- a/techlibs/gowin/cells_xtra_gw5a.v +++ b/techlibs/gowin/cells_xtra_gw5a.v @@ -1720,89 +1720,6 @@ input SPIAD; input LOAD; endmodule -module ADCLRC (...); - parameter DYN_BKEN = "FALSE"; - parameter BUF_SERDES_Q1_EN = 3'b000; - parameter BUF_BK2_EN = 6'b000000; - parameter BUF_BK3_EN = 6'b000000; - parameter BUF_BK4_EN = 6'b000000; - parameter BUF_BK5_EN = 6'b000000; - parameter BUF_BK10_EN = 5'b00000; - parameter BUF_BK11_EN = 5'b00000; - parameter CLK_SEL = 1'b0; - parameter PIOCLK_SEL = 1'b0; - parameter VSEN_CTL = 3'b000; - parameter VSEN_CTL_SEL = 1'b0; - parameter ADC_MODE = 1'b0; - parameter DIV_CTL = 2'd0; - parameter SAMPLE_CNT_SEL = 3'd4; - parameter RATE_CHANGE_CTRL = 3'd4; -endmodule - -module ADCULC (...); - parameter DYN_BKEN = "FALSE"; - parameter BUF_VCC_EN = 1'b0; - parameter BUF_VCCM_EN = 1'b0; - parameter BUF_MIPI_M0_EN = 3'b000; - parameter BUF_MIPI_M1_EN = 3'b000; - parameter BUF_SERDES_Q0_EN = 3'b000; - parameter BUF_BK6_EN = 6'b000000; - parameter BUF_BK7_EN = 6'b000000; - parameter CLK_SEL = 1'b0; - parameter PIOCLK_SEL = 1'b0; - parameter VSEN_CTL = 3'b000; - parameter VSEN_CTL_SEL = 1'b0; - parameter ADC_MODE = 1'b0; - parameter DIV_CTL = 2'd0; - parameter SAMPLE_CNT_SEL = 3'd4; - parameter RATE_CHANGE_CTRL = 3'd4; -endmodule - -module ADC (...); - parameter CLK_SEL = 1'b0; - parameter DIV_CTL = 2'd0; - parameter BUF_EN = 12'b000000000000; - parameter BUF_BK0_VREF_EN = 1'b0; - parameter BUF_BK1_VREF_EN = 1'b0; - parameter BUF_BK2_VREF_EN = 1'b0; - parameter BUF_BK3_VREF_EN = 1'b0; - parameter BUF_BK4_VREF_EN = 1'b0; - parameter BUF_BK5_VREF_EN = 1'b0; - parameter BUF_BK6_VREF_EN = 1'b0; - parameter BUF_BK7_VREF_EN = 1'b0; - parameter CSR_ADC_MODE = 1'b1; - parameter CSR_VSEN_CTRL = 3'd0; - parameter CSR_SAMPLE_CNT_SEL = 3'd4; - parameter CSR_RATE_CHANGE_CTRL = 3'd4; - parameter CSR_FSCAL = 10'd730; - parameter CSR_OFFSET = -12'd1180; -endmodule - -module ADC_SAR (...); - parameter BUF_EN = 29'b0; - parameter CLK_SEL = 1'b1; - parameter DIV_CTL = 2'd2; - parameter ADC_EN_SEL = 1'b0; - parameter PHASE_SEL = 1'b0; - parameter CSR_ADC_MODE = 1'b1; - parameter CSR_VSEN_CTRL = 3'd0; - parameter CSR_SAMPLE_CNT_SEL = 3'd4; - parameter CSR_RATE_CHANGE_CTRL = 3'd4; - parameter CSR_FSCAL = 10'd730; - parameter CSR_OFFSET = -12'd1180; - parameter ADC_CLK_DIV = 2'b00; - parameter ADC_CLKDIV_EN = 1'b0; - parameter CLK_SRC_SEL = 1'b1; - parameter VREF_BUF_EN = 1'b1; - parameter COUNT_LEN = 5'b10100; - parameter DAC_SAMPLE_END = 5'b10010; - parameter DAC_SAMPLE_START = 5'b01101; - parameter SH_SAMPLE_END = 5'b01011; - parameter SH_SAMPLE_START = 5'b00001; - parameter AUTO_CHOP_EN = 1'b0; - parameter CHOP_CLK_DIV = 4'b0; -endmodule - module LICD (...); parameter STAGE_NUM = 2'b00; parameter ENCDEC_NUM = 2'b00; @@ -2575,3 +2492,266 @@ parameter RD_PNTR = 3'b000; parameter DQS_MODE = "X1"; parameter HWL = "false"; endmodule + +// Added form adc.v + +/********ADC***********/ +//ADC for LRC,GW5AT-138K +module ADCLRC ( +//Voltage signal source, /mV + input ADCINBK2A, //input from bank2 IO, adc_in_b is the reference + input ADCINBK2B, //input from bank2 IO, adc_in_b is the reference + input ADCINBK3A, //input from bank3 IO, adc_in_b is the reference + input ADCINBK3B, //input from bank3 IO, adc_in_b is the reference + input ADCINBK4A, //input from bank4 IO, adc_in_b is the reference + input ADCINBK4B, //input from bank4 IO, adc_in_b is the reference + input ADCINBK5A, //input from bank5 IO, adc_in_b is the reference + input ADCINBK5B, //input from bank5 IO, adc_in_b is the reference + +//control signal + input [2:0] VSENCTL, //Input source selection (ciu), from 0 to 7: adcv, adct, vdd09_0, vdd09_1, vdd18_0, vdd18_1, vdd33_0, vdd33_1 + + input [9:0] FSCAL_VALUE, // temperature mode 510~948, typical value 730; Voltage mode 452~840, typical value 653 + input [11:0] OFFSET_VALUE, //signed number, temperature mode - 1560~- 760, typical value - 1180; Voltage mode - 410~410, typical value 0 + + input ADCEN, //Enable signal, active high + input CLK, //clk input,1/2 shared + input DRSTN, //0/1 shared, Digital part reset signal, active low + input ADCREQI, //Measurement request signal, valid rising edge, asynchronous signal + + //output + output ADCRDY, //The measurement completion signal, active high + output [13:0] ADCVALUE //The measurement result output, signed number. In voltage mode,/2048 is the actual measured value; In temperature mode,/4 is the actual measured value + +); + + parameter DYN_BKEN = "FALSE";//"FALSE","TRUE"."TRUE",BUF_BK2_EN[0]&BUF_BK3_EN[0]=1 +//Input source selection,1/2 shared + parameter BUF_SERDES_Q1_EN = 3'b000; //[1:0] does not support "11" + parameter BUF_BK2_EN = 6'b000000; //[3:0] Only one bit can be 1 at the same time + parameter BUF_BK3_EN = 6'b000000; //[3:0] Only one bit can be 1 at the same time + parameter BUF_BK4_EN = 6'b000000; //[3:0] Only one bit can be 1 at the same time + parameter BUF_BK5_EN = 6'b000000; //[3:0] Only one bit can be 1 at the same time + parameter BUF_BK10_EN = 5'b00000; //[3:1] Only one bit can be 1 at the same time + parameter BUF_BK11_EN = 5'b00000; //[3:1] Only one bit can be 1 at the same time +//Analog terminal option + parameter CLK_SEL = 1'b0; //Clock source selection. 0,PIOCLK_SEL,1,ciu_clk + parameter PIOCLK_SEL = 1'b0; //Clock source selection. 1/2 shared,0,mck_adc_clk_osc,1,io_clk + parameter VSEN_CTL = 3'b000; //Input source selection + parameter VSEN_CTL_SEL = 1'b0; //vsen_ctl source selection,0,VSEN_CTL,1,ciu_vsen_ctl + parameter ADC_MODE = 1'b0; //Mode selection + parameter DIV_CTL = 2'd0; //clock division,0:/1,1:/2,2:/4,3:/8,Clock after frequency division, 500kHz~8MHz + + //Digital terminal options + parameter SAMPLE_CNT_SEL = 3'd4; //total samples configuration, 0~4:64, 128, 256, 512, 1024 sampling points, and the other values are 2048 sampling points.The total number of samples shall be greater than 7 * sampling period, i.e. SAMPLR_CNT_SEL >= RATE_CHANGE_CTRL-1 + parameter RATE_CHANGE_CTRL = 3'd4; //Sampling period configuration, 0~4:4、8、16、32、64,other values are 128 + + +endmodule + +//ADCULC,GW5AT-138K +module ADCULC ( + + //Voltage signal source, /mV + input ADCINBK6A, //input from bank6 IO, adc_in_b is the reference + input ADCINBK6B, //input from bank6 IO, adc_in_b is the reference + input ADCINBK7A, //input from bank7 IO, adc_in_b is the reference + input ADCINBK7B, //input from bank7 IO, adc_in_b is the reference + + //control signal + input [2:0] VSENCTL, //Input source selection(cib),0~7: vtest, vdd09_0, vdd09_1, vdd09_2, vdd18_0, vdd18_1, reserved, vdd33 + + input [9:0] FSCAL_VALUE, // temperature mode 510~948, typical value 730; Voltage mode 452~840, typical value 653 + input [11:0] OFFSET_VALUE, //signed number, temperature mode - 1560~- 760, typical value - 1180; Voltage mode - 410~410, typical value 0 + + input ADCEN, //Enable signal, active high + input CLK, //clk input + input DRSTN, //0/1 shared, Digital part reset signal, active low + input ADCREQI, //Measurement request signal, valid rising edge, asynchronous signal + output ADCRDY, //The measurement completion signal, active high + output [13:0] ADCVALUE //The measurement result output, signed number. In voltage mode,/2048 is the actual measured value; In temperature mode,/4 is the actual measured value + +); + parameter DYN_BKEN = "FALSE";//"FALSE","TRUE"."TRUE",BUF_BK6_EN[0]&BUF_BK7_EN[0]=1 + +//Input source selection + parameter BUF_VCC_EN = 1'b0; //ulc + parameter BUF_VCCM_EN = 1'b0; //ulc + parameter BUF_MIPI_M0_EN = 3'b000; //ulc,[1:0] Only one bit can be 1 at the same time + parameter BUF_MIPI_M1_EN = 3'b000; //ulc,[1:0] Only one bit can be 1 at the same time + parameter BUF_SERDES_Q0_EN = 3'b000; //ulc,[1:0] Only one bit can be 1 at the same time + parameter BUF_BK6_EN = 6'b000000; //bk6,[3:0] Only one bit can be 1 at the same time + parameter BUF_BK7_EN = 6'b000000; //bk7,[3:0] Only one bit can be 1 at the same time +//Analog terminal option + parameter CLK_SEL = 1'b0; //Clock source selection. 0,PIOCLK_SEL,1,ciu_clk + parameter PIOCLK_SEL = 1'b0; //Clock source selection. 1/2 shared,0,mck_adc_clk_osc,1,io_clk + parameter VSEN_CTL = 3'b000; //Input source selection + parameter VSEN_CTL_SEL = 1'b0; //vsen_ctl source selection,0,VSEN_CTL,1,ciu_vsen_ctl + parameter ADC_MODE = 1'b0; //Mode selection + parameter DIV_CTL = 2'd0; //clock division,0:/1,1:/2,2:/4,3:/8,Clock after frequency division, 500kHz~8MHz + +//Digital terminal options + parameter SAMPLE_CNT_SEL = 3'd4; //total samples configuration, 0~4:64, 128, 256, 512, 1024 sampling points, and the other values are 2048 sampling points.The total number of samples shall be greater than 7 * sampling period, i.e. SAMPLR_CNT_SEL >= RATE_CHANGE_CTRL-1 + parameter RATE_CHANGE_CTRL = 3'd4; //Sampling period configuration, 0~4:4、8、16、32、64,other values are 128 + +endmodule + + +//ADC,GW5A-25 +module ADC ( + + //control signal + input CLK, //clk input + input [2:0] VSENCTL, //Input source selection (ciu), from 0 to 7: glo_left,glo_right,loc_left,vtest,vcc_rt,vccc_rt,vccm_rt,vccx_buf + input ADCMODE, //Mode selection,0:temperature mode,1:voltage mode + input DRSTN, //Digital part reset signal, active low + input ADCREQI, //Measurement request signal, valid rising edge, asynchronous signal + output ADCRDY, //The measurement completion signal, active high + output [13:0] ADCVALUE, //The measurement result output, signed number. In voltage mode,/2048 is the actual measured value; In temperature mode,/4 is the actual measured value + //mdrp + input MDRP_CLK, //mdrp clock + input [7:0] MDRP_WDATA, //mdrp write data + input MDRP_A_INC, //mdrp self-increased address + input [1:0] MDRP_OPCODE, //mdrp opcode + output [7:0] MDRP_RDATA, //mdrp read data + input ADCEN //Enable signal, active high + +); + + //Analog terminal option + parameter CLK_SEL = 1'b0; //时钟源选择,0:osc(2.5MHz),1:CLK + parameter DIV_CTL = 2'd0; //clock division,0:/1,1:/2,2:/4,3:/8,Clock after frequency division, 500kHz~8MHz + + //Input source selection + parameter BUF_EN = 12'b000000000000; // + parameter BUF_BK0_VREF_EN = 1'b0; // + parameter BUF_BK1_VREF_EN = 1'b0; // + parameter BUF_BK2_VREF_EN = 1'b0; // + parameter BUF_BK3_VREF_EN = 1'b0; // + parameter BUF_BK4_VREF_EN = 1'b0; // + parameter BUF_BK5_VREF_EN = 1'b0; // + parameter BUF_BK6_VREF_EN = 1'b0; // + parameter BUF_BK7_VREF_EN = 1'b0; // + + //Digital terminal options + parameter CSR_ADC_MODE = 1'b1; // Mode selection + parameter CSR_VSEN_CTRL = 3'd0; // signal source:vccx/vccio_*/vcc_reg -> 7, signal source:vcc_ext -> 4, others -> 0 + parameter CSR_SAMPLE_CNT_SEL = 3'd4; // total samples configuration, 0~4:64, 128, 256, 512, 1024 sampling points, and the other values are 2048 sampling points.The total number of samples shall be greater than 7 * sampling period, i.e. SAMPLR_CNT_SEL >= RATE_CHANGE_CTRL-1 + parameter CSR_RATE_CHANGE_CTRL = 3'd4; // Sampling period configuration, 0~4:4、8、16、32、64,other values are 128 + parameter CSR_FSCAL = 10'd730; // Parameter 1: temperature mode 510~948, typical value 730; Voltage mode 452~840, typical value 653 + parameter CSR_OFFSET = -12'd1180; // Parameter 2, signed number, temperature mode - 1560~- 760, typical value - 1180; Voltage mode - 410~410, typical value 0 + + +endmodule + + +//ADC_SAR,integrated saradc and adc functions. +module ADC_SAR ( +//`ifdef ADC + input ADCMODE, //Mode selection + input [2:0] VSENCTL, //Input source selection + input CLK, //clk input + //Digital + output ADCENO, //Enable signal, active high + input DRSTN, //Digital part reset signal, active low + input ADCREQI, //Measurement request signal + output ADCRDY, //The measurement completion signal, active high + output [13:0] ADCVALUE, //The measurement result output + input MDRP_CLK, //mdrp clock + input [7:0] MDRP_WDATA, //mdrp write data + input MDRP_A_INC, //mdrp self-increased address + input [1:0] MDRP_OPCODE,//mdrp opcode + output [7:0] MDRP_RDATA, //mdrp read data + //Analog + output ADC1BIT, //Analog data output + output ADCCLKO, //Analog clock output + input ADCENI, //fabric adc enable input +//`endif +// SAR +//`ifdef SARADC + output [12:0] ADCBIT, //Measurement result output + output CLKO, //output clk + output EOC, //The measurement completion signal + input CLKI, //fabric input clk + input [6:0] CHEN, //channel select + input RSTN, //resetn,active low + input SOC //Measurement request signal +//`endif +); + + parameter BUF_EN = 29'b0; // signal source selecor switch +// Δ-Σ +//`ifdef ADC + parameter CLK_SEL = 1'b1; // clk source select + parameter DIV_CTL = 2'd0; // clock division.0:/1,1:/2,2:/4,3:/8 + parameter ADC_EN_SEL = 1'b0; // adc_en source select + parameter PHASE_SEL = 1'b0; // adc internal data phase select + + //Digital terminal options + parameter CSR_ADC_MODE = 1'b1; // Mode selection + parameter CSR_VSEN_CTRL = 3'd0; // signal source:vccx/vccio_*/vcc_reg -> 7, signal source:vcc_ext -> 4, others -> 0 + parameter CSR_SAMPLE_CNT_SEL = 3'd4; // total samples configuration, 0~4:64, 128, 256, 512, 1024 sampling points, and the other values are 2048 sampling points.The total number of samples shall be greater than 7 * sampling period, i.e. SAMPLR_CNT_SEL >= RATE_CHANGE_CTRL-1 + parameter CSR_RATE_CHANGE_CTRL = 3'd4; // Sampling period configuration, 0~4:4、8、16、32、64,other values are 128 + parameter CSR_FSCAL = 10'd730; // Parameter 1: temperature mode 510~948, typical value 730; Voltage mode 452~840, typical value 653 + parameter CSR_OFFSET = -12'd1180; // Parameter 2, signed number, temperature mode - 1560~- 760, typical value - 1180; Voltage mode - 410~410, typical value 0 + +//`endif +// SAR +//`ifdef SARADC + parameter ADC_CLK_DIV = 2'b00; // clock division.00:/1,01:/2,10:/4,11:/8 + parameter ADC_CLKDIV_EN = 1'b0; // clock division enable + parameter CLK_SRC_SEL = 1'b1; // source clock sel + parameter VREF_BUF_EN = 1'b1; // BGR vref buffer enable + parameter COUNT_LEN = 5'b10100; // ADC counter length + parameter DAC_SAMPLE_END = 5'b10010; // DAC sample end point + parameter DAC_SAMPLE_START = 5'b01101; // DAC sample start point + parameter SH_SAMPLE_END = 5'b01011; // SH sample start point + parameter SH_SAMPLE_START = 5'b00001; // SH sample end point + parameter AUTO_CHOP_EN = 1'b0; // auto chop + parameter CHOP_CLK_DIV = 4'b0; // chop clock divider + +//`endif + +endmodule + + +//ADCA,15k +module ADCA ( +// analog + input ADCMODE, //Mode selection + input [2:0] VSENCTL, //Input source selection 0-7: vglo_left, vglo_right, vcc2, vccc3, vccb4, vcc5, vccm6, vccc7 + input CLK, //clk input + input ADCENI, //fabric adc enable input + input PWRON_DYN, //power enable. 1:on 0:off + // digital + input DRSTN, //Digital part reset signal, active low + input ADCREQI, //Measurement request signal + output ADCRDY, //The measurement completion signal, active high + output [13:0] ADCVALUE, //The measurement result output + input MDRP_CLK, //mdrp clock + input [7:0] MDRP_WDATA, //mdrp write data + input MDRP_A_INC, //mdrp self-increased address + input [1:0] MDRP_OPCODE,//mdrp opcode + output [7:0] MDRP_RDATA //mdrp read data +); + + parameter BUF_EN = 20'b0; // signal source selecor switch //[8:0] one-hot; [19:15] one-hot. BUF_EN[6] must be 0 + parameter CLK_SEL = 1'b1; // clk source select + parameter DIV_CTL = 2'd0; // clock division + parameter ADC_EN_SEL = 1'b0; // adc_en source select + parameter PHASE_SEL = 1'b0; // adc internal data phase select + + parameter PWRON_SEL = 1'b0; // power enbale source select. 0:PWRON 1:PWRON_DYN + parameter PWRON = 1'b1; // as PWRON_DYN + parameter LDO_MODE = 1'b0; // LDO mode 0:on(2.5/3.3V) 1:off(1.8V) + + //Digital terminal options + parameter CSR_ADC_MODE = 1'b1; // Mode selection + parameter CSR_VSEN_CTRL = 3'd0; // signal source:vccx/vccio_*/vcc_reg -> 7, signal source:vcc_ext -> 4, others -> 0 + parameter CSR_SAMPLE_CNT_SEL = 3'd4; // total samples configuration, 0~4:64, 128, 256, 512, 1024 sampling points, and the other values are 2048 sampling points.The total number of samples shall be greater than 7 * sampling period, i.e. SAMPLR_CNT_SEL >= RATE_CHANGE_CTRL-1 + parameter CSR_RATE_CHANGE_CTRL = 3'd4; // Sampling period configuration, 0~4:4、8、16、32、64,other values are 128 + parameter CSR_FSCAL = 10'd730; // Parameter 1: temperature mode 510~948, typical value 730; Voltage mode 452~840, typical value 653 + parameter CSR_OFFSET = -12'd1180; // Parameter 2, signed number, temperature mode - 1560~- 760, typical value - 1180; Voltage mode - 410~410, typical value 0 + +endmodule + From 4011d72656029e3843c219bdc0d91276f9d8101a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 30 Oct 2025 00:24:42 +0000 Subject: [PATCH 16/97] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 108c92b2a..e0b3b561d 100644 --- a/Makefile +++ b/Makefile @@ -160,7 +160,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.58+89 +YOSYS_VER := 0.58+94 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 88d101b4626dbeb0c276422c685c0b0db199dc9f Mon Sep 17 00:00:00 2001 From: Vaibhav Singh Date: Fri, 31 Oct 2025 14:06:00 +0530 Subject: [PATCH 17/97] kernel: Fix define ID issue, needs undef first --- kernel/rtlil.h | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 394c6f25d..819704cf9 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -569,6 +569,7 @@ template <> struct IDMacroHelper<-1> { } }; +#undef ID #define ID(_id) \ YOSYS_NAMESPACE_PREFIX IDMacroHelper< \ YOSYS_NAMESPACE_PREFIX lookup_well_known_id(#_id) \ From a243e4e60fa34be4b9b9db0992f9023697107717 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Sat, 1 Nov 2025 17:28:39 +1300 Subject: [PATCH 18/97] Docs: ecp5 and nexus are under lattice --- docs/source/cmd/index_techlibs_ecp5.rst | 5 ----- docs/source/cmd/index_techlibs_lattice_nexus.rst | 5 ----- 2 files changed, 10 deletions(-) delete mode 100644 docs/source/cmd/index_techlibs_ecp5.rst delete mode 100644 docs/source/cmd/index_techlibs_lattice_nexus.rst diff --git a/docs/source/cmd/index_techlibs_ecp5.rst b/docs/source/cmd/index_techlibs_ecp5.rst deleted file mode 100644 index 29fd309cf..000000000 --- a/docs/source/cmd/index_techlibs_ecp5.rst +++ /dev/null @@ -1,5 +0,0 @@ -ECP5 ------------------- - -.. autocmdgroup:: techlibs/ecp5 - :members: diff --git a/docs/source/cmd/index_techlibs_lattice_nexus.rst b/docs/source/cmd/index_techlibs_lattice_nexus.rst deleted file mode 100644 index d5ac4184c..000000000 --- a/docs/source/cmd/index_techlibs_lattice_nexus.rst +++ /dev/null @@ -1,5 +0,0 @@ -Lattice Nexus ------------------- - -.. autocmdgroup:: techlibs/nexus - :members: From 797780eda5c5b855e6404aaa2aa1e69850201ba1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 2 Nov 2025 00:26:19 +0000 Subject: [PATCH 19/97] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index e0b3b561d..5d659e5e8 100644 --- a/Makefile +++ b/Makefile @@ -160,7 +160,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.58+94 +YOSYS_VER := 0.58+98 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 5fa7feccd378ae2189346ce5e6771cb3a52e7eed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Povi=C5=A1er?= Date: Mon, 3 Nov 2025 12:48:44 +0100 Subject: [PATCH 20/97] timeest: Add top ports launching/sampling --- passes/cmds/timeest.cc | 55 +++++++++++++++++++++++++++++----------- tests/various/timeest.ys | 12 +++++++++ 2 files changed, 52 insertions(+), 15 deletions(-) create mode 100644 tests/various/timeest.ys diff --git a/passes/cmds/timeest.cc b/passes/cmds/timeest.cc index ce9c628f4..1caa1ddaf 100644 --- a/passes/cmds/timeest.cc +++ b/passes/cmds/timeest.cc @@ -39,7 +39,8 @@ const arrivalint INF_PAST = std::numeric_limits::min(); struct EstimateSta { SigMap sigmap; Module *m; - SigBit clk; + std::optional clk; + bool top_port_endpoints = false; dict>, Aig> aigs; dict cell_aigs; @@ -73,15 +74,18 @@ struct EstimateSta { } // TODO: ignores clock polarity - EstimateSta(Module *m, SigBit clk) - : sigmap(m), m(m), clk(clk) + EstimateSta(Module *m, std::optional clk, bool top_port_endpoints) + : sigmap(m), m(m), clk(clk), top_port_endpoints(top_port_endpoints) { - sigmap.apply(clk); + if (clk.has_value()) + sigmap.apply(*clk); } void run() { - log("Domain %s\n", log_signal(clk)); + log("\nModule %s\n", log_id(m)); + if (clk.has_value()) + log("Domain %s\n", log_signal(*clk)); // first, we collect launch and sample points and convert the combinational logic to AIG std::vector combinational; @@ -151,6 +155,22 @@ struct EstimateSta { } } + // add top module port launching/sampling, if requested + if (top_port_endpoints) { + SigSpec all_inputs, all_outputs; + for (auto port_id : m->ports) { + Wire *port = m->wire(port_id); + if (port->port_input && !port->port_output) { + all_inputs.append(port); + } else if (port->port_output && !port->port_input) { + all_outputs.append(port); + } else if (port->port_output && port->port_input) { + log_warning("Ignoring bi-directional port %s\n", log_id(port)); + } + } + add_seq(nullptr, all_inputs, all_outputs); + } + // now we toposort the combinational logic // each toposort node is either a SigBit or a pair of Cell * / AigNode * @@ -360,7 +380,7 @@ struct TimeestPass : Pass { log("\n"); log(" timeest [-clk ] [options] [selection]\n"); log("\n"); - log("Estimate the critical path in clock domain by counting AIG nodes.\n"); + log("Estimate the critical path by counting AIG nodes.\n"); log("\n"); log(" -all_paths\n"); log(" Print or select nodes from all critical paths instead of focusing on\n"); @@ -374,7 +394,8 @@ struct TimeestPass : Pass { { log_header(d, "Executing TIMEEST pass. (estimate timing)\n"); - std::string clk; + std::string clk_name; + bool clk_domain_specified = false; bool all_paths = false; bool select = false; size_t argidx; @@ -388,26 +409,30 @@ struct TimeestPass : Pass { continue; } if (args[argidx] == "-clk" && argidx + 1 < args.size()) { - clk = args[++argidx]; + clk_domain_specified = true; + clk_name = args[++argidx]; continue; } break; } extra_args(args, argidx, d); - if (clk.empty()) - log_cmd_error("No -clk argument provided\n"); - if (select && d->selected_modules().size() > 1) log_cmd_error("The -select option operates on a single selected module\n"); for (auto m : d->selected_modules()) { - if (!m->wire(RTLIL::escape_id(clk))) { - log_warning("No domain '%s' in module %s\n", clk, log_id(m)); - continue; + std::optional clk; + + if (clk_domain_specified) { + if (!m->wire(RTLIL::escape_id(clk_name))) { + log_warning("No domain '%s' in module %s\n", clk_name.c_str(), log_id(m)); + continue; + } + + clk = SigBit(m->wire(RTLIL::escape_id(clk_name)), 0); } - EstimateSta sta(m, SigBit(m->wire(RTLIL::escape_id(clk)), 0)); + EstimateSta sta(m, clk, /*top_port_endpoints=*/ !clk_domain_specified); sta.all_paths = all_paths; sta.select = select; sta.run(); diff --git a/tests/various/timeest.ys b/tests/various/timeest.ys new file mode 100644 index 000000000..3859de5e1 --- /dev/null +++ b/tests/various/timeest.ys @@ -0,0 +1,12 @@ +read_verilog < Date: Sat, 18 Oct 2025 14:58:56 +0300 Subject: [PATCH 21/97] pyosys: uv for non-wheel builds, update instructions - add `uv` to dependencies: saves builder(s) from manually having to manage a venv for python build dependencies - when building wheels, pip automatically creates the environment with those dependencies, so no need for uv - when running simply `make ENABLE_PYOSYS=1`, this is not the case. people attempting to `pip3 install --upgrade pybind11 cxxheaderparser` to add it to their system packages will be met with a scare message about "breaking system packages" - update installation instructions to drop boost and add uv instead - update ci scripts to use `macos-15[-intel]` (`macos-13` sunset in early december) --- .github/actions/setup-build-env/action.yml | 3 ++- .github/workflows/test-compile.yml | 2 +- .github/workflows/wheels.yml | 4 ++-- Brewfile | 2 +- Makefile | 13 ++++++++++--- README.md | 4 ++-- docs/source/getting_started/installation.rst | 10 +++++----- docs/source/using_yosys/pyosys.rst | 8 ++++++++ pyproject.toml | 2 +- 9 files changed, 32 insertions(+), 16 deletions(-) diff --git a/.github/actions/setup-build-env/action.yml b/.github/actions/setup-build-env/action.yml index e4bc8ec58..209965acb 100644 --- a/.github/actions/setup-build-env/action.yml +++ b/.github/actions/setup-build-env/action.yml @@ -8,7 +8,8 @@ runs: shell: bash run: | sudo apt-get update - sudo apt-get install gperf build-essential bison flex libfl-dev libreadline-dev gawk tcl-dev libffi-dev git graphviz xdot pkg-config python3 libboost-system-dev libboost-python-dev libboost-filesystem-dev zlib1g-dev libbz2-dev libgtest-dev + sudo apt-get install gperf build-essential bison flex libfl-dev libreadline-dev gawk tcl-dev libffi-dev git graphviz xdot pkg-config python3-dev zlib1g-dev libbz2-dev libgtest-dev + curl -LsSf https://astral.sh/uv/install.sh | sh - name: Install macOS Dependencies if: runner.os == 'macOS' diff --git a/.github/workflows/test-compile.yml b/.github/workflows/test-compile.yml index 7c18c7ba0..1604ca9d2 100644 --- a/.github/workflows/test-compile.yml +++ b/.github/workflows/test-compile.yml @@ -45,7 +45,7 @@ jobs: - 'gcc-14' include: # macOS x86 - - os: macos-13 + - os: macos-15-intel compiler: 'clang-19' # macOS arm - os: macos-latest diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index b6c9a51ac..9eea1468d 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -27,13 +27,13 @@ jobs: { name: "macOS 13", family: "macos", - runner: "macos-13", + runner: "macos-15-intel", archs: "x86_64", }, { name: "macOS 14", family: "macos", - runner: "macos-14", + runner: "macos-15", archs: "arm64", }, ## Windows is disabled because of an issue with compiling FFI as diff --git a/Brewfile b/Brewfile index c90434e62..917f1bdb4 100644 --- a/Brewfile +++ b/Brewfile @@ -6,9 +6,9 @@ brew "git" brew "graphviz" brew "pkg-config" brew "python3" +brew "uv" brew "xdot" brew "bash" -brew "boost-python3" brew "llvm@20" brew "lld" brew "googletest" diff --git a/Makefile b/Makefile index 5d659e5e8..16843b073 100644 --- a/Makefile +++ b/Makefile @@ -28,6 +28,7 @@ ENABLE_HELP_SOURCE := 0 # python wrappers ENABLE_PYOSYS := 0 +PYOSYS_USE_UV := 1 # other configuration flags ENABLE_GCOV := 0 @@ -352,16 +353,22 @@ PYTHON_OBJECTS = pyosys/wrappers.o kernel/drivers.o kernel/yosys.o passes/cmds/p ifeq ($(ENABLE_PYOSYS),1) # python-config --ldflags includes -l and -L, but LINKFLAGS is only -L + +UV_ENV := +ifeq ($(PYOSYS_USE_UV),1) +UV_ENV := uv run --no-project --with 'pybind11>3,<4' --with 'cxxheaderparser' +endif + LINKFLAGS += $(filter-out -l%,$(shell $(PYTHON_CONFIG) --ldflags)) LIBS += $(shell $(PYTHON_CONFIG) --libs) EXE_LIBS += $(filter-out $(LIBS),$(shell $(PYTHON_CONFIG_FOR_EXE) --libs)) -PYBIND11_INCLUDE ?= $(shell $(PYTHON_EXECUTABLE) -m pybind11 --includes) +PYBIND11_INCLUDE ?= $(shell $(UV_ENV) $(PYTHON_EXECUTABLE) -m pybind11 --includes) CXXFLAGS += -I$(PYBIND11_INCLUDE) -DYOSYS_ENABLE_PYTHON CXXFLAGS += $(shell $(PYTHON_CONFIG) --includes) -DYOSYS_ENABLE_PYTHON OBJS += $(PY_WRAPPER_FILE).o PY_GEN_SCRIPT = pyosys/generator.py -PY_WRAP_INCLUDES := $(shell $(PYTHON_EXECUTABLE) $(PY_GEN_SCRIPT) --print-includes) +PY_WRAP_INCLUDES := $(shell $(UV_ENV) $(PYTHON_EXECUTABLE) $(PY_GEN_SCRIPT) --print-includes) endif # ENABLE_PYOSYS ifeq ($(ENABLE_READLINE),1) @@ -777,7 +784,7 @@ endif ifeq ($(ENABLE_PYOSYS),1) $(PY_WRAPPER_FILE).cc: $(PY_GEN_SCRIPT) pyosys/wrappers_tpl.cc $(PY_WRAP_INCLUDES) pyosys/hashlib.h $(Q) mkdir -p $(dir $@) - $(P) $(PYTHON_EXECUTABLE) $(PY_GEN_SCRIPT) $(PY_WRAPPER_FILE).cc + $(P) $(UV_ENV) $(PYTHON_EXECUTABLE) $(PY_GEN_SCRIPT) $(PY_WRAPPER_FILE).cc endif %.o: %.cpp diff --git a/README.md b/README.md index 6118d6079..dd5b634f9 100644 --- a/README.md +++ b/README.md @@ -85,8 +85,8 @@ prerequisites for building yosys: $ sudo apt-get install build-essential clang lld bison flex libfl-dev \ libreadline-dev gawk tcl-dev libffi-dev git \ - graphviz xdot pkg-config python3 libboost-system-dev \ - libboost-python-dev libboost-filesystem-dev zlib1g-dev + graphviz xdot pkg-config python3-dev zlib1g-dev + $ curl -LsSf https://astral.sh/uv/install.sh | sh The environment variable `CXX` can be used to control the C++ compiler used, or run one of the following to override it: diff --git a/docs/source/getting_started/installation.rst b/docs/source/getting_started/installation.rst index 0ac85d199..fef495389 100644 --- a/docs/source/getting_started/installation.rst +++ b/docs/source/getting_started/installation.rst @@ -99,8 +99,8 @@ Installing all prerequisites for Ubuntu 22.04: sudo apt-get install gperf build-essential clang lld bison flex libfl-dev \ libreadline-dev gawk tcl-dev libffi-dev git \ - graphviz xdot pkg-config python3 libboost-system-dev \ - libboost-python-dev libboost-filesystem-dev zlib1g-dev + graphviz xdot pkg-config python3-dev zlib1g-dev + curl -LsSf https://astral.sh/uv/install.sh | sh Installing all prerequisites for macOS 13 (with Homebrew): @@ -141,7 +141,7 @@ For Cygwin use the following command to install all prerequisites, or select the missing `strdup` function when using gcc. It is instead recommended to use Windows Subsystem for Linux (WSL) and follow the instructions for Ubuntu. -.. +.. For MSYS2 (MINGW64): .. code:: console @@ -215,7 +215,7 @@ Running the build system From the root ``yosys`` directory, call the following commands: .. code:: console - + make sudo make install @@ -228,7 +228,7 @@ To use a separate (out-of-tree) build directory, provide a path to the Makefile. Out-of-tree builds require a clean source tree. -.. seealso:: +.. seealso:: Refer to :doc:`/yosys_internals/extending_yosys/test_suites` for details on testing Yosys once compiled. diff --git a/docs/source/using_yosys/pyosys.rst b/docs/source/using_yosys/pyosys.rst index 8aa7fd4fe..09b572e05 100644 --- a/docs/source/using_yosys/pyosys.rst +++ b/docs/source/using_yosys/pyosys.rst @@ -28,6 +28,14 @@ methods: ``yosys -y ./my_pyosys_script.py`` + Do note this requires some build-time dependencies to be available to Python, + namely, ``pybind11`` and ``cxxheaderparser``. By default, the required + ``uv`` package will be used to create an ephemeral environment with the + correct versions of the tools installed. + + You can force use of your current Python environment by passing the Makefile + flag ``PYOSYS_USE_UV=0``. + 2. Installing the Pyosys wheels On macOS and GNU/Linux you can install pre-built wheels of Yosys using diff --git a/pyproject.toml b/pyproject.toml index d5882084c..8893137d8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,7 +2,7 @@ requires = [ "setuptools>=42", "pybind11>=3,<4", - "cxxheaderparser", + "cxxheaderparser" ] build-backend = "setuptools.build_meta" From 1a80c26bae9b4545a7f7fb7717de842071f17a85 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 4 Nov 2025 11:11:01 +1300 Subject: [PATCH 22/97] tests: Fix for macos Drop non standard `-t` flag for putting the destination directory first. --- tests/verilog/local_include.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/verilog/local_include.sh b/tests/verilog/local_include.sh index c10c7411b..aecbef713 100755 --- a/tests/verilog/local_include.sh +++ b/tests/verilog/local_include.sh @@ -19,11 +19,11 @@ $yosys $test $source # include local to cwd mkdir -p $subdir -cp -t $subdir $source +cp $source $subdir $yosys $test $subdir/$source # include local to source -mv -t $subdir $include +mv $include $subdir $yosys $test $subdir/$source # include local to source, and source is given as an absolute path From 39fab4a07fdf52ad12e50b608e0b80430a7530ed Mon Sep 17 00:00:00 2001 From: KrystalDelusion <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 4 Nov 2025 11:46:27 +1300 Subject: [PATCH 23/97] Makefile: Add gatemate genfiles Allows files to be cleaned with `make clean`, without which it breaks out-of-tree builds if an in-tree build has previously run and subsequently cleaned. --- techlibs/gatemate/Makefile.inc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/techlibs/gatemate/Makefile.inc b/techlibs/gatemate/Makefile.inc index aeb318cc9..8a258aec8 100644 --- a/techlibs/gatemate/Makefile.inc +++ b/techlibs/gatemate/Makefile.inc @@ -2,6 +2,9 @@ OBJS += techlibs/gatemate/synth_gatemate.o OBJS += techlibs/gatemate/gatemate_foldinv.o +GENFILES += techlibs/gatemate/lut_tree_cells.genlib +GENFILES += techlibs/gatemate/lut_tree_map.v + $(eval $(call add_share_file,share/gatemate,techlibs/gatemate/reg_map.v)) $(eval $(call add_share_file,share/gatemate,techlibs/gatemate/mux_map.v)) $(eval $(call add_share_file,share/gatemate,techlibs/gatemate/lut_map.v)) @@ -28,3 +31,4 @@ techlibs/gatemate/lut_tree_map.v: techlibs/gatemate/lut_tree_lib.mk $(eval $(call add_gen_share_file,share/gatemate,techlibs/gatemate/lut_tree_cells.genlib)) $(eval $(call add_gen_share_file,share/gatemate,techlibs/gatemate/lut_tree_map.v)) + From 336877a3535d13537e9b126407be9382e6766a0b Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 4 Nov 2025 12:27:31 +1300 Subject: [PATCH 24/97] io.cc: Drop unused variable --- kernel/io.cc | 6 ------ 1 file changed, 6 deletions(-) diff --git a/kernel/io.cc b/kernel/io.cc index 45aa496b0..e9801f63e 100644 --- a/kernel/io.cc +++ b/kernel/io.cc @@ -392,12 +392,6 @@ void append_globbed(std::vector& paths, std::string pattern) copy(globbed.begin(), globbed.end(), back_inserter(paths)); } -#ifdef _WIN32 -const char* const OS_PATH_SEP = "/\\"; -#else -const char* const OS_PATH_SEP = "/"; -#endif - std::string name_from_file_path(std::string path) { return std::filesystem::path(path).filename().string(); } From 2d778a94fa01b7083184e40b3c10eace5cd09de5 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Sat, 1 Nov 2025 12:04:13 +1300 Subject: [PATCH 25/97] action.yml: Playing with apt cache --- .github/actions/setup-build-env/action.yml | 15 ++++++++++----- .github/workflows/test-build.yml | 8 ++++++++ .github/workflows/test-compile.yml | 2 ++ .github/workflows/test-sanitizers.yml | 2 ++ 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/.github/actions/setup-build-env/action.yml b/.github/actions/setup-build-env/action.yml index 209965acb..0bd7bf71b 100644 --- a/.github/actions/setup-build-env/action.yml +++ b/.github/actions/setup-build-env/action.yml @@ -1,15 +1,20 @@ name: Build environment setup description: Configure build env for Yosys builds + +inputs: + runs-on: + required: true + type: string + runs: using: composite steps: - name: Install Linux Dependencies if: runner.os == 'Linux' - shell: bash - run: | - sudo apt-get update - sudo apt-get install gperf build-essential bison flex libfl-dev libreadline-dev gawk tcl-dev libffi-dev git graphviz xdot pkg-config python3-dev zlib1g-dev libbz2-dev libgtest-dev - curl -LsSf https://astral.sh/uv/install.sh | sh + uses: awalsh128/cache-apt-pkgs-action@v1.6.0 + with: + packages: gperf build-essential bison flex libfl-dev libreadline-dev gawk tcl-dev libffi-dev git graphviz xdot pkg-config python3 libboost-system-dev libboost-python-dev libboost-filesystem-dev zlib1g-dev libbz2-dev libgtest-dev + version: ${{ inputs.runs-on }}-buildys - name: Install macOS Dependencies if: runner.os == 'macOS' diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml index 2d4a7a6c8..eb52da203 100644 --- a/.github/workflows/test-build.yml +++ b/.github/workflows/test-build.yml @@ -60,6 +60,8 @@ jobs: - name: Setup environment uses: ./.github/actions/setup-build-env + with: + runs-on: ${{ matrix.os }} - name: Build shell: bash @@ -105,6 +107,8 @@ jobs: - name: Setup environment uses: ./.github/actions/setup-build-env + with: + runs-on: ${{ matrix.os }} - name: Get iverilog id: get-iverilog @@ -191,6 +195,8 @@ jobs: - name: Setup environment uses: ./.github/actions/setup-build-env + with: + runs-on: ${{ matrix.os }} - name: Download build artifact uses: actions/download-artifact@v4 @@ -229,6 +235,8 @@ jobs: - name: Setup environment uses: ./.github/actions/setup-build-env + with: + runs-on: ${{ matrix.os }} - name: Download build artifact uses: actions/download-artifact@v4 diff --git a/.github/workflows/test-compile.yml b/.github/workflows/test-compile.yml index 1604ca9d2..af8f1328d 100644 --- a/.github/workflows/test-compile.yml +++ b/.github/workflows/test-compile.yml @@ -60,6 +60,8 @@ jobs: - name: Setup environment uses: ./.github/actions/setup-build-env + with: + runs-on: ${{ matrix.os }} - name: Setup Cpp uses: aminya/setup-cpp@v1 diff --git a/.github/workflows/test-sanitizers.yml b/.github/workflows/test-sanitizers.yml index 9c0f6d746..38e51f7b4 100644 --- a/.github/workflows/test-sanitizers.yml +++ b/.github/workflows/test-sanitizers.yml @@ -44,6 +44,8 @@ jobs: - name: Setup environment uses: ./.github/actions/setup-build-env + with: + runs-on: ${{ matrix.os }} - name: Get iverilog id: get-iverilog From 0e2d24edd3b9a45c98dcc9a4dd1090918e8f402c Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Sat, 1 Nov 2025 12:43:45 +1300 Subject: [PATCH 26/97] CI: iverilog setup as composite action Called during setup-build-env. --- .github/actions/setup-build-env/action.yml | 11 +++++ .github/actions/setup-iverilog/action.yml | 57 ++++++++++++++++++++++ .github/workflows/test-build.yml | 43 +--------------- .github/workflows/test-sanitizers.yml | 48 +----------------- 4 files changed, 70 insertions(+), 89 deletions(-) create mode 100644 .github/actions/setup-iverilog/action.yml diff --git a/.github/actions/setup-build-env/action.yml b/.github/actions/setup-build-env/action.yml index 0bd7bf71b..6bf0afa15 100644 --- a/.github/actions/setup-build-env/action.yml +++ b/.github/actions/setup-build-env/action.yml @@ -5,6 +5,11 @@ inputs: runs-on: required: true type: string + get-iverilog: + description: 'Install iverilog' + default: false + required: false + type: boolean runs: using: composite @@ -38,3 +43,9 @@ runs: echo "$(brew --prefix bison)/bin" >> $GITHUB_PATH echo "$(brew --prefix flex)/bin" >> $GITHUB_PATH echo "procs=$(sysctl -n hw.ncpu)" >> $GITHUB_ENV + + - name: Setup iverilog + if: inputs.get-iverilog + uses: ./.github/actions/setup-iverilog + with: + runs-on: ${{ inputs.runs-on }} diff --git a/.github/actions/setup-iverilog/action.yml b/.github/actions/setup-iverilog/action.yml new file mode 100644 index 000000000..7f264a462 --- /dev/null +++ b/.github/actions/setup-iverilog/action.yml @@ -0,0 +1,57 @@ +name: iverilog setup +description: Cached build and install of iverilog + +inputs: + runs-on: + required: true + type: string + +runs: + using: composite + steps: + - name: Get iverilog + id: get-iverilog + shell: bash + run: | + git clone https://github.com/steveicarus/iverilog.git + cd iverilog + echo "IVERILOG_GIT=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT + + - 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: ${{ inputs.runs-on }}-${{ steps.get-iverilog.outputs.IVERILOG_GIT }} + + - name: iverilog macOS deps + if: steps.cache-iverilog.outputs.cache-hit != 'true' && runner.os == 'macOS' + shell: bash + run: | + brew install autoconf + + - 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: Check iverilog + shell: bash + run: | + iverilog -V diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml index eb52da203..6bd5495f0 100644 --- a/.github/workflows/test-build.yml +++ b/.github/workflows/test-build.yml @@ -109,48 +109,7 @@ jobs: uses: ./.github/actions/setup-build-env with: runs-on: ${{ matrix.os }} - - - name: Get iverilog - id: get-iverilog - shell: bash - run: | - git clone https://github.com/steveicarus/iverilog.git - cd iverilog - echo "IVERILOG_GIT=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT - - - 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 }}-${{ steps.get-iverilog.outputs.IVERILOG_GIT }} - - - name: iverilog macOS deps - if: steps.cache-iverilog.outputs.cache-hit != 'true' && runner.os == 'macOS' - shell: bash - run: | - brew install autoconf - - - 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 + setup-iverilog: true - name: Download build artifact uses: actions/download-artifact@v4 diff --git a/.github/workflows/test-sanitizers.yml b/.github/workflows/test-sanitizers.yml index 38e51f7b4..6e3dfb2f2 100644 --- a/.github/workflows/test-sanitizers.yml +++ b/.github/workflows/test-sanitizers.yml @@ -46,53 +46,7 @@ jobs: uses: ./.github/actions/setup-build-env with: runs-on: ${{ matrix.os }} - - - name: Get iverilog - id: get-iverilog - shell: bash - run: | - git clone https://github.com/steveicarus/iverilog.git - cd iverilog - echo "IVERILOG_GIT=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT - - - 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 }}-${{ steps.get-iverilog.outputs.IVERILOG_GIT }} - - - name: iverilog macOS deps - if: steps.cache-iverilog.outputs.cache-hit != 'true' && runner.os == 'macOS' - shell: bash - run: | - brew install autoconf - - - 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: Check iverilog - shell: bash - run: | - iverilog -V + setup-iverilog: true - name: Build shell: bash From c597bf70b077a4211cfede64f9d1dffe4b907cd7 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Sat, 1 Nov 2025 13:03:33 +1300 Subject: [PATCH 27/97] CI: Save iverilog cache in action We still want to cache iverilog even if the rest of the action fails, so explicitly save/restore instead of standard cache. --- .github/actions/setup-build-env/action.yml | 2 +- .github/actions/setup-iverilog/action.yml | 16 +++++++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/.github/actions/setup-build-env/action.yml b/.github/actions/setup-build-env/action.yml index 6bf0afa15..6e46e1dfb 100644 --- a/.github/actions/setup-build-env/action.yml +++ b/.github/actions/setup-build-env/action.yml @@ -45,7 +45,7 @@ runs: echo "procs=$(sysctl -n hw.ncpu)" >> $GITHUB_ENV - name: Setup iverilog - if: inputs.get-iverilog + if: inputs.get-iverilog == 'true' uses: ./.github/actions/setup-iverilog with: runs-on: ${{ inputs.runs-on }} diff --git a/.github/actions/setup-iverilog/action.yml b/.github/actions/setup-iverilog/action.yml index 7f264a462..1517ad9c4 100644 --- a/.github/actions/setup-iverilog/action.yml +++ b/.github/actions/setup-iverilog/action.yml @@ -27,21 +27,20 @@ runs: make -j$procs make install - - name: Cache iverilog - id: cache-iverilog - uses: actions/cache@v4 + - uses: actions/cache/restore@v4 + id: restore-iverilog with: path: .local/ key: ${{ inputs.runs-on }}-${{ steps.get-iverilog.outputs.IVERILOG_GIT }} - name: iverilog macOS deps - if: steps.cache-iverilog.outputs.cache-hit != 'true' && runner.os == 'macOS' + if: steps.restore-iverilog.outputs.cache-hit != 'true' && runner.os == 'macOS' shell: bash run: | brew install autoconf - name: Build iverilog - if: steps.cache-iverilog.outputs.cache-hit != 'true' + if: steps.restore-iverilog.outputs.cache-hit != 'true' shell: bash run: | mkdir -p ${{ github.workspace }}/.local/ @@ -55,3 +54,10 @@ runs: shell: bash run: | iverilog -V + + - uses: actions/cache/save@v4 + id: save-iverilog + if: steps.restore-iverilog.outputs.cache-hit != 'true' + with: + path: .local/ + key: ${{ steps.restore-iverilog.outputs.cache-primary-key }} From 1f6ac5f392b62a07c7fabe5d71327048cd3d6c7e Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Sat, 1 Nov 2025 14:29:58 +1300 Subject: [PATCH 28/97] CI: Split dependency setup Split into common + build/docs/test (common always installs, build/docs/test are installed as requested with `build-*-deps` input flag). --- .github/actions/setup-build-env/action.yml | 40 ++++++++++++++++++++-- .github/workflows/codeql.yml | 7 ++-- .github/workflows/test-build.yml | 6 +++- .github/workflows/test-compile.yml | 1 + .github/workflows/test-sanitizers.yml | 4 ++- 5 files changed, 52 insertions(+), 6 deletions(-) diff --git a/.github/actions/setup-build-env/action.yml b/.github/actions/setup-build-env/action.yml index 6e46e1dfb..24e7d84a5 100644 --- a/.github/actions/setup-build-env/action.yml +++ b/.github/actions/setup-build-env/action.yml @@ -5,6 +5,21 @@ inputs: runs-on: required: true type: string + get-build-deps: + description: 'Install Yosys build dependencies' + default: false + required: false + type: boolean + get-docs-deps: + description: 'Install Yosys docs dependencies' + default: false + required: false + type: boolean + get-test-deps: + description: 'Install Yosys test dependencies' + default: false + required: false + type: boolean get-iverilog: description: 'Install iverilog' default: false @@ -14,13 +29,34 @@ inputs: runs: using: composite steps: - - name: Install Linux Dependencies + - name: Linux common dependencies if: runner.os == 'Linux' uses: awalsh128/cache-apt-pkgs-action@v1.6.0 with: - packages: gperf build-essential bison flex libfl-dev libreadline-dev gawk tcl-dev libffi-dev git graphviz xdot pkg-config python3 libboost-system-dev libboost-python-dev libboost-filesystem-dev zlib1g-dev libbz2-dev libgtest-dev + packages: autoconf git make python3 + version: ${{ inputs.runs-on }}-commonys + + - name: Linux build dependencies + if: runner.os == 'Linux' && inputs.get-build-deps == 'true' + uses: awalsh128/cache-apt-pkgs-action@v1.6.0 + with: + packages: bison clang flex libboost-filesystem-dev libboost-python-dev libboost-system-dev libbz2-dev libffi-dev libfl-dev libreadline-dev pkg-config tcl-dev zlib1g-dev version: ${{ inputs.runs-on }}-buildys + - name: Linux docs dependencies + if: runner.os == 'Linux' && inputs.get-docs-deps == 'true' + uses: awalsh128/cache-apt-pkgs-action@v1.6.0 + with: + packages: graphviz xdot + version: ${{ inputs.runs-on }}-docsys + + - name: Linux test dependencies + if: runner.os == 'Linux' && inputs.get-test-deps == 'true' + uses: awalsh128/cache-apt-pkgs-action@v1.6.0 + with: + packages: gawk libgtest-dev + version: ${{ inputs.runs-on }}-testys + - name: Install macOS Dependencies if: runner.os == 'macOS' shell: bash diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 95595924a..da30e3da4 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -10,8 +10,11 @@ jobs: name: Analyze runs-on: ubuntu-latest steps: - - name: Install deps - run: sudo apt-get install bison flex libfl-dev libreadline-dev tcl-dev libffi-dev + - name: Setup environment + uses: ./.github/actions/setup-build-env + with: + runs-on: ubuntu-latest + get-build-deps: true - name: Checkout repository uses: actions/checkout@v4 diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml index 6bd5495f0..8c1a3bbd2 100644 --- a/.github/workflows/test-build.yml +++ b/.github/workflows/test-build.yml @@ -62,6 +62,7 @@ jobs: uses: ./.github/actions/setup-build-env with: runs-on: ${{ matrix.os }} + get-build-deps: true - name: Build shell: bash @@ -109,7 +110,8 @@ jobs: uses: ./.github/actions/setup-build-env with: runs-on: ${{ matrix.os }} - setup-iverilog: true + get-test-deps: true + get-iverilog: true - name: Download build artifact uses: actions/download-artifact@v4 @@ -196,6 +198,8 @@ jobs: uses: ./.github/actions/setup-build-env with: runs-on: ${{ matrix.os }} + get-build-deps: true + get-docs-deps: true - name: Download build artifact uses: actions/download-artifact@v4 diff --git a/.github/workflows/test-compile.yml b/.github/workflows/test-compile.yml index af8f1328d..31c8bccf6 100644 --- a/.github/workflows/test-compile.yml +++ b/.github/workflows/test-compile.yml @@ -62,6 +62,7 @@ jobs: uses: ./.github/actions/setup-build-env with: runs-on: ${{ matrix.os }} + get-build-deps: true - name: Setup Cpp uses: aminya/setup-cpp@v1 diff --git a/.github/workflows/test-sanitizers.yml b/.github/workflows/test-sanitizers.yml index 6e3dfb2f2..4c8e3ec51 100644 --- a/.github/workflows/test-sanitizers.yml +++ b/.github/workflows/test-sanitizers.yml @@ -46,7 +46,9 @@ jobs: uses: ./.github/actions/setup-build-env with: runs-on: ${{ matrix.os }} - setup-iverilog: true + get-build-deps: true + get-test-deps: true + get-iverilog: true - name: Build shell: bash From a4bd40e1992faafd3e7d5c73af2f0928844bcc6c Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Sat, 1 Nov 2025 15:36:07 +1300 Subject: [PATCH 29/97] CI: Fix iverilog deps --- .github/actions/setup-build-env/action.yml | 4 ++-- .github/actions/setup-iverilog/action.yml | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/actions/setup-build-env/action.yml b/.github/actions/setup-build-env/action.yml index 24e7d84a5..c8dc5dc64 100644 --- a/.github/actions/setup-build-env/action.yml +++ b/.github/actions/setup-build-env/action.yml @@ -33,7 +33,7 @@ runs: if: runner.os == 'Linux' uses: awalsh128/cache-apt-pkgs-action@v1.6.0 with: - packages: autoconf git make python3 + packages: gawk git make python3 version: ${{ inputs.runs-on }}-commonys - name: Linux build dependencies @@ -54,7 +54,7 @@ runs: if: runner.os == 'Linux' && inputs.get-test-deps == 'true' uses: awalsh128/cache-apt-pkgs-action@v1.6.0 with: - packages: gawk libgtest-dev + packages: libgtest-dev version: ${{ inputs.runs-on }}-testys - name: Install macOS Dependencies diff --git a/.github/actions/setup-iverilog/action.yml b/.github/actions/setup-iverilog/action.yml index 1517ad9c4..ac4f33ad8 100644 --- a/.github/actions/setup-iverilog/action.yml +++ b/.github/actions/setup-iverilog/action.yml @@ -33,6 +33,13 @@ runs: path: .local/ key: ${{ inputs.runs-on }}-${{ steps.get-iverilog.outputs.IVERILOG_GIT }} + - name: iverilog Linux deps + if: steps.restore-iverilog.outputs.cache-hit != 'true' && runner.os == 'Linux' + uses: awalsh128/cache-apt-pkgs-action@v1.6.0 + with: + packages: autoconf gperf make gcc g++ bison flex + version: ${{ inputs.runs-on }}-iverilog + - name: iverilog macOS deps if: steps.restore-iverilog.outputs.cache-hit != 'true' && runner.os == 'macOS' shell: bash From cc5642c904fe610cf18937fd54ea225f6de281f7 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Sat, 1 Nov 2025 16:19:38 +1300 Subject: [PATCH 30/97] Docs: Bringing prereqs in line Add comments in setup-build-env/action.yml for where to document prereqs (and the separation between build/run and test). Add some initial (very basic) text for `test_suites.rst`, listing prereqs and how to run the tests (with subsections for the different optional tests, which is currently docs, functional and unit). Add sphinx-inline-tabs, use it for tidying up prereq instructions based on OS/platform (mostly helpful in the test suites doc where there are multiple sections split by OS). Also fixes some single backticks that should be double backtick. --- .github/actions/setup-build-env/action.yml | 4 ++ README.md | 8 ++- docs/source/conf.py | 2 +- docs/source/getting_started/installation.rst | 72 ++++++++++--------- docs/source/requirements.txt | 1 + .../extending_yosys/test_suites.rst | 69 +++++++++++++++++- 6 files changed, 117 insertions(+), 39 deletions(-) diff --git a/.github/actions/setup-build-env/action.yml b/.github/actions/setup-build-env/action.yml index c8dc5dc64..4fea7ad46 100644 --- a/.github/actions/setup-build-env/action.yml +++ b/.github/actions/setup-build-env/action.yml @@ -29,6 +29,8 @@ inputs: runs: using: composite steps: + # if updating common/build/docs dependencies, make sure to update README.md + # and docs/source/getting_started/installation.rst to match. - name: Linux common dependencies if: runner.os == 'Linux' uses: awalsh128/cache-apt-pkgs-action@v1.6.0 @@ -50,6 +52,8 @@ runs: packages: graphviz xdot version: ${{ inputs.runs-on }}-docsys + # if updating test dependencies, make sure to update + # docs/source/yosys_internals/extending_yosys/test_suites.rst to match. - name: Linux test dependencies if: runner.os == 'Linux' && inputs.get-test-deps == 'true' uses: awalsh128/cache-apt-pkgs-action@v1.6.0 diff --git a/README.md b/README.md index dd5b634f9..2e659a46f 100644 --- a/README.md +++ b/README.md @@ -83,9 +83,11 @@ Xdot (graphviz) is used by the ``show`` command in yosys to display schematics. For example on Ubuntu Linux 22.04 LTS the following commands will install all prerequisites for building yosys: - $ sudo apt-get install build-essential clang lld bison flex libfl-dev \ - libreadline-dev gawk tcl-dev libffi-dev git \ - graphviz xdot pkg-config python3-dev zlib1g-dev + $ sudo apt-get install gawk git make python3 lld \ + bison clang flex libboost-filesystem-dev libboost-python-dev \ + libboost-system-dev libbz2-dev libffi-dev libfl-dev \ + libreadline-dev pkg-config tcl-dev zlib1g-dev \ + graphviz xdot $ curl -LsSf https://astral.sh/uv/install.sh | sh The environment variable `CXX` can be used to control the C++ compiler used, or diff --git a/docs/source/conf.py b/docs/source/conf.py index 49f8f5eab..6740fab83 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -50,7 +50,7 @@ rst_prolog = """ :language: yoscrypt """ -extensions = ['sphinx.ext.autosectionlabel', 'sphinxcontrib.bibtex'] +extensions = ['sphinx.ext.autosectionlabel', 'sphinxcontrib.bibtex', 'sphinx_inline_tabs'] if os.getenv("READTHEDOCS"): # Use rtds_action if we are building on read the docs and have a github token env var diff --git a/docs/source/getting_started/installation.rst b/docs/source/getting_started/installation.rst index fef495389..48a4c5fdd 100644 --- a/docs/source/getting_started/installation.rst +++ b/docs/source/getting_started/installation.rst @@ -93,56 +93,64 @@ tools: readline, libffi, Tcl and zlib; are optional but enabled by default (see :makevar:`ENABLE_*` settings in Makefile). Graphviz and Xdot are used by the `show` command to display schematics. -Installing all prerequisites for Ubuntu 22.04: +Installing all prerequisites: -.. code:: console +.. tab:: Ubuntu 22.04 - sudo apt-get install gperf build-essential clang lld bison flex libfl-dev \ - libreadline-dev gawk tcl-dev libffi-dev git \ - graphviz xdot pkg-config python3-dev zlib1g-dev - curl -LsSf https://astral.sh/uv/install.sh | sh + .. code:: console -Installing all prerequisites for macOS 13 (with Homebrew): + sudo apt-get install gawk git make python3 lld \ + bison clang flex libboost-filesystem-dev libboost-python-dev \ + libboost-system-dev libbz2-dev libffi-dev libfl-dev \ + libreadline-dev pkg-config tcl-dev zlib1g-dev \ + graphviz xdot + curl -LsSf https://astral.sh/uv/install.sh | sh -.. code:: console +.. tab:: macOS 13 (with Homebrew) - brew tap Homebrew/bundle && brew bundle + .. code:: console -or MacPorts: + brew tap Homebrew/bundle && brew bundle -.. code:: console +.. tab:: MacPorts - sudo port install bison flex readline gawk libffi graphviz \ - pkgconfig python311 boost zlib tcl + .. code:: console -On FreeBSD use the following command to install all prerequisites: + sudo port install bison flex readline gawk libffi graphviz \ + pkgconfig python311 boost zlib tcl -.. code:: console +.. tab:: FreeBSD - pkg install bison flex readline gawk libffi graphviz \ - pkgconf python311 tcl-wrapper boost-libs + .. code:: console -.. note:: On FreeBSD system use gmake instead of make. To run tests use: - ``MAKE=gmake CXX=cxx CC=cc gmake test`` + pkg install bison flex readline gawk libffi graphviz \ + pkgconf python311 tcl-wrapper boost-libs -For Cygwin use the following command to install all prerequisites, or select these additional packages: + .. note:: On FreeBSD system use gmake instead of make. To run tests use: + ``MAKE=gmake CXX=cxx CC=cc gmake test`` -.. code:: console +.. tab:: Cygwin - setup-x86_64.exe -q --packages=bison,flex,gcc-core,gcc-g++,git,libffi-devel,libreadline-devel,make,pkg-config,python3,tcl-devel,boost-build,zlib-devel + Use the following command to install all prerequisites, or select these + additional packages: -.. warning:: + .. code:: console - As of this writing, Cygwin only supports up to Python 3.9.16 while the - minimum required version of Python is 3.11. This means that Cygwin is not - compatible with many of the Python-based frontends. While this does not - currently prevent Yosys itself from working, no guarantees are made for - continued support. You may also need to specify `CXXSTD=gnu++17` to resolve - missing `strdup` function when using gcc. It is instead recommended to use - Windows Subsystem for Linux (WSL) and follow the instructions for Ubuntu. + setup-x86_64.exe -q --packages=bison,flex,gcc-core,gcc-g++,git,libffi-devel,libreadline-devel,make,pkg-config,python3,tcl-devel,boost-build,zlib-devel -.. - For MSYS2 (MINGW64): + .. warning:: + + As of this writing, Cygwin only supports up to Python 3.9.16 while the + minimum required version of Python is 3.11. This means that Cygwin is not + compatible with many of the Python-based frontends. While this does not + currently prevent Yosys itself from working, no guarantees are made for + continued support. You may also need to specify ``CXXSTD=gnu++17`` to + resolve missing ``strdup`` function when using gcc. It is instead + recommended to use Windows Subsystem for Linux (WSL) and follow the + instructions for Ubuntu. + +.. + tab:: MSYS2 (MINGW64) .. code:: console diff --git a/docs/source/requirements.txt b/docs/source/requirements.txt index 203205169..403bfb1c6 100644 --- a/docs/source/requirements.txt +++ b/docs/source/requirements.txt @@ -1,3 +1,4 @@ furo-ys @ git+https://github.com/YosysHQ/furo-ys sphinxcontrib-bibtex rtds-action +sphinx-inline-tabs diff --git a/docs/source/yosys_internals/extending_yosys/test_suites.rst b/docs/source/yosys_internals/extending_yosys/test_suites.rst index 3e5f45b94..81a79e77f 100644 --- a/docs/source/yosys_internals/extending_yosys/test_suites.rst +++ b/docs/source/yosys_internals/extending_yosys/test_suites.rst @@ -1,7 +1,72 @@ Testing Yosys ============= -.. TODO:: more about the included test suite and how to add tests +.. todo:: adding tests (makefile-tests vs seed-tests) + +Running the included test suite +------------------------------- + +The Yosys source comes with a test suite to avoid regressions and keep +everything working as expected. Tests can be run by calling ``make test`` from +the root Yosys directory. + +Functional tests +~~~~~~~~~~~~~~~~ + +Testing functional backends (see +:doc:`/yosys_internals/extending_yosys/functional_ir`) has a few requirements in +addition to those listed in :ref:`getting_started/installation:Build +prerequisites`: + +.. tab:: Ubuntu + + .. code:: console + + sudo apt-get install racket + raco pkg install rosette + pip install pytest-xdist pytest-xdist-gnumake + +.. tab:: macOS + + .. code:: console + + brew install racket + raco pkg install rosette + pip install pytest-xdist pytest-xdist-gnumake + +If you don't have one of the :ref:`getting_started/installation:CAD suite(s)` +installed, you should also install Z3 `following their +instructions `_. + +Then, set the :makevar:`ENABLE_FUNCTIONAL_TESTS` make variable when calling +``make test`` and the functional tests will be run as well. + +Unit tests +~~~~~~~~~~ + +Running the unit tests requires the following additional packages: + +.. tab:: Ubuntu + + .. code:: console + + sudo apt-get install libgtest-dev + +.. tab:: macOS + + No additional requirements. + +Unit tests can be run with ``make unit-test``. + +Docs tests +~~~~~~~~~~ + +There are some additional tests for checking examples included in the +documentation, which can be run by calling ``make test`` from the +:file:`yosys/docs` sub-directory (or ``make -C docs test`` from the root). This +also includes checking some macro commands to ensure that descriptions of them +are kept up to date, and is mostly intended for CI. + Automatic testing ----------------- @@ -14,8 +79,6 @@ compiler versions. For up to date information, including OS versions, refer to .. _Yosys Git repo: https://github.com/YosysHQ/yosys .. _the git actions page: https://github.com/YosysHQ/yosys/actions -.. todo:: are unit tests currently working - .. How to add a unit test ---------------------- From bf7c79cc8520f13b0da30299ac07a8d59b6fe282 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Sat, 1 Nov 2025 17:27:09 +1300 Subject: [PATCH 31/97] CI: vcd2fst needs deps --- .github/actions/setup-iverilog/action.yml | 26 +++++++++++------------ 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/actions/setup-iverilog/action.yml b/.github/actions/setup-iverilog/action.yml index ac4f33ad8..557ff6add 100644 --- a/.github/actions/setup-iverilog/action.yml +++ b/.github/actions/setup-iverilog/action.yml @@ -9,6 +9,19 @@ inputs: runs: using: composite steps: + - name: iverilog Linux deps + if: steps.restore-iverilog.outputs.cache-hit != 'true' && runner.os == 'Linux' + uses: awalsh128/cache-apt-pkgs-action@v1.6.0 + with: + packages: autoconf gperf make gcc g++ bison flex + version: ${{ inputs.runs-on }}-iverilog + + - name: iverilog macOS deps + if: steps.restore-iverilog.outputs.cache-hit != 'true' && runner.os == 'macOS' + shell: bash + run: | + brew install autoconf + - name: Get iverilog id: get-iverilog shell: bash @@ -33,19 +46,6 @@ runs: path: .local/ key: ${{ inputs.runs-on }}-${{ steps.get-iverilog.outputs.IVERILOG_GIT }} - - name: iverilog Linux deps - if: steps.restore-iverilog.outputs.cache-hit != 'true' && runner.os == 'Linux' - uses: awalsh128/cache-apt-pkgs-action@v1.6.0 - with: - packages: autoconf gperf make gcc g++ bison flex - version: ${{ inputs.runs-on }}-iverilog - - - name: iverilog macOS deps - if: steps.restore-iverilog.outputs.cache-hit != 'true' && runner.os == 'macOS' - shell: bash - run: | - brew install autoconf - - name: Build iverilog if: steps.restore-iverilog.outputs.cache-hit != 'true' shell: bash From 684bbf6a25f4dc8a600a9cf8cf9614313b2945d2 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Sat, 1 Nov 2025 20:08:45 +1300 Subject: [PATCH 32/97] CI: Move libbz2 to iverilog setup Needed for vcd2fst. --- .github/actions/setup-build-env/action.yml | 2 +- .github/actions/setup-iverilog/action.yml | 2 +- README.md | 4 ++-- docs/source/getting_started/installation.rst | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/actions/setup-build-env/action.yml b/.github/actions/setup-build-env/action.yml index 4fea7ad46..216742791 100644 --- a/.github/actions/setup-build-env/action.yml +++ b/.github/actions/setup-build-env/action.yml @@ -42,7 +42,7 @@ runs: if: runner.os == 'Linux' && inputs.get-build-deps == 'true' uses: awalsh128/cache-apt-pkgs-action@v1.6.0 with: - packages: bison clang flex libboost-filesystem-dev libboost-python-dev libboost-system-dev libbz2-dev libffi-dev libfl-dev libreadline-dev pkg-config tcl-dev zlib1g-dev + packages: bison clang flex libboost-filesystem-dev libboost-python-dev libboost-system-dev libffi-dev libfl-dev libreadline-dev pkg-config tcl-dev zlib1g-dev version: ${{ inputs.runs-on }}-buildys - name: Linux docs dependencies diff --git a/.github/actions/setup-iverilog/action.yml b/.github/actions/setup-iverilog/action.yml index 557ff6add..0acb582e3 100644 --- a/.github/actions/setup-iverilog/action.yml +++ b/.github/actions/setup-iverilog/action.yml @@ -13,7 +13,7 @@ runs: if: steps.restore-iverilog.outputs.cache-hit != 'true' && runner.os == 'Linux' uses: awalsh128/cache-apt-pkgs-action@v1.6.0 with: - packages: autoconf gperf make gcc g++ bison flex + packages: autoconf gperf make gcc g++ bison flex libbz2-dev version: ${{ inputs.runs-on }}-iverilog - name: iverilog macOS deps diff --git a/README.md b/README.md index 2e659a46f..6a204fa8d 100644 --- a/README.md +++ b/README.md @@ -85,8 +85,8 @@ prerequisites for building yosys: $ sudo apt-get install gawk git make python3 lld \ bison clang flex libboost-filesystem-dev libboost-python-dev \ - libboost-system-dev libbz2-dev libffi-dev libfl-dev \ - libreadline-dev pkg-config tcl-dev zlib1g-dev \ + libboost-system-dev libffi-dev libfl-dev libreadline-dev \ + pkg-config tcl-dev zlib1g-dev \ graphviz xdot $ curl -LsSf https://astral.sh/uv/install.sh | sh diff --git a/docs/source/getting_started/installation.rst b/docs/source/getting_started/installation.rst index 48a4c5fdd..5c538a959 100644 --- a/docs/source/getting_started/installation.rst +++ b/docs/source/getting_started/installation.rst @@ -101,8 +101,8 @@ Installing all prerequisites: sudo apt-get install gawk git make python3 lld \ bison clang flex libboost-filesystem-dev libboost-python-dev \ - libboost-system-dev libbz2-dev libffi-dev libfl-dev \ - libreadline-dev pkg-config tcl-dev zlib1g-dev \ + libboost-system-dev libffi-dev libfl-dev libreadline-dev \ + pkg-config tcl-dev zlib1g-dev \ graphviz xdot curl -LsSf https://astral.sh/uv/install.sh | sh From 17c1388303af4f5c2d71c2b03450dcb1d389a04c Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Sat, 1 Nov 2025 20:11:36 +1300 Subject: [PATCH 33/97] Drop boost-python --- .github/actions/setup-build-env/action.yml | 2 +- README.md | 5 ++--- docs/source/getting_started/installation.rst | 5 ++--- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/.github/actions/setup-build-env/action.yml b/.github/actions/setup-build-env/action.yml index 216742791..5ecb4d3a9 100644 --- a/.github/actions/setup-build-env/action.yml +++ b/.github/actions/setup-build-env/action.yml @@ -42,7 +42,7 @@ runs: if: runner.os == 'Linux' && inputs.get-build-deps == 'true' uses: awalsh128/cache-apt-pkgs-action@v1.6.0 with: - packages: bison clang flex libboost-filesystem-dev libboost-python-dev libboost-system-dev libffi-dev libfl-dev libreadline-dev pkg-config tcl-dev zlib1g-dev + packages: bison clang flex libboost-filesystem-dev libboost-system-dev libffi-dev libfl-dev libreadline-dev pkg-config tcl-dev zlib1g-dev version: ${{ inputs.runs-on }}-buildys - name: Linux docs dependencies diff --git a/README.md b/README.md index 6a204fa8d..42462efbc 100644 --- a/README.md +++ b/README.md @@ -84,9 +84,8 @@ For example on Ubuntu Linux 22.04 LTS the following commands will install all prerequisites for building yosys: $ sudo apt-get install gawk git make python3 lld \ - bison clang flex libboost-filesystem-dev libboost-python-dev \ - libboost-system-dev libffi-dev libfl-dev libreadline-dev \ - pkg-config tcl-dev zlib1g-dev \ + bison clang flex libboost-filesystem-dev libboost-system-dev \ + libffi-dev libfl-dev libreadline-dev pkg-config tcl-dev zlib1g-dev \ graphviz xdot $ curl -LsSf https://astral.sh/uv/install.sh | sh diff --git a/docs/source/getting_started/installation.rst b/docs/source/getting_started/installation.rst index 5c538a959..8ec5c4e35 100644 --- a/docs/source/getting_started/installation.rst +++ b/docs/source/getting_started/installation.rst @@ -100,9 +100,8 @@ Installing all prerequisites: .. code:: console sudo apt-get install gawk git make python3 lld \ - bison clang flex libboost-filesystem-dev libboost-python-dev \ - libboost-system-dev libffi-dev libfl-dev libreadline-dev \ - pkg-config tcl-dev zlib1g-dev \ + bison clang flex libboost-filesystem-dev libboost-system-dev \ + libffi-dev libfl-dev libreadline-dev pkg-config tcl-dev zlib1g-dev \ graphviz xdot curl -LsSf https://astral.sh/uv/install.sh | sh From 35e4d967c6cb637bb50900196aac8e4a73b59290 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Tue, 4 Nov 2025 08:00:35 +0100 Subject: [PATCH 34/97] install UV in wheels.yml --- .github/workflows/wheels.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 9eea1468d..e75e02ad2 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -54,6 +54,11 @@ jobs: fetch-depth: 0 submodules: true persist-credentials: false + - if: ${{ matrix.os.family == 'linux' }} + name: "[Linux] Install UV" + shell: bash + run: | + curl -LsSf https://astral.sh/uv/install.sh | sh - uses: actions/setup-python@v5 - name: Get FFI shell: bash From db76eebc0f69d791ec455f9b0f9e006d25b0bcbb Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Tue, 4 Nov 2025 08:35:07 +0100 Subject: [PATCH 35/97] Remove mentions of Boost --- .github/actions/setup-build-env/action.yml | 2 +- .github/workflows/wheels/_run_cibw_linux.py | 4 ++-- .gitignore | 1 - README.md | 3 +-- docs/source/getting_started/installation.rst | 11 +++++------ flake.nix | 2 +- 6 files changed, 10 insertions(+), 13 deletions(-) diff --git a/.github/actions/setup-build-env/action.yml b/.github/actions/setup-build-env/action.yml index 5ecb4d3a9..60fe481e7 100644 --- a/.github/actions/setup-build-env/action.yml +++ b/.github/actions/setup-build-env/action.yml @@ -42,7 +42,7 @@ runs: if: runner.os == 'Linux' && inputs.get-build-deps == 'true' uses: awalsh128/cache-apt-pkgs-action@v1.6.0 with: - packages: bison clang flex libboost-filesystem-dev libboost-system-dev libffi-dev libfl-dev libreadline-dev pkg-config tcl-dev zlib1g-dev + packages: bison clang flex libffi-dev libfl-dev libreadline-dev pkg-config tcl-dev zlib1g-dev version: ${{ inputs.runs-on }}-buildys - name: Linux docs dependencies diff --git a/.github/workflows/wheels/_run_cibw_linux.py b/.github/workflows/wheels/_run_cibw_linux.py index fb4e0b839..1e8a0f497 100644 --- a/.github/workflows/wheels/_run_cibw_linux.py +++ b/.github/workflows/wheels/_run_cibw_linux.py @@ -24,10 +24,10 @@ from pathlib import Path __yosys_root__ = Path(__file__).absolute().parents[3] -for source in ["boost", "ffi", "bison"]: +for source in ["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." + "You need to download ffi and bison in a similar manner to wheels.yml first." ) exit(-1) diff --git a/.gitignore b/.gitignore index 2367bccb3..a8b04ac45 100644 --- a/.gitignore +++ b/.gitignore @@ -55,7 +55,6 @@ # pyosys /kernel/*.pyh /kernel/python_wrappers.cc -/boost /ffi /bison /venv diff --git a/README.md b/README.md index 42462efbc..427d59c9e 100644 --- a/README.md +++ b/README.md @@ -83,8 +83,7 @@ Xdot (graphviz) is used by the ``show`` command in yosys to display schematics. For example on Ubuntu Linux 22.04 LTS the following commands will install all prerequisites for building yosys: - $ sudo apt-get install gawk git make python3 lld \ - bison clang flex libboost-filesystem-dev libboost-system-dev \ + $ sudo apt-get install gawk git make python3 lld bison clang flex \ libffi-dev libfl-dev libreadline-dev pkg-config tcl-dev zlib1g-dev \ graphviz xdot $ curl -LsSf https://astral.sh/uv/install.sh | sh diff --git a/docs/source/getting_started/installation.rst b/docs/source/getting_started/installation.rst index 8ec5c4e35..43b996353 100644 --- a/docs/source/getting_started/installation.rst +++ b/docs/source/getting_started/installation.rst @@ -99,8 +99,7 @@ Installing all prerequisites: .. code:: console - sudo apt-get install gawk git make python3 lld \ - bison clang flex libboost-filesystem-dev libboost-system-dev \ + sudo apt-get install gawk git make python3 lld bison clang flex \ libffi-dev libfl-dev libreadline-dev pkg-config tcl-dev zlib1g-dev \ graphviz xdot curl -LsSf https://astral.sh/uv/install.sh | sh @@ -116,14 +115,14 @@ Installing all prerequisites: .. code:: console sudo port install bison flex readline gawk libffi graphviz \ - pkgconfig python311 boost zlib tcl + pkgconfig python311 zlib tcl .. tab:: FreeBSD .. code:: console pkg install bison flex readline gawk libffi graphviz \ - pkgconf python311 tcl-wrapper boost-libs + pkgconf python311 tcl-wrapper .. note:: On FreeBSD system use gmake instead of make. To run tests use: ``MAKE=gmake CXX=cxx CC=cc gmake test`` @@ -135,7 +134,7 @@ Installing all prerequisites: .. code:: console - setup-x86_64.exe -q --packages=bison,flex,gcc-core,gcc-g++,git,libffi-devel,libreadline-devel,make,pkg-config,python3,tcl-devel,boost-build,zlib-devel + setup-x86_64.exe -q --packages=bison,flex,gcc-core,gcc-g++,git,libffi-devel,libreadline-devel,make,pkg-config,python3,tcl-devel,zlib-devel .. warning:: @@ -153,7 +152,7 @@ Installing all prerequisites: .. code:: console - pacman -S bison flex mingw-w64-x86_64-gcc git libffi-devel libreadline-devel make pkg-config python3 tcl-devel mingw-w64-x86_64-boost zlib-devel + pacman -S bison flex mingw-w64-x86_64-gcc git libffi-devel libreadline-devel make pkg-config python3 tcl-devel zlib-devel Not that I can get this to work; it's failing during ld with what looks like math library issues: ``multiple definition of `tanh'`` and diff --git a/flake.nix b/flake.nix index 19ba59f17..1993b803b 100644 --- a/flake.nix +++ b/flake.nix @@ -41,7 +41,7 @@ packages.default = yosys; defaultPackage = yosys; devShell = pkgs.mkShell { - buildInputs = with pkgs; [ clang llvmPackages.bintools gcc bison flex libffi tcl readline python3 zlib git gtest abc-verifier verilog boost python3Packages.boost ]; + buildInputs = with pkgs; [ clang llvmPackages.bintools gcc bison flex libffi tcl readline python3 zlib git gtest abc-verifier verilog ]; }; } ); From ad3ae52e9a6f830766c3b9b8fb8c99e0d2a2826a Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Tue, 4 Nov 2025 09:30:04 +0100 Subject: [PATCH 36/97] Upload only on manual action --- .github/workflows/wheels.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index e75e02ad2..3fdde6abf 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -25,13 +25,13 @@ jobs: archs: "aarch64", }, { - name: "macOS 13", + name: "macOS 15 x64", family: "macos", runner: "macos-15-intel", archs: "x86_64", }, { - name: "macOS 14", + name: "macOS 15 arm64", family: "macos", runner: "macos-15", archs: "arm64", @@ -119,7 +119,7 @@ jobs: path: ./wheelhouse/*.whl upload_wheels: name: Upload Wheels - if: github.repository == 'YosysHQ/Yosys' + if: (github.repository == 'YosysHQ/Yosys') && (github.event_name == 'workflow_dispatch') runs-on: ubuntu-latest # Specifying a GitHub environment is optional, but strongly encouraged environment: pypi From 3a54ed6916f45e558e3f26d1a9abcb932ea04b32 Mon Sep 17 00:00:00 2001 From: Mohamed Gaber Date: Tue, 4 Nov 2025 14:32:38 +0200 Subject: [PATCH 37/97] hotfix: don't use uv when building wheels --- .github/workflows/wheels.yml | 5 ----- setup.py | 1 + 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 3fdde6abf..b3a25a43a 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -54,11 +54,6 @@ jobs: fetch-depth: 0 submodules: true persist-credentials: false - - if: ${{ matrix.os.family == 'linux' }} - name: "[Linux] Install UV" - shell: bash - run: | - curl -LsSf https://astral.sh/uv/install.sh | sh - uses: actions/setup-python@v5 - name: Get FFI shell: bash diff --git a/setup.py b/setup.py index 59c1c4b33..8b786cb32 100644 --- a/setup.py +++ b/setup.py @@ -51,6 +51,7 @@ class libyosys_so_ext(Extension): "ENABLE_TCL=0", "ENABLE_READLINE=0", "ENABLE_EDITLINE=0", + "PYOSYS_USE_UV=0", # + install requires takes its role when building wheels # Always compile and include ABC in wheel "ABCEXTERNAL=", # Show compile commands From 51c8193643cbda5c3aefe22c9fb1235388f8fd14 Mon Sep 17 00:00:00 2001 From: Mohamed Gaber Date: Tue, 4 Nov 2025 14:58:48 +0200 Subject: [PATCH 38/97] hotfix: update libffi in wheels ci update libffi to a version where https://github.com/libffi/libffi/issues/852 is fixed --- .github/workflows/wheels.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index b3a25a43a..8e055f526 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -59,7 +59,7 @@ jobs: shell: bash 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 + curl -L https://github.com/libffi/libffi/releases/download/v3.4.8/libffi-3.4.8.tar.gz | tar --strip-components=1 -xzC ffi - if: ${{ matrix.os.family == 'linux' }} name: "[Linux] Bison 3.8.2" shell: bash From 12cb8e95110af37c46dea77f46484db72ae7cdc9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 5 Nov 2025 00:24:49 +0000 Subject: [PATCH 39/97] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index a46b865ed..d72cbee7e 100644 --- a/Makefile +++ b/Makefile @@ -161,7 +161,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.58+98 +YOSYS_VER := 0.58+132 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 e89c5914fe279bfee42e1bbaf6fd017cb333ff64 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 5 Nov 2025 07:10:08 +0100 Subject: [PATCH 40/97] CodeQL CI fix --- .github/workflows/codeql.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index da30e3da4..4bca5a8a5 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -10,18 +10,18 @@ jobs: name: Analyze runs-on: ubuntu-latest steps: - - name: Setup environment - uses: ./.github/actions/setup-build-env - with: - runs-on: ubuntu-latest - get-build-deps: true - - name: Checkout repository uses: actions/checkout@v4 with: submodules: true persist-credentials: false + - name: Setup environment + uses: ./.github/actions/setup-build-env + with: + runs-on: ubuntu-latest + get-build-deps: true + - name: Initialize CodeQL uses: github/codeql-action/init@v3 with: From 66d8fc5c287aa67e13148c3b27ce966155e48975 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Wed, 5 Nov 2025 11:00:25 +0100 Subject: [PATCH 41/97] libparse: quirk-compatibility for unquoted boolean expression strings --- passes/techmap/libparse.cc | 81 +++++++++++++++++++++++++++----------- passes/techmap/libparse.h | 2 + 2 files changed, 61 insertions(+), 22 deletions(-) diff --git a/passes/techmap/libparse.cc b/passes/techmap/libparse.cc index 7d4fd77ad..cf1854c87 100644 --- a/passes/techmap/libparse.cc +++ b/passes/techmap/libparse.cc @@ -364,7 +364,7 @@ std::string LibertyExpression::str(int indent) #endif -int LibertyParser::lexer(std::string &str) +int LibertyParser::lexer_inner(std::string &str) { int c; @@ -390,11 +390,9 @@ int LibertyParser::lexer(std::string &str) if (str == "+" || str == "-") { /* Single operator is not an identifier */ - // fprintf(stderr, "LEX: char >>%s<<\n", str.c_str()); return str[0]; } else { - // fprintf(stderr, "LEX: identifier >>%s<<\n", str.c_str()); return 'v'; } } @@ -402,24 +400,25 @@ int LibertyParser::lexer(std::string &str) // if it wasn't an identifer, number of array range, // maybe it's a string? if (c == '"') { + f.consume(1); size_t i = 0; while (true) { c = f.peek(i); line += (c == '\n'); - if (c != '"') + if (c != '"' && c != EOF) i += 1; else break; } str.clear(); -#ifdef FILTERLIB f.unget(); - str.append(f.buffered_data(), f.buffered_data() + i + 2); - f.consume(i + 2); -#else - str.append(f.buffered_data(), f.buffered_data() + i); - f.consume(i + 1); + str.append(f.buffered_data(), f.buffered_data() + i + 1); + // Usage in filterlib is expected to retain quotes + // but yosys expects to get unquoted +#ifdef FILTERLIB + str = "\"" + str + "\""; #endif + f.consume(i + 2); return 'v'; } @@ -442,13 +441,12 @@ int LibertyParser::lexer(std::string &str) return lexer(str); } f.unget(); - // fprintf(stderr, "LEX: char >>/<<\n"); return '/'; // a single '/' charater. } // check for a backslash if (c == '\\') { - c = f.get(); + c = f.get(); if (c == '\r') c = f.get(); if (c == '\n') { @@ -467,14 +465,22 @@ int LibertyParser::lexer(std::string &str) // anything else, such as ';' will get passed // through as literal items. - - // if (c >= 32 && c < 255) - // fprintf(stderr, "LEX: char >>%c<<\n", c); - // else - // fprintf(stderr, "LEX: char %d\n", c); return c; } +int LibertyParser::lexer(std::string &str) +{ + int ret = lexer_inner(str); + // if (ret >= 32 && ret < 255) { + // fprintf(stdout, "LEX: ret >>%c<<\n", ret); + // } else if (ret == 'v') { + // fprintf(stdout, "LEX: ret v str %s\n", str.c_str()); + // } else { + // fprintf(stdout, "LEX: ret %d\n", ret); + // } + return ret; +} + void LibertyParser::report_unexpected_token(int tok) { std::string eReport; @@ -545,6 +551,25 @@ void LibertyParser::parse_vector_range(int tok) } } +// Consume into out_str any string-ish tokens, seperated with spaces +// to cope with abuse of the underdefined spec by real world PDKs +// enabled by proprietary implementations. +// Sorry. +int LibertyParser::consume_wrecked_str(int tok, std::string& out_str) { + std::string str = ""; + while (tok != ';' && tok != EOF && tok != 'n') { + out_str += " "; + if (tok == 'v') + out_str += str; + else + out_str += tok; + tok = lexer(str); + } + if (tok == EOF) + error("wrecked string EOF"); + return tok; +} + LibertyAst *LibertyParser::parse(bool top_level) { std::string str; @@ -591,17 +616,29 @@ LibertyAst *LibertyParser::parse(bool top_level) if (tok == '[') { parse_vector_range(tok); tok = lexer(str); + } else { + // Hack for when an expression string is unquoted + // std::cout << "consume_wrecked_str from :\n"; + // std::cout << " weh " << str << "\n"; + tok = consume_wrecked_str(tok, ast->value); } + } else if (tok == '(') { + // Hack for when an expression string is unquoted and starts with + // parentheses + // tok = ''; + // ast->value = "("; + // std::cout << "consume_wrecked_str from (\n"; + tok = consume_wrecked_str(tok, ast->value); } while (tok == '+' || tok == '-' || tok == '*' || tok == '/' || tok == '!') { ast->value += tok; tok = lexer(str); if (tok != 'v') - error(); + error("one"); ast->value += str; tok = lexer(str); } - + // In a liberty file, all key : value pairs should end in ';' // However, there are some liberty files in the wild that // just have a newline. We'll be kind and accept a newline @@ -609,7 +646,7 @@ LibertyAst *LibertyParser::parse(bool top_level) if ((tok == ';') || (tok == 'n')) break; else - error(); + error("two"); continue; } @@ -621,11 +658,11 @@ LibertyAst *LibertyParser::parse(bool top_level) continue; if (tok == ')') break; - + if (tok == '[') { parse_vector_range(tok); - continue; + continue; } if (tok == 'n') continue; diff --git a/passes/techmap/libparse.h b/passes/techmap/libparse.h index 44b5d3d47..91f06a46c 100644 --- a/passes/techmap/libparse.h +++ b/passes/techmap/libparse.h @@ -170,10 +170,12 @@ namespace Yosys 'n': newline anything else is a single character. */ + int lexer_inner(std::string &str); int lexer(std::string &str); void report_unexpected_token(int tok); void parse_vector_range(int tok); + int consume_wrecked_str(int tok, std::string& out_str); LibertyAst *parse(bool top_level); void error() const; void error(const std::string &str) const; From 547e254a9bcd846232f54512a834c1af561a155e Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Wed, 5 Nov 2025 12:12:30 +0100 Subject: [PATCH 42/97] libparse: parse expressions in filterlib --- passes/techmap/dfflibmap.cc | 4 +- passes/techmap/libparse.cc | 120 +++++++++++++++++++++--------------- passes/techmap/libparse.h | 10 +-- 3 files changed, 79 insertions(+), 55 deletions(-) diff --git a/passes/techmap/dfflibmap.cc b/passes/techmap/dfflibmap.cc index 6d55d1b43..e8fc6fc12 100644 --- a/passes/techmap/dfflibmap.cc +++ b/passes/techmap/dfflibmap.cc @@ -127,7 +127,7 @@ static bool parse_next_state(const LibertyAst *cell, const LibertyAst *attr, std return false; } - auto pin_names = pool{}; + auto pin_names = std::unordered_set{}; tree.get_pin_names(pin_names); // from the `ff` block, we know the flop output signal name for loopback. @@ -156,7 +156,7 @@ static bool parse_next_state(const LibertyAst *cell, const LibertyAst *attr, std auto pins = std::vector(pin_names.begin(), pin_names.end()); int lut = 0; for (int n = 0; n < 8; n++) { - auto values = dict{}; + auto values = std::unordered_map{}; values.insert(std::make_pair(pins[0], (n & 1) == 1)); values.insert(std::make_pair(pins[1], (n & 2) == 2)); values.insert(std::make_pair(ff_output, (n & 4) == 4)); diff --git a/passes/techmap/libparse.cc b/passes/techmap/libparse.cc index cf1854c87..50bf2aca6 100644 --- a/passes/techmap/libparse.cc +++ b/passes/techmap/libparse.cc @@ -26,8 +26,20 @@ #include #include -#ifndef FILTERLIB +#ifdef FILTERLIB +#undef log_assert +void log_assert(bool cond) { + if (!cond) + fprintf(stderr, "Unspecified assertion failed\n"); +} +void warn(std::string str) { + std::cerr << str; +} +#else #include "kernel/log.h" +void warn(std::string str) { + Yosys::log_formatted_warning("", str); +} #endif using namespace Yosys; @@ -162,13 +174,15 @@ void LibertyAst::dump(FILE *f, sieve &blacklist, sieve &whitelist, std::string i fprintf(f, " ;\n"); } -#ifndef FILTERLIB - // binary operators excluding ' ' -bool LibertyExpression::is_nice_binop(char c) { +bool LibertyExpression::char_is_nice_binop(char c) { return c == '*' || c == '&' || c == '^' || c == '+' || c == '|'; } +bool LibertyExpression::is_binop() { + return kind == AND || kind == OR || kind == XOR; +} + // https://matklad.github.io/2020/04/13/simple-but-powerful-pratt-parsing.html LibertyExpression LibertyExpression::parse(Lexer &s, int min_prio) { if (s.empty()) @@ -191,7 +205,9 @@ LibertyExpression LibertyExpression::parse(Lexer &s, int min_prio) { s.next(); lhs = parse(s); if (s.peek() != ')') { - log_warning("expected ')' instead of '%c' while parsing Liberty expression '%s'\n", s.peek(), s.full_expr()); + std::stringstream ss; + ss << "expected ')' instead of " << s.peek() << " while parsing Liberty expression '" << s.full_expr() << "'\n"; + warn(ss.str()); return lhs; } s.next(); @@ -200,7 +216,9 @@ LibertyExpression LibertyExpression::parse(Lexer &s, int min_prio) { lhs.kind = Kind::NOT; lhs.children.push_back(parse(s, 7)); } else { - log_warning("unrecognised character '%c' while parsing Liberty expression '%s'\n", c, s.full_expr()); + std::stringstream ss; + ss << "unrecognised character " << c << " while parsing Liberty expression " << s.full_expr() << "\n"; + warn(ss.str()); return lhs; } @@ -246,7 +264,7 @@ LibertyExpression LibertyExpression::parse(Lexer &s, int min_prio) { s.next(); c = s.peek(); } - if (is_nice_binop(c)) { + if (char_is_nice_binop(c)) { // We found a real binop, so this space wasn't an AND // and we just discard it as meaningless whitespace continue; @@ -286,7 +304,7 @@ LibertyExpression LibertyExpression::parse(Lexer &s, int min_prio) { return lhs; } -void LibertyExpression::get_pin_names(pool& names) { +void LibertyExpression::get_pin_names(std::unordered_set& names) { if (kind == Kind::PIN) { names.insert(name); } else { @@ -295,7 +313,7 @@ void LibertyExpression::get_pin_names(pool& names) { } } -bool LibertyExpression::eval(dict& values) { +bool LibertyExpression::eval(std::unordered_map& values) { bool result = false; switch (kind) { case Kind::AND: @@ -324,7 +342,7 @@ bool LibertyExpression::eval(dict& values) { return false; } -std::string LibertyExpression::str(int indent) +std::string LibertyExpression::sexpr_str(int indent) { std::string prefix; switch (kind) { @@ -355,14 +373,53 @@ std::string LibertyExpression::str(int indent) if (!first) { prefix += "\n" + std::string(indent + add_indent, ' '); } - prefix += child.str(indent + add_indent); + prefix += child.sexpr_str(indent + add_indent); first = false; } prefix += ")"; return prefix; } -#endif +std::string LibertyExpression::vlog_str() +{ + std::string prefix; + if (kind != PIN) + prefix += "("; + if (is_binop()) { + log_assert(children.size() == 2); + prefix += children[0].vlog_str(); + switch (kind) { + case AND: + prefix += "&"; + break; + case OR: + prefix += "|"; + break; + case XOR: + prefix += "^"; + break; + default: + log_assert(false); + } + prefix += children[1].vlog_str(); + } else { + switch (kind) { + case NOT: + log_assert(children.size() == 1); + prefix += "~"; + prefix += children[0].vlog_str(); + break; + case PIN: + prefix += name; + break; + default: + log_assert(false); + } + } + if (kind != PIN) + prefix += ")"; + return prefix; +} int LibertyParser::lexer_inner(std::string &str) { @@ -764,43 +821,8 @@ const LibertyAst *find_non_null(const LibertyAst *node, const char *name) std::string func2vl(std::string str) { - for (size_t pos = str.find_first_of("\" \t"); pos != std::string::npos; pos = str.find_first_of("\" \t")) { - char c_left = pos > 0 ? str[pos-1] : ' '; - char c_right = pos+1 < str.size() ? str[pos+1] : ' '; - if (std::string("\" \t*+").find(c_left) != std::string::npos) - str.erase(pos, 1); - else if (std::string("\" \t*+").find(c_right) != std::string::npos) - str.erase(pos, 1); - else - str[pos] = '*'; - } - - std::vector group_start; - for (size_t pos = 0; pos < str.size(); pos++) { - if (str[pos] == '(') - group_start.push_back(pos); - if (str[pos] == ')' && group_start.size() > 0) { - if (pos+1 < str.size() && str[pos+1] == '\'') { - std::string group = str.substr(group_start.back(), pos-group_start.back()+1); - str[group_start.back()] = '~'; - str.replace(group_start.back()+1, group.size(), group); - pos++; - } - group_start.pop_back(); - } - if (str[pos] == '\'' && pos > 0) { - size_t start = str.find_last_of("()'*+^&| ", pos-1)+1; - std::string group = str.substr(start, pos-start); - str[start] = '~'; - str.replace(start+1, group.size(), group); - } - if (str[pos] == '*') - str[pos] = '&'; - if (str[pos] == '+') - str[pos] = '|'; - } - - return str; + auto helper = LibertyExpression::Lexer(str); + return LibertyExpression::parse(helper).vlog_str(); } void event2vl(const LibertyAst *ast, std::string &edge, std::string &expr) diff --git a/passes/techmap/libparse.h b/passes/techmap/libparse.h index 91f06a46c..f1138567d 100644 --- a/passes/techmap/libparse.h +++ b/passes/techmap/libparse.h @@ -91,11 +91,13 @@ namespace Yosys LibertyExpression() : kind(Kind::EMPTY) {} static LibertyExpression parse(Lexer &s, int min_prio = 0); - void get_pin_names(pool& names); - bool eval(dict& values); - std::string str(int indent = 0); + void get_pin_names(std::unordered_set& names); + bool eval(std::unordered_map& values); + std::string sexpr_str(int indent = 0); + std::string vlog_str(); private: - static bool is_nice_binop(char c); + static bool char_is_nice_binop(char c); + bool is_binop(); }; class LibertyInputStream { From 4fac7a1b20078ee2a73afc815f8244ba5f345528 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Wed, 5 Nov 2025 12:35:58 +0100 Subject: [PATCH 43/97] libparse: fix space before closing paren in expressions --- passes/techmap/libparse.cc | 6 +++--- tests/unit/techmap/libparseTest.cc | 7 ++++++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/passes/techmap/libparse.cc b/passes/techmap/libparse.cc index 50bf2aca6..6db204c2e 100644 --- a/passes/techmap/libparse.cc +++ b/passes/techmap/libparse.cc @@ -191,7 +191,7 @@ LibertyExpression LibertyExpression::parse(Lexer &s, int min_prio) { char c = s.peek(); auto lhs = LibertyExpression{}; - while (isspace(c)) { + while (isspace(c) || c == '"') { if (s.empty()) return lhs; s.next(); @@ -221,7 +221,6 @@ LibertyExpression LibertyExpression::parse(Lexer &s, int min_prio) { warn(ss.str()); return lhs; } - while (true) { if (s.empty()) break; @@ -264,9 +263,10 @@ LibertyExpression LibertyExpression::parse(Lexer &s, int min_prio) { s.next(); c = s.peek(); } - if (char_is_nice_binop(c)) { + if (char_is_nice_binop(c) || c == ')') { // We found a real binop, so this space wasn't an AND // and we just discard it as meaningless whitespace + // Closing paren is also always terminating here continue; } } else { diff --git a/tests/unit/techmap/libparseTest.cc b/tests/unit/techmap/libparseTest.cc index b58e55bf2..95070dd04 100644 --- a/tests/unit/techmap/libparseTest.cc +++ b/tests/unit/techmap/libparseTest.cc @@ -13,7 +13,7 @@ namespace RTLIL { void checkAll(std::initializer_list expressions, std::string expected) { for (const auto& e : expressions) { auto helper = LibertyExpression::Lexer(e); - auto tree_s = LibertyExpression::parse(helper).str(); + auto tree_s = LibertyExpression::parse(helper).sexpr_str(); EXPECT_EQ(tree_s, expected); } } @@ -82,6 +82,11 @@ namespace RTLIL { }, "(and (pin \"x\")\n" " (not (pin \"y\")))" ); + checkAll({ + "( D & EN )", + }, "(and (pin \"D\")\n" + " (pin \"EN\"))" + ); } } From bf29f6dc11630a3d97254bfaed3652fe8be35890 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Wed, 5 Nov 2025 12:50:50 +0100 Subject: [PATCH 44/97] libparse: tolerate closing quotes in expression parsing --- passes/techmap/libparse.cc | 4 ++-- passes/techmap/libparse.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/passes/techmap/libparse.cc b/passes/techmap/libparse.cc index 6db204c2e..eddc68263 100644 --- a/passes/techmap/libparse.cc +++ b/passes/techmap/libparse.cc @@ -263,10 +263,10 @@ LibertyExpression LibertyExpression::parse(Lexer &s, int min_prio) { s.next(); c = s.peek(); } - if (char_is_nice_binop(c) || c == ')') { + if (char_is_nice_binop(c) || c == ')' || c == '\'' || c == '\"') { // We found a real binop, so this space wasn't an AND // and we just discard it as meaningless whitespace - // Closing paren is also always terminating here + // Tail operators also imply this isn't an AND continue; } } else { diff --git a/passes/techmap/libparse.h b/passes/techmap/libparse.h index f1138567d..674484dad 100644 --- a/passes/techmap/libparse.h +++ b/passes/techmap/libparse.h @@ -63,7 +63,7 @@ namespace Yosys } std::string pin() { - auto length = s.find_first_of("\t()'!^*& +|"); + auto length = s.find_first_of("\t()'!^*& +|\""); if (length == std::string::npos) { // nothing found so use size of s length = s.size(); From b0a3d6a3e7b01e57c707af7c575ad243ab16ce9c Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Wed, 5 Nov 2025 13:05:30 +0100 Subject: [PATCH 45/97] libparse: fix up tests since liberty expression parsing now normalizes the form of these expressions --- tests/liberty/XNOR2X1.lib.verilogsim.ok | 2 +- tests/liberty/dff.lib | 4 +- tests/liberty/dff.lib.filtered.ok | 4 +- tests/liberty/dff.lib.verilogsim.ok | 6 +-- tests/liberty/normal.lib.verilogsim.ok | 18 +++---- tests/liberty/unquoted.lib | 60 ++++++++++++++++++++++++ tests/liberty/unquoted.lib.filtered.ok | 60 ++++++++++++++++++++++++ tests/liberty/unquoted.lib.verilogsim.ok | 39 +++++++++++++++ 8 files changed, 176 insertions(+), 17 deletions(-) create mode 100644 tests/liberty/unquoted.lib create mode 100644 tests/liberty/unquoted.lib.filtered.ok create mode 100644 tests/liberty/unquoted.lib.verilogsim.ok diff --git a/tests/liberty/XNOR2X1.lib.verilogsim.ok b/tests/liberty/XNOR2X1.lib.verilogsim.ok index 89e55e8b8..6c9ec26dd 100644 --- a/tests/liberty/XNOR2X1.lib.verilogsim.ok +++ b/tests/liberty/XNOR2X1.lib.verilogsim.ok @@ -2,5 +2,5 @@ module XNOR2X1 (B, A, Y); input B; input A; output Y; - assign Y = !(B&!A|!B&A); // "!(B&!A|!B&A)" + assign Y = (~((B&(~A))|((~B)&A))); // "!(B&!A|!B&A)" endmodule diff --git a/tests/liberty/dff.lib b/tests/liberty/dff.lib index 61f5966f5..b5df36587 100644 --- a/tests/liberty/dff.lib +++ b/tests/liberty/dff.lib @@ -5,7 +5,7 @@ library(dff) { area : 1; ff("IQ", "IQN") { next_state : "(D)"; - clocked_on : "CLK"; + clocked_on : (CLK); } pin(D) { direction : input; @@ -15,7 +15,7 @@ library(dff) { } pin(Q) { direction: output; - function : "IQ"; + function : IQ; } } diff --git a/tests/liberty/dff.lib.filtered.ok b/tests/liberty/dff.lib.filtered.ok index b7dcb96be..2c2804ca1 100644 --- a/tests/liberty/dff.lib.filtered.ok +++ b/tests/liberty/dff.lib.filtered.ok @@ -3,7 +3,7 @@ library(dff) { area : 1 ; ff("IQ", "IQN") { next_state : "(D)" ; - clocked_on : "CLK" ; + clocked_on : ( CLK ) ; } pin(D) { direction : input ; @@ -13,7 +13,7 @@ library(dff) { } pin(Q) { direction : output ; - function : "IQ" ; + function : IQ ; } } } diff --git a/tests/liberty/dff.lib.verilogsim.ok b/tests/liberty/dff.lib.verilogsim.ok index 46441d0fc..4f2a5750c 100644 --- a/tests/liberty/dff.lib.verilogsim.ok +++ b/tests/liberty/dff.lib.verilogsim.ok @@ -3,10 +3,10 @@ module dff (D, CLK, Q); input D; input CLK; output Q; - assign Q = IQ; // "IQ" + assign Q = IQ; // IQ always @(posedge CLK) begin // "(D)" - "IQ" <= (D); - "IQN" <= ~((D)); + "IQ" <= D; + "IQN" <= ~(D); end endmodule diff --git a/tests/liberty/normal.lib.verilogsim.ok b/tests/liberty/normal.lib.verilogsim.ok index 85aed5f4e..190ecd285 100644 --- a/tests/liberty/normal.lib.verilogsim.ok +++ b/tests/liberty/normal.lib.verilogsim.ok @@ -1,13 +1,13 @@ module inv (A, Y); input A; output Y; - assign Y = ~A; // "A'" + assign Y = (~A); // "A'" endmodule module tri_inv (A, S, Z); input A; input S; output Z; - assign Z = ~A; // "A'" + assign Z = (~A); // "A'" endmodule module buffer (A, Y); input A; @@ -18,26 +18,26 @@ module nand2 (A, B, Y); input A; input B; output Y; - assign Y = ~(A&B); // "(A * B)'" + assign Y = (~(A&B)); // "(A * B)'" endmodule module nor2 (A, B, Y); input A; input B; output Y; - assign Y = ~(A|B); // "(A + B)'" + assign Y = (~(A|B)); // "(A + B)'" endmodule module xor2 (A, B, Y); input A; input B; output Y; - assign Y = (A&~B)|(~A&B); // "(A *B') + (A' * B)" + assign Y = ((A&(~B))|((~A)&B)); // "(A *B') + (A' * B)" endmodule module imux2 (A, B, S, Y); input A; input B; input S; output Y; - assign Y = ~(&(A&S)|(B&~S)&); // "( (A * S) + (B * S') )'" + assign Y = (~((A&S)|(B&(~S)))); // "( (A * S) + (B * S') )'" endmodule module dff (D, CLK, RESET, PRESET, Q, QN); reg "IQ", "IQN"; @@ -89,14 +89,14 @@ module aoi211 (A, B, C, Y); input B; input C; output Y; - assign Y = ~((A&B)|C); // "((A * B) + C)'" + assign Y = (~((A&B)|C)); // "((A * B) + C)'" endmodule module oai211 (A, B, C, Y); input A; input B; input C; output Y; - assign Y = ~((A|B)&C); // "((A + B) * C)'" + assign Y = (~((A|B)&C)); // "((A + B) * C)'" endmodule module halfadder (A, B, C, Y); input A; @@ -104,7 +104,7 @@ module halfadder (A, B, C, Y); output C; assign C = (A&B); // "(A * B)" output Y; - assign Y = (A&~B)|(~A&B); // "(A *B') + (A' * B)" + assign Y = ((A&(~B))|((~A)&B)); // "(A *B') + (A' * B)" endmodule module fulladder (A, B, CI, CO, Y); input A; diff --git a/tests/liberty/unquoted.lib b/tests/liberty/unquoted.lib new file mode 100644 index 000000000..c2bf538d2 --- /dev/null +++ b/tests/liberty/unquoted.lib @@ -0,0 +1,60 @@ +library(dff_unquoted) { + cell (dff1) { + area : 1; + ff("IQ", "IQN") { + next_state : !D; + clocked_on : (CLK); + } + pin(D) { + direction : input; + } + pin(CLK) { + direction : input; + } + pin(Q) { + direction: output; + function : IQ; + } + } + cell (dff2) { + area : 1; + ff(IQ, IQN) { + next_state : D'; + clocked_on : CLK; + } + pin(D) { + direction : input; + } + pin(CLK) { + direction : input; + } + pin(Q) { + direction: output; + function : "IQ"; + } + } + cell (dffe) { + area : 6; + ff("IQ", "IQN") { + next_state : (D&EN) | (IQ&!EN); + clocked_on : !CLK; + } + pin(D) { + direction : input; + } + pin(EN) { + direction : input; + } + pin(CLK) { + direction : input; + } + pin(Q) { + direction: output; + function : "IQ"; + } + pin(QN) { + direction: output; + function : "IQN"; + } + } +} diff --git a/tests/liberty/unquoted.lib.filtered.ok b/tests/liberty/unquoted.lib.filtered.ok new file mode 100644 index 000000000..0ffc157b4 --- /dev/null +++ b/tests/liberty/unquoted.lib.filtered.ok @@ -0,0 +1,60 @@ +library(dff_unquoted) { + cell(dff1) { + area : 1 ; + ff("IQ", "IQN") { + next_state : !D ; + clocked_on : ( CLK ) ; + } + pin(D) { + direction : input ; + } + pin(CLK) { + direction : input ; + } + pin(Q) { + direction : output ; + function : IQ ; + } + } + cell(dff2) { + area : 1 ; + ff(IQ, IQN) { + next_state : D ' ; + clocked_on : CLK ; + } + pin(D) { + direction : input ; + } + pin(CLK) { + direction : input ; + } + pin(Q) { + direction : output ; + function : "IQ" ; + } + } + cell(dffe) { + area : 6 ; + ff("IQ", "IQN") { + next_state : ( D & EN ) | ( IQ & ! EN ) ; + clocked_on : !CLK ; + } + pin(D) { + direction : input ; + } + pin(EN) { + direction : input ; + } + pin(CLK) { + direction : input ; + } + pin(Q) { + direction : output ; + function : "IQ" ; + } + pin(QN) { + direction : output ; + function : "IQN" ; + } + } +} diff --git a/tests/liberty/unquoted.lib.verilogsim.ok b/tests/liberty/unquoted.lib.verilogsim.ok new file mode 100644 index 000000000..8706d1773 --- /dev/null +++ b/tests/liberty/unquoted.lib.verilogsim.ok @@ -0,0 +1,39 @@ +module dff1 (D, CLK, Q); + reg "IQ", "IQN"; + input D; + input CLK; + output Q; + assign Q = IQ; // IQ + always @(posedge CLK) begin + // !D + "IQ" <= (~D); + "IQN" <= ~((~D)); + end +endmodule +module dff2 (D, CLK, Q); + reg IQ, IQN; + input D; + input CLK; + output Q; + assign Q = IQ; // "IQ" + always @(posedge CLK) begin + // D ' + IQ <= (~D); + IQN <= ~((~D)); + end +endmodule +module dffe (D, EN, CLK, Q, QN); + reg "IQ", "IQN"; + input D; + input EN; + input CLK; + output Q; + assign Q = IQ; // "IQ" + output QN; + assign QN = IQN; // "IQN" + always @(posedge (~CLK)) begin + // ( D & EN ) | ( IQ & ! EN ) + "IQ" <= ((D&EN)|(IQ&(~EN))); + "IQN" <= ~(((D&EN)|(IQ&(~EN)))); + end +endmodule From 504b668ea64b755bfa8090db78ac024a46d4e0ec Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Wed, 5 Nov 2025 13:49:05 +0100 Subject: [PATCH 46/97] libparse: fix verilogsim negedge --- passes/techmap/libparse.cc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/passes/techmap/libparse.cc b/passes/techmap/libparse.cc index eddc68263..da88dfc66 100644 --- a/passes/techmap/libparse.cc +++ b/passes/techmap/libparse.cc @@ -831,11 +831,13 @@ void event2vl(const LibertyAst *ast, std::string &edge, std::string &expr) expr.clear(); if (ast != NULL) { - expr = func2vl(ast->value); - if (expr.size() > 0 && expr[0] == '~') - edge = "negedge " + expr.substr(1); + auto helper = LibertyExpression::Lexer(ast->value); + auto parsed = LibertyExpression::parse(helper); + expr = parsed.vlog_str(); + if (parsed.kind == LibertyExpression::Kind::NOT) + edge = "negedge " + parsed.children[0].vlog_str(); else - edge = "posedge " + expr; + edge = "posedge " + parsed.vlog_str(); } } From 90553267b0a3a98bad21b6892f0e170422fdddad Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Wed, 5 Nov 2025 14:13:58 +0100 Subject: [PATCH 47/97] libparse: fix quoting and negedge in filterlib -verilogsim --- passes/techmap/libparse.cc | 26 ++++++++++++++++-------- tests/liberty/dff.lib.verilogsim.ok | 6 +++--- tests/liberty/normal.lib.verilogsim.ok | 24 +++++++++++----------- tests/liberty/unquoted.lib.verilogsim.ok | 14 ++++++------- 4 files changed, 39 insertions(+), 31 deletions(-) diff --git a/passes/techmap/libparse.cc b/passes/techmap/libparse.cc index da88dfc66..2d3f1792a 100644 --- a/passes/techmap/libparse.cc +++ b/passes/techmap/libparse.cc @@ -25,6 +25,7 @@ #include #include #include +#include #ifdef FILTERLIB #undef log_assert @@ -825,6 +826,12 @@ std::string func2vl(std::string str) return LibertyExpression::parse(helper).vlog_str(); } +std::string vlog_identifier(std::string str) +{ + str.erase(std::remove(str.begin(), str.end(), '\"'), str.end()); + return str; +} + void event2vl(const LibertyAst *ast, std::string &edge, std::string &expr) { edge.clear(); @@ -867,13 +874,13 @@ void gen_verilogsim_cell(const LibertyAst *ast) return; CHECK_NV(ast->args.size(), == 1); - printf("module %s (", ast->args[0].c_str()); + printf("module %s (", vlog_identifier(ast->args[0]).c_str()); bool first = true; for (auto child : ast->children) { if (child->id != "pin") continue; CHECK_NV(child->args.size(), == 1); - printf("%s%s", first ? "" : ", ", child->args[0].c_str()); + printf("%s%s", first ? "" : ", ", vlog_identifier(child->args[0]).c_str()); first = false; } printf(");\n"); @@ -884,7 +891,7 @@ void gen_verilogsim_cell(const LibertyAst *ast) printf(" reg "); first = true; for (auto arg : child->args) { - printf("%s%s", first ? "" : ", ", arg.c_str()); + printf("%s%s", first ? "" : ", ", vlog_identifier(arg).c_str()); first = false; } printf(";\n"); @@ -896,9 +903,10 @@ void gen_verilogsim_cell(const LibertyAst *ast) CHECK_NV(child->args.size(), == 1); const LibertyAst *dir = find_non_null(child, "direction"); const LibertyAst *func = child->find("function"); - printf(" %s %s;\n", dir->value.c_str(), child->args[0].c_str()); + std::string var = vlog_identifier(child->args[0]); + printf(" %s %s;\n", dir->value.c_str(), var.c_str()); if (func != NULL) - printf(" assign %s = %s; // %s\n", child->args[0].c_str(), func2vl(func->value).c_str(), func->value.c_str()); + printf(" assign %s = %s; // %s\n", var.c_str(), func2vl(func->value).c_str(), func->value.c_str()); } for (auto child : ast->children) @@ -906,8 +914,8 @@ void gen_verilogsim_cell(const LibertyAst *ast) if (child->id != "ff" || child->args.size() != 2) continue; - std::string iq_var = child->args[0]; - std::string iqn_var = child->args[1]; + std::string iq_var = vlog_identifier(child->args[0]); + std::string iqn_var = vlog_identifier(child->args[1]); std::string clock_edge, clock_expr; event2vl(child->find("clocked_on"), clock_edge, clock_expr); @@ -970,8 +978,8 @@ void gen_verilogsim_cell(const LibertyAst *ast) if (child->id != "latch" || child->args.size() != 2) continue; - std::string iq_var = child->args[0]; - std::string iqn_var = child->args[1]; + std::string iq_var = vlog_identifier(child->args[0]); + std::string iqn_var = vlog_identifier(child->args[1]); std::string enable_edge, enable_expr; event2vl(child->find("enable"), enable_edge, enable_expr); diff --git a/tests/liberty/dff.lib.verilogsim.ok b/tests/liberty/dff.lib.verilogsim.ok index 4f2a5750c..e560df539 100644 --- a/tests/liberty/dff.lib.verilogsim.ok +++ b/tests/liberty/dff.lib.verilogsim.ok @@ -1,12 +1,12 @@ module dff (D, CLK, Q); - reg "IQ", "IQN"; + reg IQ, IQN; input D; input CLK; output Q; assign Q = IQ; // IQ always @(posedge CLK) begin // "(D)" - "IQ" <= D; - "IQN" <= ~(D); + IQ <= D; + IQN <= ~(D); end endmodule diff --git a/tests/liberty/normal.lib.verilogsim.ok b/tests/liberty/normal.lib.verilogsim.ok index 190ecd285..92efbf8aa 100644 --- a/tests/liberty/normal.lib.verilogsim.ok +++ b/tests/liberty/normal.lib.verilogsim.ok @@ -40,7 +40,7 @@ module imux2 (A, B, S, Y); assign Y = (~((A&S)|(B&(~S)))); // "( (A * S) + (B * S') )'" endmodule module dff (D, CLK, RESET, PRESET, Q, QN); - reg "IQ", "IQN"; + reg IQ, IQN; input D; input CLK; input RESET; @@ -51,26 +51,26 @@ module dff (D, CLK, RESET, PRESET, Q, QN); assign QN = IQN; // "IQN" always @(posedge CLK, posedge RESET, posedge PRESET) begin if ((RESET) && (PRESET)) begin - "IQ" <= 0; - "IQN" <= 0; + IQ <= 0; + IQN <= 0; end else if (RESET) begin - "IQ" <= 0; - "IQN" <= 1; + IQ <= 0; + IQN <= 1; end else if (PRESET) begin - "IQ" <= 1; - "IQN" <= 0; + IQ <= 1; + IQN <= 0; end else begin // "D" - "IQ" <= D; - "IQN" <= ~(D); + IQ <= D; + IQN <= ~(D); end end endmodule module latch (D, G, Q, QN); - reg "IQ", "IQN"; + reg IQ, IQN; input D; input G; output Q; @@ -79,8 +79,8 @@ module latch (D, G, Q, QN); assign QN = IQN; // "IQN" always @* begin if (G) begin - "IQ" <= D; - "IQN" <= ~(D); + IQ <= D; + IQN <= ~(D); end end endmodule diff --git a/tests/liberty/unquoted.lib.verilogsim.ok b/tests/liberty/unquoted.lib.verilogsim.ok index 8706d1773..2a2f1d173 100644 --- a/tests/liberty/unquoted.lib.verilogsim.ok +++ b/tests/liberty/unquoted.lib.verilogsim.ok @@ -1,13 +1,13 @@ module dff1 (D, CLK, Q); - reg "IQ", "IQN"; + reg IQ, IQN; input D; input CLK; output Q; assign Q = IQ; // IQ always @(posedge CLK) begin // !D - "IQ" <= (~D); - "IQN" <= ~((~D)); + IQ <= (~D); + IQN <= ~((~D)); end endmodule module dff2 (D, CLK, Q); @@ -23,7 +23,7 @@ module dff2 (D, CLK, Q); end endmodule module dffe (D, EN, CLK, Q, QN); - reg "IQ", "IQN"; + reg IQ, IQN; input D; input EN; input CLK; @@ -31,9 +31,9 @@ module dffe (D, EN, CLK, Q, QN); assign Q = IQ; // "IQ" output QN; assign QN = IQN; // "IQN" - always @(posedge (~CLK)) begin + always @(negedge CLK) begin // ( D & EN ) | ( IQ & ! EN ) - "IQ" <= ((D&EN)|(IQ&(~EN))); - "IQN" <= ~(((D&EN)|(IQ&(~EN)))); + IQ <= ((D&EN)|(IQ&(~EN))); + IQN <= ~(((D&EN)|(IQ&(~EN)))); end endmodule From f8341affe397ae1622d12ff90cb38dab3f81b5b4 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 5 Nov 2025 14:20:30 +0100 Subject: [PATCH 48/97] Fix generatory.py location for out of tree builds --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index d72cbee7e..685fec40e 100644 --- a/Makefile +++ b/Makefile @@ -366,7 +366,7 @@ CXXFLAGS += -I$(PYBIND11_INCLUDE) -DYOSYS_ENABLE_PYTHON CXXFLAGS += $(shell $(PYTHON_CONFIG) --includes) -DYOSYS_ENABLE_PYTHON OBJS += $(PY_WRAPPER_FILE).o -PY_GEN_SCRIPT = pyosys/generator.py +PY_GEN_SCRIPT = $(YOSYS_SRC)/pyosys/generator.py PY_WRAP_INCLUDES := $(shell $(UV_ENV) $(PYTHON_EXECUTABLE) $(PY_GEN_SCRIPT) --print-includes) endif # ENABLE_PYOSYS From 0f770285f39ae865882fa2b9dde5d07ad3d996b0 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Mon, 3 Nov 2025 15:45:30 +0000 Subject: [PATCH 49/97] Move global ABC configuration variables into AbcConfig and initialize them properly --- passes/techmap/abc.cc | 110 ++++++++++++++++++------------------- tests/techmap/abc_state.ys | 26 +++++++++ 2 files changed, 80 insertions(+), 56 deletions(-) create mode 100644 tests/techmap/abc_state.ys diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index c5c653317..e2894aee3 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -117,15 +117,6 @@ struct gate_t std::string bit_str; }; -bool map_mux4; -bool map_mux8; -bool map_mux16; - -bool markgroups; - -pool enabled_gates; -bool cmos_cost; - struct AbcConfig { std::string global_tempdir_name; @@ -146,6 +137,12 @@ struct AbcConfig bool show_tempdir = false; bool sop_mode = false; bool abc_dress = false; + bool map_mux4 = false; + bool map_mux8 = false; + bool map_mux16 = false; + bool markgroups = false; + pool enabled_gates; + bool cmos_cost = false; }; struct AbcSigVal { @@ -1382,7 +1379,7 @@ void emit_global_input_files(const AbcConfig &config) fprintf(f, "%d %d.00 1.00\n", i+1, config.lut_costs.at(i)); fclose(f); } else { - auto &cell_cost = cmos_cost ? CellCosts::cmos_gate_cost() : CellCosts::default_gate_cost(); + auto &cell_cost = config.cmos_cost ? CellCosts::cmos_gate_cost() : CellCosts::default_gate_cost(); std::string buffer = stringf("%s/stdcells.genlib", config.global_tempdir_name.c_str()); FILE *f = fopen(buffer.c_str(), "wt"); @@ -1392,39 +1389,39 @@ void emit_global_input_files(const AbcConfig &config) fprintf(f, "GATE ONE 1 Y=CONST1;\n"); fprintf(f, "GATE BUF %d Y=A; PIN * NONINV 1 999 1 0 1 0\n", cell_cost.at(ID($_BUF_))); fprintf(f, "GATE NOT %d Y=!A; PIN * INV 1 999 1 0 1 0\n", cell_cost.at(ID($_NOT_))); - if (enabled_gates.count("AND")) + if (config.enabled_gates.count("AND")) fprintf(f, "GATE AND %d Y=A*B; PIN * NONINV 1 999 1 0 1 0\n", cell_cost.at(ID($_AND_))); - if (enabled_gates.count("NAND")) + if (config.enabled_gates.count("NAND")) fprintf(f, "GATE NAND %d Y=!(A*B); PIN * INV 1 999 1 0 1 0\n", cell_cost.at(ID($_NAND_))); - if (enabled_gates.count("OR")) + if (config.enabled_gates.count("OR")) fprintf(f, "GATE OR %d Y=A+B; PIN * NONINV 1 999 1 0 1 0\n", cell_cost.at(ID($_OR_))); - if (enabled_gates.count("NOR")) + if (config.enabled_gates.count("NOR")) fprintf(f, "GATE NOR %d Y=!(A+B); PIN * INV 1 999 1 0 1 0\n", cell_cost.at(ID($_NOR_))); - if (enabled_gates.count("XOR")) + if (config.enabled_gates.count("XOR")) fprintf(f, "GATE XOR %d Y=(A*!B)+(!A*B); PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost.at(ID($_XOR_))); - if (enabled_gates.count("XNOR")) + if (config.enabled_gates.count("XNOR")) fprintf(f, "GATE XNOR %d Y=(A*B)+(!A*!B); PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost.at(ID($_XNOR_))); - if (enabled_gates.count("ANDNOT")) + if (config.enabled_gates.count("ANDNOT")) fprintf(f, "GATE ANDNOT %d Y=A*!B; PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost.at(ID($_ANDNOT_))); - if (enabled_gates.count("ORNOT")) + if (config.enabled_gates.count("ORNOT")) fprintf(f, "GATE ORNOT %d Y=A+!B; PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost.at(ID($_ORNOT_))); - if (enabled_gates.count("AOI3")) + if (config.enabled_gates.count("AOI3")) fprintf(f, "GATE AOI3 %d Y=!((A*B)+C); PIN * INV 1 999 1 0 1 0\n", cell_cost.at(ID($_AOI3_))); - if (enabled_gates.count("OAI3")) + if (config.enabled_gates.count("OAI3")) fprintf(f, "GATE OAI3 %d Y=!((A+B)*C); PIN * INV 1 999 1 0 1 0\n", cell_cost.at(ID($_OAI3_))); - if (enabled_gates.count("AOI4")) + if (config.enabled_gates.count("AOI4")) fprintf(f, "GATE AOI4 %d Y=!((A*B)+(C*D)); PIN * INV 1 999 1 0 1 0\n", cell_cost.at(ID($_AOI4_))); - if (enabled_gates.count("OAI4")) + if (config.enabled_gates.count("OAI4")) fprintf(f, "GATE OAI4 %d Y=!((A+B)*(C+D)); PIN * INV 1 999 1 0 1 0\n", cell_cost.at(ID($_OAI4_))); - if (enabled_gates.count("MUX")) + if (config.enabled_gates.count("MUX")) fprintf(f, "GATE MUX %d Y=(A*B)+(S*B)+(!S*A); PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost.at(ID($_MUX_))); - if (enabled_gates.count("NMUX")) + if (config.enabled_gates.count("NMUX")) fprintf(f, "GATE NMUX %d Y=!((A*B)+(S*B)+(!S*A)); PIN * UNKNOWN 1 999 1 0 1 0\n", cell_cost.at(ID($_NMUX_))); - if (map_mux4) + if (config.map_mux4) fprintf(f, "GATE MUX4 %d Y=(!S*!T*A)+(S*!T*B)+(!S*T*C)+(S*T*D); PIN * UNKNOWN 1 999 1 0 1 0\n", 2*cell_cost.at(ID($_MUX_))); - if (map_mux8) + if (config.map_mux8) fprintf(f, "GATE MUX8 %d Y=(!S*!T*!U*A)+(S*!T*!U*B)+(!S*T*!U*C)+(S*T*!U*D)+(!S*!T*U*E)+(S*!T*U*F)+(!S*T*U*G)+(S*T*U*H); PIN * UNKNOWN 1 999 1 0 1 0\n", 4*cell_cost.at(ID($_MUX_))); - if (map_mux16) + if (config.map_mux16) 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); } @@ -1456,6 +1453,7 @@ void AbcModuleState::extract(AbcSigMap &assign_map, RTLIL::Design *design, RTLIL 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"); + bool markgroups = run_abc.config.markgroups; for (auto w : mapped_mod->wires()) { RTLIL::Wire *orig_wire = nullptr; RTLIL::Wire *wire = module->addWire(remap_name(w->name, &orig_wire)); @@ -1998,9 +1996,9 @@ struct AbcPass : public Pass { lut_arg = design->scratchpad_get_string("abc.lut", lut_arg); luts_arg = design->scratchpad_get_string("abc.luts", luts_arg); 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); + config.map_mux4 = design->scratchpad_get_bool("abc.mux4", false); + config.map_mux8 = design->scratchpad_get_bool("abc.mux8", false); + config.map_mux16 = design->scratchpad_get_bool("abc.mux16", false); config.abc_dress = design->scratchpad_get_bool("abc.dress", false); g_arg = design->scratchpad_get_string("abc.g", g_arg); @@ -2014,7 +2012,7 @@ struct AbcPass : public Pass { 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); + config.markgroups = design->scratchpad_get_bool("abc.markgroups", false); if (config.cleanup) config.global_tempdir_name = get_base_tmpdir() + "/"; @@ -2094,15 +2092,15 @@ struct AbcPass : public Pass { continue; } if (arg == "-mux4") { - map_mux4 = true; + config.map_mux4 = true; continue; } if (arg == "-mux8") { - map_mux8 = true; + config.map_mux8 = true; continue; } if (arg == "-mux16") { - map_mux16 = true; + config.map_mux16 = true; continue; } if (arg == "-dress") { @@ -2143,7 +2141,7 @@ struct AbcPass : public Pass { continue; } if (arg == "-markgroups") { - markgroups = true; + config.markgroups = true; continue; } break; @@ -2236,14 +2234,14 @@ struct AbcPass : public Pass { } if (g == "cmos2") { if (!remove_gates) - cmos_cost = true; + config.cmos_cost = true; gate_list.push_back("NAND"); gate_list.push_back("NOR"); goto ok_alias; } if (g == "cmos3") { if (!remove_gates) - cmos_cost = true; + config.cmos_cost = true; gate_list.push_back("NAND"); gate_list.push_back("NOR"); gate_list.push_back("AOI3"); @@ -2252,7 +2250,7 @@ struct AbcPass : public Pass { } if (g == "cmos4") { if (!remove_gates) - cmos_cost = true; + config.cmos_cost = true; gate_list.push_back("NAND"); gate_list.push_back("NOR"); gate_list.push_back("AOI3"); @@ -2263,7 +2261,7 @@ struct AbcPass : public Pass { } if (g == "cmos") { if (!remove_gates) - cmos_cost = true; + config.cmos_cost = true; gate_list.push_back("NAND"); gate_list.push_back("NOR"); gate_list.push_back("AOI3"); @@ -2322,9 +2320,9 @@ struct AbcPass : public Pass { ok_alias: for (auto gate : gate_list) { if (remove_gates) - enabled_gates.erase(gate); + config.enabled_gates.erase(gate); else - enabled_gates.insert(gate); + config.enabled_gates.insert(gate); } } } @@ -2334,21 +2332,21 @@ struct AbcPass : public Pass { 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()) { - enabled_gates.insert("AND"); - enabled_gates.insert("NAND"); - enabled_gates.insert("OR"); - enabled_gates.insert("NOR"); - enabled_gates.insert("XOR"); - enabled_gates.insert("XNOR"); - enabled_gates.insert("ANDNOT"); - enabled_gates.insert("ORNOT"); - // enabled_gates.insert("AOI3"); - // enabled_gates.insert("OAI3"); - // enabled_gates.insert("AOI4"); - // enabled_gates.insert("OAI4"); - enabled_gates.insert("MUX"); - // enabled_gates.insert("NMUX"); + if (config.enabled_gates.empty()) { + config.enabled_gates.insert("AND"); + config.enabled_gates.insert("NAND"); + config.enabled_gates.insert("OR"); + config.enabled_gates.insert("NOR"); + config.enabled_gates.insert("XOR"); + config.enabled_gates.insert("XNOR"); + config.enabled_gates.insert("ANDNOT"); + config.enabled_gates.insert("ORNOT"); + // config.enabled_gates.insert("AOI3"); + // config.enabled_gates.insert("OAI3"); + // config.enabled_gates.insert("AOI4"); + // config.enabled_gates.insert("OAI4"); + config.enabled_gates.insert("MUX"); + // config.enabled_gates.insert("NMUX"); } emit_global_input_files(config); diff --git a/tests/techmap/abc_state.ys b/tests/techmap/abc_state.ys new file mode 100644 index 000000000..bc2a744f5 --- /dev/null +++ b/tests/techmap/abc_state.ys @@ -0,0 +1,26 @@ +read_verilog < Date: Thu, 6 Nov 2025 00:24:21 +0000 Subject: [PATCH 50/97] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 685fec40e..93091bd6d 100644 --- a/Makefile +++ b/Makefile @@ -161,7 +161,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.58+132 +YOSYS_VER := 0.58+138 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 75ce33c7b25c602027e3e741c77ef20deaf1cb1a Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Thu, 6 Nov 2025 09:54:47 +0100 Subject: [PATCH 51/97] Update ABC --- abc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/abc b/abc index fa186342b..1c5ed1ce3 160000 --- a/abc +++ b/abc @@ -1 +1 @@ -Subproject commit fa186342baefea06e7c2aa13fe51f338ffc84912 +Subproject commit 1c5ed1ce378cc04beac30bb31abc4c37c8467042 From fdcc4c1507392f722014c77c5847e63113508666 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Thu, 6 Nov 2025 13:30:09 +0100 Subject: [PATCH 52/97] libparse: remove leftover comments --- passes/techmap/libparse.cc | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/passes/techmap/libparse.cc b/passes/techmap/libparse.cc index 2d3f1792a..9e2556891 100644 --- a/passes/techmap/libparse.cc +++ b/passes/techmap/libparse.cc @@ -676,23 +676,18 @@ LibertyAst *LibertyParser::parse(bool top_level) tok = lexer(str); } else { // Hack for when an expression string is unquoted - // std::cout << "consume_wrecked_str from :\n"; - // std::cout << " weh " << str << "\n"; tok = consume_wrecked_str(tok, ast->value); } } else if (tok == '(') { // Hack for when an expression string is unquoted and starts with // parentheses - // tok = ''; - // ast->value = "("; - // std::cout << "consume_wrecked_str from (\n"; tok = consume_wrecked_str(tok, ast->value); } while (tok == '+' || tok == '-' || tok == '*' || tok == '/' || tok == '!') { ast->value += tok; tok = lexer(str); if (tok != 'v') - error("one"); + error(); ast->value += str; tok = lexer(str); } @@ -704,7 +699,7 @@ LibertyAst *LibertyParser::parse(bool top_level) if ((tok == ';') || (tok == 'n')) break; else - error("two"); + error(); continue; } From 2bf7aac9d12d79695d858fb6590adeb35f0691fe Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Thu, 6 Nov 2025 13:59:14 +0100 Subject: [PATCH 53/97] Makefile: clean unit test on clean, ensure prepared to fix parallelism --- Makefile | 2 +- tests/unit/Makefile | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 93091bd6d..7ee59bb79 100644 --- a/Makefile +++ b/Makefile @@ -1135,7 +1135,7 @@ DOC_TARGET ?= html docs: docs/prep $(Q) $(MAKE) -C docs $(DOC_TARGET) -clean: clean-py +clean: clean-py clean-unit-test rm -rf share rm -f $(OBJS) $(GENFILES) $(TARGETS) $(EXTRA_TARGETS) $(EXTRA_OBJS) rm -f kernel/version_*.o kernel/version_*.cc diff --git a/tests/unit/Makefile b/tests/unit/Makefile index eee60ef9f..b275d7f41 100644 --- a/tests/unit/Makefile +++ b/tests/unit/Makefile @@ -30,11 +30,11 @@ TESTS := $(addprefix $(BINTEST)/, $(basename $(ALLTESTFILE:%Test.cc=%Test.o))) all: prepare $(TESTS) run-tests -$(BINTEST)/%: $(OBJTEST)/%.o +$(BINTEST)/%: $(OBJTEST)/%.o | prepare $(CXX) -L$(ROOTPATH) $(RPATH) $(LINKFLAGS) -o $@ $^ $(LIBS) \ $(GTEST_LDFLAGS) $(EXTRAFLAGS) -$(OBJTEST)/%.o: $(basename $(subst $(OBJTEST),.,%)).cc +$(OBJTEST)/%.o: $(basename $(subst $(OBJTEST),.,%)).cc | prepare $(CXX) -o $@ -c -I$(ROOTPATH) $(CPPFLAGS) $(CXXFLAGS) $(GTEST_CXXFLAGS) $^ .PHONY: prepare run-tests clean From dc9a78702500ba180d28104886e28255bcfbb646 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Thu, 6 Nov 2025 14:28:28 +0100 Subject: [PATCH 54/97] Fix out of tree clean --- Makefile | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 7ee59bb79..fced3c4ae 100644 --- a/Makefile +++ b/Makefile @@ -95,14 +95,14 @@ TARGETS = $(PROGRAM_PREFIX)yosys$(EXE) $(PROGRAM_PREFIX)yosys-config PRETTY = 1 SMALL = 0 -# Unit test -UNITESTPATH := tests/unit - all: top-all YOSYS_SRC := $(dir $(firstword $(MAKEFILE_LIST))) VPATH := $(YOSYS_SRC) +# Unit test +UNITESTPATH := $(YOSYS_SRC)/tests/unit + export CXXSTD ?= c++17 CXXFLAGS := $(CXXFLAGS) -Wall -Wextra -ggdb -I. -I"$(YOSYS_SRC)" -MD -MP -D_YOSYS_ -fPIC -I$(PREFIX)/include LIBS := $(LIBS) -lstdc++ -lm @@ -1150,7 +1150,7 @@ clean: clean-py clean-unit-test rm -f tests/svinterfaces/*.log_stdout tests/svinterfaces/*.log_stderr tests/svinterfaces/dut_result.txt tests/svinterfaces/reference_result.txt tests/svinterfaces/a.out tests/svinterfaces/*_syn.v tests/svinterfaces/*.diff rm -f tests/tools/cmp_tbdata rm -f $(addsuffix /run-test.mk,$(MK_TEST_DIRS)) - -$(MAKE) -C docs clean + -$(MAKE) -C $(YOSYS_SRC)/docs clean rm -rf docs/util/__pycache__ rm -f libyosys.so @@ -1162,7 +1162,7 @@ clean-py: rm -rf kernel/*.pyh clean-abc: - $(MAKE) -C abc DEP= clean + $(MAKE) -C $(YOSYS_SRC)/abc DEP= clean rm -f $(PROGRAM_PREFIX)yosys-abc$(EXE) $(PROGRAM_PREFIX)yosys-libabc.a abc/abc-[0-9a-f]* abc/libabc-[0-9a-f]*.a .git-abc-submodule-hash mrproper: clean From 5d0847f6fbef980914134a6a98b2397ecb0a3189 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 7 Nov 2025 00:24:35 +0000 Subject: [PATCH 55/97] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index fced3c4ae..dd7a8c022 100644 --- a/Makefile +++ b/Makefile @@ -161,7 +161,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.58+138 +YOSYS_VER := 0.58+162 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 8d4f790951b237eeb4871f719d4f72ab385797ec Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Mon, 27 Oct 2025 12:41:50 +0000 Subject: [PATCH 56/97] Make Module stop accessing internals of SigSpec --- kernel/rtlil.cc | 25 +++++++++++++++---------- kernel/rtlil.h | 6 ++---- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index adfda7d5f..1d0d45197 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -2657,10 +2657,9 @@ void RTLIL::Module::cloneInto(RTLIL::Module *new_mod) const RTLIL::Module *mod; void operator()(RTLIL::SigSpec &sig) { - sig.pack(); - for (auto &c : sig.chunks_) - if (c.wire != NULL) - c.wire = mod->wires_.at(c.wire->name); + sig.rewrite_wires([this](RTLIL::Wire *&wire) { + wire = mod->wires_.at(wire->name); + }); } }; @@ -2808,12 +2807,10 @@ void RTLIL::Module::remove(const pool &wires) const pool *wires_p; void operator()(RTLIL::SigSpec &sig) { - sig.pack(); - for (auto &c : sig.chunks_) - if (c.wire != NULL && wires_p->count(c.wire)) { - c.wire = module->addWire(stringf("$delete_wire$%d", autoidx++), c.width); - c.offset = 0; - } + sig.rewrite_wires([this](RTLIL::Wire *&wire) { + if (wires_p->count(wire)) + wire = module->addWire(stringf("$delete_wire$%d", autoidx++), wire->width); + }); } void operator()(RTLIL::SigSpec &lhs, RTLIL::SigSpec &rhs) { @@ -5159,6 +5156,14 @@ RTLIL::SigSpec RTLIL::SigSpec::extract(int offset, int length) const } } +void RTLIL::SigSpec::rewrite_wires(std::function rewrite) +{ + pack(); + for (RTLIL::SigChunk &chunk : chunks_) + if (chunk.wire != nullptr) + rewrite(chunk.wire); +} + void RTLIL::SigSpec::append(const RTLIL::SigSpec &signal) { if (signal.width_ == 0) diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 7e699b365..77b434e1d 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1252,10 +1252,6 @@ private: unpack(); } - // Only used by Module::remove(const pool &wires) - // but cannot be more specific as it isn't yet declared - friend struct RTLIL::Module; - public: SigSpec() : width_(0), hash_(0) {} SigSpec(std::initializer_list parts); @@ -1327,6 +1323,8 @@ public: RTLIL::SigSpec extract(int offset, int length = 1) const; RTLIL::SigSpec extract_end(int offset) const { return extract(offset, width_ - offset); } + void rewrite_wires(std::function rewrite); + RTLIL::SigBit lsb() const { log_assert(width_); return (*this)[0]; }; RTLIL::SigBit msb() const { log_assert(width_); return (*this)[width_ - 1]; }; From 3f7af10edae8d4a5b633b984a4b30bac33cd540f Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Mon, 27 Oct 2025 15:46:36 +0000 Subject: [PATCH 57/97] Make SigSpec::chunks() return an object that can be iterated over without packing the SigSpec --- kernel/rtlil.cc | 25 ++++++++++++ kernel/rtlil.h | 80 ++++++++++++++++++++++++++++++++++++-- passes/cmds/show.cc | 7 ++-- passes/techmap/abc9_ops.cc | 4 +- 4 files changed, 107 insertions(+), 9 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 1d0d45197..0991b9709 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -4656,6 +4656,31 @@ RTLIL::SigSpec::SigSpec(bool bit) check(); } +void RTLIL::SigSpec::Chunks::const_iterator::next_chunk_bits() +{ + int bits_size = GetSize(spec.bits_); + if (bit_index >= bits_size) + return; + int i = bit_index; + const SigBit &bit = spec.bits_[i++]; + chunk.wire = bit.wire; + chunk.data.clear(); + if (bit.is_wire()) { + chunk.offset = bit.offset; + while (i < bits_size && spec.bits_[i].wire == bit.wire && + spec.bits_[i].offset == bit.offset + i - bit_index) + ++i; + } else { + chunk.offset = 0; + chunk.data.push_back(bit.data); + while (i < bits_size && !spec.bits_[i].is_wire()) { + chunk.data.push_back(spec.bits_[i].data); + ++i; + } + } + chunk.width = i - bit_index; +} + void RTLIL::SigSpec::pack() const { RTLIL::SigSpec *that = (RTLIL::SigSpec*)this; diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 77b434e1d..8e93f5f05 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1276,7 +1276,78 @@ public: SigSpec &operator=(const SigSpec &rhs) = default; SigSpec &operator=(SigSpec &&rhs) = default; - inline const std::vector &chunks() const { pack(); return chunks_; } + struct Chunks { + const SigSpec &spec; + + struct const_iterator { + using iterator_category = std::forward_iterator_tag; + using value_type = const SigChunk &; + using difference_type = std::ptrdiff_t; + using pointer = const SigChunk *; + using reference = const SigChunk &; + + const SigSpec &spec; + int chunk_index; + int bit_index; + SigChunk chunk; + + const_iterator(const SigSpec &spec) : spec(spec) { + chunk_index = 0; + bit_index = 0; + if (!spec.packed()) + next_chunk_bits(); + } + enum End { END }; + const_iterator(const SigSpec &spec, End) : spec(spec) { + bit_index = spec.size(); + } + void next_chunk_bits(); + + const SigChunk &operator*() { + if (spec.packed()) + return spec.chunks_[chunk_index]; + return chunk; + }; + const SigChunk *operator->() { return &**this; } + const_iterator &operator++() { + bit_index += (**this).width; + ++chunk_index; + if (!spec.packed()) + next_chunk_bits(); + return *this; + } + bool operator==(const const_iterator &rhs) const { return bit_index == rhs.bit_index; } + bool operator!=(const const_iterator &rhs) const { return !(*this == rhs); } + }; + const_iterator begin() const { return const_iterator(spec); } + const_iterator end() const { + const_iterator it(spec, const_iterator::END); + return it; + } + std::vector::const_reverse_iterator rbegin() const { + spec.pack(); + return spec.chunks_.rbegin(); + } + std::vector::const_reverse_iterator rend() const { + spec.pack(); + return spec.chunks_.rend(); + } + int size() const { + spec.pack(); + return spec.chunks_.size(); + } + const SigChunk &at(int index) const { + spec.pack(); + return spec.chunks_.at(index); + } + operator const std::vector&() const { + spec.pack(); + return spec.chunks_; + } + }; + friend struct Chunks::const_iterator; + + inline Chunks chunks() const { return {*this}; } inline const std::vector &bits() const { inline_unpack(); return bits_; } inline int size() const { return width_; } @@ -1403,7 +1474,7 @@ public: static bool parse_sel(RTLIL::SigSpec &sig, RTLIL::Design *design, RTLIL::Module *module, std::string str); static bool parse_rhs(const RTLIL::SigSpec &lhs, RTLIL::SigSpec &sig, RTLIL::Module *module, std::string str); - operator std::vector() const { return chunks(); } + operator std::vector() const { pack(); return chunks_; } operator std::vector() const { return bits(); } const RTLIL::SigBit &at(int offset, const RTLIL::SigBit &defval) { return offset < width_ ? (*this)[offset] : defval; } @@ -2317,8 +2388,9 @@ inline const RTLIL::SigBit &RTLIL::SigSpecConstIterator::operator*() const { } inline RTLIL::SigBit::SigBit(const RTLIL::SigSpec &sig) { - log_assert(sig.size() == 1 && sig.chunks().size() == 1); - *this = SigBit(sig.chunks().front()); + log_assert(sig.size() == 1); + auto it = sig.chunks().begin(); + *this = SigBit(*it); } template diff --git a/passes/cmds/show.cc b/passes/cmds/show.cc index d0d9c0f85..14a251c41 100644 --- a/passes/cmds/show.cc +++ b/passes/cmds/show.cc @@ -278,11 +278,12 @@ struct ShowWorker std::vector label_pieces; int bitpos = sig.size()-1; - for (int rep, chunk_idx = ((int) sig.chunks().size()) - 1; chunk_idx >= 0; chunk_idx -= rep) { - const RTLIL::SigChunk &c = sig.chunks().at(chunk_idx); + RTLIL::SigSpec::Chunks sig_chunks = sig.chunks(); + for (int rep, chunk_idx = ((int) sig_chunks.size()) - 1; chunk_idx >= 0; chunk_idx -= rep) { + const RTLIL::SigChunk &c = sig_chunks.at(chunk_idx); // Find the number of times this chunk is repeating - for (rep = 1; chunk_idx - rep >= 0 && c == sig.chunks().at(chunk_idx - rep); rep++); + for (rep = 1; chunk_idx - rep >= 0 && c == sig_chunks.at(chunk_idx - rep); rep++); int cl, cr; cl = c.offset + c.width - 1; diff --git a/passes/techmap/abc9_ops.cc b/passes/techmap/abc9_ops.cc index 373d5d15e..8d3869ece 100644 --- a/passes/techmap/abc9_ops.cc +++ b/passes/techmap/abc9_ops.cc @@ -1428,13 +1428,13 @@ void reintegrate(RTLIL::Module *module, bool dff_mode) // Copy connections (and rename) from mapped_mod to module for (auto conn : mapped_mod->connections()) { if (!conn.first.is_fully_const()) { - auto chunks = conn.first.chunks(); + std::vector chunks = conn.first.chunks(); for (auto &c : chunks) c.wire = module->wires_.at(remap_name(c.wire->name)); conn.first = std::move(chunks); } if (!conn.second.is_fully_const()) { - auto chunks = conn.second.chunks(); + std::vector chunks = conn.second.chunks(); for (auto &c : chunks) if (c.wire) c.wire = module->wires_.at(remap_name(c.wire->name)); From fc7d61132d9c95d6c07ba00b0019cd66797b49b0 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 28 Oct 2025 12:35:47 +0000 Subject: [PATCH 58/97] Make SigSpec::updhash() use chunk iterator --- kernel/rtlil.cc | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 0991b9709..e7330842f 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -4744,10 +4744,9 @@ void RTLIL::SigSpec::updhash() const return; cover("kernel.rtlil.sigspec.hash"); - that->pack(); Hasher h; - for (auto &c : that->chunks_) + for (auto &c : that->chunks()) if (c.wire == NULL) { for (auto &v : c.data) h.eat(v); @@ -5201,13 +5200,8 @@ void RTLIL::SigSpec::append(const RTLIL::SigSpec &signal) cover("kernel.rtlil.sigspec.append"); - if (packed() != signal.packed()) { - pack(); - signal.pack(); - } - if (packed()) - for (auto &other_c : signal.chunks_) + for (auto &other_c : signal.chunks()) { auto &my_last_c = chunks_.back(); if (my_last_c.wire == NULL && other_c.wire == NULL) { @@ -5221,8 +5215,10 @@ void RTLIL::SigSpec::append(const RTLIL::SigSpec &signal) } else chunks_.push_back(other_c); } - else + else { + signal.unpack(); bits_.insert(bits_.end(), signal.bits_.begin(), signal.bits_.end()); + } width_ += signal.width_; check(); From b0ee67a3557568bfd4adc9f254972ba047ac8947 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 28 Oct 2025 12:36:12 +0000 Subject: [PATCH 59/97] Make SigSpec::is_wire/is_chunk/is_fully_const use chunk iterator --- kernel/rtlil.cc | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index e7330842f..38b798052 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5409,22 +5409,28 @@ bool RTLIL::SigSpec::is_wire() const { cover("kernel.rtlil.sigspec.is_wire"); - pack(); - return GetSize(chunks_) == 1 && chunks_[0].wire && chunks_[0].wire->width == width_; + Chunks cs = chunks(); + auto it = cs.begin(); + if (it == cs.end()) + return false; + const RTLIL::SigChunk &chunk = *it; + return chunk.wire && chunk.wire->width == width_ && ++it == cs.end(); } bool RTLIL::SigSpec::is_chunk() const { cover("kernel.rtlil.sigspec.is_chunk"); - pack(); - return GetSize(chunks_) == 1; + Chunks cs = chunks(); + auto it = cs.begin(); + if (it == cs.end()) + return false; + return ++it == cs.end(); } bool RTLIL::SigSpec::known_driver() const { - pack(); - for (auto &chunk : chunks_) + for (auto &chunk : chunks()) if (chunk.is_wire() && !chunk.wire->known_driver()) return false; return true; From a7ac396fd9f971c240a842d88e5c1162e120ea40 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 28 Oct 2025 12:36:36 +0000 Subject: [PATCH 60/97] Make is_fully_const use chunk iterator --- kernel/rtlil.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 38b798052..d3030831e 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5440,9 +5440,8 @@ bool RTLIL::SigSpec::is_fully_const() const { cover("kernel.rtlil.sigspec.is_fully_const"); - pack(); - for (auto it = chunks_.begin(); it != chunks_.end(); it++) - if (it->width > 0 && it->wire != NULL) + for (auto &chunk : chunks()) + if (chunk.width > 0 && chunk.wire != NULL) return false; return true; } From ddd04e13e087167bb3425dc3f256ea78836b18c7 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 28 Oct 2025 12:36:47 +0000 Subject: [PATCH 61/97] Make SigSpec::is_fully_zero use chunk iterator --- kernel/rtlil.cc | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index d3030831e..f91ca821c 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5450,12 +5450,11 @@ bool RTLIL::SigSpec::is_fully_zero() const { cover("kernel.rtlil.sigspec.is_fully_zero"); - pack(); - for (auto it = chunks_.begin(); it != chunks_.end(); it++) { - if (it->width > 0 && it->wire != NULL) + for (auto &chunk : chunks()) { + if (chunk.width > 0 && chunk.wire != NULL) return false; - for (size_t i = 0; i < it->data.size(); i++) - if (it->data[i] != RTLIL::State::S0) + for (RTLIL::State d : chunk.data) + if (d != RTLIL::State::S0) return false; } return true; From 152a487cc8df50b0ef612c24abd614000807d20d Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 28 Oct 2025 12:36:58 +0000 Subject: [PATCH 62/97] Make SigSpec::is_fully_ones use chunk iterator --- kernel/rtlil.cc | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index f91ca821c..3183cb7bc 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5464,12 +5464,11 @@ bool RTLIL::SigSpec::is_fully_ones() const { cover("kernel.rtlil.sigspec.is_fully_ones"); - pack(); - for (auto it = chunks_.begin(); it != chunks_.end(); it++) { - if (it->width > 0 && it->wire != NULL) + for (auto &chunk : chunks()) { + if (chunk.width > 0 && chunk.wire != NULL) return false; - for (size_t i = 0; i < it->data.size(); i++) - if (it->data[i] != RTLIL::State::S1) + for (RTLIL::State d : chunk.data) + if (d != RTLIL::State::S1) return false; } return true; From e2defe78982562c09ba9e9a1b19511342dbe9b66 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 28 Oct 2025 12:37:08 +0000 Subject: [PATCH 63/97] Make SigSpec::is_fully_def use chunk iterator --- kernel/rtlil.cc | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 3183cb7bc..9fb8098ba 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5478,12 +5478,11 @@ bool RTLIL::SigSpec::is_fully_def() const { cover("kernel.rtlil.sigspec.is_fully_def"); - pack(); - for (auto it = chunks_.begin(); it != chunks_.end(); it++) { - if (it->width > 0 && it->wire != NULL) + for (auto &chunk : chunks()) { + if (chunk.width > 0 && chunk.wire != NULL) return false; - for (size_t i = 0; i < it->data.size(); i++) - if (it->data[i] != RTLIL::State::S0 && it->data[i] != RTLIL::State::S1) + for (RTLIL::State d : chunk.data) + if (d != RTLIL::State::S0 && d != RTLIL::State::S1) return false; } return true; From 1893c61fe29aae7e31925ba01849e482925adff2 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 28 Oct 2025 12:37:17 +0000 Subject: [PATCH 64/97] Make SigSpec::is_fully_undef use chunk iterator --- kernel/rtlil.cc | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 9fb8098ba..70fd14856 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5492,12 +5492,11 @@ bool RTLIL::SigSpec::is_fully_undef() const { cover("kernel.rtlil.sigspec.is_fully_undef"); - pack(); - for (auto it = chunks_.begin(); it != chunks_.end(); it++) { - if (it->width > 0 && it->wire != NULL) + for (auto &chunk : chunks()) { + if (chunk.width > 0 && chunk.wire != NULL) return false; - for (size_t i = 0; i < it->data.size(); i++) - if (it->data[i] != RTLIL::State::Sx && it->data[i] != RTLIL::State::Sz) + for (RTLIL::State d : chunk.data) + if (d != RTLIL::State::Sx && d != RTLIL::State::Sz) return false; } return true; From ed8022f53faaade7e8f5ebccf5d69f765f2351b0 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 28 Oct 2025 12:37:38 +0000 Subject: [PATCH 65/97] Make SigSpec::has_const use chunk iterator --- kernel/rtlil.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 70fd14856..cfc841b9f 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5506,9 +5506,8 @@ bool RTLIL::SigSpec::has_const() const { cover("kernel.rtlil.sigspec.has_const"); - pack(); - for (auto it = chunks_.begin(); it != chunks_.end(); it++) - if (it->width > 0 && it->wire == NULL) + for (auto &chunk : chunks()) + if (chunk.width > 0 && chunk.wire == NULL) return true; return false; } From 80b3efb3dabba0d8ef76b6014f622af943ba0906 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 28 Oct 2025 12:37:51 +0000 Subject: [PATCH 66/97] Make SigSpec::has_const(State) use chunk iterator --- kernel/rtlil.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index cfc841b9f..979f115be 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5516,9 +5516,8 @@ bool RTLIL::SigSpec::has_const(State state) const { cover("kernel.rtlil.sigspec.has_const"); - pack(); - for (auto it = chunks_.begin(); it != chunks_.end(); it++) - if (it->width > 0 && it->wire == NULL && std::find(it->data.begin(), it->data.end(), state) != it->data.end()) + for (auto &chunk : chunks()) + if (chunk.width > 0 && chunk.wire == NULL && std::find(chunk.data.begin(), chunk.data.end(), state) != chunk.data.end()) return true; return false; } From 0091d14e6d35cd7987195028b7bd56397cf52208 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 28 Oct 2025 12:38:03 +0000 Subject: [PATCH 67/97] Make SigSpec::has_marked_bits use chunk iterator --- kernel/rtlil.cc | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 979f115be..2647e4876 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5527,11 +5527,10 @@ bool RTLIL::SigSpec::has_marked_bits() const { cover("kernel.rtlil.sigspec.has_marked_bits"); - pack(); - for (auto it = chunks_.begin(); it != chunks_.end(); it++) - if (it->width > 0 && it->wire == NULL) { - for (size_t i = 0; i < it->data.size(); i++) - if (it->data[i] == RTLIL::State::Sm) + for (auto &chunk : chunks()) + if (chunk.width > 0 && chunk.wire == NULL) { + for (RTLIL::State d : chunk.data) + if (d == RTLIL::State::Sm) return true; } return false; From 0281ed1458e5e43d845b031236b73bc435c47430 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 28 Oct 2025 15:48:24 +0000 Subject: [PATCH 68/97] Add try_as_const and use the const iterator a bit more --- kernel/rtlil.cc | 37 ++++++++++++++++++++++++++----------- kernel/rtlil.h | 3 +++ 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 2647e4876..a2e766a9b 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5629,33 +5629,48 @@ std::string RTLIL::SigSpec::as_string() const return str; } +std::optional RTLIL::SigSpec::try_as_const() const +{ + cover("kernel.rtlil.sigspec.as_const"); + + auto it = chunks().begin(); + if (it == chunks().end()) + return RTLIL::Const(); + SigChunk chunk = *it; + if (chunk.wire != NULL || ++it != chunks().end()) + return std::nullopt; + return RTLIL::Const(std::move(chunk.data)); +} + RTLIL::Const RTLIL::SigSpec::as_const() const { cover("kernel.rtlil.sigspec.as_const"); - pack(); - log_assert(is_fully_const() && GetSize(chunks_) <= 1); - if (width_) - return chunks_[0].data; - return RTLIL::Const(); + std::optional c = try_as_const(); + log_assert(c.has_value()); + return *c; } RTLIL::Wire *RTLIL::SigSpec::as_wire() const { cover("kernel.rtlil.sigspec.as_wire"); - pack(); - log_assert(is_wire()); - return chunks_[0].wire; + auto it = chunks().begin(); + log_assert(it != chunks().end()); + RTLIL::SigChunk chunk = *it; + log_assert(++it == chunks().end() && chunk.wire && chunk.wire->width == width_); + return chunk.wire; } RTLIL::SigChunk RTLIL::SigSpec::as_chunk() const { cover("kernel.rtlil.sigspec.as_chunk"); - pack(); - log_assert(is_chunk()); - return chunks_[0]; + auto it = chunks().begin(); + log_assert(it != chunks().end()); + RTLIL::SigChunk chunk = *it; + log_assert(++it == chunks().end()); + return chunk; } RTLIL::SigBit RTLIL::SigSpec::as_bit() const diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 8e93f5f05..5bc60d1e9 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1457,6 +1457,9 @@ public: int as_int_saturating(bool is_signed = false) const; std::string as_string() const; + // Returns std::nullopt if there are any non-constant bits. Returns an empty + // Const if this has zero width. + std::optional try_as_const() const; RTLIL::Const as_const() const; RTLIL::Wire *as_wire() const; RTLIL::SigChunk as_chunk() const; From ce597dc38c8b47a2ba3a83460fdc2c0d8b4cfbda Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Thu, 30 Oct 2025 11:59:57 +0000 Subject: [PATCH 69/97] Fix try_as_const/as_wire/as_chunk --- kernel/rtlil.cc | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index a2e766a9b..68cc596fc 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5633,11 +5633,12 @@ std::optional RTLIL::SigSpec::try_as_const() const { cover("kernel.rtlil.sigspec.as_const"); - auto it = chunks().begin(); - if (it == chunks().end()) + Chunks cs = chunks(); + auto it = cs.begin(); + if (it == cs.end()) return RTLIL::Const(); SigChunk chunk = *it; - if (chunk.wire != NULL || ++it != chunks().end()) + if (chunk.wire != NULL || ++it != cs.end()) return std::nullopt; return RTLIL::Const(std::move(chunk.data)); } @@ -5655,10 +5656,11 @@ RTLIL::Wire *RTLIL::SigSpec::as_wire() const { cover("kernel.rtlil.sigspec.as_wire"); - auto it = chunks().begin(); - log_assert(it != chunks().end()); + Chunks cs = chunks(); + auto it = cs.begin(); + log_assert(it != cs.end()); RTLIL::SigChunk chunk = *it; - log_assert(++it == chunks().end() && chunk.wire && chunk.wire->width == width_); + log_assert(++it == cs.end() && chunk.wire && chunk.wire->width == width_); return chunk.wire; } @@ -5666,10 +5668,11 @@ RTLIL::SigChunk RTLIL::SigSpec::as_chunk() const { cover("kernel.rtlil.sigspec.as_chunk"); - auto it = chunks().begin(); - log_assert(it != chunks().end()); + Chunks cs = chunks(); + auto it = cs.begin(); + log_assert(it != cs.end()); RTLIL::SigChunk chunk = *it; - log_assert(++it == chunks().end()); + log_assert(++it == cs.end()); return chunk; } From dd3940c8bb8a771e3d067c34d7e0f9b7a216f31d Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 28 Oct 2025 12:39:31 +0000 Subject: [PATCH 70/97] Make SigSpec::is_one_hot use try_as_const --- kernel/rtlil.cc | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 68cc596fc..4b27c95c2 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5540,12 +5540,8 @@ bool RTLIL::SigSpec::is_onehot(int *pos) const { cover("kernel.rtlil.sigspec.is_onehot"); - pack(); - if (!is_fully_const()) - return false; - log_assert(GetSize(chunks_) <= 1); - if (width_) - return RTLIL::Const(chunks_[0].data).is_onehot(pos); + if (std::optional c = try_as_const()) + return c->is_onehot(pos); return false; } From 39b89aae88e05a429f073b6a9b8e4824296b289e Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 28 Oct 2025 12:39:53 +0000 Subject: [PATCH 71/97] Use SigSpec::try_as_const in some places --- kernel/rtlil.cc | 52 +++++++++++++++++-------------------------------- 1 file changed, 18 insertions(+), 34 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 4b27c95c2..a87161465 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5549,74 +5549,58 @@ bool RTLIL::SigSpec::as_bool() const { cover("kernel.rtlil.sigspec.as_bool"); - pack(); - log_assert(is_fully_const() && GetSize(chunks_) <= 1); - if (width_) - return RTLIL::Const(chunks_[0].data).as_bool(); - return false; + std::optional c = try_as_const(); + log_assert(c.has_value()); + return c->as_bool(); } int RTLIL::SigSpec::as_int(bool is_signed) const { cover("kernel.rtlil.sigspec.as_int"); - pack(); - log_assert(is_fully_const() && GetSize(chunks_) <= 1); - if (width_) - return RTLIL::Const(chunks_[0].data).as_int(is_signed); - return 0; + std::optional c = try_as_const(); + log_assert(c.has_value()); + return c->as_int(is_signed); } bool RTLIL::SigSpec::convertible_to_int(bool is_signed) const { cover("kernel.rtlil.sigspec.convertible_to_int"); - pack(); - if (!is_fully_const()) + std::optional c = try_as_const(); + if (!c.has_value()) return false; - - if (empty()) - return true; - - return RTLIL::Const(chunks_[0].data).convertible_to_int(is_signed); + return c->convertible_to_int(is_signed); } std::optional RTLIL::SigSpec::try_as_int(bool is_signed) const { cover("kernel.rtlil.sigspec.try_as_int"); - pack(); - if (!is_fully_const()) + std::optional c = try_as_const(); + if (!c.has_value()) return std::nullopt; - - if (empty()) - return 0; - - return RTLIL::Const(chunks_[0].data).try_as_int(is_signed); + return c->try_as_int(is_signed); } int RTLIL::SigSpec::as_int_saturating(bool is_signed) const { cover("kernel.rtlil.sigspec.try_as_int"); - pack(); - log_assert(is_fully_const() && GetSize(chunks_) <= 1); - - if (empty()) - return 0; - - return RTLIL::Const(chunks_[0].data).as_int_saturating(is_signed); + std::optional c = try_as_const(); + log_assert(c.has_value()); + return c->as_int_saturating(is_signed); } std::string RTLIL::SigSpec::as_string() const { cover("kernel.rtlil.sigspec.as_string"); - pack(); std::string str; str.reserve(size()); - for (size_t i = chunks_.size(); i > 0; i--) { - const RTLIL::SigChunk &chunk = chunks_[i-1]; + std::vector chunks = *this; + for (size_t i = chunks.size(); i > 0; i--) { + const RTLIL::SigChunk &chunk = chunks[i-1]; if (chunk.wire != NULL) str.append(chunk.width, '?'); else From 4ed25c05382d5fe481c992d1187b74a69998a6f5 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 28 Oct 2025 12:40:08 +0000 Subject: [PATCH 72/97] Make SigSpec::to_sigbit_set use chunk iterator --- kernel/rtlil.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index a87161465..2aa85f6fb 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5700,9 +5700,8 @@ std::set RTLIL::SigSpec::to_sigbit_set() const { cover("kernel.rtlil.sigspec.to_sigbit_set"); - pack(); std::set sigbits; - for (auto &c : chunks_) + for (auto &c : chunks()) for (int i = 0; i < c.width; i++) sigbits.insert(RTLIL::SigBit(c, i)); return sigbits; From 62cd3ddfb898d8c867a19fb6e19587e77f05f3fd Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 28 Oct 2025 12:40:20 +0000 Subject: [PATCH 73/97] Make SigSpec::to_sigbit_pool use chunk iterator --- kernel/rtlil.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 2aa85f6fb..028f0e895 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5711,10 +5711,9 @@ pool RTLIL::SigSpec::to_sigbit_pool() const { cover("kernel.rtlil.sigspec.to_sigbit_pool"); - pack(); pool sigbits; sigbits.reserve(size()); - for (auto &c : chunks_) + for (auto &c : chunks()) for (int i = 0; i < c.width; i++) sigbits.insert(RTLIL::SigBit(c, i)); return sigbits; From 974b4dbe25c617dbef5c742f11258eecbbd8ed1e Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Tue, 28 Oct 2025 12:40:45 +0000 Subject: [PATCH 74/97] Make SigSpec::parse_rhs use is_chunk to avoid direct access to chunks_ --- kernel/rtlil.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 028f0e895..5594df6e7 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5890,7 +5890,7 @@ bool RTLIL::SigSpec::parse_rhs(const RTLIL::SigSpec &lhs, RTLIL::SigSpec &sig, R return true; } - if (lhs.chunks_.size() == 1) { + if (lhs.is_chunk()) { char *p = (char*)str.c_str(), *endptr; long int val = strtol(p, &endptr, 10); if (endptr && endptr != p && *endptr == 0) { From 7394a2c59780ceb7ef73211ff5a162d7f0d7d3a5 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Thu, 30 Oct 2025 10:30:03 +0000 Subject: [PATCH 75/97] Make SigSpec conversion to vector of SigChunk use chunks iterator --- kernel/rtlil.cc | 8 ++++++++ kernel/rtlil.h | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 5594df6e7..cc3714948 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5907,6 +5907,14 @@ bool RTLIL::SigSpec::parse_rhs(const RTLIL::SigSpec &lhs, RTLIL::SigSpec &sig, R return true; } +RTLIL::SigSpec::operator std::vector() const +{ + std::vector result; + for (const RTLIL::SigChunk &c : chunks()) + result.push_back(c); + return result; +} + RTLIL::CaseRule::~CaseRule() { for (auto it = switches.begin(); it != switches.end(); it++) diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 5bc60d1e9..64e96ea53 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1477,7 +1477,7 @@ public: static bool parse_sel(RTLIL::SigSpec &sig, RTLIL::Design *design, RTLIL::Module *module, std::string str); static bool parse_rhs(const RTLIL::SigSpec &lhs, RTLIL::SigSpec &sig, RTLIL::Module *module, std::string str); - operator std::vector() const { pack(); return chunks_; } + operator std::vector() const; operator std::vector() const { return bits(); } const RTLIL::SigBit &at(int offset, const RTLIL::SigBit &defval) { return offset < width_ ? (*this)[offset] : defval; } From 92ea557979ff4acfaa8b81def29a37587895918b Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Thu, 30 Oct 2025 11:07:02 +0000 Subject: [PATCH 76/97] Build a temporary SigChunk list in the iterator in the cases where that's needed --- backends/rtlil/rtlil_backend.cc | 3 +- backends/verilog/verilog_backend.cc | 5 +-- kernel/rtlil.h | 48 +++++++++++++++++++---------- kernel/utils.h | 24 +++++++++++---- 4 files changed, 55 insertions(+), 25 deletions(-) diff --git a/backends/rtlil/rtlil_backend.cc b/backends/rtlil/rtlil_backend.cc index d607be837..057edc584 100644 --- a/backends/rtlil/rtlil_backend.cc +++ b/backends/rtlil/rtlil_backend.cc @@ -121,7 +121,8 @@ void RTLIL_BACKEND::dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig, boo dump_sigchunk(f, sig.as_chunk(), autoint); } else { f << stringf("{ "); - for (const auto& chunk : reversed(sig.chunks())) { + auto chunks = sig.chunks(); + for (const auto& chunk : reversed(chunks)) { dump_sigchunk(f, chunk, false); f << stringf(" "); } diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index c747aa901..faeb2cd0b 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -382,8 +382,9 @@ void dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig) dump_sigchunk(f, sig.as_chunk()); } else { f << stringf("{ "); - for (auto it = sig.chunks().rbegin(); it != sig.chunks().rend(); ++it) { - if (it != sig.chunks().rbegin()) + auto chunks = sig.chunks(); + for (auto it = chunks.rbegin(); it != chunks.rend(); ++it) { + if (it != chunks.rbegin()) f << stringf(", "); dump_sigchunk(f, *it, true); } diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 64e96ea53..3a21f898f 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1277,8 +1277,7 @@ public: SigSpec &operator=(SigSpec &&rhs) = default; struct Chunks { - const SigSpec &spec; - + Chunks(const SigSpec &spec) : spec(spec) {} struct const_iterator { using iterator_category = std::forward_iterator_tag; using value_type = const SigChunk &; @@ -1324,26 +1323,43 @@ public: const_iterator it(spec, const_iterator::END); return it; } - std::vector::const_reverse_iterator rbegin() const { - spec.pack(); - return spec.chunks_.rbegin(); + // Later we should deprecate these and remove their in-tree calls, + // so we can eventually remove chunk_vector. + std::vector::const_reverse_iterator rbegin() { + ensure_chunk_vector(); + return chunk_vector.rbegin(); } - std::vector::const_reverse_iterator rend() const { - spec.pack(); - return spec.chunks_.rend(); + std::vector::const_reverse_iterator rend() { + ensure_chunk_vector(); + return chunk_vector.rend(); + } + int size() { + ensure_chunk_vector(); + return chunk_vector.size(); } int size() const { - spec.pack(); - return spec.chunks_.size(); + int result = 0; + for (const SigChunk &_: *this) + ++result; + return result; } - const SigChunk &at(int index) const { - spec.pack(); - return spec.chunks_.at(index); + const SigChunk &at(int index) { + ensure_chunk_vector(); + return chunk_vector.at(index); } - operator const std::vector&() const { - spec.pack(); - return spec.chunks_; + operator const std::vector&() { + ensure_chunk_vector(); + return chunk_vector; } + private: + void ensure_chunk_vector() { + if (spec.size() > 0 && chunk_vector.empty()) { + for (const RTLIL::SigChunk &c : *this) + chunk_vector.push_back(c); + } + } + const SigSpec &spec; + std::vector chunk_vector; }; friend struct Chunks::const_iterator; diff --git a/kernel/utils.h b/kernel/utils.h index 5c739aceb..e90ba09d8 100644 --- a/kernel/utils.h +++ b/kernel/utils.h @@ -277,14 +277,26 @@ inline int ceil_log2(int x) #endif } +template +auto reversed(T& container) { + struct reverse_view { + reverse_view(T& container) : container(container) {} + auto begin() const { return container.rbegin(); } + auto end() const { return container.rend(); } + T& container; + }; + return reverse_view{container}; +} + template auto reversed(const T& container) { - struct reverse_view { - const T& cont; - auto begin() const { return cont.rbegin(); } - auto end() const { return cont.rend(); } - }; - return reverse_view{container}; + struct reverse_view { + reverse_view(const T& container) : container(container) {} + auto begin() const { return container.rbegin(); } + auto end() const { return container.rend(); } + const T& container; + }; + return reverse_view{container}; } YOSYS_NAMESPACE_END From a69d48dd19cb9f1b0f26795566b96969aba0d7eb Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Thu, 30 Oct 2025 11:24:00 +0000 Subject: [PATCH 77/97] Instead of using packing and hashing to compute SigSpec ordering and equality, just use the width and chunkwise comparisons This avoids having to pack and compute hashes, and generally results in a simpler ordering. --- kernel/rtlil.cc | 50 +++++++++++-------------------------------------- 1 file changed, 11 insertions(+), 39 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index cc3714948..634269d9d 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5345,23 +5345,12 @@ bool RTLIL::SigSpec::operator <(const RTLIL::SigSpec &other) const if (width_ != other.width_) return width_ < other.width_; - pack(); - other.pack(); - - if (chunks_.size() != other.chunks_.size()) - return chunks_.size() < other.chunks_.size(); - - updhash(); - other.updhash(); - - if (hash_ != other.hash_) - return hash_ < other.hash_; - - for (size_t i = 0; i < chunks_.size(); i++) - if (chunks_[i] != other.chunks_[i]) { - cover("kernel.rtlil.sigspec.comp_lt.hash_collision"); - return chunks_[i] < other.chunks_[i]; - } + auto other_it = other.chunks().begin(); + for (const SigChunk &c : chunks()) { + if (c != *other_it) + return c < *other_it; + ++other_it; + } cover("kernel.rtlil.sigspec.comp_lt.equal"); return false; @@ -5377,29 +5366,12 @@ bool RTLIL::SigSpec::operator ==(const RTLIL::SigSpec &other) const if (width_ != other.width_) return false; - // Without this, SigSpec() == SigSpec(State::S0, 0) will fail - // since the RHS will contain one SigChunk of width 0 causing - // the size check below to fail - if (width_ == 0) - return true; - - pack(); - other.pack(); - - if (chunks_.size() != other.chunks_.size()) - return false; - - updhash(); - other.updhash(); - - if (hash_ != other.hash_) - return false; - - for (size_t i = 0; i < chunks_.size(); i++) - if (chunks_[i] != other.chunks_[i]) { - cover("kernel.rtlil.sigspec.comp_eq.hash_collision"); + auto other_it = other.chunks().begin(); + for (const SigChunk &c : chunks()) { + if (c != *other_it) return false; - } + ++other_it; + } cover("kernel.rtlil.sigspec.comp_eq.equal"); return true; From b612c1bb39aefea933241784ae1b69fb2c5b4deb Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Thu, 30 Oct 2025 11:34:42 +0000 Subject: [PATCH 78/97] Simplify SigSpec::as_bit() --- kernel/rtlil.cc | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 634269d9d..c4a53ddd5 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5631,12 +5631,7 @@ RTLIL::SigChunk RTLIL::SigSpec::as_chunk() const RTLIL::SigBit RTLIL::SigSpec::as_bit() const { cover("kernel.rtlil.sigspec.as_bit"); - - log_assert(width_ == 1); - if (packed()) - return RTLIL::SigBit(*chunks_.begin()); - else - return bits_[0]; + return RTLIL::SigBit(*this); } bool RTLIL::SigSpec::match(const char* pattern) const From 619f49eabe37650dd7ccbe49d26bf8afad8db242 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Thu, 30 Oct 2025 13:42:53 +0000 Subject: [PATCH 79/97] Remove unnecessary pack() from SigSpec::extend_u0() --- kernel/rtlil.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index c4a53ddd5..8713f5755 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5259,8 +5259,6 @@ void RTLIL::SigSpec::extend_u0(int width, bool is_signed) { cover("kernel.rtlil.sigspec.extend_u0"); - pack(); - if (width_ > width) remove(width, width_ - width); From aa4a0fe815b6c479dcac4643a3b28ff96ee3f9f1 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Thu, 30 Oct 2025 14:13:46 +0000 Subject: [PATCH 80/97] Use size() instead of direct access to width_ in many places --- kernel/rtlil.cc | 122 ++++++++++++++++++++++++++---------------------- kernel/rtlil.h | 16 +++---- 2 files changed, 73 insertions(+), 65 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 8713f5755..2a3c72c51 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -4727,7 +4727,7 @@ void RTLIL::SigSpec::unpack() const cover("kernel.rtlil.sigspec.convert.unpack"); log_assert(that->bits_.empty()); - that->bits_.reserve(that->width_); + that->bits_.reserve(that->size()); for (auto &c : that->chunks_) for (int i = 0; i < c.width; i++) that->bits_.emplace_back(c, i); @@ -4791,8 +4791,8 @@ void RTLIL::SigSpec::replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec void RTLIL::SigSpec::replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with, RTLIL::SigSpec *other) const { log_assert(other != NULL); - log_assert(width_ == other->width_); - log_assert(pattern.width_ == with.width_); + log_assert(size() == other->size()); + log_assert(pattern.size() == with.size()); pattern.unpack(); with.unpack(); @@ -4826,7 +4826,7 @@ void RTLIL::SigSpec::replace(const dict &rules, RT cover("kernel.rtlil.sigspec.replace_dict"); log_assert(other != NULL); - log_assert(width_ == other->width_); + log_assert(size() == other->size()); if (rules.empty()) return; unpack(); @@ -4851,7 +4851,7 @@ void RTLIL::SigSpec::replace(const std::map &rules cover("kernel.rtlil.sigspec.replace_map"); log_assert(other != NULL); - log_assert(width_ == other->width_); + log_assert(size() == other->size()); if (rules.empty()) return; unpack(); @@ -4886,7 +4886,7 @@ void RTLIL::SigSpec::remove2(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *othe unpack(); if (other != NULL) { - log_assert(width_ == other->width_); + log_assert(size() == other->size()); other->unpack(); } @@ -4932,7 +4932,7 @@ void RTLIL::SigSpec::remove2(const pool &pattern, RTLIL::SigSpec unpack(); if (other != NULL) { - log_assert(width_ == other->width_); + log_assert(size() == other->size()); other->unpack(); } @@ -4960,7 +4960,7 @@ void RTLIL::SigSpec::remove2(const std::set &pattern, RTLIL::SigS unpack(); if (other != NULL) { - log_assert(width_ == other->width_); + log_assert(size() == other->size()); other->unpack(); } @@ -4988,7 +4988,7 @@ void RTLIL::SigSpec::remove2(const pool &pattern, RTLIL::SigSpec * unpack(); if (other != NULL) { - log_assert(width_ == other->width_); + log_assert(size() == other->size()); other->unpack(); } @@ -5013,7 +5013,7 @@ RTLIL::SigSpec RTLIL::SigSpec::extract(const RTLIL::SigSpec &pattern, const RTLI else cover("kernel.rtlil.sigspec.extract"); - log_assert(other == NULL || width_ == other->width_); + log_assert(other == NULL || size() == other->size()); RTLIL::SigSpec ret; std::vector bits_match = to_sigbit_vector(); @@ -5021,19 +5021,22 @@ RTLIL::SigSpec RTLIL::SigSpec::extract(const RTLIL::SigSpec &pattern, const RTLI for (auto& pattern_chunk : pattern.chunks()) { if (other) { std::vector bits_other = other->to_sigbit_vector(); - for (int i = 0; i < width_; i++) - if (bits_match[i].wire && - bits_match[i].wire == pattern_chunk.wire && - bits_match[i].offset >= pattern_chunk.offset && - bits_match[i].offset < pattern_chunk.offset + pattern_chunk.width) + int i = 0; + for (const RTLIL::SigBit &bit : bits_match) { + if (bit.wire && + bit.wire == pattern_chunk.wire && + bit.offset >= pattern_chunk.offset && + bit.offset < pattern_chunk.offset + pattern_chunk.width) ret.append(bits_other[i]); + ++i; + } } else { - for (int i = 0; i < width_; i++) - if (bits_match[i].wire && - bits_match[i].wire == pattern_chunk.wire && - bits_match[i].offset >= pattern_chunk.offset && - bits_match[i].offset < pattern_chunk.offset + pattern_chunk.width) - ret.append(bits_match[i]); + for (const RTLIL::SigBit &bit : bits_match) + if (bit.wire && + bit.wire == pattern_chunk.wire && + bit.offset >= pattern_chunk.offset && + bit.offset < pattern_chunk.offset + pattern_chunk.width) + ret.append(bit); } } @@ -5048,20 +5051,23 @@ RTLIL::SigSpec RTLIL::SigSpec::extract(const pool &pattern, const else cover("kernel.rtlil.sigspec.extract"); - log_assert(other == NULL || width_ == other->width_); + log_assert(other == NULL || size() == other->size()); std::vector bits_match = to_sigbit_vector(); RTLIL::SigSpec ret; if (other) { std::vector bits_other = other->to_sigbit_vector(); - for (int i = 0; i < width_; i++) - if (bits_match[i].wire && pattern.count(bits_match[i])) + int i = 0; + for (const RTLIL::SigBit &bit : bits_match) { + if (bit.wire && pattern.count(bit)) ret.append(bits_other[i]); + ++i; + } } else { - for (int i = 0; i < width_; i++) - if (bits_match[i].wire && pattern.count(bits_match[i])) - ret.append(bits_match[i]); + for (const RTLIL::SigBit &bit : bits_match) + if (bit.wire && pattern.count(bit)) + ret.append(bit); } ret.check(); @@ -5073,14 +5079,16 @@ void RTLIL::SigSpec::replace(int offset, const RTLIL::SigSpec &with) cover("kernel.rtlil.sigspec.replace_pos"); unpack(); - with.unpack(); log_assert(offset >= 0); - log_assert(with.width_ >= 0); - log_assert(offset+with.width_ <= width_); + log_assert(with.size() >= 0); + log_assert(offset+with.size() <= size()); - for (int i = 0; i < with.width_; i++) - bits_.at(offset + i) = with.bits_.at(i); + int i = 0; + for (const RTLIL::SigBit &bit : with.bits()) { + bits_.at(offset + i) = bit; + ++i; + } check(); } @@ -5135,7 +5143,7 @@ void RTLIL::SigSpec::remove(int offset, int length) log_assert(offset >= 0); log_assert(length >= 0); - log_assert(offset + length <= width_); + log_assert(offset + length <= size()); bits_.erase(bits_.begin() + offset, bits_.begin() + offset + length); width_ = bits_.size(); @@ -5147,7 +5155,7 @@ RTLIL::SigSpec RTLIL::SigSpec::extract(int offset, int length) const { log_assert(offset >= 0); log_assert(length >= 0); - log_assert(offset + length <= width_); + log_assert(offset + length <= size()); cover("kernel.rtlil.sigspec.extract_pos"); @@ -5190,10 +5198,10 @@ void RTLIL::SigSpec::rewrite_wires(std::function rewri void RTLIL::SigSpec::append(const RTLIL::SigSpec &signal) { - if (signal.width_ == 0) + if (signal.size() == 0) return; - if (width_ == 0) { + if (size() == 0) { *this = signal; return; } @@ -5220,7 +5228,7 @@ void RTLIL::SigSpec::append(const RTLIL::SigSpec &signal) bits_.insert(bits_.end(), signal.bits_.begin(), signal.bits_.end()); } - width_ += signal.width_; + width_ += signal.size(); check(); } @@ -5259,14 +5267,14 @@ void RTLIL::SigSpec::extend_u0(int width, bool is_signed) { cover("kernel.rtlil.sigspec.extend_u0"); - if (width_ > width) - remove(width, width_ - width); + if (size() > width) + remove(width, size() - width); - if (width_ < width) { - RTLIL::SigBit padding = width_ > 0 ? (*this)[width_ - 1] : RTLIL::State::Sx; + if (size() < width) { + RTLIL::SigBit padding = size() > 0 ? (*this)[size() - 1] : RTLIL::State::Sx; if (!is_signed) padding = RTLIL::State::S0; - while (width_ < width) + while (size() < width) append(padding); } @@ -5285,7 +5293,7 @@ RTLIL::SigSpec RTLIL::SigSpec::repeat(int num) const #ifndef NDEBUG void RTLIL::SigSpec::check(Module *mod) const { - if (width_ > 64) + if (size() > 64) { cover("kernel.rtlil.sigspec.check.skip"); } @@ -5314,7 +5322,7 @@ void RTLIL::SigSpec::check(Module *mod) const } w += chunk.width; } - log_assert(w == width_); + log_assert(w == size()); log_assert(bits_.empty()); } else @@ -5327,7 +5335,7 @@ void RTLIL::SigSpec::check(Module *mod) const log_assert(bits_[i].wire->module == mod); } - log_assert(width_ == GetSize(bits_)); + log_assert(size() == GetSize(bits_)); log_assert(chunks_.empty()); } } @@ -5340,8 +5348,8 @@ bool RTLIL::SigSpec::operator <(const RTLIL::SigSpec &other) const if (this == &other) return false; - if (width_ != other.width_) - return width_ < other.width_; + if (size() != other.size()) + return size() < other.size(); auto other_it = other.chunks().begin(); for (const SigChunk &c : chunks()) { @@ -5361,7 +5369,7 @@ bool RTLIL::SigSpec::operator ==(const RTLIL::SigSpec &other) const if (this == &other) return true; - if (width_ != other.width_) + if (size() != other.size()) return false; auto other_it = other.chunks().begin(); @@ -5384,7 +5392,7 @@ bool RTLIL::SigSpec::is_wire() const if (it == cs.end()) return false; const RTLIL::SigChunk &chunk = *it; - return chunk.wire && chunk.wire->width == width_ && ++it == cs.end(); + return chunk.wire && chunk.wire->width == size() && ++it == cs.end(); } bool RTLIL::SigSpec::is_chunk() const @@ -5610,7 +5618,7 @@ RTLIL::Wire *RTLIL::SigSpec::as_wire() const auto it = cs.begin(); log_assert(it != cs.end()); RTLIL::SigChunk chunk = *it; - log_assert(++it == cs.end() && chunk.wire && chunk.wire->width == width_); + log_assert(++it == cs.end() && chunk.wire && chunk.wire->width == size()); return chunk.wire; } @@ -5699,7 +5707,7 @@ std::map RTLIL::SigSpec::to_sigbit_map(const RTLIL unpack(); other.unpack(); - log_assert(width_ == other.width_); + log_assert(size() == other.size()); std::map new_map; for (int i = 0; i < width_; i++) @@ -5715,7 +5723,7 @@ dict RTLIL::SigSpec::to_sigbit_dict(const RTLIL::S unpack(); other.unpack(); - log_assert(width_ == other.width_); + log_assert(size() == other.size()); dict new_map; new_map.reserve(size()); @@ -5845,13 +5853,13 @@ bool RTLIL::SigSpec::parse_rhs(const RTLIL::SigSpec &lhs, RTLIL::SigSpec &sig, R { if (str == "0") { cover("kernel.rtlil.sigspec.parse.rhs_zeros"); - sig = RTLIL::SigSpec(RTLIL::State::S0, lhs.width_); + sig = RTLIL::SigSpec(RTLIL::State::S0, lhs.size()); return true; } if (str == "~0") { cover("kernel.rtlil.sigspec.parse.rhs_ones"); - sig = RTLIL::SigSpec(RTLIL::State::S1, lhs.width_); + sig = RTLIL::SigSpec(RTLIL::State::S1, lhs.size()); return true; } @@ -5859,7 +5867,7 @@ bool RTLIL::SigSpec::parse_rhs(const RTLIL::SigSpec &lhs, RTLIL::SigSpec &sig, R char *p = (char*)str.c_str(), *endptr; long int val = strtol(p, &endptr, 10); if (endptr && endptr != p && *endptr == 0) { - sig = RTLIL::SigSpec(val, lhs.width_); + sig = RTLIL::SigSpec(val, lhs.size()); cover("kernel.rtlil.sigspec.parse.rhs_dec"); return true; } @@ -5867,8 +5875,8 @@ bool RTLIL::SigSpec::parse_rhs(const RTLIL::SigSpec &lhs, RTLIL::SigSpec &sig, R if (!parse(sig, module, str)) return false; - if (sig.width_ > lhs.width_) - sig.remove(lhs.width_, sig.width_ - lhs.width_); + if (sig.size() > lhs.size()) + sig.remove(lhs.size(), sig.size() - lhs.size()); return true; } diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 3a21f898f..85ef0f056 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1367,16 +1367,16 @@ public: inline const std::vector &bits() const { inline_unpack(); return bits_; } inline int size() const { return width_; } - inline bool empty() const { return width_ == 0; } + inline bool empty() const { return size() == 0; } inline RTLIL::SigBit &operator[](int index) { inline_unpack(); return bits_.at(index); } inline const RTLIL::SigBit &operator[](int index) const { inline_unpack(); return bits_.at(index); } inline RTLIL::SigSpecIterator begin() { RTLIL::SigSpecIterator it; it.sig_p = this; it.index = 0; return it; } - inline RTLIL::SigSpecIterator end() { RTLIL::SigSpecIterator it; it.sig_p = this; it.index = width_; return it; } + inline RTLIL::SigSpecIterator end() { RTLIL::SigSpecIterator it; it.sig_p = this; it.index = size(); return it; } inline RTLIL::SigSpecConstIterator begin() const { RTLIL::SigSpecConstIterator it; it.sig_p = this; it.index = 0; return it; } - inline RTLIL::SigSpecConstIterator end() const { RTLIL::SigSpecConstIterator it; it.sig_p = this; it.index = width_; return it; } + inline RTLIL::SigSpecConstIterator end() const { RTLIL::SigSpecConstIterator it; it.sig_p = this; it.index = size(); return it; } void sort(); void sort_and_unify(); @@ -1408,12 +1408,12 @@ public: RTLIL::SigSpec extract(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec *other = NULL) const; RTLIL::SigSpec extract(const pool &pattern, const RTLIL::SigSpec *other = NULL) const; RTLIL::SigSpec extract(int offset, int length = 1) const; - RTLIL::SigSpec extract_end(int offset) const { return extract(offset, width_ - offset); } + RTLIL::SigSpec extract_end(int offset) const { return extract(offset, size() - offset); } void rewrite_wires(std::function rewrite); - RTLIL::SigBit lsb() const { log_assert(width_); return (*this)[0]; }; - RTLIL::SigBit msb() const { log_assert(width_); return (*this)[width_ - 1]; }; + RTLIL::SigBit lsb() const { log_assert(size()); return (*this)[0]; }; + RTLIL::SigBit msb() const { log_assert(size()); return (*this)[size() - 1]; }; void append(const RTLIL::SigSpec &signal); inline void append(Wire *wire) { append(RTLIL::SigSpec(wire)); } @@ -1436,7 +1436,7 @@ public: bool is_wire() const; bool is_chunk() const; - inline bool is_bit() const { return width_ == 1; } + inline bool is_bit() const { return size() == 1; } bool known_driver() const; @@ -1495,7 +1495,7 @@ public: operator std::vector() const; operator std::vector() const { return bits(); } - const RTLIL::SigBit &at(int offset, const RTLIL::SigBit &defval) { return offset < width_ ? (*this)[offset] : defval; } + const RTLIL::SigBit &at(int offset, const RTLIL::SigBit &defval) { return offset < size() ? (*this)[offset] : defval; } [[nodiscard]] Hasher hash_into(Hasher h) const { if (!hash_) updhash(); h.eat(hash_); return h; } From 4939484840d50275aed247758bcdd4120f485a0a Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Thu, 30 Oct 2025 15:03:47 +0000 Subject: [PATCH 81/97] Don't reset the hash when unpacking, instead clear the hash whenever bits are modified --- kernel/rtlil.cc | 21 +++++++++++++++++++-- kernel/rtlil.h | 2 +- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 2a3c72c51..1291432c2 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -4733,7 +4733,6 @@ void RTLIL::SigSpec::unpack() const that->bits_.emplace_back(c, i); that->chunks_.clear(); - that->hash_ = 0; } void RTLIL::SigSpec::updhash() const @@ -4765,6 +4764,7 @@ void RTLIL::SigSpec::sort() unpack(); cover("kernel.rtlil.sigspec.sort"); std::sort(bits_.begin(), bits_.end()); + hash_ = 0; } void RTLIL::SigSpec::sort_and_unify() @@ -4781,6 +4781,7 @@ void RTLIL::SigSpec::sort_and_unify() unique_bits.erase(last, unique_bits.end()); *this = unique_bits; + hash_ = 0; } void RTLIL::SigSpec::replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with) @@ -4812,6 +4813,7 @@ void RTLIL::SigSpec::replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec other->bits_[j] = with.bits_[it->second]; } } + other->hash_ = 0; other->check(); } @@ -4837,6 +4839,7 @@ void RTLIL::SigSpec::replace(const dict &rules, RT if (it != rules.end()) other->bits_[i] = it->second; } + other->hash_ = 0; other->check(); } @@ -4862,6 +4865,7 @@ void RTLIL::SigSpec::replace(const std::map &rules if (it != rules.end()) other->bits_[i] = it->second; } + other->hash_ = 0; other->check(); } @@ -4888,6 +4892,7 @@ void RTLIL::SigSpec::remove2(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *othe if (other != NULL) { log_assert(size() == other->size()); other->unpack(); + other->hash_ = 0; } for (int i = GetSize(bits_) - 1; i >= 0; i--) @@ -4907,6 +4912,7 @@ void RTLIL::SigSpec::remove2(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *othe break; } } + hash_ = 0; check(); } @@ -4934,6 +4940,7 @@ void RTLIL::SigSpec::remove2(const pool &pattern, RTLIL::SigSpec if (other != NULL) { log_assert(size() == other->size()); other->unpack(); + other->hash_ = 0; } for (int i = GetSize(bits_) - 1; i >= 0; i--) { @@ -4946,6 +4953,7 @@ void RTLIL::SigSpec::remove2(const pool &pattern, RTLIL::SigSpec } } } + hash_ = 0; check(); } @@ -4962,6 +4970,7 @@ void RTLIL::SigSpec::remove2(const std::set &pattern, RTLIL::SigS if (other != NULL) { log_assert(size() == other->size()); other->unpack(); + other->hash_ = 0; } for (int i = GetSize(bits_) - 1; i >= 0; i--) { @@ -4974,6 +4983,7 @@ void RTLIL::SigSpec::remove2(const std::set &pattern, RTLIL::SigS } } } + hash_ = 0; check(); } @@ -4990,6 +5000,7 @@ void RTLIL::SigSpec::remove2(const pool &pattern, RTLIL::SigSpec * if (other != NULL) { log_assert(size() == other->size()); other->unpack(); + other->hash_ = 0; } for (int i = GetSize(bits_) - 1; i >= 0; i--) { @@ -5002,6 +5013,7 @@ void RTLIL::SigSpec::remove2(const pool &pattern, RTLIL::SigSpec * } } } + hash_ = 0; check(); } @@ -5089,6 +5101,7 @@ void RTLIL::SigSpec::replace(int offset, const RTLIL::SigSpec &with) bits_.at(offset + i) = bit; ++i; } + hash_ = 0; check(); } @@ -5132,6 +5145,7 @@ void RTLIL::SigSpec::remove_const() width_ = bits_.size(); } + hash_ = 0; check(); } @@ -5148,6 +5162,7 @@ void RTLIL::SigSpec::remove(int offset, int length) bits_.erase(bits_.begin() + offset, bits_.begin() + offset + length); width_ = bits_.size(); + hash_ = 0; check(); } @@ -5194,6 +5209,7 @@ void RTLIL::SigSpec::rewrite_wires(std::function rewri for (RTLIL::SigChunk &chunk : chunks_) if (chunk.wire != nullptr) rewrite(chunk.wire); + hash_ = 0; } void RTLIL::SigSpec::append(const RTLIL::SigSpec &signal) @@ -5229,6 +5245,7 @@ void RTLIL::SigSpec::append(const RTLIL::SigSpec &signal) } width_ += signal.size(); + hash_ = 0; check(); } @@ -5260,6 +5277,7 @@ void RTLIL::SigSpec::append(const RTLIL::SigBit &bit) } width_++; + hash_ = 0; check(); } @@ -5277,7 +5295,6 @@ void RTLIL::SigSpec::extend_u0(int width, bool is_signed) while (size() < width) append(padding); } - } RTLIL::SigSpec RTLIL::SigSpec::repeat(int num) const diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 85ef0f056..02b23a69a 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1369,7 +1369,7 @@ public: inline int size() const { return width_; } inline bool empty() const { return size() == 0; } - inline RTLIL::SigBit &operator[](int index) { inline_unpack(); return bits_.at(index); } + inline RTLIL::SigBit &operator[](int index) { inline_unpack(); hash_ = 0; return bits_.at(index); } inline const RTLIL::SigBit &operator[](int index) const { inline_unpack(); return bits_.at(index); } inline RTLIL::SigSpecIterator begin() { RTLIL::SigSpecIterator it; it.sig_p = this; it.index = 0; return it; } From e1169d03fe0e5c1dd9a5074c7444df25485f1a87 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Thu, 30 Oct 2025 17:42:58 +0000 Subject: [PATCH 82/97] Use chunks iterator for SigSpec::extract() --- kernel/rtlil.cc | 44 +++++++++++++++++++------------------------- 1 file changed, 19 insertions(+), 25 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 1291432c2..6fccaf1d3 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -5174,33 +5174,27 @@ RTLIL::SigSpec RTLIL::SigSpec::extract(int offset, int length) const cover("kernel.rtlil.sigspec.extract_pos"); - if (packed()) { - SigSpec extracted; - extracted.width_ = length; - - auto it = chunks_.begin(); - for (; offset; offset -= it->width, it++) { - if (offset < it->width) { - int chunk_length = min(it->width - offset, length); - extracted.chunks_.emplace_back(it->extract(offset, chunk_length)); - length -= chunk_length; - it++; - break; - } + SigSpec extracted; + Chunks cs = chunks(); + auto it = cs.begin(); + for (; offset; offset -= it->width, ++it) { + if (offset < it->width) { + int chunk_length = min(it->width - offset, length); + extracted.append(it->extract(offset, chunk_length)); + length -= chunk_length; + ++it; + break; } - for (; length; length -= it->width, it++) { - if (length >= it->width) { - extracted.chunks_.emplace_back(*it); - } else { - extracted.chunks_.emplace_back(it->extract(0, length)); - break; - } - } - - return extracted; - } else { - return std::vector(bits_.begin() + offset, bits_.begin() + offset + length); } + for (; length; length -= it->width, ++it) { + if (length >= it->width) { + extracted.append(*it); + } else { + extracted.append(it->extract(0, length)); + break; + } + } + return extracted; } void RTLIL::SigSpec::rewrite_wires(std::function rewrite) From 870ae18a2d069af6f953db5b9b825202d1a02c93 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Thu, 30 Oct 2025 15:02:39 +0000 Subject: [PATCH 83/97] Switch the SigSpec packed representation to allow just a single chunk that's inline in the SigSpec. Single-chunk SigSpecs are very common and this avoids a heap allocation. It also simplifies some algorithms. --- kernel/rtlil.cc | 363 +++++++++++++++++++----------------------------- kernel/rtlil.h | 88 +++++++++--- 2 files changed, 208 insertions(+), 243 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 6fccaf1d3..eda732619 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -4456,9 +4456,7 @@ RTLIL::SigSpec::SigSpec(std::initializer_list parts) { cover("kernel.rtlil.sigspec.init.list"); - width_ = 0; - hash_ = 0; - + init_empty_bits(); log_assert(parts.size() > 0); auto ie = parts.begin(); auto it = ie + parts.size() - 1; @@ -4471,12 +4469,11 @@ RTLIL::SigSpec::SigSpec(const RTLIL::Const &value) cover("kernel.rtlil.sigspec.init.const"); if (GetSize(value) != 0) { - chunks_.emplace_back(value); - width_ = chunks_.back().width; + rep_ = CHUNK; + new (&chunk_) RTLIL::SigChunk(value); } else { - width_ = 0; + init_empty_bits(); } - hash_ = 0; check(); } @@ -4485,12 +4482,11 @@ RTLIL::SigSpec::SigSpec(RTLIL::Const &&value) cover("kernel.rtlil.sigspec.init.const.move"); if (GetSize(value) != 0) { - chunks_.emplace_back(std::move(value)); - width_ = chunks_.back().width; + rep_ = CHUNK; + new (&chunk_) RTLIL::SigChunk(value); } else { - width_ = 0; + init_empty_bits(); } - hash_ = 0; check(); } @@ -4499,12 +4495,11 @@ RTLIL::SigSpec::SigSpec(const RTLIL::SigChunk &chunk) cover("kernel.rtlil.sigspec.init.chunk"); if (chunk.width != 0) { - chunks_.emplace_back(chunk); - width_ = chunks_.back().width; + rep_ = CHUNK; + new (&chunk_) RTLIL::SigChunk(chunk); } else { - width_ = 0; + init_empty_bits(); } - hash_ = 0; check(); } @@ -4513,12 +4508,11 @@ RTLIL::SigSpec::SigSpec(RTLIL::SigChunk &&chunk) cover("kernel.rtlil.sigspec.init.chunk.move"); if (chunk.width != 0) { - chunks_.emplace_back(std::move(chunk)); - width_ = chunks_.back().width; + rep_ = CHUNK; + new (&chunk_) RTLIL::SigChunk(chunk); } else { - width_ = 0; + init_empty_bits(); } - hash_ = 0; check(); } @@ -4527,12 +4521,11 @@ RTLIL::SigSpec::SigSpec(RTLIL::Wire *wire) cover("kernel.rtlil.sigspec.init.wire"); if (wire->width != 0) { - chunks_.emplace_back(wire); - width_ = chunks_.back().width; + rep_ = CHUNK; + new (&chunk_) RTLIL::SigChunk(wire); } else { - width_ = 0; + init_empty_bits(); } - hash_ = 0; check(); } @@ -4541,12 +4534,11 @@ RTLIL::SigSpec::SigSpec(RTLIL::Wire *wire, int offset, int width) cover("kernel.rtlil.sigspec.init.wire_part"); if (width != 0) { - chunks_.emplace_back(wire, offset, width); - width_ = chunks_.back().width; + rep_ = CHUNK; + new (&chunk_) RTLIL::SigChunk(wire, offset, width); } else { - width_ = 0; + init_empty_bits(); } - hash_ = 0; check(); } @@ -4555,12 +4547,11 @@ RTLIL::SigSpec::SigSpec(const std::string &str) cover("kernel.rtlil.sigspec.init.str"); if (str.size() != 0) { - chunks_.emplace_back(str); - width_ = chunks_.back().width; + rep_ = CHUNK; + new (&chunk_) RTLIL::SigChunk(str); } else { - width_ = 0; + init_empty_bits(); } - hash_ = 0; check(); } @@ -4568,10 +4559,11 @@ RTLIL::SigSpec::SigSpec(int val, int width) { cover("kernel.rtlil.sigspec.init.int"); - if (width != 0) - chunks_.emplace_back(val, width); - width_ = width; - hash_ = 0; + if (width != 0) { + rep_ = CHUNK; + new (&chunk_) RTLIL::SigChunk(val, width); + } else + init_empty_bits(); check(); } @@ -4579,10 +4571,11 @@ RTLIL::SigSpec::SigSpec(RTLIL::State bit, int width) { cover("kernel.rtlil.sigspec.init.state"); - if (width != 0) - chunks_.emplace_back(bit, width); - width_ = width; - hash_ = 0; + if (width != 0) { + rep_ = CHUNK; + new (&chunk_) RTLIL::SigChunk(bit, width); + } else + init_empty_bits(); check(); } @@ -4591,14 +4584,20 @@ RTLIL::SigSpec::SigSpec(const RTLIL::SigBit &bit, int width) cover("kernel.rtlil.sigspec.init.bit"); if (width != 0) { - if (bit.wire == NULL) - chunks_.emplace_back(bit.data, width); - else + if (bit.wire == NULL) { + rep_ = CHUNK; + new (&chunk_) RTLIL::SigChunk(bit.data, width); + } else if (width == 1) { + rep_ = CHUNK; + new (&chunk_) RTLIL::SigChunk(bit); + } else { + init_empty_bits(); + bits_.reserve(width); for (int i = 0; i < width; i++) - chunks_.push_back(bit); - } - width_ = width; - hash_ = 0; + bits_.push_back(bit); + } + } else + init_empty_bits(); check(); } @@ -4606,8 +4605,7 @@ RTLIL::SigSpec::SigSpec(const std::vector &chunks) { cover("kernel.rtlil.sigspec.init.stdvec_chunks"); - width_ = 0; - hash_ = 0; + init_empty_bits(); for (const auto &c : chunks) append(c); check(); @@ -4617,8 +4615,7 @@ RTLIL::SigSpec::SigSpec(const std::vector &bits) { cover("kernel.rtlil.sigspec.init.stdvec_bits"); - width_ = 0; - hash_ = 0; + init_empty_bits(); for (const auto &bit : bits) append(bit); check(); @@ -4628,8 +4625,7 @@ RTLIL::SigSpec::SigSpec(const pool &bits) { cover("kernel.rtlil.sigspec.init.pool_bits"); - width_ = 0; - hash_ = 0; + init_empty_bits(); for (const auto &bit : bits) append(bit); check(); @@ -4639,8 +4635,7 @@ RTLIL::SigSpec::SigSpec(const std::set &bits) { cover("kernel.rtlil.sigspec.init.stdset_bits"); - width_ = 0; - hash_ = 0; + init_empty_bits(); for (const auto &bit : bits) append(bit); check(); @@ -4650,9 +4645,8 @@ RTLIL::SigSpec::SigSpec(bool bit) { cover("kernel.rtlil.sigspec.init.bool"); - width_ = 0; - hash_ = 0; - append(SigBit(bit)); + rep_ = CHUNK; + new (&chunk_) RTLIL::SigChunk(bit ? RTLIL::S1 : RTLIL::S0); check(); } @@ -4681,58 +4675,23 @@ void RTLIL::SigSpec::Chunks::const_iterator::next_chunk_bits() chunk.width = i - bit_index; } -void RTLIL::SigSpec::pack() const -{ - RTLIL::SigSpec *that = (RTLIL::SigSpec*)this; - - if (that->bits_.empty()) - return; - - cover("kernel.rtlil.sigspec.convert.pack"); - log_assert(that->chunks_.empty()); - - std::vector old_bits; - old_bits.swap(that->bits_); - - RTLIL::SigChunk *last = NULL; - int last_end_offset = 0; - - for (auto &bit : old_bits) { - if (last && bit.wire == last->wire) { - if (bit.wire == NULL) { - last->data.push_back(bit.data); - last->width++; - continue; - } else if (last_end_offset == bit.offset) { - last_end_offset++; - last->width++; - continue; - } - } - that->chunks_.push_back(bit); - last = &that->chunks_.back(); - last_end_offset = bit.offset + 1; - } - - check(); -} - void RTLIL::SigSpec::unpack() const { - RTLIL::SigSpec *that = (RTLIL::SigSpec*)this; - - if (that->chunks_.empty()) + if (rep_ == BITS) return; + RTLIL::SigSpec *that = (RTLIL::SigSpec*)this; + cover("kernel.rtlil.sigspec.convert.unpack"); - log_assert(that->bits_.empty()); - that->bits_.reserve(that->size()); - for (auto &c : that->chunks_) - for (int i = 0; i < c.width; i++) - that->bits_.emplace_back(c, i); + std::vector bits; + bits.reserve(that->chunk_.width); + for (int i = 0; i < that->chunk_.width; i++) + bits.emplace_back(that->chunk_, i); - that->chunks_.clear(); + that->chunk_.~SigChunk(); + that->rep_ = BITS; + new (&that->bits_) std::vector(std::move(bits)); } void RTLIL::SigSpec::updhash() const @@ -4904,11 +4863,8 @@ void RTLIL::SigSpec::remove2(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *othe bits_[i].offset >= pattern_chunk.offset && bits_[i].offset < pattern_chunk.offset + pattern_chunk.width) { bits_.erase(bits_.begin() + i); - width_--; - if (other != NULL) { + if (other != NULL) other->bits_.erase(other->bits_.begin() + i); - other->width_--; - } break; } } @@ -4946,11 +4902,8 @@ void RTLIL::SigSpec::remove2(const pool &pattern, RTLIL::SigSpec for (int i = GetSize(bits_) - 1; i >= 0; i--) { if (bits_[i].wire != NULL && pattern.count(bits_[i])) { bits_.erase(bits_.begin() + i); - width_--; - if (other != NULL) { + if (other != NULL) other->bits_.erase(other->bits_.begin() + i); - other->width_--; - } } } hash_ = 0; @@ -4976,11 +4929,8 @@ void RTLIL::SigSpec::remove2(const std::set &pattern, RTLIL::SigS for (int i = GetSize(bits_) - 1; i >= 0; i--) { if (bits_[i].wire != NULL && pattern.count(bits_[i])) { bits_.erase(bits_.begin() + i); - width_--; - if (other != NULL) { + if (other != NULL) other->bits_.erase(other->bits_.begin() + i); - other->width_--; - } } } hash_ = 0; @@ -5006,11 +4956,8 @@ void RTLIL::SigSpec::remove2(const pool &pattern, RTLIL::SigSpec * for (int i = GetSize(bits_) - 1; i >= 0; i--) { if (bits_[i].wire != NULL && pattern.count(bits_[i].wire)) { bits_.erase(bits_.begin() + i); - width_--; - if (other != NULL) { + if (other != NULL) other->bits_.erase(other->bits_.begin() + i); - other->width_--; - } } } hash_ = 0; @@ -5108,41 +5055,27 @@ void RTLIL::SigSpec::replace(int offset, const RTLIL::SigSpec &with) void RTLIL::SigSpec::remove_const() { - if (packed()) + if (rep_ == CHUNK) { cover("kernel.rtlil.sigspec.remove_const.packed"); - std::vector new_chunks; - new_chunks.reserve(GetSize(chunks_)); - - width_ = 0; - for (auto &chunk : chunks_) - if (chunk.wire != NULL) { - if (!new_chunks.empty() && - new_chunks.back().wire == chunk.wire && - new_chunks.back().offset + new_chunks.back().width == chunk.offset) { - new_chunks.back().width += chunk.width; - } else { - new_chunks.push_back(chunk); - } - width_ += chunk.width; - } - - chunks_.swap(new_chunks); + if (chunk_.wire == NULL) { + chunk_.~SigChunk(); + init_empty_bits(); + } } else { cover("kernel.rtlil.sigspec.remove_const.unpacked"); std::vector new_bits; - new_bits.reserve(width_); + new_bits.reserve(bits_.size()); for (auto &bit : bits_) if (bit.wire != NULL) new_bits.push_back(bit); bits_.swap(new_bits); - width_ = bits_.size(); } hash_ = 0; @@ -5160,7 +5093,6 @@ void RTLIL::SigSpec::remove(int offset, int length) log_assert(offset + length <= size()); bits_.erase(bits_.begin() + offset, bits_.begin() + offset + length); - width_ = bits_.size(); hash_ = 0; check(); @@ -5199,10 +5131,21 @@ RTLIL::SigSpec RTLIL::SigSpec::extract(int offset, int length) const void RTLIL::SigSpec::rewrite_wires(std::function rewrite) { - pack(); - for (RTLIL::SigChunk &chunk : chunks_) - if (chunk.wire != nullptr) - rewrite(chunk.wire); + if (rep_ == CHUNK) { + if (chunk_.wire != nullptr) + rewrite(chunk_.wire); + return; + } + + std::vector new_bits; + for (const RTLIL::SigChunk &chunk : chunks()) { + RTLIL::SigChunk c = chunk; + if (c.wire != nullptr) + rewrite(c.wire); + for (int i = 0; i < c.width; i++) + new_bits.emplace_back(c, i); + } + bits_ = std::move(new_bits); hash_ = 0; } @@ -5218,60 +5161,54 @@ void RTLIL::SigSpec::append(const RTLIL::SigSpec &signal) cover("kernel.rtlil.sigspec.append"); - if (packed()) - for (auto &other_c : signal.chunks()) - { - auto &my_last_c = chunks_.back(); - if (my_last_c.wire == NULL && other_c.wire == NULL) { - auto &this_data = my_last_c.data; - auto &other_data = other_c.data; - this_data.insert(this_data.end(), other_data.begin(), other_data.end()); - my_last_c.width += other_c.width; - } else - if (my_last_c.wire == other_c.wire && my_last_c.offset + my_last_c.width == other_c.offset) { - my_last_c.width += other_c.width; - } else - chunks_.push_back(other_c); + hash_ = 0; + if (rep_ == CHUNK && signal.rep_ == CHUNK && chunk_.wire == signal.chunk_.wire) { + if (chunk_.wire == NULL) { + chunk_.data.insert(chunk_.data.end(), signal.chunk_.data.begin(), signal.chunk_.data.end()); + chunk_.width = GetSize(chunk_.data); + return; + } + if (chunk_.offset + chunk_.width == signal.chunk_.offset) { + chunk_.width += signal.chunk_.width; + return; } - else { - signal.unpack(); - bits_.insert(bits_.end(), signal.bits_.begin(), signal.bits_.end()); } - width_ += signal.size(); - hash_ = 0; + unpack(); + for (const SigBit &bit : signal.bits()) + bits_.push_back(bit); check(); } void RTLIL::SigSpec::append(const RTLIL::SigBit &bit) { - if (packed()) - { + hash_ = 0; + + if (size() == 0) { + destroy(); + rep_ = CHUNK; + new (&chunk_) RTLIL::SigChunk(bit); + return; + } + + if (rep_ == CHUNK && chunk_.wire == bit.wire) { cover("kernel.rtlil.sigspec.append_bit.packed"); - if (chunks_.size() == 0) - chunks_.push_back(bit); - else - if (bit.wire == NULL) - if (chunks_.back().wire == NULL) { - chunks_.back().data.push_back(bit.data); - chunks_.back().width++; - } else - chunks_.push_back(bit); - else - if (chunks_.back().wire == bit.wire && chunks_.back().offset + chunks_.back().width == bit.offset) - chunks_.back().width++; - else - chunks_.push_back(bit); - } - else - { - cover("kernel.rtlil.sigspec.append_bit.unpacked"); - bits_.push_back(bit); + if (chunk_.wire == NULL) { + chunk_.data.push_back(bit.data); + chunk_.width++; + return; + } + if (chunk_.offset + chunk_.width == bit.offset) { + chunk_.width++; + return; + } } - width_++; - hash_ = 0; + unpack(); + + cover("kernel.rtlil.sigspec.append_bit.unpacked"); + bits_.push_back(bit); check(); } @@ -5304,50 +5241,36 @@ RTLIL::SigSpec RTLIL::SigSpec::repeat(int num) const #ifndef NDEBUG void RTLIL::SigSpec::check(Module *mod) const { - if (size() > 64) - { - cover("kernel.rtlil.sigspec.check.skip"); - } - else if (packed()) + if (rep_ == CHUNK) { cover("kernel.rtlil.sigspec.check.packed"); - int w = 0; - for (size_t i = 0; i < chunks_.size(); i++) { - const RTLIL::SigChunk &chunk = chunks_[i]; - log_assert(chunk.width != 0); - if (chunk.wire == NULL) { - if (i > 0) - log_assert(chunks_[i-1].wire != NULL); - log_assert(chunk.offset == 0); - log_assert(chunk.data.size() == (size_t)chunk.width); - } else { - if (i > 0 && chunks_[i-1].wire == chunk.wire) - log_assert(chunk.offset != chunks_[i-1].offset + chunks_[i-1].width); - log_assert(chunk.offset >= 0); - log_assert(chunk.width >= 0); - log_assert(chunk.offset + chunk.width <= chunk.wire->width); - log_assert(chunk.data.size() == 0); - if (mod != nullptr) - log_assert(chunk.wire->module == mod); - } - w += chunk.width; + log_assert(chunk_.width != 0); + if (chunk_.wire == NULL) { + log_assert(chunk_.offset == 0); + log_assert(chunk_.data.size() == (size_t)chunk_.width); + } else { + log_assert(chunk_.offset >= 0); + log_assert(chunk_.width >= 0); + log_assert(chunk_.offset + chunk_.width <= chunk_.wire->width); + log_assert(chunk_.data.size() == 0); + if (mod != nullptr) + log_assert(chunk_.wire->module == mod); } - log_assert(w == size()); - log_assert(bits_.empty()); + } + else if (size() > 64) + { + cover("kernel.rtlil.sigspec.check.skip"); } else { cover("kernel.rtlil.sigspec.check.unpacked"); if (mod != nullptr) { - for (size_t i = 0; i < bits_.size(); i++) - if (bits_[i].wire != nullptr) - log_assert(bits_[i].wire->module == mod); + for (const RTLIL::SigBit &bit : bits_) + if (bit.wire != nullptr) + log_assert(bit.wire->module == mod); } - - log_assert(size() == GetSize(bits_)); - log_assert(chunks_.empty()); } } #endif @@ -5721,7 +5644,7 @@ std::map RTLIL::SigSpec::to_sigbit_map(const RTLIL log_assert(size() == other.size()); std::map new_map; - for (int i = 0; i < width_; i++) + for (int i = 0; i < GetSize(bits_); i++) new_map[bits_[i]] = other.bits_[i]; return new_map; @@ -5738,7 +5661,7 @@ dict RTLIL::SigSpec::to_sigbit_dict(const RTLIL::S dict new_map; new_map.reserve(size()); - for (int i = 0; i < width_; i++) + for (int i = 0; i < GetSize(bits_); i++) new_map[bits_[i]] = other.bits_[i]; return new_map; diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 02b23a69a..436b8b440 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1234,29 +1234,53 @@ struct RTLIL::SigSpecConstIterator struct RTLIL::SigSpec { private: - int width_; - Hasher::hash_t hash_; - std::vector chunks_; // LSB at index 0 - std::vector bits_; // LSB at index 0 + enum Representation : char { + CHUNK, + BITS, + }; - void pack() const; - void unpack() const; - void updhash() const; + Representation rep_; + Hasher::hash_t hash_ = 0; + union { + RTLIL::SigChunk chunk_; + std::vector bits_; // LSB at index 0 + }; - inline bool packed() const { - return bits_.empty(); + void init_empty_bits() { + rep_ = BITS; + new (&bits_) std::vector; } + void unpack() const; inline void inline_unpack() const { - if (!chunks_.empty()) + if (rep_ == CHUNK) unpack(); } + void updhash() const; + void destroy() { + if (rep_ == CHUNK) + chunk_.~SigChunk(); + else + bits_.~vector(); + } + friend struct Chunks; + public: - SigSpec() : width_(0), hash_(0) {} + SigSpec() { init_empty_bits(); } SigSpec(std::initializer_list parts); - SigSpec(const SigSpec &value) = default; - SigSpec(SigSpec &&value) = default; + SigSpec(const SigSpec &value) : rep_(value.rep_), hash_(value.hash_) { + if (value.rep_ == CHUNK) + new (&chunk_) RTLIL::SigChunk(value.chunk_); + else + new (&bits_) std::vector(value.bits_); + } + SigSpec(SigSpec &&value) : rep_(value.rep_), hash_(value.hash_) { + if (value.rep_ == CHUNK) + new (&chunk_) RTLIL::SigChunk(std::move(value.chunk_)); + else + new (&bits_) std::vector(std::move(value.bits_)); + } SigSpec(const RTLIL::Const &value); SigSpec(RTLIL::Const &&value); SigSpec(const RTLIL::SigChunk &chunk); @@ -1272,9 +1296,30 @@ public: SigSpec(const pool &bits); SigSpec(const std::set &bits); explicit SigSpec(bool bit); + ~SigSpec() { + destroy(); + } - SigSpec &operator=(const SigSpec &rhs) = default; - SigSpec &operator=(SigSpec &&rhs) = default; + SigSpec &operator=(const SigSpec &rhs) { + destroy(); + rep_ = rhs.rep_; + hash_ = rhs.hash_; + if (rep_ == CHUNK) + new (&chunk_) RTLIL::SigChunk(rhs.chunk_); + else + new (&bits_) std::vector(rhs.bits_); + return *this; + } + SigSpec &operator=(SigSpec &&rhs) { + destroy(); + rep_ = rhs.rep_; + hash_ = rhs.hash_; + if (rep_ == CHUNK) + new (&chunk_) RTLIL::SigChunk(std::move(rhs.chunk_)); + else + new (&bits_) std::vector(std::move(rhs.bits_)); + return *this; + } struct Chunks { Chunks(const SigSpec &spec) : spec(spec) {} @@ -1286,14 +1331,12 @@ public: using reference = const SigChunk &; const SigSpec &spec; - int chunk_index; int bit_index; SigChunk chunk; const_iterator(const SigSpec &spec) : spec(spec) { - chunk_index = 0; bit_index = 0; - if (!spec.packed()) + if (spec.rep_ == BITS) next_chunk_bits(); } enum End { END }; @@ -1303,15 +1346,14 @@ public: void next_chunk_bits(); const SigChunk &operator*() { - if (spec.packed()) - return spec.chunks_[chunk_index]; + if (spec.rep_ == CHUNK) + return spec.chunk_; return chunk; }; const SigChunk *operator->() { return &**this; } const_iterator &operator++() { bit_index += (**this).width; - ++chunk_index; - if (!spec.packed()) + if (spec.rep_ == BITS) next_chunk_bits(); return *this; } @@ -1366,7 +1408,7 @@ public: inline Chunks chunks() const { return {*this}; } inline const std::vector &bits() const { inline_unpack(); return bits_; } - inline int size() const { return width_; } + inline int size() const { return rep_ == CHUNK ? chunk_.width : GetSize(bits_); } inline bool empty() const { return size() == 0; } inline RTLIL::SigBit &operator[](int index) { inline_unpack(); hash_ = 0; return bits_.at(index); } From 745222fa3bf2ac570935ffd044c86fa2eb12d123 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Fri, 31 Oct 2025 10:06:13 +0000 Subject: [PATCH 84/97] Make SigSpec::unpack() non-const --- kernel/rtlil.cc | 108 ++++++++++++++++++++++-------------------------- kernel/rtlil.h | 29 +++++++++---- 2 files changed, 71 insertions(+), 66 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index eda732619..95db45e64 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -4675,23 +4675,21 @@ void RTLIL::SigSpec::Chunks::const_iterator::next_chunk_bits() chunk.width = i - bit_index; } -void RTLIL::SigSpec::unpack() const +void RTLIL::SigSpec::unpack() { if (rep_ == BITS) return; - RTLIL::SigSpec *that = (RTLIL::SigSpec*)this; - cover("kernel.rtlil.sigspec.convert.unpack"); std::vector bits; - bits.reserve(that->chunk_.width); - for (int i = 0; i < that->chunk_.width; i++) - bits.emplace_back(that->chunk_, i); + bits.reserve(chunk_.width); + for (int i = 0; i < chunk_.width; i++) + bits.emplace_back(chunk_, i); - that->chunk_.~SigChunk(); - that->rep_ = BITS; - new (&that->bits_) std::vector(std::move(bits)); + chunk_.~SigChunk(); + rep_ = BITS; + new (&bits_) std::vector(std::move(bits)); } void RTLIL::SigSpec::updhash() const @@ -4754,25 +4752,22 @@ void RTLIL::SigSpec::replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec log_assert(size() == other->size()); log_assert(pattern.size() == with.size()); - pattern.unpack(); - with.unpack(); - unpack(); - other->unpack(); - dict pattern_to_with; - for (int i = 0; i < GetSize(pattern.bits_); i++) { - if (pattern.bits_[i].wire != NULL) { - pattern_to_with.emplace(pattern.bits_[i], i); + int pattern_size = pattern.size(); + for (int i = 0; i < pattern_size; i++) { + SigBit pattern_bit = pattern[i]; + if (pattern_bit.wire != NULL) { + pattern_to_with.emplace(pattern_bit, i); } } - for (int j = 0; j < GetSize(bits_); j++) { - auto it = pattern_to_with.find(bits_[j]); + int this_size = size(); + for (int j = 0; j < this_size; j++) { + auto it = pattern_to_with.find((*this)[j]); if (it != pattern_to_with.end()) { - other->bits_[j] = with.bits_[it->second]; + (*other)[j] = with[it->second]; } } - other->hash_ = 0; other->check(); } @@ -4790,15 +4785,13 @@ void RTLIL::SigSpec::replace(const dict &rules, RT log_assert(size() == other->size()); if (rules.empty()) return; - unpack(); - other->unpack(); - for (int i = 0; i < GetSize(bits_); i++) { - auto it = rules.find(bits_[i]); + int this_size = size(); + for (int i = 0; i < this_size; i++) { + auto it = rules.find((*this)[i]); if (it != rules.end()) - other->bits_[i] = it->second; + (*other)[i] = it->second; } - other->hash_ = 0; other->check(); } @@ -4816,15 +4809,13 @@ void RTLIL::SigSpec::replace(const std::map &rules log_assert(size() == other->size()); if (rules.empty()) return; - unpack(); - other->unpack(); - for (int i = 0; i < GetSize(bits_); i++) { - auto it = rules.find(bits_[i]); + int this_size = size(); + for (int i = 0; i < this_size; i++) { + auto it = rules.find((*this)[i]); if (it != rules.end()) - other->bits_[i] = it->second; + (*other)[i] = it->second; } - other->hash_ = 0; other->check(); } @@ -5578,23 +5569,25 @@ bool RTLIL::SigSpec::match(const char* pattern) const { cover("kernel.rtlil.sigspec.match"); - unpack(); - log_assert(int(strlen(pattern)) == GetSize(bits_)); + int pattern_len = strlen(pattern); + log_assert(pattern_len == size()); - for (auto it = bits_.rbegin(); it != bits_.rend(); it++, pattern++) { - if (*pattern == ' ') + for (int i = 0; i < pattern_len; ++i) { + char ch = pattern[i]; + if (ch == ' ') continue; - if (*pattern == '*') { - if (*it != State::Sz && *it != State::Sx) + RTLIL::SigBit bit = (*this)[pattern_len - 1 - i]; + if (ch == '*') { + if (bit != State::Sz && bit != State::Sx) return false; continue; } - if (*pattern == '0') { - if (*it != State::S0) + if (ch == '0') { + if (bit != State::S0) return false; } else - if (*pattern == '1') { - if (*it != State::S1) + if (ch == '1') { + if (bit != State::S1) return false; } else log_abort(); @@ -5630,22 +5623,23 @@ std::vector RTLIL::SigSpec::to_sigbit_vector() const { cover("kernel.rtlil.sigspec.to_sigbit_vector"); - unpack(); - return bits_; + std::vector result; + result.reserve(size()); + for (SigBit bit : *this) + result.push_back(bit); + return result; } std::map RTLIL::SigSpec::to_sigbit_map(const RTLIL::SigSpec &other) const { cover("kernel.rtlil.sigspec.to_sigbit_map"); - unpack(); - other.unpack(); - - log_assert(size() == other.size()); + int this_size = size(); + log_assert(this_size == other.size()); std::map new_map; - for (int i = 0; i < GetSize(bits_); i++) - new_map[bits_[i]] = other.bits_[i]; + for (int i = 0; i < this_size; i++) + new_map[(*this)[i]] = other[i]; return new_map; } @@ -5654,15 +5648,13 @@ dict RTLIL::SigSpec::to_sigbit_dict(const RTLIL::S { cover("kernel.rtlil.sigspec.to_sigbit_dict"); - unpack(); - other.unpack(); - - log_assert(size() == other.size()); + int this_size = size(); + log_assert(this_size == other.size()); dict new_map; - new_map.reserve(size()); - for (int i = 0; i < GetSize(bits_); i++) - new_map[bits_[i]] = other.bits_[i]; + new_map.reserve(this_size); + for (int i = 0; i < this_size; i++) + new_map[(*this)[i]] = other[i]; return new_map; } diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 436b8b440..fb184fe50 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1223,9 +1223,10 @@ struct RTLIL::SigSpecConstIterator typedef RTLIL::SigBit& reference; const RTLIL::SigSpec *sig_p; + RTLIL::SigBit bit; int index; - inline const RTLIL::SigBit &operator*() const; + inline const RTLIL::SigBit &operator*(); inline bool operator!=(const RTLIL::SigSpecConstIterator &other) const { return index != other.index; } inline bool operator==(const RTLIL::SigSpecIterator &other) const { return index == other.index; } inline void operator++() { index++; } @@ -1251,8 +1252,8 @@ private: new (&bits_) std::vector; } - void unpack() const; - inline void inline_unpack() const { + void unpack(); + inline void inline_unpack() { if (rep_ == CHUNK) unpack(); } @@ -1406,13 +1407,22 @@ public: friend struct Chunks::const_iterator; inline Chunks chunks() const { return {*this}; } - inline const std::vector &bits() const { inline_unpack(); return bits_; } + inline const SigSpec &bits() const { return *this; } inline int size() const { return rep_ == CHUNK ? chunk_.width : GetSize(bits_); } inline bool empty() const { return size() == 0; } inline RTLIL::SigBit &operator[](int index) { inline_unpack(); hash_ = 0; return bits_.at(index); } - inline const RTLIL::SigBit &operator[](int index) const { inline_unpack(); return bits_.at(index); } + inline RTLIL::SigBit operator[](int index) const { + if (rep_ == CHUNK) { + if (index < 0 || index >= chunk_.width) + throw std::out_of_range("SigSpec::operator[]"); + if (chunk_.wire) + return RTLIL::SigBit(chunk_.wire, chunk_.offset + index); + return RTLIL::SigBit(chunk_.data[index]); + } + return bits_.at(index); + } inline RTLIL::SigSpecIterator begin() { RTLIL::SigSpecIterator it; it.sig_p = this; it.index = 0; return it; } inline RTLIL::SigSpecIterator end() { RTLIL::SigSpecIterator it; it.sig_p = this; it.index = size(); return it; } @@ -1456,6 +1466,8 @@ public: RTLIL::SigBit lsb() const { log_assert(size()); return (*this)[0]; }; RTLIL::SigBit msb() const { log_assert(size()); return (*this)[size() - 1]; }; + RTLIL::SigBit front() const { return (*this)[0]; } + RTLIL::SigBit back() const { return (*this)[size() - 1]; } void append(const RTLIL::SigSpec &signal); inline void append(Wire *wire) { append(RTLIL::SigSpec(wire)); } @@ -1536,7 +1548,7 @@ public: static bool parse_rhs(const RTLIL::SigSpec &lhs, RTLIL::SigSpec &sig, RTLIL::Module *module, std::string str); operator std::vector() const; - operator std::vector() const { return bits(); } + operator std::vector() const { return to_sigbit_vector(); } const RTLIL::SigBit &at(int offset, const RTLIL::SigBit &defval) { return offset < size() ? (*this)[offset] : defval; } [[nodiscard]] Hasher hash_into(Hasher h) const { if (!hash_) updhash(); h.eat(hash_); return h; } @@ -2444,8 +2456,9 @@ inline RTLIL::SigBit &RTLIL::SigSpecIterator::operator*() const { return (*sig_p)[index]; } -inline const RTLIL::SigBit &RTLIL::SigSpecConstIterator::operator*() const { - return (*sig_p)[index]; +inline const RTLIL::SigBit &RTLIL::SigSpecConstIterator::operator*() { + bit = (*sig_p)[index]; + return bit; } inline RTLIL::SigBit::SigBit(const RTLIL::SigSpec &sig) { From 38d1d071a5db00e9cc60953fa3c1b00f2e8b29ee Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Fri, 31 Oct 2025 10:48:39 +0000 Subject: [PATCH 85/97] Implement SigSpec::updhash() using a relaxed atomic for thread-safety --- kernel/rtlil.cc | 49 +++++++++++++++++++++++-------------------------- kernel/rtlil.h | 48 +++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 66 insertions(+), 31 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 95db45e64..46ed8287c 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -4692,17 +4692,12 @@ void RTLIL::SigSpec::unpack() new (&bits_) std::vector(std::move(bits)); } -void RTLIL::SigSpec::updhash() const +Hasher::hash_t RTLIL::SigSpec::updhash() const { - RTLIL::SigSpec *that = (RTLIL::SigSpec*)this; - - if (that->hash_ != 0) - return; - cover("kernel.rtlil.sigspec.hash"); Hasher h; - for (auto &c : that->chunks()) + for (auto &c : chunks()) if (c.wire == NULL) { for (auto &v : c.data) h.eat(v); @@ -4711,9 +4706,11 @@ void RTLIL::SigSpec::updhash() const h.eat(c.offset); h.eat(c.width); } - that->hash_ = h.yield(); - if (that->hash_ == 0) - that->hash_ = 1; + Hasher::hash_t result = h.yield(); + if (result == 0) + result = 1; + hash_.set(result); + return result; } void RTLIL::SigSpec::sort() @@ -4721,7 +4718,7 @@ void RTLIL::SigSpec::sort() unpack(); cover("kernel.rtlil.sigspec.sort"); std::sort(bits_.begin(), bits_.end()); - hash_ = 0; + hash_.clear(); } void RTLIL::SigSpec::sort_and_unify() @@ -4738,7 +4735,7 @@ void RTLIL::SigSpec::sort_and_unify() unique_bits.erase(last, unique_bits.end()); *this = unique_bits; - hash_ = 0; + hash_.clear(); } void RTLIL::SigSpec::replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with) @@ -4842,7 +4839,7 @@ void RTLIL::SigSpec::remove2(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *othe if (other != NULL) { log_assert(size() == other->size()); other->unpack(); - other->hash_ = 0; + other->hash_.clear(); } for (int i = GetSize(bits_) - 1; i >= 0; i--) @@ -4859,7 +4856,7 @@ void RTLIL::SigSpec::remove2(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *othe break; } } - hash_ = 0; + hash_.clear(); check(); } @@ -4887,7 +4884,7 @@ void RTLIL::SigSpec::remove2(const pool &pattern, RTLIL::SigSpec if (other != NULL) { log_assert(size() == other->size()); other->unpack(); - other->hash_ = 0; + other->hash_.clear(); } for (int i = GetSize(bits_) - 1; i >= 0; i--) { @@ -4897,7 +4894,7 @@ void RTLIL::SigSpec::remove2(const pool &pattern, RTLIL::SigSpec other->bits_.erase(other->bits_.begin() + i); } } - hash_ = 0; + hash_.clear(); check(); } @@ -4914,7 +4911,7 @@ void RTLIL::SigSpec::remove2(const std::set &pattern, RTLIL::SigS if (other != NULL) { log_assert(size() == other->size()); other->unpack(); - other->hash_ = 0; + other->hash_.clear(); } for (int i = GetSize(bits_) - 1; i >= 0; i--) { @@ -4924,7 +4921,7 @@ void RTLIL::SigSpec::remove2(const std::set &pattern, RTLIL::SigS other->bits_.erase(other->bits_.begin() + i); } } - hash_ = 0; + hash_.clear(); check(); } @@ -4941,7 +4938,7 @@ void RTLIL::SigSpec::remove2(const pool &pattern, RTLIL::SigSpec * if (other != NULL) { log_assert(size() == other->size()); other->unpack(); - other->hash_ = 0; + other->hash_.clear(); } for (int i = GetSize(bits_) - 1; i >= 0; i--) { @@ -4951,7 +4948,7 @@ void RTLIL::SigSpec::remove2(const pool &pattern, RTLIL::SigSpec * other->bits_.erase(other->bits_.begin() + i); } } - hash_ = 0; + hash_.clear(); check(); } @@ -5039,7 +5036,7 @@ void RTLIL::SigSpec::replace(int offset, const RTLIL::SigSpec &with) bits_.at(offset + i) = bit; ++i; } - hash_ = 0; + hash_.clear(); check(); } @@ -5069,7 +5066,7 @@ void RTLIL::SigSpec::remove_const() bits_.swap(new_bits); } - hash_ = 0; + hash_.clear(); check(); } @@ -5085,7 +5082,7 @@ void RTLIL::SigSpec::remove(int offset, int length) bits_.erase(bits_.begin() + offset, bits_.begin() + offset + length); - hash_ = 0; + hash_.clear(); check(); } @@ -5137,7 +5134,7 @@ void RTLIL::SigSpec::rewrite_wires(std::function rewri new_bits.emplace_back(c, i); } bits_ = std::move(new_bits); - hash_ = 0; + hash_.clear(); } void RTLIL::SigSpec::append(const RTLIL::SigSpec &signal) @@ -5152,7 +5149,7 @@ void RTLIL::SigSpec::append(const RTLIL::SigSpec &signal) cover("kernel.rtlil.sigspec.append"); - hash_ = 0; + hash_.clear(); if (rep_ == CHUNK && signal.rep_ == CHUNK && chunk_.wire == signal.chunk_.wire) { if (chunk_.wire == NULL) { chunk_.data.insert(chunk_.data.end(), signal.chunk_.data.begin(), signal.chunk_.data.end()); @@ -5173,7 +5170,7 @@ void RTLIL::SigSpec::append(const RTLIL::SigSpec &signal) void RTLIL::SigSpec::append(const RTLIL::SigBit &bit) { - hash_ = 0; + hash_.clear(); if (size() == 0) { destroy(); diff --git a/kernel/rtlil.h b/kernel/rtlil.h index fb184fe50..c11e603fb 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1239,9 +1239,39 @@ private: CHUNK, BITS, }; + // An AtomicHash is either clear or a nonzero integer. + struct AtomicHash { + // Create an initially clear value. + AtomicHash() : atomic_(0) {} + AtomicHash(const AtomicHash &rhs) : atomic_(rhs.load()) {} + AtomicHash &operator=(const AtomicHash &rhs) { store(rhs.load()); return *this; } + // Read the hash. Returns nullopt if the hash is clear. + std::optional read() const { + Hasher::hash_t value = load(); + if (value == 0) + return std::nullopt; + return value; + } + // Set the hash. If the value is already set, then the new value must + // equal the current value. + void set(Hasher::hash_t value) const { + log_assert(value != 0); + Hasher::hash_t old = const_cast&>(atomic_) + .exchange(value, std::memory_order_relaxed); + log_assert(old == 0 || old == value); + } + void clear() { store(0); } + private: + int load() const { return atomic_.load(std::memory_order_relaxed); } + void store(Hasher::hash_t value) const { + const_cast&>(atomic_).store(value, std::memory_order_relaxed); + } + + std::atomic atomic_; + }; Representation rep_; - Hasher::hash_t hash_ = 0; + AtomicHash hash_; union { RTLIL::SigChunk chunk_; std::vector bits_; // LSB at index 0 @@ -1258,7 +1288,7 @@ private: unpack(); } - void updhash() const; + Hasher::hash_t updhash() const; void destroy() { if (rep_ == CHUNK) chunk_.~SigChunk(); @@ -1410,9 +1440,9 @@ public: inline const SigSpec &bits() const { return *this; } inline int size() const { return rep_ == CHUNK ? chunk_.width : GetSize(bits_); } - inline bool empty() const { return size() == 0; } + inline bool empty() const { return size() == 0; }; - inline RTLIL::SigBit &operator[](int index) { inline_unpack(); hash_ = 0; return bits_.at(index); } + inline RTLIL::SigBit &operator[](int index) { inline_unpack(); hash_.clear(); return bits_.at(index); } inline RTLIL::SigBit operator[](int index) const { if (rep_ == CHUNK) { if (index < 0 || index >= chunk_.width) @@ -1551,7 +1581,15 @@ public: operator std::vector() const { return to_sigbit_vector(); } const RTLIL::SigBit &at(int offset, const RTLIL::SigBit &defval) { return offset < size() ? (*this)[offset] : defval; } - [[nodiscard]] Hasher hash_into(Hasher h) const { if (!hash_) updhash(); h.eat(hash_); return h; } + [[nodiscard]] Hasher hash_into(Hasher h) const { + Hasher::hash_t val; + if (std::optional current = hash_.read()) + val = *current; + else + val = updhash(); + h.eat(val); + return h; + } #ifndef NDEBUG void check(Module *mod = nullptr) const; From 1cf3497d15070ce49bbc6258d1bee5d47b72ab81 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Fri, 7 Nov 2025 15:50:57 +0000 Subject: [PATCH 86/97] Repack SigSpecs when possible --- kernel/rtlil.cc | 139 +++++++++++++++++++++++++++++++++++++++++------- kernel/rtlil.h | 1 + 2 files changed, 122 insertions(+), 18 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 46ed8287c..a58487216 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -4692,6 +4692,39 @@ void RTLIL::SigSpec::unpack() new (&bits_) std::vector(std::move(bits)); } +void RTLIL::SigSpec::try_repack() +{ + if (rep_ != BITS) + return; + + cover("kernel.rtlil.sigspec.convert.try_repack"); + + int bits_size = GetSize(bits_); + if (bits_size == 0) + return; + if (bits_[0].is_wire()) { + for (int i = 1; i < bits_size; i++) + if (bits_[0].wire != bits_[i].wire || bits_[0].offset + i != bits_[i].offset) + return; + SigChunk chunk(bits_[0].wire, bits_[0].offset, bits_size); + bits_.~vector(); + rep_ = CHUNK; + new (&chunk_) SigChunk(std::move(chunk)); + return; + } + std::vector bits; + bits.reserve(bits_size); + bits.push_back(bits_[0].data); + for (int i = 1; i < bits_size; i++) { + if (bits_[i].is_wire()) + return; + bits.push_back(bits_[i].data); + } + bits_.~vector(); + rep_ = CHUNK; + new (&chunk_) SigChunk(std::move(bits)); +} + Hasher::hash_t RTLIL::SigSpec::updhash() const { cover("kernel.rtlil.sigspec.hash"); @@ -4719,6 +4752,7 @@ void RTLIL::SigSpec::sort() cover("kernel.rtlil.sigspec.sort"); std::sort(bits_.begin(), bits_.end()); hash_.clear(); + try_repack(); } void RTLIL::SigSpec::sort_and_unify() @@ -4736,6 +4770,7 @@ void RTLIL::SigSpec::sort_and_unify() *this = unique_bits; hash_.clear(); + try_repack(); } void RTLIL::SigSpec::replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec &with) @@ -4759,13 +4794,17 @@ void RTLIL::SigSpec::replace(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec } int this_size = size(); + bool other_modified = false; for (int j = 0; j < this_size; j++) { auto it = pattern_to_with.find((*this)[j]); if (it != pattern_to_with.end()) { + other_modified = true; (*other)[j] = with[it->second]; } } + if (other_modified) + other->try_repack(); other->check(); } @@ -4784,12 +4823,17 @@ void RTLIL::SigSpec::replace(const dict &rules, RT if (rules.empty()) return; int this_size = size(); + bool other_modified = false; for (int i = 0; i < this_size; i++) { auto it = rules.find((*this)[i]); - if (it != rules.end()) + if (it != rules.end()) { + other_modified = true; (*other)[i] = it->second; + } } + if (other_modified) + other->try_repack(); other->check(); } @@ -4808,12 +4852,17 @@ void RTLIL::SigSpec::replace(const std::map &rules if (rules.empty()) return; int this_size = size(); + bool other_modified = false; for (int i = 0; i < this_size; i++) { auto it = rules.find((*this)[i]); - if (it != rules.end()) + if (it != rules.end()) { + other_modified = true; (*other)[i] = it->second; + } } + if (other_modified) + other->try_repack(); other->check(); } @@ -4839,9 +4888,10 @@ void RTLIL::SigSpec::remove2(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *othe if (other != NULL) { log_assert(size() == other->size()); other->unpack(); - other->hash_.clear(); } + bool modified = false; + bool other_modified = false; for (int i = GetSize(bits_) - 1; i >= 0; i--) { if (bits_[i].wire == NULL) continue; @@ -4850,14 +4900,24 @@ void RTLIL::SigSpec::remove2(const RTLIL::SigSpec &pattern, RTLIL::SigSpec *othe if (bits_[i].wire == pattern_chunk.wire && bits_[i].offset >= pattern_chunk.offset && bits_[i].offset < pattern_chunk.offset + pattern_chunk.width) { + modified = true; bits_.erase(bits_.begin() + i); - if (other != NULL) + if (other != NULL) { + other_modified = true; other->bits_.erase(other->bits_.begin() + i); + } break; } } - hash_.clear(); + if (modified) { + hash_.clear(); + try_repack(); + } + if (other_modified) { + other->hash_.clear(); + other->try_repack(); + } check(); } @@ -4884,18 +4944,29 @@ void RTLIL::SigSpec::remove2(const pool &pattern, RTLIL::SigSpec if (other != NULL) { log_assert(size() == other->size()); other->unpack(); - other->hash_.clear(); } + bool modified = false; + bool other_modified = false; for (int i = GetSize(bits_) - 1; i >= 0; i--) { if (bits_[i].wire != NULL && pattern.count(bits_[i])) { + modified = true; bits_.erase(bits_.begin() + i); - if (other != NULL) + if (other != NULL) { + other_modified = true; other->bits_.erase(other->bits_.begin() + i); + } } } - hash_.clear(); + if (modified) { + hash_.clear(); + try_repack(); + } + if (other_modified) { + other->hash_.clear(); + other->try_repack(); + } check(); } @@ -4911,18 +4982,29 @@ void RTLIL::SigSpec::remove2(const std::set &pattern, RTLIL::SigS if (other != NULL) { log_assert(size() == other->size()); other->unpack(); - other->hash_.clear(); } + bool modified = false; + bool other_modified = false; for (int i = GetSize(bits_) - 1; i >= 0; i--) { if (bits_[i].wire != NULL && pattern.count(bits_[i])) { + modified = true; bits_.erase(bits_.begin() + i); - if (other != NULL) + if (other != NULL) { + other_modified = true; other->bits_.erase(other->bits_.begin() + i); + } } } - hash_.clear(); + if (modified) { + hash_.clear(); + try_repack(); + } + if (other_modified) { + other->hash_.clear(); + other->try_repack(); + } check(); } @@ -4938,18 +5020,29 @@ void RTLIL::SigSpec::remove2(const pool &pattern, RTLIL::SigSpec * if (other != NULL) { log_assert(size() == other->size()); other->unpack(); - other->hash_.clear(); } + bool modified = false; + bool other_modified = false; for (int i = GetSize(bits_) - 1; i >= 0; i--) { if (bits_[i].wire != NULL && pattern.count(bits_[i].wire)) { + modified = true; bits_.erase(bits_.begin() + i); - if (other != NULL) + if (other != NULL) { + other_modified = true; other->bits_.erase(other->bits_.begin() + i); + } } } - hash_.clear(); + if (modified) { + hash_.clear(); + try_repack(); + } + if (other_modified) { + other->hash_.clear(); + other->try_repack(); + } check(); } @@ -5025,6 +5118,9 @@ void RTLIL::SigSpec::replace(int offset, const RTLIL::SigSpec &with) { cover("kernel.rtlil.sigspec.replace_pos"); + if (with.size() == 0) + return; + unpack(); log_assert(offset >= 0); @@ -5037,6 +5133,7 @@ void RTLIL::SigSpec::replace(int offset, const RTLIL::SigSpec &with) ++i; } hash_.clear(); + try_repack(); check(); } @@ -5050,6 +5147,7 @@ void RTLIL::SigSpec::remove_const() if (chunk_.wire == NULL) { chunk_.~SigChunk(); init_empty_bits(); + hash_.clear(); } } else @@ -5058,15 +5156,16 @@ void RTLIL::SigSpec::remove_const() std::vector new_bits; new_bits.reserve(bits_.size()); - for (auto &bit : bits_) if (bit.wire != NULL) new_bits.push_back(bit); - - bits_.swap(new_bits); + if (GetSize(new_bits) != GetSize(bits_)) { + bits_.swap(new_bits); + hash_.clear(); + try_repack(); + } } - hash_.clear(); check(); } @@ -5074,6 +5173,9 @@ void RTLIL::SigSpec::remove(int offset, int length) { cover("kernel.rtlil.sigspec.remove_pos"); + if (length == 0) + return; + unpack(); log_assert(offset >= 0); @@ -5083,6 +5185,7 @@ void RTLIL::SigSpec::remove(int offset, int length) bits_.erase(bits_.begin() + offset, bits_.begin() + offset + length); hash_.clear(); + try_repack(); check(); } diff --git a/kernel/rtlil.h b/kernel/rtlil.h index c11e603fb..98230ab1f 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1287,6 +1287,7 @@ private: if (rep_ == CHUNK) unpack(); } + void try_repack(); Hasher::hash_t updhash() const; void destroy() { From 224109151da988618ede22c284a218e9bb3f3c06 Mon Sep 17 00:00:00 2001 From: Rahul Bhagwat Date: Sat, 8 Nov 2025 23:05:10 +0530 Subject: [PATCH 87/97] add specific package imports and tests --- frontends/ast/simplify.cc | 25 +++++++++++++- frontends/verilog/verilog_parser.y | 33 ++++++++++++++++++- tests/verilog/package_import_specific.sv | 14 ++++++++ tests/verilog/package_import_specific.ys | 5 +++ .../verilog/package_import_specific_module.sv | 16 +++++++++ 5 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 tests/verilog/package_import_specific.sv create mode 100644 tests/verilog/package_import_specific.ys create mode 100644 tests/verilog/package_import_specific_module.sv diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 97abf7452..010f4e14f 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1123,16 +1123,39 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin } if (package_node) { - // Import all names from the package into current scope + bool is_wildcard = child->children.empty(); + std::set import_items; + + // For specific imports, collect the list of items to import + if (!is_wildcard) { + for (auto& import_item : child->children) { + import_items.insert(import_item->str); + } + } + + // Import names from the package into current scope for (auto& pkg_child : package_node->children) { + // Check if this is a specific import and if this item should be imported + if (!is_wildcard && import_items.count(pkg_child->str) == 0) + continue; + if (pkg_child->type == AST_PARAMETER || pkg_child->type == AST_LOCALPARAM || pkg_child->type == AST_TYPEDEF || pkg_child->type == AST_FUNCTION || pkg_child->type == AST_TASK || pkg_child->type == AST_ENUM) { + // For wildcard imports, check if item already exists (from specific import) + if (is_wildcard && current_scope.count(pkg_child->str) > 0) + continue; current_scope[pkg_child->str] = pkg_child.get(); } if (pkg_child->type == AST_ENUM) { for (auto& enode : pkg_child->children) { log_assert(enode->type==AST_ENUM_ITEM); + // Check if this enum item should be imported + if (!is_wildcard && import_items.count(enode->str) == 0) + continue; + // For wildcard imports, check if item already exists (from specific import) + if (is_wildcard && current_scope.count(enode->str) > 0) + continue; if (current_scope.count(enode->str) == 0) current_scope[enode->str] = enode.get(); else diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index ef8427679..e6c7f3672 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -428,6 +428,7 @@ #include #include #include + #include #include "frontends/verilog/verilog_frontend.h" struct specify_target { @@ -462,6 +463,7 @@ using string_t = std::unique_ptr; using ast_t = std::unique_ptr; + using ast_list_t = std::vector; using al_t = std::unique_ptr>>; using specify_target_ptr_t = std::unique_ptr; using specify_triple_ptr_t = std::unique_ptr; @@ -557,6 +559,8 @@ %type struct_union %type asgn_binop inc_or_dec_op %type genvar_identifier +%type import_item_list +%type import_item %type specify_target %type specify_triple specify_opt_triple @@ -830,10 +834,37 @@ package_body_stmt: import_stmt: TOK_IMPORT hierarchical_id TOK_PACKAGESEP TOK_ASTER TOK_SEMICOL { - // Create an import node to track package imports + // Create an import node to track specific and wildcard package imports auto import_node = std::make_unique(@$, AST_IMPORT); import_node->str = *$2; extra->ast_stack.back()->children.push_back(std::move(import_node)); + } | + TOK_IMPORT hierarchical_id TOK_PACKAGESEP import_item_list TOK_SEMICOL { + // Create an import node to track specific package imports + auto import_node = std::make_unique(@$, AST_IMPORT); + import_node->str = *$2; + // Move children from import_item_list to import_node + import_node->children = std::move($4); + extra->ast_stack.back()->children.push_back(std::move(import_node)); + }; + +import_item_list: + import_item { + ast_list_t list; + list.push_back(std::move($1)); + $$ = std::move(list); + } | + import_item_list TOK_COMMA import_item { + $1.push_back(std::move($3)); + $$ = std::move($1); + }; + +import_item: + TOK_ID { + // Create a simple node to store the imported item name + auto item_node = std::make_unique(@$, AST_NONE); + item_node->str = *$1; + $$ = std::move(item_node); }; interface: diff --git a/tests/verilog/package_import_specific.sv b/tests/verilog/package_import_specific.sv new file mode 100644 index 000000000..97004ed56 --- /dev/null +++ b/tests/verilog/package_import_specific.sv @@ -0,0 +1,14 @@ +package package_import_specific; + + localparam integer + DATA_WIDTH = 8, + ADDR_WIDTH = 4; + + localparam logic [2:0] + IDLE = 3'b000, + START = 3'b001, + DATA = 3'b010, + STOP = 3'b100, + DONE = 3'b101; + +endpackage diff --git a/tests/verilog/package_import_specific.ys b/tests/verilog/package_import_specific.ys new file mode 100644 index 000000000..8b183aac4 --- /dev/null +++ b/tests/verilog/package_import_specific.ys @@ -0,0 +1,5 @@ +read_verilog -sv package_import_specific.sv +read_verilog -sv package_import_specific_module.sv +hierarchy -check +proc +opt -full diff --git a/tests/verilog/package_import_specific_module.sv b/tests/verilog/package_import_specific_module.sv new file mode 100644 index 000000000..a568af4d2 --- /dev/null +++ b/tests/verilog/package_import_specific_module.sv @@ -0,0 +1,16 @@ +import package_import_specific::DATA_WIDTH; +import package_import_specific::IDLE; + +module package_import_specific_module; + logic [DATA_WIDTH-1:0] data; + logic [3:0] addr; + logic [2:0] state; + + always_comb begin + case (state) + IDLE: data = 8'h00; + default: data = 8'hFF; + endcase + end + +endmodule From 54e5eb1c3c7dea139401e811564bbf2e9ca91f60 Mon Sep 17 00:00:00 2001 From: Rahul Bhagwat Date: Sat, 8 Nov 2025 23:16:52 +0530 Subject: [PATCH 88/97] no use vector --- frontends/verilog/verilog_parser.y | 35 ++++++++++-------------------- 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index e6c7f3672..684727d5b 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -428,7 +428,6 @@ #include #include #include - #include #include "frontends/verilog/verilog_frontend.h" struct specify_target { @@ -463,7 +462,6 @@ using string_t = std::unique_ptr; using ast_t = std::unique_ptr; - using ast_list_t = std::vector; using al_t = std::unique_ptr>>; using specify_target_ptr_t = std::unique_ptr; using specify_triple_ptr_t = std::unique_ptr; @@ -559,8 +557,6 @@ %type struct_union %type asgn_binop inc_or_dec_op %type genvar_identifier -%type import_item_list -%type import_item %type specify_target %type specify_triple specify_opt_triple @@ -833,38 +829,31 @@ package_body_stmt: typedef_decl | localparam_decl | param_decl | task_func_decl; import_stmt: - TOK_IMPORT hierarchical_id TOK_PACKAGESEP TOK_ASTER TOK_SEMICOL { - // Create an import node to track specific and wildcard package imports + TOK_IMPORT TOK_ID TOK_PACKAGESEP TOK_ASTER TOK_SEMICOL { + // Create an import node to track wildcard package imports auto import_node = std::make_unique(@$, AST_IMPORT); import_node->str = *$2; extra->ast_stack.back()->children.push_back(std::move(import_node)); } | - TOK_IMPORT hierarchical_id TOK_PACKAGESEP import_item_list TOK_SEMICOL { - // Create an import node to track specific package imports - auto import_node = std::make_unique(@$, AST_IMPORT); + TOK_IMPORT TOK_ID TOK_PACKAGESEP { + // Start a specific import: create and push the AST_IMPORT node + AstNode* import_node = extra->pushChild(std::make_unique(@$, AST_IMPORT)); import_node->str = *$2; - // Move children from import_item_list to import_node - import_node->children = std::move($4); - extra->ast_stack.back()->children.push_back(std::move(import_node)); + } import_item_list TOK_SEMICOL { + // Done collecting specific items, pop the AST_IMPORT node + extra->ast_stack.pop_back(); }; import_item_list: - import_item { - ast_list_t list; - list.push_back(std::move($1)); - $$ = std::move(list); - } | - import_item_list TOK_COMMA import_item { - $1.push_back(std::move($3)); - $$ = std::move($1); - }; + import_item | + import_item_list TOK_COMMA import_item ; import_item: TOK_ID { - // Create a simple node to store the imported item name + // Append this specific import name under the current AST_IMPORT auto item_node = std::make_unique(@$, AST_NONE); item_node->str = *$1; - $$ = std::move(item_node); + extra->ast_stack.back()->children.push_back(std::move(item_node)); }; interface: From 0452955069e051d5916f0d1ab04bd0ca43f75697 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Mon, 10 Nov 2025 12:02:21 +0100 Subject: [PATCH 89/97] rtlil: add explanatory note to SigSpec::Chunks --- kernel/rtlil.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 98230ab1f..f81cba38c 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1353,6 +1353,9 @@ public: return *this; } + // SigSpec::Chunks holds one reconstructed chunk at a time + // to provide the SigSpec::chunks() read-only chunks view + // since vector SigSpec::chunks_ has been removed struct Chunks { Chunks(const SigSpec &spec) : spec(spec) {} struct const_iterator { From ee5b8a97b9b6cbd0c22ee5555091b0094092d450 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Mon, 10 Nov 2025 12:02:36 +0100 Subject: [PATCH 90/97] rtlil: avoid clang warning --- kernel/rtlil.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/kernel/rtlil.h b/kernel/rtlil.h index f81cba38c..79cc73e45 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1415,10 +1415,7 @@ public: return chunk_vector.size(); } int size() const { - int result = 0; - for (const SigChunk &_: *this) - ++result; - return result; + return std::distance(begin(), end()); } const SigChunk &at(int index) { ensure_chunk_vector(); From 4dac5cd1f85d9b90ba5dd86422213aeff1bcd951 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Mon, 10 Nov 2025 12:08:35 +0100 Subject: [PATCH 91/97] rtlil: note SigSpec only has one chunk in internal docs --- .../yosys_internals/formats/rtlil_rep.rst | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/docs/source/yosys_internals/formats/rtlil_rep.rst b/docs/source/yosys_internals/formats/rtlil_rep.rst index b0cbfe3a5..dbd69c7e4 100644 --- a/docs/source/yosys_internals/formats/rtlil_rep.rst +++ b/docs/source/yosys_internals/formats/rtlil_rep.rst @@ -194,17 +194,18 @@ RTLIL::SigSpec A "signal" is everything that can be applied to a cell port. I.e. -- | Any constant value of arbitrary bit-width +- | A bit from a wire (``RTLIL::SigBit``) + | 1em For example: ``mywire[24]`` + +- | A range of bits from a wire (wire variant of ``RTLIL::SigChunk``) + | 1em For example: ``mywire, mywire[15:8]`` + +- | Any constant value of arbitrary bit-width (``std::vector>`` variant of ``RTLIL::SigChunk``) | 1em For example: ``1337, 16'b0000010100111001, 1'b1, 1'bx`` -- | All bits of a wire or a selection of bits from a wire - | 1em For example: ``mywire, mywire[24], mywire[15:8]`` - -- | Concatenations of the above - | 1em For example: ``{16'd1337, mywire[15:8]}`` - -The ``RTLIL::SigSpec`` data type is used to represent signals. The -``RTLIL::Cell`` object contains one ``RTLIL::SigSpec`` for each cell port. +The ``RTLIL::SigSpec`` data type is used to represent signals. +It contains a single ``RTLIL::SigChunk`` or a vector of ``RTLIL::SigBit``. +The ``RTLIL::Cell`` object contains one ``RTLIL::SigSpec`` for each cell port. In addition, connections between wires are represented using a pair of ``RTLIL::SigSpec`` objects. Such pairs are needed in different locations. From 8f53d21ea7eaec66ab93cb611f36fbf9e798935b Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Mon, 10 Nov 2025 14:26:10 +0100 Subject: [PATCH 92/97] simplify: refactor specific package import --- frontends/ast/simplify.cc | 85 ++++++++++++++++++++++----------------- 1 file changed, 48 insertions(+), 37 deletions(-) diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 010f4e14f..308406591 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -889,6 +889,52 @@ static void check_auto_nosync(AstNode *node) check_auto_nosync(child.get()); } +class PackageImporter { + std::set import_items; + bool is_wildcard; + const AstNode* node; +public: + PackageImporter(const AstNode* n, const AstNode* child) : node(n) { + is_wildcard = child->children.empty(); + // For specific imports, collect the list of items to import + if (!is_wildcard) { + for (auto& item : child->children) { + import_items.insert(item->str); + } + } + } + + void import(std::map& scope, AstNode* to_import) const { + // Check if this is a specific import and if this item should be imported + if (!is_wildcard && import_items.count(to_import->str) == 0) + return; + + if (to_import->type == AST_PARAMETER || to_import->type == AST_LOCALPARAM || + to_import->type == AST_TYPEDEF || to_import->type == AST_FUNCTION || + to_import->type == AST_TASK || to_import->type == AST_ENUM) { + // For wildcard imports, check if item already exists (from specific import) + if (is_wildcard && scope.count(to_import->str) > 0) + return; + scope[to_import->str] = to_import; + } + if (to_import->type == AST_ENUM) { + for (auto& enode : to_import->children) { + log_assert(enode->type==AST_ENUM_ITEM); + // Check if this enum item should be imported + if (!is_wildcard && import_items.count(enode->str) == 0) + continue; + // For wildcard imports, check if item already exists (from specific import) + if (is_wildcard && scope.count(enode->str) > 0) + continue; + if (scope.count(enode->str) == 0) + scope[enode->str] = enode.get(); + else + node->input_error("enum item %s already exists in current scope\n", enode->str); + } + } + } +}; + // convert the AST into a simpler AST that has all parameters substituted by their // values, unrolled for-loops, expanded generate blocks, etc. when this function // is done with an AST it can be converted into RTLIL using genRTLIL(). @@ -1123,45 +1169,10 @@ bool AstNode::simplify(bool const_fold, int stage, int width_hint, bool sign_hin } if (package_node) { - bool is_wildcard = child->children.empty(); - std::set import_items; - - // For specific imports, collect the list of items to import - if (!is_wildcard) { - for (auto& import_item : child->children) { - import_items.insert(import_item->str); - } - } - + PackageImporter importer(this, child); // Import names from the package into current scope for (auto& pkg_child : package_node->children) { - // Check if this is a specific import and if this item should be imported - if (!is_wildcard && import_items.count(pkg_child->str) == 0) - continue; - - if (pkg_child->type == AST_PARAMETER || pkg_child->type == AST_LOCALPARAM || - pkg_child->type == AST_TYPEDEF || pkg_child->type == AST_FUNCTION || - pkg_child->type == AST_TASK || pkg_child->type == AST_ENUM) { - // For wildcard imports, check if item already exists (from specific import) - if (is_wildcard && current_scope.count(pkg_child->str) > 0) - continue; - current_scope[pkg_child->str] = pkg_child.get(); - } - if (pkg_child->type == AST_ENUM) { - for (auto& enode : pkg_child->children) { - log_assert(enode->type==AST_ENUM_ITEM); - // Check if this enum item should be imported - if (!is_wildcard && import_items.count(enode->str) == 0) - continue; - // For wildcard imports, check if item already exists (from specific import) - if (is_wildcard && current_scope.count(enode->str) > 0) - continue; - if (current_scope.count(enode->str) == 0) - current_scope[enode->str] = enode.get(); - else - input_error("enum item %s already exists in current scope\n", enode->str); - } - } + importer.import(current_scope, pkg_child.get()); } // Remove the import node since it's been processed children.erase(children.begin() + i); From f7881ced9e8d2a1fdeef33ceb5a4021fb8eaaf24 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 11 Nov 2025 00:25:20 +0000 Subject: [PATCH 93/97] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index dd7a8c022..575d1a7f3 100644 --- a/Makefile +++ b/Makefile @@ -161,7 +161,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.58+162 +YOSYS_VER := 0.58+202 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 03eb2206d7b8a830dd32d0e1673986318111a4c3 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Tue, 11 Nov 2025 07:57:22 +0100 Subject: [PATCH 94/97] Release version 0.59 --- CHANGELOG | 17 ++++++++++++++++- Makefile | 4 ++-- docs/source/conf.py | 2 +- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 8ceefee41..d267a4826 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,8 +2,23 @@ List of major changes and improvements between releases ======================================================= -Yosys 0.58 .. Yosys 0.59-dev +Yosys 0.58 .. Yosys 0.59 -------------------------- + * Various + - Pyosys is rewritten using pybind11. + - alumacc: merge independent of sign. + - write_btor: Include $assert and $assume cells in -ywmap output. + - RTLIL parser rewritten for efficiency. + - Wildcards enabled for Liberty file consuming. + - timeest: Add top ports launching/sampling. + + * New commands and options + - Added "-apply_derived_type" option to "box_derive" pass. + - Added "-publish_icells" option to "chtype" pass. + - Added "-width" option to "sim" pass. + - Added "sort" pass for sorting the design objects. + - Merged "synth_ecp5" and "synth_nexus" into "synth_lattice" pass. + - Added "-strict-gw5a-dffs" and "-setundef" options to "synth_gowin" pass. Yosys 0.57 .. Yosys 0.58 -------------------------- diff --git a/Makefile b/Makefile index 575d1a7f3..2501a7ea0 100644 --- a/Makefile +++ b/Makefile @@ -161,7 +161,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.58+202 +YOSYS_VER := 0.59 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) @@ -184,7 +184,7 @@ endif OBJS = kernel/version_$(GIT_REV).o bumpversion: - sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 157aabb.. | wc -l`/;" Makefile +# sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 157aabb.. | wc -l`/;" Makefile ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABC_USE_NAMESPACE=abc VERBOSE=$(Q) diff --git a/docs/source/conf.py b/docs/source/conf.py index 6740fab83..fb106bddb 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -6,7 +6,7 @@ import os project = 'YosysHQ Yosys' author = 'YosysHQ GmbH' copyright ='2025 YosysHQ GmbH' -yosys_ver = "0.58" +yosys_ver = "0.59" # select HTML theme html_theme = 'furo-ys' From fd40418c102eb2fdc15ca5cd5c2276468fa7ddd0 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Tue, 11 Nov 2025 09:26:05 +0100 Subject: [PATCH 95/97] Next dev cycle --- CHANGELOG | 3 +++ Makefile | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index d267a4826..6cefcc3ac 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,9 @@ List of major changes and improvements between releases ======================================================= +Yosys 0.59 .. Yosys 0.60-dev +-------------------------- + Yosys 0.58 .. Yosys 0.59 -------------------------- * Various diff --git a/Makefile b/Makefile index 2501a7ea0..09dcd0639 100644 --- a/Makefile +++ b/Makefile @@ -161,7 +161,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.59 +YOSYS_VER := 0.59+0 YOSYS_MAJOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f1) YOSYS_MINOR := $(shell echo $(YOSYS_VER) | cut -d'.' -f2 | cut -d'+' -f1) YOSYS_COMMIT := $(shell echo $(YOSYS_VER) | cut -d'+' -f2) @@ -184,7 +184,7 @@ endif OBJS = kernel/version_$(GIT_REV).o bumpversion: -# sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 157aabb.. | wc -l`/;" Makefile + sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 03eb220.. | wc -l`/;" Makefile ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABC_USE_NAMESPACE=abc VERBOSE=$(Q) From e29328ec99e6b8a3cc5bd60c169ebed47f1b279c Mon Sep 17 00:00:00 2001 From: Mohamed Gaber Date: Tue, 11 Nov 2025 13:48:35 +0200 Subject: [PATCH 96/97] hotfix: workaround for pyosys build failure temporarily exclude `SigSpec::chunks` from the interface until nested structs/classes are supported --- pyosys/generator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyosys/generator.py b/pyosys/generator.py index 65d886cf0..0883a7ba4 100644 --- a/pyosys/generator.py +++ b/pyosys/generator.py @@ -192,7 +192,7 @@ pyosys_headers = [ ), PyosysClass("SigChunk"), PyosysClass("SigBit", hash_expr="s"), - PyosysClass("SigSpec", hash_expr="s"), + PyosysClass("SigSpec", hash_expr="s", denylist={"chunks"}), PyosysClass( "Cell", ref_only=True, From 967e91aa73e84d921591f2f3b34aa5cad5124f5c Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Tue, 11 Nov 2025 13:44:50 +0100 Subject: [PATCH 97/97] libparse: fix parsing and memory safety of quoted values --- passes/techmap/libparse.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/passes/techmap/libparse.cc b/passes/techmap/libparse.cc index 9e2556891..a9ae75c01 100644 --- a/passes/techmap/libparse.cc +++ b/passes/techmap/libparse.cc @@ -123,7 +123,9 @@ int LibertyInputStream::peek_cold(size_t offset) if (!extend_buffer_at_least(offset + 1)) return EOF; } - +#ifdef log_assert + log_assert(buf_pos + offset < buffer.size()); +#endif return buffer[buf_pos + offset]; } @@ -458,7 +460,6 @@ int LibertyParser::lexer_inner(std::string &str) // if it wasn't an identifer, number of array range, // maybe it's a string? if (c == '"') { - f.consume(1); size_t i = 0; while (true) { c = f.peek(i); @@ -469,14 +470,13 @@ int LibertyParser::lexer_inner(std::string &str) break; } str.clear(); - f.unget(); - str.append(f.buffered_data(), f.buffered_data() + i + 1); + str.append(f.buffered_data(), f.buffered_data() + i); // Usage in filterlib is expected to retain quotes // but yosys expects to get unquoted #ifdef FILTERLIB str = "\"" + str + "\""; #endif - f.consume(i + 2); + f.consume(i + 1); return 'v'; }