From 9315f02c17ef5b3149a4767d9851045f2cee15cb Mon Sep 17 00:00:00 2001 From: Gabriel Gouvine Date: Mon, 25 Mar 2024 11:33:52 +0000 Subject: [PATCH 01/58] ezsat: New Sat class to call an external command --- Makefile | 2 + libs/ezsat/ezcommand.cc | 83 +++++++++++++++++++++++++++++++++++++++++ libs/ezsat/ezcommand.h | 36 ++++++++++++++++++ 3 files changed, 121 insertions(+) create mode 100644 libs/ezsat/ezcommand.cc create mode 100644 libs/ezsat/ezcommand.h diff --git a/Makefile b/Makefile index 8205bb3ed..afe559712 100644 --- a/Makefile +++ b/Makefile @@ -638,6 +638,7 @@ $(eval $(call add_include_file,kernel/yosys_common.h)) $(eval $(call add_include_file,kernel/yw.h)) $(eval $(call add_include_file,libs/ezsat/ezsat.h)) $(eval $(call add_include_file,libs/ezsat/ezminisat.h)) +$(eval $(call add_include_file,libs/ezsat/ezcommand.h)) ifeq ($(ENABLE_ZLIB),1) $(eval $(call add_include_file,libs/fst/fstapi.h)) endif @@ -683,6 +684,7 @@ OBJS += libs/json11/json11.o OBJS += libs/ezsat/ezsat.o OBJS += libs/ezsat/ezminisat.o +OBJS += libs/ezsat/ezcommand.o OBJS += libs/minisat/Options.o OBJS += libs/minisat/SimpSolver.o diff --git a/libs/ezsat/ezcommand.cc b/libs/ezsat/ezcommand.cc new file mode 100644 index 000000000..10104a2cd --- /dev/null +++ b/libs/ezsat/ezcommand.cc @@ -0,0 +1,83 @@ + +#include "ezcommand.h" + +#include "../../kernel/yosys.h" + +ezSATCommand::ezSATCommand(const std::string &cmd) : command(cmd) {} + +ezSATCommand::~ezSATCommand() {} + +bool ezSATCommand::solver(const std::vector &modelExpressions, std::vector &modelValues, const std::vector &assumptions) +{ + if (!assumptions.empty()) { + Yosys::log_error("Assumptions are not supported yet by command-based Sat solver\n"); + } + const std::string tempdir_name = Yosys::make_temp_dir(Yosys::get_base_tmpdir() + "/yosys-sat-XXXXXX"); + const std::string cnf_filename = Yosys::stringf("%s/problem.cnf", tempdir_name.c_str()); + const std::string sat_command = Yosys::stringf("%s %s", command.c_str(), cnf_filename.c_str()); + FILE *dimacs = fopen(cnf_filename.c_str(), "w"); + printDIMACS(dimacs); + fclose(dimacs); + + std::vector modelIdx; + for (auto id : modelExpressions) + modelIdx.push_back(bind(id)); + + bool status_sat = false; + bool status_unsat = false; + std::vector values; + + auto line_callback = [&](const std::string &line) { + if (line.empty()) { + return; + } + if (line[0] == 's') { + if (line.substr(0, 5) == "s SAT") { + status_sat = true; + } + if (line.substr(0, 7) == "s UNSAT") { + status_unsat = true; + } + return; + } + if (line[0] == 'v') { + std::stringstream ss(line.substr(1)); + int lit; + while (ss >> lit) { + if (lit == 0) { + return; + } + bool val = lit >= 0; + int ind = lit >= 0 ? lit - 1 : -lit - 1; + if (Yosys::GetSize(values) <= ind) { + values.resize(ind + 1); + } + values[ind] = val; + } + } + }; + if (Yosys::run_command(sat_command, line_callback) != 0) { + Yosys::log_cmd_error("Shell command failed!\n"); + } + + modelValues.clear(); + modelValues.resize(modelIdx.size()); + + if (!status_sat && !status_unsat) { + solverTimoutStatus = true; + } + if (!status_sat) { + return false; + } + + for (size_t i = 0; i < modelIdx.size(); i++) { + int idx = modelIdx[i]; + bool refvalue = true; + + if (idx < 0) + idx = -idx, refvalue = false; + + modelValues[i] = (values.at(idx - 1) == refvalue); + } + return true; +} \ No newline at end of file diff --git a/libs/ezsat/ezcommand.h b/libs/ezsat/ezcommand.h new file mode 100644 index 000000000..a0e3de4ed --- /dev/null +++ b/libs/ezsat/ezcommand.h @@ -0,0 +1,36 @@ +/* + * ezSAT -- A simple and easy to use CNF generator for SAT solvers + * + * Copyright (C) 2013 Claire Xenia Wolf + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#ifndef EZSATCOMMAND_H +#define EZSATCOMMAND_H + +#include "ezsat.h" + +class ezSATCommand : public ezSAT +{ +private: + std::string command; + +public: + ezSATCommand(const std::string &cmd); + virtual ~ezSATCommand(); + bool solver(const std::vector &modelExpressions, std::vector &modelValues, const std::vector &assumptions) override; +}; + +#endif From 12315c0d17c911a971298e233c4a1d1aa291c9c7 Mon Sep 17 00:00:00 2001 From: Gabriel Gouvine Date: Thu, 28 Mar 2024 09:56:48 +0000 Subject: [PATCH 02/58] ezsat: Support for assumptions in Sat command --- libs/ezsat/ezcommand.cc | 11 ++++++----- libs/ezsat/ezsat.cc | 6 ++++-- libs/ezsat/ezsat.h | 2 +- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/libs/ezsat/ezcommand.cc b/libs/ezsat/ezcommand.cc index 10104a2cd..c2925b647 100644 --- a/libs/ezsat/ezcommand.cc +++ b/libs/ezsat/ezcommand.cc @@ -9,19 +9,20 @@ ezSATCommand::~ezSATCommand() {} bool ezSATCommand::solver(const std::vector &modelExpressions, std::vector &modelValues, const std::vector &assumptions) { - if (!assumptions.empty()) { - Yosys::log_error("Assumptions are not supported yet by command-based Sat solver\n"); - } const std::string tempdir_name = Yosys::make_temp_dir(Yosys::get_base_tmpdir() + "/yosys-sat-XXXXXX"); const std::string cnf_filename = Yosys::stringf("%s/problem.cnf", tempdir_name.c_str()); const std::string sat_command = Yosys::stringf("%s %s", command.c_str(), cnf_filename.c_str()); FILE *dimacs = fopen(cnf_filename.c_str(), "w"); - printDIMACS(dimacs); - fclose(dimacs); std::vector modelIdx; for (auto id : modelExpressions) modelIdx.push_back(bind(id)); + std::vector> extraClauses; + for (auto id : assumptions) + extraClauses.push_back({bind(id)}); + + printDIMACS(dimacs, false, extraClauses); + fclose(dimacs); bool status_sat = false; bool status_unsat = false; diff --git a/libs/ezsat/ezsat.cc b/libs/ezsat/ezsat.cc index 20a210abe..fbdfc20f6 100644 --- a/libs/ezsat/ezsat.cc +++ b/libs/ezsat/ezsat.cc @@ -1222,7 +1222,7 @@ ezSATvec ezSAT::vec(const std::vector &vec) return ezSATvec(*this, vec); } -void ezSAT::printDIMACS(FILE *f, bool verbose) const +void ezSAT::printDIMACS(FILE *f, bool verbose, const std::vector> &extraClauses) const { if (cnfConsumed) { fprintf(stderr, "Usage error: printDIMACS() must not be called after cnfConsumed()!"); @@ -1259,8 +1259,10 @@ void ezSAT::printDIMACS(FILE *f, bool verbose) const std::vector> all_clauses; getFullCnf(all_clauses); assert(cnfClausesCount == int(all_clauses.size())); + for (auto c : extraClauses) + all_clauses.push_back(c); - fprintf(f, "p cnf %d %d\n", cnfVariableCount, cnfClausesCount); + fprintf(f, "p cnf %d %d\n", cnfVariableCount, (int) all_clauses.size()); int maxClauseLen = 0; for (auto &clause : all_clauses) maxClauseLen = std::max(int(clause.size()), maxClauseLen); diff --git a/libs/ezsat/ezsat.h b/libs/ezsat/ezsat.h index 7f3bdf68d..507708cb2 100644 --- a/libs/ezsat/ezsat.h +++ b/libs/ezsat/ezsat.h @@ -295,7 +295,7 @@ public: // printing CNF and internal state - void printDIMACS(FILE *f, bool verbose = false) const; + void printDIMACS(FILE *f, bool verbose = false, const std::vector> &extraClauses = std::vector>()) const; void printInternalState(FILE *f) const; // more sophisticated constraints (designed to be used directly with assume(..)) From 6565bf3ebfeba59bd17acce26632bc0ae6858304 Mon Sep 17 00:00:00 2001 From: Gabriel Gouvine Date: Thu, 28 Mar 2024 10:14:30 +0000 Subject: [PATCH 03/58] ezsat: Fix build for emscripten/wasi --- libs/ezsat/ezcommand.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libs/ezsat/ezcommand.cc b/libs/ezsat/ezcommand.cc index c2925b647..2040d3c1a 100644 --- a/libs/ezsat/ezcommand.cc +++ b/libs/ezsat/ezcommand.cc @@ -9,6 +9,7 @@ ezSATCommand::~ezSATCommand() {} bool ezSATCommand::solver(const std::vector &modelExpressions, std::vector &modelValues, const std::vector &assumptions) { +#if !defined(YOSYS_DISABLE_SPAWN) const std::string tempdir_name = Yosys::make_temp_dir(Yosys::get_base_tmpdir() + "/yosys-sat-XXXXXX"); const std::string cnf_filename = Yosys::stringf("%s/problem.cnf", tempdir_name.c_str()); const std::string sat_command = Yosys::stringf("%s %s", command.c_str(), cnf_filename.c_str()); @@ -81,4 +82,7 @@ bool ezSATCommand::solver(const std::vector &modelExpressions, std::vector< modelValues[i] = (values.at(idx - 1) == refvalue); } return true; +#else + Yosys::log_error("SAT solver command not available in this build!\n"); +#endif } \ No newline at end of file From d2b6bd00b1eb73d1d800544fcd16e21050f35a80 Mon Sep 17 00:00:00 2001 From: Gabriel Gouvine Date: Thu, 28 Mar 2024 17:25:19 +0000 Subject: [PATCH 04/58] ezsat: Rename files and class for ezCmdlineSat --- Makefile | 4 ++-- libs/ezsat/{ezcommand.cc => ezcmdline.cc} | 10 +++++----- libs/ezsat/{ezcommand.h => ezcmdline.h} | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) rename libs/ezsat/{ezcommand.cc => ezcmdline.cc} (91%) rename libs/ezsat/{ezcommand.h => ezcmdline.h} (92%) diff --git a/Makefile b/Makefile index afe559712..0fe20288b 100644 --- a/Makefile +++ b/Makefile @@ -638,7 +638,7 @@ $(eval $(call add_include_file,kernel/yosys_common.h)) $(eval $(call add_include_file,kernel/yw.h)) $(eval $(call add_include_file,libs/ezsat/ezsat.h)) $(eval $(call add_include_file,libs/ezsat/ezminisat.h)) -$(eval $(call add_include_file,libs/ezsat/ezcommand.h)) +$(eval $(call add_include_file,libs/ezsat/ezcmdline.h)) ifeq ($(ENABLE_ZLIB),1) $(eval $(call add_include_file,libs/fst/fstapi.h)) endif @@ -684,7 +684,7 @@ OBJS += libs/json11/json11.o OBJS += libs/ezsat/ezsat.o OBJS += libs/ezsat/ezminisat.o -OBJS += libs/ezsat/ezcommand.o +OBJS += libs/ezsat/ezcmdline.o OBJS += libs/minisat/Options.o OBJS += libs/minisat/SimpSolver.o diff --git a/libs/ezsat/ezcommand.cc b/libs/ezsat/ezcmdline.cc similarity index 91% rename from libs/ezsat/ezcommand.cc rename to libs/ezsat/ezcmdline.cc index 2040d3c1a..1b5278fab 100644 --- a/libs/ezsat/ezcommand.cc +++ b/libs/ezsat/ezcmdline.cc @@ -1,13 +1,13 @@ -#include "ezcommand.h" +#include "ezcmdline.h" #include "../../kernel/yosys.h" -ezSATCommand::ezSATCommand(const std::string &cmd) : command(cmd) {} +ezCmdlineSAT::ezCmdlineSAT(const std::string &cmd) : command(cmd) {} -ezSATCommand::~ezSATCommand() {} +ezCmdlineSAT::~ezCmdlineSAT() {} -bool ezSATCommand::solver(const std::vector &modelExpressions, std::vector &modelValues, const std::vector &assumptions) +bool ezCmdlineSAT::solver(const std::vector &modelExpressions, std::vector &modelValues, const std::vector &assumptions) { #if !defined(YOSYS_DISABLE_SPAWN) const std::string tempdir_name = Yosys::make_temp_dir(Yosys::get_base_tmpdir() + "/yosys-sat-XXXXXX"); @@ -85,4 +85,4 @@ bool ezSATCommand::solver(const std::vector &modelExpressions, std::vector< #else Yosys::log_error("SAT solver command not available in this build!\n"); #endif -} \ No newline at end of file +} diff --git a/libs/ezsat/ezcommand.h b/libs/ezsat/ezcmdline.h similarity index 92% rename from libs/ezsat/ezcommand.h rename to libs/ezsat/ezcmdline.h index a0e3de4ed..8ec8c7043 100644 --- a/libs/ezsat/ezcommand.h +++ b/libs/ezsat/ezcmdline.h @@ -22,14 +22,14 @@ #include "ezsat.h" -class ezSATCommand : public ezSAT +class ezCmdlineSAT : public ezSAT { private: std::string command; public: - ezSATCommand(const std::string &cmd); - virtual ~ezSATCommand(); + ezCmdlineSAT(const std::string &cmd); + virtual ~ezCmdlineSAT(); bool solver(const std::vector &modelExpressions, std::vector &modelValues, const std::vector &assumptions) override; }; From 979b673f206bb92e2f76b0c59afe27741b516717 Mon Sep 17 00:00:00 2001 From: Gabriel Gouvine Date: Tue, 9 Apr 2024 15:56:36 +0100 Subject: [PATCH 05/58] ezsat: Fix handling of error codes --- libs/ezsat/ezcmdline.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libs/ezsat/ezcmdline.cc b/libs/ezsat/ezcmdline.cc index 1b5278fab..dddec1067 100644 --- a/libs/ezsat/ezcmdline.cc +++ b/libs/ezsat/ezcmdline.cc @@ -58,7 +58,8 @@ bool ezCmdlineSAT::solver(const std::vector &modelExpressions, std::vector< } } }; - if (Yosys::run_command(sat_command, line_callback) != 0) { + int return_code = Yosys::run_command(sat_command, line_callback); + if (return_code != 0 && return_code != 10 && return_code != 20) { Yosys::log_cmd_error("Shell command failed!\n"); } From 0f6ef777750e9c537d71b37a1698c08d38add2b7 Mon Sep 17 00:00:00 2001 From: Gus Smith Date: Tue, 20 Jan 2026 09:28:00 -0800 Subject: [PATCH 06/58] Add test for ezCmdlineSAT --- tests/various/.gitignore | 2 + tests/various/ezcmdline_dummy_solver | 61 ++++++++++++++++++++++++++++ tests/various/ezcmdline_plugin.cc | 53 ++++++++++++++++++++++++ tests/various/ezcmdline_plugin.sh | 8 ++++ 4 files changed, 124 insertions(+) create mode 100755 tests/various/ezcmdline_dummy_solver create mode 100644 tests/various/ezcmdline_plugin.cc create mode 100644 tests/various/ezcmdline_plugin.sh diff --git a/tests/various/.gitignore b/tests/various/.gitignore index e116179ae..9296a04c0 100644 --- a/tests/various/.gitignore +++ b/tests/various/.gitignore @@ -4,6 +4,8 @@ /plugin.so /plugin_search /plugin.so.dSYM +/ezcmdline_plugin.so +/ezcmdline_plugin.so.dSYM /temp /smtlib2_module.smt2 /smtlib2_module-filtered.smt2 diff --git a/tests/various/ezcmdline_dummy_solver b/tests/various/ezcmdline_dummy_solver new file mode 100755 index 000000000..db5b21b8e --- /dev/null +++ b/tests/various/ezcmdline_dummy_solver @@ -0,0 +1,61 @@ +#!/bin/sh +# Dummy SAT solver for ezCmdlineSAT tests. +# Accepts exactly two CNF shapes: +# - SAT: p cnf 1 1; clause: "1 0" -> exits 10 with v 1 +# - UNSAT: p cnf 1 2; clauses: "1 0" and "-1 0" -> exits 20 +set -e + +if [ "$#" -ne 1 ]; then + echo "usage: $0 " >&2 + exit 1 +fi + +awk ' +BEGIN { + vars = 0; + clauses = 0; + clause_count = 0; + clause_data = ""; + current = ""; +} +$1 == "c" { + next; +} +$1 == "p" && $2 == "cnf" { + vars = $3; + clauses = $4; + next; +} +{ + for (i = 1; i <= NF; i++) { + lit = $i; + if (lit == 0) { + clause_count++; + if (clause_data != "") + clause_data = clause_data ";" current; + else + clause_data = current; + current = ""; + } else { + if (current == "") + current = lit; + else + current = current "," lit; + } + } +} +END { + if (vars == 1 && clause_count == 1 && clause_data == "1") { + print "s SATISFIABLE"; + print "v 1 0"; + exit 10; + } + if (vars == 1 && clause_count == 2 && clause_data == "1;-1") { + print "s UNSATISFIABLE"; + exit 20; + } + print "c unexpected CNF for dummy solver"; + print "c vars=" vars " header_clauses=" clauses " parsed_clauses=" clause_count " data=" clause_data; + exit 1; +} +' "$1" diff --git a/tests/various/ezcmdline_plugin.cc b/tests/various/ezcmdline_plugin.cc new file mode 100644 index 000000000..b775829b3 --- /dev/null +++ b/tests/various/ezcmdline_plugin.cc @@ -0,0 +1,53 @@ +#include "kernel/yosys.h" +#include "libs/ezsat/ezcmdline.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct EzCmdlineTestPass : public Pass { + EzCmdlineTestPass() : Pass("ezcmdline_test", "smoke-test ezCmdlineSAT") { } + void execute(std::vector args, RTLIL::Design *design) override + { + std::string cmd; + size_t argidx = 1; + + while (argidx < args.size()) { + if (args[argidx] == "-cmd" && argidx + 1 < args.size()) { + cmd = args[argidx + 1]; + argidx += 2; + continue; + } + break; + } + + extra_args(args, argidx, design); + + if (cmd.empty()) + log_error("Missing -cmd argument.\n"); + + ezCmdlineSAT sat(cmd); + sat.non_incremental(); + + // assume("A") adds a permanent CNF clause "A". + sat.assume(sat.VAR("A")); + + std::vector model_expressions; + std::vector model_values; + model_expressions.push_back(sat.VAR("A")); + + // Expect SAT with A=true. + if (!sat.solve(model_expressions, model_values)) + log_error("ezCmdlineSAT SAT case failed.\n"); + if (model_values.size() != 1 || !model_values[0]) + log_error("ezCmdlineSAT SAT model mismatch.\n"); + + // Passing NOT("A") here adds a temporary unit clause for this solve call, + // so the solver sees A && !A and must return UNSAT. + if (sat.solve(model_expressions, model_values, sat.NOT("A"))) + log_error("ezCmdlineSAT UNSAT case failed.\n"); + + log("ezcmdline_test passed!\n"); + } +} EzCmdlineTestPass; + +PRIVATE_NAMESPACE_END diff --git a/tests/various/ezcmdline_plugin.sh b/tests/various/ezcmdline_plugin.sh new file mode 100644 index 000000000..cc1ed4bc9 --- /dev/null +++ b/tests/various/ezcmdline_plugin.sh @@ -0,0 +1,8 @@ +set -e + +DIR=$(cd "$(dirname "$0")" && pwd) +BASEDIR=$(cd "$DIR/../.." && pwd) +rm -f "$DIR/ezcmdline_plugin.so" +chmod +x "$DIR/ezcmdline_dummy_solver" +"$BASEDIR/yosys-config" --build "$DIR/ezcmdline_plugin.so" "$DIR/ezcmdline_plugin.cc" +"$BASEDIR/yosys" -m "$DIR/ezcmdline_plugin.so" -p "ezcmdline_test -cmd $DIR/ezcmdline_dummy_solver" | grep -q "ezcmdline_test passed!" From bd9dbea4eac201c4fee2e93785e357c1b837c5e3 Mon Sep 17 00:00:00 2001 From: Gus Smith Date: Tue, 20 Jan 2026 10:07:44 -0800 Subject: [PATCH 07/58] Add -I --- tests/various/ezcmdline_plugin.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/various/ezcmdline_plugin.sh b/tests/various/ezcmdline_plugin.sh index cc1ed4bc9..58dc7d9c8 100644 --- a/tests/various/ezcmdline_plugin.sh +++ b/tests/various/ezcmdline_plugin.sh @@ -4,5 +4,5 @@ DIR=$(cd "$(dirname "$0")" && pwd) BASEDIR=$(cd "$DIR/../.." && pwd) rm -f "$DIR/ezcmdline_plugin.so" chmod +x "$DIR/ezcmdline_dummy_solver" -"$BASEDIR/yosys-config" --build "$DIR/ezcmdline_plugin.so" "$DIR/ezcmdline_plugin.cc" +"$BASEDIR/yosys-config" --build "$DIR/ezcmdline_plugin.so" "$DIR/ezcmdline_plugin.cc" -I"$BASEDIR" "$BASEDIR/yosys" -m "$DIR/ezcmdline_plugin.so" -p "ezcmdline_test -cmd $DIR/ezcmdline_dummy_solver" | grep -q "ezcmdline_test passed!" From 9ed56ac72c3d391119174a9f9029a5b71caf8e70 Mon Sep 17 00:00:00 2001 From: Gus Smith Date: Tue, 20 Jan 2026 10:44:47 -0800 Subject: [PATCH 08/58] Mimic pattern of how other tests build plugins Seems like using --build isn't supported in CI --- tests/various/ezcmdline_plugin.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/various/ezcmdline_plugin.sh b/tests/various/ezcmdline_plugin.sh index 58dc7d9c8..cad0475a8 100644 --- a/tests/various/ezcmdline_plugin.sh +++ b/tests/various/ezcmdline_plugin.sh @@ -4,5 +4,9 @@ DIR=$(cd "$(dirname "$0")" && pwd) BASEDIR=$(cd "$DIR/../.." && pwd) rm -f "$DIR/ezcmdline_plugin.so" chmod +x "$DIR/ezcmdline_dummy_solver" -"$BASEDIR/yosys-config" --build "$DIR/ezcmdline_plugin.so" "$DIR/ezcmdline_plugin.cc" -I"$BASEDIR" +CXXFLAGS=$("$BASEDIR/yosys-config" --cxxflags) +DATDIR=$("$BASEDIR/yosys-config" --datdir) +DATDIR=${DATDIR//\//\\\/} +CXXFLAGS=${CXXFLAGS//$DATDIR/..\/..\/share} +"$BASEDIR/yosys-config" --exec --cxx ${CXXFLAGS} -I"$BASEDIR" --ldflags -shared -o "$DIR/ezcmdline_plugin.so" "$DIR/ezcmdline_plugin.cc" "$BASEDIR/yosys" -m "$DIR/ezcmdline_plugin.so" -p "ezcmdline_test -cmd $DIR/ezcmdline_dummy_solver" | grep -q "ezcmdline_test passed!" From 808ec8c04b37e0e6c73b8873d4051c19dc41fa25 Mon Sep 17 00:00:00 2001 From: Maxim Kudinov Date: Sun, 25 Jan 2026 22:10:08 +0300 Subject: [PATCH 09/58] gowin: synth_gowin: Add MULT inference for GW1N and GW2A --- techlibs/gowin/Makefile.inc | 1 + techlibs/gowin/dsp_map.v | 70 +++++++++++++++++++++++++++++++++++ techlibs/gowin/synth_gowin.cc | 44 +++++++++++++++++++++- 3 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 techlibs/gowin/dsp_map.v diff --git a/techlibs/gowin/Makefile.inc b/techlibs/gowin/Makefile.inc index df1b79317..0744b1389 100644 --- a/techlibs/gowin/Makefile.inc +++ b/techlibs/gowin/Makefile.inc @@ -12,3 +12,4 @@ $(eval $(call add_share_file,share/gowin,techlibs/gowin/brams_map_gw5a.v)) $(eval $(call add_share_file,share/gowin,techlibs/gowin/brams.txt)) $(eval $(call add_share_file,share/gowin,techlibs/gowin/lutrams_map.v)) $(eval $(call add_share_file,share/gowin,techlibs/gowin/lutrams.txt)) +$(eval $(call add_share_file,share/gowin,techlibs/gowin/dsp_map.v)) diff --git a/techlibs/gowin/dsp_map.v b/techlibs/gowin/dsp_map.v new file mode 100644 index 000000000..dfde0b6a1 --- /dev/null +++ b/techlibs/gowin/dsp_map.v @@ -0,0 +1,70 @@ +module \$__MUL9X9 (input [8:0] A, input [8:0] B, output [17:0] Y); + + parameter A_WIDTH = 9; + parameter B_WIDTH = 9; + parameter Y_WIDTH = 18; + parameter A_SIGNED = 0; + parameter B_SIGNED = 0; + + MULT9X9 __TECHMAP_REPLACE__ ( + .CLK(1'b0), + .CE(1'b0), + .RESET(1'b0), + .A(A), + .SIA({A_WIDTH{1'b0}}), + .ASEL(1'b0), + .ASIGN(A_SIGNED ? 1'b1 : 1'b0), + .B(B), + .SIB({B_WIDTH{1'b0}}), + .BSEL(1'b0), + .BSIGN(B_SIGNED ? 1'b1 : 1'b0), + .DOUT(Y) + ); + +endmodule + +module \$__MUL18X18 (input [17:0] A, input [17:0] B, output [35:0] Y); + + parameter A_WIDTH = 18; + parameter B_WIDTH = 18; + parameter Y_WIDTH = 36; + parameter A_SIGNED = 0; + parameter B_SIGNED = 0; + + MULT18X18 __TECHMAP_REPLACE__ ( + .CLK(1'b0), + .CE(1'b0), + .RESET(1'b0), + .A(A), + .SIA({A_WIDTH{1'b0}}), + .ASEL(1'b0), + .ASIGN(A_SIGNED ? 1'b1 : 1'b0), + .B(B), + .SIB({B_WIDTH{1'b0}}), + .BSEL(1'b0), + .BSIGN(B_SIGNED ? 1'b1 : 1'b0), + .DOUT(Y) + ); + +endmodule + +module \$__MUL36X36 (input [35:0] A, input [35:0] B, output [71:0] Y); + + parameter A_WIDTH = 36; + parameter B_WIDTH = 36; + parameter Y_WIDTH = 72; + parameter A_SIGNED = 0; + parameter B_SIGNED = 0; + + MULT36X36 __TECHMAP_REPLACE__ ( + .CLK(1'b0), + .RESET(1'b0), + .CE(1'b0), + .A(A), + .ASIGN(A_SIGNED ? 1'b1 : 1'b0), + .B(B), + .BSIGN(B_SIGNED ? 1'b1 : 1'b0), + .DOUT(Y) + ); + +endmodule diff --git a/techlibs/gowin/synth_gowin.cc b/techlibs/gowin/synth_gowin.cc index b9902659c..9cc213945 100644 --- a/techlibs/gowin/synth_gowin.cc +++ b/techlibs/gowin/synth_gowin.cc @@ -29,6 +29,21 @@ struct SynthGowinPass : public ScriptPass { SynthGowinPass() : ScriptPass("synth_gowin", "synthesis for Gowin FPGAs") { } + struct DSPRule { + int a_maxwidth; + int b_maxwidth; + int a_minwidth; + int b_minwidth; + std::string prim; + }; + + const std::vector dsp_rules = { + {36, 36, 22, 22, "$__MUL36X36"}, + {18, 18, 10, 4, "$__MUL18X18"}, + {18, 18, 4, 10, "$__MUL18X18"}, + {9, 9, 4, 4, "$__MUL9X9"}, + }; + void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| @@ -249,7 +264,34 @@ struct SynthGowinPass : public ScriptPass if (check_label("coarse")) { - run("synth -run coarse" + no_rw_check_opt); + run("proc"); + run("opt_expr"); + run("opt_clean"); + run("check"); + run("opt -nodffe -nosdff"); + run("fsm"); + run("opt"); + run("wreduce"); + run("peepopt"); + run("opt_clean"); + run("share"); + + if (help_mode) { + run("techmap -map +/mul2dsp.v [...]", "(if -family gw1n or gw2a)"); + run("techmap -map +/gowin/dsp_map.v", "(if -family gw1n or gw2a)"); + } else if (family == "gw1n" || family == "gw2a") { + for (const auto &rule : dsp_rules) { + run(stringf("techmap -map +/mul2dsp.v -D DSP_A_MAXWIDTH=%d -D DSP_B_MAXWIDTH=%d -D DSP_A_MINWIDTH=%d -D DSP_B_MINWIDTH=%d -D DSP_NAME=%s", + rule.a_maxwidth, rule.b_maxwidth, rule.a_minwidth, rule.b_minwidth, rule.prim)); + run("chtype -set $mul t:$__soft_mul"); + } + run("techmap -map +/gowin/dsp_map.v"); + } + + run("alumacc"); + run("opt"); + run("memory -nomap" + no_rw_check_opt); + run("opt_clean"); } if (check_label("map_ram")) From 44afd4bbdd2094144fa178f3bbfb4f92c135850c Mon Sep 17 00:00:00 2001 From: Jeppe Johansen Date: Wed, 24 Aug 2022 18:31:45 +0200 Subject: [PATCH 10/58] Add support for subtraction in preadder --- techlibs/xilinx/xilinx_dsp.cc | 20 +++++++++++++------- techlibs/xilinx/xilinx_dsp.pmg | 32 +++++++++++++++++++++++++++++++- 2 files changed, 44 insertions(+), 8 deletions(-) diff --git a/techlibs/xilinx/xilinx_dsp.cc b/techlibs/xilinx/xilinx_dsp.cc index 22e6bce5b..194b9ac10 100644 --- a/techlibs/xilinx/xilinx_dsp.cc +++ b/techlibs/xilinx/xilinx_dsp.cc @@ -263,6 +263,7 @@ void xilinx_dsp_pack(xilinx_dsp_pm &pm) log("Analysing %s.%s for Xilinx DSP packing.\n", log_id(pm.module), log_id(st.dsp)); log_debug("preAdd: %s\n", log_id(st.preAdd, "--")); + log_debug("preSub: %s\n", log_id(st.preSub, "--")); log_debug("ffAD: %s\n", log_id(st.ffAD, "--")); log_debug("ffA2: %s\n", log_id(st.ffA2, "--")); log_debug("ffA1: %s\n", log_id(st.ffA1, "--")); @@ -278,17 +279,22 @@ void xilinx_dsp_pack(xilinx_dsp_pm &pm) Cell *cell = st.dsp; - if (st.preAdd) { - log(" preadder %s (%s)\n", log_id(st.preAdd), log_id(st.preAdd->type)); - bool A_SIGNED = st.preAdd->getParam(ID::A_SIGNED).as_bool(); - bool D_SIGNED = st.preAdd->getParam(ID::B_SIGNED).as_bool(); - if (st.sigA == st.preAdd->getPort(ID::B)) + if (st.preAdd || st.preSub) { + Cell* preAdder = st.preAdd ? st.preAdd : st.preSub; + + log(" preadder %s (%s)\n", log_id(preAdder), log_id(preAdder->type)); + bool A_SIGNED = preAdder->getParam(ID::A_SIGNED).as_bool(); + bool D_SIGNED = preAdder->getParam(ID::B_SIGNED).as_bool(); + if (st.sigA == preAdder->getPort(ID::B)) std::swap(A_SIGNED, D_SIGNED); st.sigA.extend_u0(30, A_SIGNED); st.sigD.extend_u0(25, D_SIGNED); cell->setPort(ID::A, st.sigA); cell->setPort(ID::D, st.sigD); - cell->setPort(ID(INMODE), Const::from_string("00100")); + if (preAdder->type == ID($add)) + cell->setPort(ID(INMODE), Const::from_string("00100")); + else + cell->setPort(ID(INMODE), Const::from_string("01100")); if (st.ffAD) { if (st.ffAD->type.in(ID($dffe), ID($sdffe))) { @@ -303,7 +309,7 @@ void xilinx_dsp_pack(xilinx_dsp_pm &pm) cell->setParam(ID(USE_DPORT), Const("TRUE")); - pm.autoremove(st.preAdd); + pm.autoremove(preAdder); } if (st.postAdd) { log(" postadder %s (%s)\n", log_id(st.postAdd), log_id(st.postAdd->type)); diff --git a/techlibs/xilinx/xilinx_dsp.pmg b/techlibs/xilinx/xilinx_dsp.pmg index ef0157621..6ec891290 100644 --- a/techlibs/xilinx/xilinx_dsp.pmg +++ b/techlibs/xilinx/xilinx_dsp.pmg @@ -6,6 +6,8 @@ // If ADREG matched, treat 'A' input as input of ADREG // ( 3) Match the driver of the 'A' and 'D' inputs for a possible $add cell // (pre-adder) +// (3.1) Match the driver of the 'A' and 'D' inputs for a possible $sub cell +// (pre-adder) // ( 4) If pre-adder was present, find match 'A' input for A2REG // If pre-adder was not present, move ADREG to A2REG // If A2REG, then match 'A' input for A1REG @@ -152,13 +154,41 @@ code sigA sigD } endcode +// (3.1) Match the driver of the 'A' and 'D' inputs for a possible $sub cell +// (pre-adder) +match preSub + if sigD.empty() || sigD.is_fully_zero() + // Ensure that preAdder not already used + if param(dsp, \USE_DPORT).decode_string() == "FALSE" + if port(dsp, \INMODE, Const(0, 5)).is_fully_zero() + + select preSub->type.in($sub) + // Output has to be 25 bits or less + select GetSize(port(preSub, \Y)) <= 25 + select nusers(port(preSub, \Y)) == 2 + // D port has to be 25 bits or less + select GetSize(port(preSub, \A)) <= 25 + // A port has to be 30 bits or less + select GetSize(port(preSub, \B)) <= 30 + index port(preSub, \Y) === sigA + + optional +endmatch + +code sigA sigD + if (preSub) { + sigD = port(preSub, \A); + sigA = port(preSub, \B); + } +endcode + // (4) If pre-adder was present, find match 'A' input for A2REG // If pre-adder was not present, move ADREG to A2REG // Then match 'A' input for A1REG code argQ ffAD sigA clock ffA2 ffA1 // Only search for ffA2 if there was a pre-adder // (otherwise ffA2 would have been matched as ffAD) - if (preAdd) { + if (preAdd || preSub) { if (param(dsp, \AREG).as_int() == 0) { argQ = sigA; subpattern(in_dffe); From 3f01d7a33ae27df8f1d120dce082b02e526e8a0c Mon Sep 17 00:00:00 2001 From: Gus Smith Date: Tue, 3 Feb 2026 14:41:08 -0800 Subject: [PATCH 11/58] Add test --- tests/arch/xilinx/dsp_preadder_sub.ys | 41 +++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 tests/arch/xilinx/dsp_preadder_sub.ys diff --git a/tests/arch/xilinx/dsp_preadder_sub.ys b/tests/arch/xilinx/dsp_preadder_sub.ys new file mode 100644 index 000000000..04e5e9da0 --- /dev/null +++ b/tests/arch/xilinx/dsp_preadder_sub.ys @@ -0,0 +1,41 @@ +read_verilog < Date: Sat, 7 Feb 2026 12:12:13 +1300 Subject: [PATCH 12/58] Sanitize ABC global and per-run temporary directory names in logs --- passes/techmap/abc.cc | 56 ++++++++++++---------- tests/techmap/abc_temp_dir_sanitization.ys | 13 +++++ 2 files changed, 45 insertions(+), 24 deletions(-) create mode 100644 tests/techmap/abc_temp_dir_sanitization.ys diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index f7fa095a0..6e5b1fba8 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -285,7 +285,7 @@ using AbcSigMap = SigValMap; struct RunAbcState { const AbcConfig &config; - std::string tempdir_name; + std::string per_run_tempdir_name; std::vector signal_list; bool did_run = false; bool err = false; @@ -836,16 +836,23 @@ std::string fold_abc_cmd(std::string str) return new_str; } -std::string replace_tempdir(std::string text, std::string tempdir_name, bool show_tempdir) +std::string replace_tempdir(std::string text, std::string_view global_tempdir_name, std::string_view per_run_tempdir_name, bool show_tempdir) { if (show_tempdir) return text; while (1) { - size_t pos = text.find(tempdir_name); + size_t pos = text.find(global_tempdir_name); if (pos == std::string::npos) break; - text = text.substr(0, pos) + "" + text.substr(pos + GetSize(tempdir_name)); + text = text.substr(0, pos) + "" + text.substr(pos + GetSize(global_tempdir_name)); + } + + while (1) { + size_t pos = text.find(per_run_tempdir_name); + if (pos == std::string::npos) + break; + text = text.substr(0, pos) + "" + text.substr(pos + GetSize(per_run_tempdir_name)); } std::string selfdir_name = proc_self_dirname(); @@ -867,11 +874,12 @@ struct abc_output_filter bool got_cr; int escape_seq_state; std::string linebuf; - std::string tempdir_name; + std::string global_tempdir_name; + std::string per_run_tempdir_name; bool show_tempdir; - abc_output_filter(RunAbcState& state, std::string tempdir_name, bool show_tempdir) - : state(state), tempdir_name(tempdir_name), show_tempdir(show_tempdir) + abc_output_filter(RunAbcState& state, std::string global_tempdir_name, std::string per_run_tempdir_name, bool show_tempdir) + : state(state), global_tempdir_name(global_tempdir_name), per_run_tempdir_name(per_run_tempdir_name), show_tempdir(show_tempdir) { got_cr = false; escape_seq_state = 0; @@ -898,7 +906,7 @@ struct abc_output_filter return; } if (ch == '\n') { - state.logs.log("ABC: %s\n", replace_tempdir(linebuf, tempdir_name, show_tempdir)); + state.logs.log("ABC: %s\n", replace_tempdir(linebuf, global_tempdir_name, per_run_tempdir_name, show_tempdir)); got_cr = false, linebuf.clear(); return; } @@ -999,15 +1007,15 @@ void AbcModuleState::prepare_module(RTLIL::Design *design, RTLIL::Module *module const AbcConfig &config = run_abc.config; if (config.cleanup) - run_abc.tempdir_name = get_base_tmpdir() + "/"; + run_abc.per_run_tempdir_name = get_base_tmpdir() + "/"; else - run_abc.tempdir_name = "_tmp_"; - run_abc.tempdir_name += proc_program_prefix() + "yosys-abc-XXXXXX"; - run_abc.tempdir_name = make_temp_dir(run_abc.tempdir_name); + run_abc.per_run_tempdir_name = "_tmp_"; + run_abc.per_run_tempdir_name += proc_program_prefix() + "yosys-abc-XXXXXX"; + run_abc.per_run_tempdir_name = make_temp_dir(run_abc.per_run_tempdir_name); log_header(design, "Extracting gate netlist of module `%s' to `%s/input.blif'..\n", - module->name.c_str(), replace_tempdir(run_abc.tempdir_name, run_abc.tempdir_name, config.show_tempdir).c_str()); + module->name.c_str(), replace_tempdir(run_abc.per_run_tempdir_name, config.global_tempdir_name, run_abc.per_run_tempdir_name, config.show_tempdir).c_str()); - std::string abc_script = stringf("read_blif \"%s/input.blif\"; ", run_abc.tempdir_name); + std::string abc_script = stringf("read_blif \"%s/input.blif\"; ", run_abc.per_run_tempdir_name); if (!config.liberty_files.empty() || !config.genlib_files.empty()) { std::string dont_use_args; @@ -1073,8 +1081,8 @@ void AbcModuleState::prepare_module(RTLIL::Design *design, RTLIL::Module *module for (size_t pos = abc_script.find("{S}"); pos != std::string::npos; pos = abc_script.find("{S}", pos)) abc_script = abc_script.substr(0, pos) + config.lutin_shared + abc_script.substr(pos+3); if (config.abc_dress) - abc_script += stringf("; dress \"%s/input.blif\"", run_abc.tempdir_name); - abc_script += stringf("; write_blif %s/output.blif", run_abc.tempdir_name); + abc_script += stringf("; dress \"%s/input.blif\"", run_abc.per_run_tempdir_name); + abc_script += stringf("; write_blif %s/output.blif", run_abc.per_run_tempdir_name); abc_script = add_echos_to_abc_cmd(abc_script); #if defined(REUSE_YOSYS_ABC_PROCESSES) if (config.is_yosys_abc()) @@ -1085,7 +1093,7 @@ void AbcModuleState::prepare_module(RTLIL::Design *design, RTLIL::Module *module if (abc_script[i] == ';' && abc_script[i+1] == ' ') abc_script[i+1] = '\n'; - std::string buffer = stringf("%s/abc.script", run_abc.tempdir_name); + std::string buffer = stringf("%s/abc.script", run_abc.per_run_tempdir_name); FILE *f = fopen(buffer.c_str(), "wt"); if (f == nullptr) log_error("Opening %s for writing failed: %s\n", buffer, strerror(errno)); @@ -1220,7 +1228,7 @@ void RunAbcState::run(ConcurrentStack &process_pool) void RunAbcState::run(ConcurrentStack &) #endif { - std::string buffer = stringf("%s/input.blif", tempdir_name); + std::string buffer = stringf("%s/input.blif", per_run_tempdir_name); FILE *f = fopen(buffer.c_str(), "wt"); if (f == nullptr) { logs.log("Opening %s for writing failed: %s\n", buffer, strerror(errno)); @@ -1348,14 +1356,14 @@ void RunAbcState::run(ConcurrentStack &) return; } int ret; - std::string tmp_script_name = stringf("%s/abc.script", tempdir_name); + std::string tmp_script_name = stringf("%s/abc.script", per_run_tempdir_name); do { - logs.log("Running ABC script: %s\n", replace_tempdir(tmp_script_name, tempdir_name, config.show_tempdir)); + logs.log("Running ABC script: %s\n", replace_tempdir(tmp_script_name, config.global_tempdir_name, per_run_tempdir_name, config.show_tempdir)); errno = 0; - abc_output_filter filt(*this, tempdir_name, config.show_tempdir); + abc_output_filter filt(*this, config.global_tempdir_name, per_run_tempdir_name, config.show_tempdir); #ifdef YOSYS_LINK_ABC - string temp_stdouterr_name = stringf("%s/stdouterr.txt", tempdir_name); + string temp_stdouterr_name = stringf("%s/stdouterr.txt", per_run_tempdir_name); FILE *temp_stdouterr_w = fopen(temp_stdouterr_name.c_str(), "w"); if (temp_stdouterr_w == NULL) log_error("ABC: cannot open a temporary file for output redirection"); @@ -1502,7 +1510,7 @@ void AbcModuleState::extract(AbcSigMap &assign_map, RTLIL::Design *design, RTLIL return; } - std::string buffer = stringf("%s/%s", run_abc.tempdir_name, "output.blif"); + std::string buffer = stringf("%s/%s", run_abc.per_run_tempdir_name, "output.blif"); std::ifstream ifs; ifs.open(buffer); if (ifs.fail()) @@ -1789,7 +1797,7 @@ void AbcModuleState::finish() if (run_abc.config.cleanup) { log("Removing temp directory.\n"); - remove_directory(run_abc.tempdir_name); + remove_directory(run_abc.per_run_tempdir_name); } log_pop(); } diff --git a/tests/techmap/abc_temp_dir_sanitization.ys b/tests/techmap/abc_temp_dir_sanitization.ys new file mode 100644 index 000000000..ed87ff980 --- /dev/null +++ b/tests/techmap/abc_temp_dir_sanitization.ys @@ -0,0 +1,13 @@ +read_verilog < Date: Fri, 6 Feb 2026 17:26:08 -0800 Subject: [PATCH 13/58] Typo --- libs/ezsat/ezcmdline.cc | 2 +- libs/ezsat/ezminisat.cc | 4 ++-- libs/ezsat/ezsat.cc | 2 +- libs/ezsat/ezsat.h | 6 +++--- passes/sat/sat.cc | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/libs/ezsat/ezcmdline.cc b/libs/ezsat/ezcmdline.cc index dddec1067..2eef1b06d 100644 --- a/libs/ezsat/ezcmdline.cc +++ b/libs/ezsat/ezcmdline.cc @@ -67,7 +67,7 @@ bool ezCmdlineSAT::solver(const std::vector &modelExpressions, std::vector< modelValues.resize(modelIdx.size()); if (!status_sat && !status_unsat) { - solverTimoutStatus = true; + solverTimeoutStatus = true; } if (!status_sat) { return false; diff --git a/libs/ezsat/ezminisat.cc b/libs/ezsat/ezminisat.cc index 30df625cb..1f4b8855f 100644 --- a/libs/ezsat/ezminisat.cc +++ b/libs/ezsat/ezminisat.cc @@ -103,7 +103,7 @@ bool ezMiniSAT::solver(const std::vector &modelExpressions, std::vector 0) { if (alarmHandlerTimeout == 0) - solverTimoutStatus = true; + solverTimeoutStatus = true; alarm(0); sigaction(SIGALRM, &old_sig_action, NULL); alarm(old_alarm_timeout); diff --git a/libs/ezsat/ezsat.cc b/libs/ezsat/ezsat.cc index fbdfc20f6..3e63d3e84 100644 --- a/libs/ezsat/ezsat.cc +++ b/libs/ezsat/ezsat.cc @@ -54,7 +54,7 @@ ezSAT::ezSAT() cnfClausesCount = 0; solverTimeout = 0; - solverTimoutStatus = false; + solverTimeoutStatus = false; literal("CONST_TRUE"); literal("CONST_FALSE"); diff --git a/libs/ezsat/ezsat.h b/libs/ezsat/ezsat.h index 507708cb2..445c8edba 100644 --- a/libs/ezsat/ezsat.h +++ b/libs/ezsat/ezsat.h @@ -78,7 +78,7 @@ protected: public: int solverTimeout; - bool solverTimoutStatus; + bool solverTimeoutStatus; ezSAT(); virtual ~ezSAT(); @@ -153,8 +153,8 @@ public: solverTimeout = newTimeoutSeconds; } - bool getSolverTimoutStatus() { - return solverTimoutStatus; + bool getSolverTimeoutStatus() { + return solverTimeoutStatus; } // manage CNF (usually only accessed by SAT solvers) diff --git a/passes/sat/sat.cc b/passes/sat/sat.cc index 90b85d709..bb7b9ee29 100644 --- a/passes/sat/sat.cc +++ b/passes/sat/sat.cc @@ -441,7 +441,7 @@ struct SatHelper log_assert(gotTimeout == false); ez->setSolverTimeout(timeout); bool success = ez->solve(modelExpressions, modelValues, assumptions); - if (ez->getSolverTimoutStatus()) + if (ez->getSolverTimeoutStatus()) gotTimeout = true; return success; } @@ -451,7 +451,7 @@ struct SatHelper log_assert(gotTimeout == false); ez->setSolverTimeout(timeout); bool success = ez->solve(modelExpressions, modelValues, a, b, c, d, e, f); - if (ez->getSolverTimoutStatus()) + if (ez->getSolverTimeoutStatus()) gotTimeout = true; return success; } From 2bb352a86171ac2bb36d3baa9ac3fb3046a521f5 Mon Sep 17 00:00:00 2001 From: Gus Smith Date: Fri, 6 Feb 2026 17:45:00 -0800 Subject: [PATCH 14/58] Missing newline --- libs/ezsat/ezsat.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/ezsat/ezsat.cc b/libs/ezsat/ezsat.cc index 3e63d3e84..69a59c8cd 100644 --- a/libs/ezsat/ezsat.cc +++ b/libs/ezsat/ezsat.cc @@ -1225,7 +1225,7 @@ ezSATvec ezSAT::vec(const std::vector &vec) void ezSAT::printDIMACS(FILE *f, bool verbose, const std::vector> &extraClauses) const { if (cnfConsumed) { - fprintf(stderr, "Usage error: printDIMACS() must not be called after cnfConsumed()!"); + fprintf(stderr, "Usage error: printDIMACS() must not be called after cnfConsumed()!\n"); abort(); } From b2f9ac4fb5d5a79515b9f905bf76a493b301fad3 Mon Sep 17 00:00:00 2001 From: Gus Smith Date: Fri, 6 Feb 2026 18:18:03 -0800 Subject: [PATCH 15/58] Check for dimacs nullptr on file creation+fn call --- libs/ezsat/ezcmdline.cc | 3 +++ libs/ezsat/ezsat.cc | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/libs/ezsat/ezcmdline.cc b/libs/ezsat/ezcmdline.cc index 2eef1b06d..57800591c 100644 --- a/libs/ezsat/ezcmdline.cc +++ b/libs/ezsat/ezcmdline.cc @@ -14,6 +14,9 @@ bool ezCmdlineSAT::solver(const std::vector &modelExpressions, std::vector< const std::string cnf_filename = Yosys::stringf("%s/problem.cnf", tempdir_name.c_str()); const std::string sat_command = Yosys::stringf("%s %s", command.c_str(), cnf_filename.c_str()); FILE *dimacs = fopen(cnf_filename.c_str(), "w"); + if (dimacs == nullptr) { + Yosys::log_cmd_error("Failed to create CNF file `%s`.\n", cnf_filename.c_str()); + } std::vector modelIdx; for (auto id : modelExpressions) diff --git a/libs/ezsat/ezsat.cc b/libs/ezsat/ezsat.cc index 69a59c8cd..8e3114705 100644 --- a/libs/ezsat/ezsat.cc +++ b/libs/ezsat/ezsat.cc @@ -1224,6 +1224,11 @@ ezSATvec ezSAT::vec(const std::vector &vec) void ezSAT::printDIMACS(FILE *f, bool verbose, const std::vector> &extraClauses) const { + if (f == nullptr) { + fprintf(stderr, "Usage error: printDIMACS() must not be called with a null FILE pointer\n"); + abort(); + } + if (cnfConsumed) { fprintf(stderr, "Usage error: printDIMACS() must not be called after cnfConsumed()!\n"); abort(); From 1502e233715854c8835563b3f0d26fb7c84f49d3 Mon Sep 17 00:00:00 2001 From: Gus Smith Date: Fri, 6 Feb 2026 19:26:32 -0800 Subject: [PATCH 16/58] Set solver from scratchpad or command line --- kernel/satgen.h | 1 + passes/sat/sat.cc | 46 +++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/kernel/satgen.h b/kernel/satgen.h index 7815847b3..c53d20fe0 100644 --- a/kernel/satgen.h +++ b/kernel/satgen.h @@ -59,6 +59,7 @@ struct SatSolver struct ezSatPtr : public std::unique_ptr { ezSatPtr() : unique_ptr(yosys_satsolver->create()) { } + explicit ezSatPtr(SatSolver *solver) : unique_ptr((solver ? solver : yosys_satsolver)->create()) { } }; struct SatGen diff --git a/passes/sat/sat.cc b/passes/sat/sat.cc index bb7b9ee29..8a0a45dcf 100644 --- a/passes/sat/sat.cc +++ b/passes/sat/sat.cc @@ -31,6 +31,22 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN +static SatSolver *find_satsolver(const std::string &name) +{ + for (auto solver = yosys_satsolver_list; solver != nullptr; solver = solver->next) + if (solver->name == name) + return solver; + return nullptr; +} + +static std::string list_satsolvers() +{ + std::string result; + for (auto solver = yosys_satsolver_list; solver != nullptr; solver = solver->next) + result += result.empty() ? solver->name : ", " + solver->name; + return result; +} + struct SatHelper { RTLIL::Design *design; @@ -60,8 +76,8 @@ struct SatHelper int max_timestep, timeout; bool gotTimeout; - SatHelper(RTLIL::Design *design, RTLIL::Module *module, bool enable_undef, bool set_def_formal) : - design(design), module(module), sigmap(module), ct(design), satgen(ez.get(), &sigmap) + SatHelper(RTLIL::Design *design, RTLIL::Module *module, SatSolver *solver, bool enable_undef, bool set_def_formal) : + design(design), module(module), sigmap(module), ct(design), ez(solver), satgen(ez.get(), &sigmap) { this->enable_undef = enable_undef; satgen.model_undef = enable_undef; @@ -1066,6 +1082,10 @@ struct SatPass : public Pass { log(" -timeout \n"); log(" Maximum number of seconds a single SAT instance may take.\n"); log("\n"); + log(" -select-solver \n"); + log(" Select SAT solver implementation for this invocation.\n"); + log(" If not given, uses scratchpad key 'sat.solver' if set, otherwise default.\n"); + log("\n"); log(" -verify\n"); log(" Return an error and stop the synthesis script if the proof fails.\n"); log("\n"); @@ -1097,8 +1117,14 @@ struct SatPass : public Pass { log_header(design, "Executing SAT pass (solving SAT problems in the circuit).\n"); + std::string solver_name = design->scratchpad_get_string("sat.solver", ""); + size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { + if (args[argidx] == "-select-solver" && argidx+1 < args.size()) { + solver_name = args[++argidx]; + continue; + } if (args[argidx] == "-all") { loopcount = -1; continue; @@ -1336,6 +1362,14 @@ struct SatPass : public Pass { } extra_args(args, argidx, design); + SatSolver *solver = yosys_satsolver; + if (!solver_name.empty()) { + solver = find_satsolver(solver_name); + if (solver == nullptr) + log_cmd_error("Unknown SAT solver '%s'. Available solvers: %s\n", + solver_name, list_satsolvers()); + } + RTLIL::Module *module = NULL; for (auto mod : design->selected_modules()) { if (module) @@ -1398,13 +1432,15 @@ struct SatPass : public Pass { shows.push_back(wire->name.str()); } + log("Using SAT solver `%s`.\n", solver->name.c_str()); + if (tempinduct) { if (loopcount > 0 || max_undef) log_cmd_error("The options -max, -all, and -max_undef are not supported for temporal induction proofs!\n"); - SatHelper basecase(design, module, enable_undef, set_def_formal); - SatHelper inductstep(design, module, enable_undef, set_def_formal); + SatHelper basecase(design, module, solver, enable_undef, set_def_formal); + SatHelper inductstep(design, module, solver, enable_undef, set_def_formal); basecase.sets = sets; basecase.set_assumes = set_assumes; @@ -1593,7 +1629,7 @@ struct SatPass : public Pass { if (maxsteps > 0) log_cmd_error("The options -maxsteps is only supported for temporal induction proofs!\n"); - SatHelper sathelper(design, module, enable_undef, set_def_formal); + SatHelper sathelper(design, module, solver, enable_undef, set_def_formal); sathelper.sets = sets; sathelper.set_assumes = set_assumes; From b8ee50d77f92da71420186a9ab2918918b32b809 Mon Sep 17 00:00:00 2001 From: Rowan Goemans Date: Mon, 9 Feb 2026 14:13:40 +0100 Subject: [PATCH 17/58] kernel/celledges: cover more cell types --- kernel/celledges.cc | 144 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 136 insertions(+), 8 deletions(-) diff --git a/kernel/celledges.cc b/kernel/celledges.cc index c39ced95a..195d4b15b 100644 --- a/kernel/celledges.cc +++ b/kernel/celledges.cc @@ -112,6 +112,41 @@ void reduce_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) db->add_edge(cell, ID::A, i, ID::Y, 0, -1); } +void logic_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) +{ + int a_width = GetSize(cell->getPort(ID::A)); + int b_width = GetSize(cell->getPort(ID::B)); + + for (int i = 0; i < a_width; i++) + db->add_edge(cell, ID::A, i, ID::Y, 0, -1); + for (int i = 0; i < b_width; i++) + db->add_edge(cell, ID::B, i, ID::Y, 0, -1); +} + +void concat_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) +{ + int a_width = GetSize(cell->getPort(ID::A)); + int b_width = GetSize(cell->getPort(ID::B)); + + for (int i = 0; i < a_width; i++) + db->add_edge(cell, ID::A, i, ID::Y, i, -1); + for (int i = 0; i < b_width; i++) + db->add_edge(cell, ID::B, i, ID::Y, a_width + i, -1); +} + +void slice_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) +{ + int offset = cell->getParam(ID::OFFSET).as_int(); + int a_width = GetSize(cell->getPort(ID::A)); + int y_width = GetSize(cell->getPort(ID::Y)); + + for (int i = 0; i < y_width; i++) { + int a_bit = offset + i; + if (a_bit >= 0 && a_bit < a_width) + db->add_edge(cell, ID::A, a_bit, ID::Y, i, -1); + } +} + void compare_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) { int a_width = GetSize(cell->getPort(ID::A)); @@ -254,7 +289,7 @@ void shift_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) int skip = 1 << (k + 1); int base = skip -1; if (i % skip != base && i - a_width + 2 < 1 << b_width_capped) - db->add_edge(cell, ID::B, k, ID::Y, i, -1); + db->add_edge(cell, ID::B, k, ID::Y, i, -1); } else if (is_signed) { if (i - a_width + 2 < 1 << b_width_capped) db->add_edge(cell, ID::B, k, ID::Y, i, -1); @@ -388,6 +423,64 @@ void ff_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) db->add_edge(cell, ID::ARST, 0, ID::Q, k, -1); } +void full_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) +{ + std::vector input_ports; + std::vector output_ports; + + for (auto &conn : cell->connections()) + { + RTLIL::IdString port = conn.first; + RTLIL::PortDir dir = cell->port_dir(port); + if (cell->input(port) || dir == RTLIL::PortDir::PD_INOUT) + input_ports.push_back(port); + if (cell->output(port) || dir == RTLIL::PortDir::PD_INOUT) + output_ports.push_back(port); + } + + for (auto out_port : output_ports) + { + int out_width = GetSize(cell->getPort(out_port)); + for (int out_bit = 0; out_bit < out_width; out_bit++) + { + for (auto in_port : input_ports) + { + int in_width = GetSize(cell->getPort(in_port)); + for (int in_bit = 0; in_bit < in_width; in_bit++) + db->add_edge(cell, in_port, in_bit, out_port, out_bit, -1); + } + } + } +} + +void bweqx_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) +{ + int width = GetSize(cell->getPort(ID::Y)); + int a_width = GetSize(cell->getPort(ID::A)); + int b_width = GetSize(cell->getPort(ID::B)); + int max_width = std::min(width, std::min(a_width, b_width)); + + for (int i = 0; i < max_width; i++) { + db->add_edge(cell, ID::A, i, ID::Y, i, -1); + db->add_edge(cell, ID::B, i, ID::Y, i, -1); + } +} + +void bwmux_op(AbstractCellEdgesDatabase *db, RTLIL::Cell *cell) +{ + int width = GetSize(cell->getPort(ID::Y)); + int a_width = GetSize(cell->getPort(ID::A)); + int b_width = GetSize(cell->getPort(ID::B)); + int s_width = GetSize(cell->getPort(ID::S)); + int max_width = std::min(width, std::min(a_width, std::min(b_width, s_width))); + + for (int i = 0; i < max_width; i++) { + db->add_edge(cell, ID::A, i, ID::Y, i, -1); + db->add_edge(cell, ID::B, i, ID::Y, i, -1); + db->add_edge(cell, ID::S, i, ID::Y, i, -1); + } +} + PRIVATE_NAMESPACE_END bool YOSYS_NAMESPACE_PREFIX AbstractCellEdgesDatabase::add_edges_from_cell(RTLIL::Cell *cell) @@ -417,6 +510,21 @@ bool YOSYS_NAMESPACE_PREFIX AbstractCellEdgesDatabase::add_edges_from_cell(RTLIL return true; } + if (cell->type.in(ID($logic_and), ID($logic_or))) { + logic_op(this, cell); + return true; + } + + if (cell->type == ID($slice)) { + slice_op(this, cell); + return true; + } + + if (cell->type == ID($concat)) { + concat_op(this, cell); + return true; + } + if (cell->type.in(ID($shl), ID($shr), ID($sshl), ID($sshr), ID($shift), ID($shiftx))) { shift_op(this, cell); return true; @@ -442,6 +550,16 @@ bool YOSYS_NAMESPACE_PREFIX AbstractCellEdgesDatabase::add_edges_from_cell(RTLIL return true; } + if (cell->type == ID($bweqx)) { + bweqx_op(this, cell); + return true; + } + + if (cell->type == ID($bwmux)) { + bwmux_op(this, cell); + return true; + } + if (cell->type.in(ID($mem_v2), ID($memrd), ID($memrd_v2), ID($memwr), ID($memwr_v2), ID($meminit))) { mem_op(this, cell); return true; @@ -452,13 +570,24 @@ bool YOSYS_NAMESPACE_PREFIX AbstractCellEdgesDatabase::add_edges_from_cell(RTLIL return true; } - // FIXME: $mul $div $mod $divfloor $modfloor $slice $concat - // FIXME: $lut $sop $alu $lcu $macc $macc_v2 $fa - // FIXME: $mul $div $mod $divfloor $modfloor $pow $slice $concat $bweqx - // FIXME: $lut $sop $alu $lcu $macc $fa $logic_and $logic_or $bwmux + if (cell->type.in(ID($mul), ID($div), ID($mod), ID($divfloor), ID($modfloor), ID($pow))) { + full_op(this, cell); + return true; + } - // FIXME: $_BUF_ $_NOT_ $_AND_ $_NAND_ $_OR_ $_NOR_ $_XOR_ $_XNOR_ $_ANDNOT_ $_ORNOT_ - // FIXME: $_MUX_ $_NMUX_ $_MUX4_ $_MUX8_ $_MUX16_ $_AOI3_ $_OAI3_ $_AOI4_ $_OAI4_ + if (cell->type.in(ID($lut), ID($sop), ID($alu), ID($lcu), ID($macc), ID($macc_v2))) { + full_op(this, cell); + return true; + } + + if (cell->type.in( + ID($_BUF_), ID($_NOT_), ID($_AND_), ID($_NAND_), ID($_OR_), ID($_NOR_), + ID($_XOR_), ID($_XNOR_), ID($_ANDNOT_), ID($_ORNOT_), ID($_MUX_), ID($_NMUX_), + ID($_MUX4_), ID($_MUX8_), ID($_MUX16_), ID($_AOI3_), ID($_OAI3_), ID($_AOI4_), + ID($_OAI4_), ID($_TBUF_))) { + full_op(this, cell); + return true; + } // FIXME: $specify2 $specify3 $specrule ??? // FIXME: $equiv $set_tag $get_tag $overwrite_tag $original_tag @@ -468,4 +597,3 @@ bool YOSYS_NAMESPACE_PREFIX AbstractCellEdgesDatabase::add_edges_from_cell(RTLIL return false; } - From 6f6fa49d3cac7f2d379a162b0dc6dc3ea49faa54 Mon Sep 17 00:00:00 2001 From: Gus Smith Date: Mon, 9 Feb 2026 09:05:56 -0800 Subject: [PATCH 18/58] Typo --- passes/cmds/scratchpad.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/cmds/scratchpad.cc b/passes/cmds/scratchpad.cc index f64ce943c..24ab5cfd8 100644 --- a/passes/cmds/scratchpad.cc +++ b/passes/cmds/scratchpad.cc @@ -37,7 +37,7 @@ struct ScratchpadPass : public Pass { log("\n"); log(" scratchpad [options]\n"); log("\n"); - log("This pass allows to read and modify values from the scratchpad of the current\n"); + log("This pass allows reading and modifying values from the scratchpad of the current\n"); log("design. Options:\n"); log("\n"); log(" -get \n"); From b04948a8cdd2f13838f2472b7af4afa1ad516f6f Mon Sep 17 00:00:00 2001 From: Gus Smith Date: Mon, 9 Feb 2026 09:38:45 -0800 Subject: [PATCH 19/58] Simplify test --- tests/arch/xilinx/dsp_preadder_sub.ys | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/tests/arch/xilinx/dsp_preadder_sub.ys b/tests/arch/xilinx/dsp_preadder_sub.ys index 04e5e9da0..0e23ac373 100644 --- a/tests/arch/xilinx/dsp_preadder_sub.ys +++ b/tests/arch/xilinx/dsp_preadder_sub.ys @@ -1,23 +1,11 @@ read_verilog < Date: Mon, 9 Feb 2026 23:16:47 +0100 Subject: [PATCH 20/58] Makefile: test target requires unit-test, add vanilla-test for old test target --- .github/workflows/test-sanitizers.yml | 4 +- .github/workflows/test-verific.yml | 4 +- Makefile | 6 +- README.md | 4 +- .../extending_yosys/test_suites.rst | 55 +++++++++++++------ 5 files changed, 47 insertions(+), 26 deletions(-) diff --git a/.github/workflows/test-sanitizers.yml b/.github/workflows/test-sanitizers.yml index 11a339cd3..c6b3d8db0 100644 --- a/.github/workflows/test-sanitizers.yml +++ b/.github/workflows/test-sanitizers.yml @@ -65,7 +65,7 @@ jobs: - name: Run tests shell: bash run: | - make -j$procs test TARGETS= EXTRA_TARGETS= + make -j$procs vanilla-test TARGETS= EXTRA_TARGETS= - name: Report errors if: ${{ failure() }} @@ -76,4 +76,4 @@ jobs: - name: Run unit tests shell: bash run: | - make -j$procs unit-test ENABLE_LIBYOSYS=1 + make -j$procs unit-test diff --git a/.github/workflows/test-verific.yml b/.github/workflows/test-verific.yml index adc6f59d8..feba3c0f9 100644 --- a/.github/workflows/test-verific.yml +++ b/.github/workflows/test-verific.yml @@ -68,7 +68,7 @@ jobs: - name: Run Yosys tests run: | - make -j$procs test + make -j$procs vanilla-test - name: Run Verific specific Yosys tests run: | @@ -83,7 +83,7 @@ jobs: - name: Run unit tests shell: bash run: | - make -j$procs unit-test ENABLE_LTO=1 ENABLE_LIBYOSYS=1 + make -j$procs unit-test ENABLE_LTO=1 test-pyosys: needs: pre-job diff --git a/Makefile b/Makefile index 364e1ce8d..7ce3153df 100644 --- a/Makefile +++ b/Makefile @@ -977,9 +977,11 @@ makefile-tests/%: %/run-test.mk $(TARGETS) $(EXTRA_TARGETS) $(MAKE) -C $* -f run-test.mk +@echo "...passed tests in $*" -test: makefile-tests abcopt-tests seed-tests +test: vanilla-test unit-test + +vanilla-test: makefile-tests abcopt-tests seed-tests @echo "" - @echo " Passed \"make test\"." + @echo " Passed \"make vanilla-test\"." ifeq ($(ENABLE_VERIFIC),1) ifeq ($(YOSYS_NOVERIFIC),1) @echo " Ran tests without verific support due to YOSYS_NOVERIFIC=1." diff --git a/README.md b/README.md index 3b2f41768..df65a6a10 100644 --- a/README.md +++ b/README.md @@ -114,8 +114,8 @@ To build Yosys simply type 'make' in this directory. $ sudo make install Tests are located in the tests subdirectory and can be executed using the test -target. Note that you need gawk as well as a recent version of iverilog (i.e. -build from git). Then, execute tests via: +target. Note that you need gawk, a recent version of iverilog, and gtest. +Execute tests via: $ make test diff --git a/docs/source/yosys_internals/extending_yosys/test_suites.rst b/docs/source/yosys_internals/extending_yosys/test_suites.rst index 81a79e77f..c43dc3a84 100644 --- a/docs/source/yosys_internals/extending_yosys/test_suites.rst +++ b/docs/source/yosys_internals/extending_yosys/test_suites.rst @@ -8,7 +8,43 @@ 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. +the root Yosys directory. By default, this runs vanilla and unit tests. + +Vanilla tests +~~~~~~~~~~~~~ + +These make up the majority of our testing coverage. +They can be run with ``make vanilla-test`` and are based on calls to +make subcommands (``make makefile-tests``) and shell scripts +(``make seed-tests`` and ``make abcopt-tests``). Both use ``run-test.sh`` +files, but make-based tests only call ``tests/gen-tests-makefile.sh`` +to generate a makefile appropriate for the given directory, so only +afterwards when make is invoked do the tests actually run. + +Usually their structure looks something like this: +you write a .ys file that gets automatically run, +which runs a frontend like ``read_verilog`` or ``read_rtlil`` with +a relative path or a heredoc, then runs some commands including the command +under test, and then uses :doc:`/using_yosys/more_scripting/selections` +with ``-assert-count``. Usually it's unnecessary to "register" the test anywhere +as if it's similar to other tests it will be run together with the rest. + +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``. Functional tests ~~~~~~~~~~~~~~~~ @@ -41,23 +77,6 @@ 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 ~~~~~~~~~~ From a6e33d99161d9fe0be662b51de376bfa3227e311 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 10 Feb 2026 00:38:43 +0000 Subject: [PATCH 21/58] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 81f9e0652..d0ca321e3 100644 --- a/Makefile +++ b/Makefile @@ -161,7 +161,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.62+9 +YOSYS_VER := 0.62+14 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 030e495c8b617ba59b4cd01393f85448450c373a Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 10 Feb 2026 15:05:17 +1300 Subject: [PATCH 22/58] test-build: Build and cache libyosys.so --- .github/workflows/test-build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml index ab6eb3148..6cb60f1fd 100644 --- a/.github/workflows/test-build.yml +++ b/.github/workflows/test-build.yml @@ -71,7 +71,7 @@ jobs: mkdir build cd build make -f ../Makefile config-$CC - make -f ../Makefile -j$procs + make -f ../Makefile -j$procs ENABLE_LIBYOSYS=1 - name: Log yosys-config output run: | @@ -81,7 +81,7 @@ jobs: shell: bash run: | cd build - tar -cvf ../build.tar share/ yosys yosys-* + tar -cvf ../build.tar share/ yosys yosys-* libyosys.so - name: Store build artifact uses: actions/upload-artifact@v4 From 9f30f0e7d668f9caba7a53953152e4d981eadab8 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 10 Feb 2026 15:34:47 +1300 Subject: [PATCH 23/58] test-build: Don't rebuild OBJS --- .github/workflows/test-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml index 6cb60f1fd..a14234925 100644 --- a/.github/workflows/test-build.yml +++ b/.github/workflows/test-build.yml @@ -131,7 +131,7 @@ jobs: - name: Run tests shell: bash run: | - make -j$procs test TARGETS= EXTRA_TARGETS= CONFIG=$CC + make -j$procs test OBJS= TARGETS= EXTRA_TARGETS= CONFIG=$CC - name: Report errors if: ${{ failure() }} From dfbef2fe24715bb1f8d74a0d10941afad3de3327 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Wed, 11 Feb 2026 00:55:36 +0100 Subject: [PATCH 24/58] .github: run unit tests in build jobs, not test jobs --- .github/workflows/test-build.yml | 5 +++-- .github/workflows/test-sanitizers.yml | 4 ---- .github/workflows/test-verific.yml | 5 ----- 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml index a14234925..06eb8187c 100644 --- a/.github/workflows/test-build.yml +++ b/.github/workflows/test-build.yml @@ -71,7 +71,8 @@ jobs: mkdir build cd build make -f ../Makefile config-$CC - make -f ../Makefile -j$procs ENABLE_LIBYOSYS=1 + make -f ../Makefile -j$procs + make -f ../Makefile unit-test -j$procs - name: Log yosys-config output run: | @@ -219,7 +220,7 @@ jobs: - name: Run tests shell: bash run: | - make -C docs test -j$procs + make -C docs vanilla-test -j$procs test-docs-build: name: Try build docs diff --git a/.github/workflows/test-sanitizers.yml b/.github/workflows/test-sanitizers.yml index c6b3d8db0..7650470c3 100644 --- a/.github/workflows/test-sanitizers.yml +++ b/.github/workflows/test-sanitizers.yml @@ -73,7 +73,3 @@ jobs: run: | find tests/**/*.err -print -exec cat {} \; - - name: Run unit tests - shell: bash - run: | - make -j$procs unit-test diff --git a/.github/workflows/test-verific.yml b/.github/workflows/test-verific.yml index feba3c0f9..cd2545cc8 100644 --- a/.github/workflows/test-verific.yml +++ b/.github/workflows/test-verific.yml @@ -80,11 +80,6 @@ jobs: run: | make -C sby run_ci - - name: Run unit tests - shell: bash - run: | - make -j$procs unit-test ENABLE_LTO=1 - test-pyosys: needs: pre-job if: ${{ needs.pre-job.outputs.should_skip != 'true' && github.repository == 'YosysHQ/Yosys' }} From 98c3f03497938dc1f314aa6fd8768e3a71eb4eb9 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Wed, 11 Feb 2026 00:58:29 +0100 Subject: [PATCH 25/58] docs: clarify vanilla test run-test.sh --- docs/source/yosys_internals/extending_yosys/test_suites.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/source/yosys_internals/extending_yosys/test_suites.rst b/docs/source/yosys_internals/extending_yosys/test_suites.rst index c43dc3a84..d3422b23a 100644 --- a/docs/source/yosys_internals/extending_yosys/test_suites.rst +++ b/docs/source/yosys_internals/extending_yosys/test_suites.rst @@ -27,7 +27,8 @@ which runs a frontend like ``read_verilog`` or ``read_rtlil`` with a relative path or a heredoc, then runs some commands including the command under test, and then uses :doc:`/using_yosys/more_scripting/selections` with ``-assert-count``. Usually it's unnecessary to "register" the test anywhere -as if it's similar to other tests it will be run together with the rest. +as if it's being added to an existing directory, depending +on how the ``run-test.sh`` in that directory works. Unit tests ~~~~~~~~~~ From a6a07fb39c0f3e79aea7b543ffb2e36a04e887b3 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Wed, 11 Feb 2026 00:59:12 +0100 Subject: [PATCH 26/58] Dockerfile: remove --- Dockerfile | 58 ------------------------------------------------------ 1 file changed, 58 deletions(-) delete mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 9806696e0..000000000 --- a/Dockerfile +++ /dev/null @@ -1,58 +0,0 @@ -ARG IMAGE="python:3-slim-buster" - -#--- - -FROM $IMAGE AS base - -RUN apt-get update -qq \ - && DEBIAN_FRONTEND=noninteractive apt-get -y install --no-install-recommends \ - ca-certificates \ - clang \ - lld \ - curl \ - libffi-dev \ - libreadline-dev \ - tcl-dev \ - graphviz \ - xdot \ - && apt-get autoclean && apt-get clean && apt-get -y autoremove \ - && update-ca-certificates \ - && rm -rf /var/lib/apt/lists - -#--- - -FROM base AS build - -RUN apt-get update -qq \ - && DEBIAN_FRONTEND=noninteractive apt-get -y install --no-install-recommends \ - bison \ - flex \ - gawk \ - gcc \ - git \ - iverilog \ - pkg-config \ - && apt-get autoclean && apt-get clean && apt-get -y autoremove \ - && rm -rf /var/lib/apt/lists - -COPY . /yosys - -ENV PREFIX /opt/yosys - -RUN cd /yosys \ - && make \ - && make install \ - && make test - -#--- - -FROM base - -COPY --from=build /opt/yosys /opt/yosys - -ENV PATH /opt/yosys/bin:$PATH - -RUN useradd -m yosys -USER yosys - -CMD ["yosys"] From 5a46106a46a739fb4a4a164353349e6fb3077221 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Wed, 11 Feb 2026 01:04:50 +0100 Subject: [PATCH 27/58] abc9: remove -liberty --- passes/techmap/abc9.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 8b61a9299..138fa0aee 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -221,7 +221,7 @@ struct Abc9Pass : public ScriptPass if ((arg == "-exe" || arg == "-script" || arg == "-D" || /*arg == "-S" ||*/ arg == "-lut" || arg == "-luts" || /*arg == "-box" ||*/ arg == "-W" || arg == "-genlib" || - arg == "-constr" || arg == "-dont_use" || arg == "-liberty") && + arg == "-constr" || arg == "-dont_use") && argidx+1 < args.size()) { if (arg == "-lut" || arg == "-luts") lut_mode = true; From fe613f29b90337e1251ed2e038b78a4c299f967d Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Wed, 11 Feb 2026 11:33:27 +0100 Subject: [PATCH 28/58] .github: move gtest to build dependencies --- .github/actions/setup-build-env/action.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/actions/setup-build-env/action.yml b/.github/actions/setup-build-env/action.yml index 60fe481e7..3c5465a9b 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 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 libgtest-dev version: ${{ inputs.runs-on }}-buildys - name: Linux docs dependencies @@ -54,12 +54,12 @@ runs: # 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 - with: - packages: libgtest-dev - version: ${{ inputs.runs-on }}-testys + # - name: Linux test dependencies + # if: runner.os == 'Linux' && inputs.get-test-deps == 'true' + # uses: awalsh128/cache-apt-pkgs-action@v1.6.0 + # with: + # packages: + # version: ${{ inputs.runs-on }}-testys - name: Install macOS Dependencies if: runner.os == 'macOS' From c4094e457b5013d64c60342444c7cd204382c3c7 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Wed, 11 Feb 2026 11:34:54 +0100 Subject: [PATCH 29/58] abc9: remove -genlib, -constr --- passes/techmap/abc9.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 138fa0aee..7ed94617e 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -219,9 +219,8 @@ struct Abc9Pass : public ScriptPass for (argidx = 1; argidx < args.size(); argidx++) { std::string arg = args[argidx]; if ((arg == "-exe" || arg == "-script" || arg == "-D" || - /*arg == "-S" ||*/ arg == "-lut" || arg == "-luts" || - /*arg == "-box" ||*/ arg == "-W" || arg == "-genlib" || - arg == "-constr" || arg == "-dont_use") && + arg == "-lut" || arg == "-luts" || + arg == "-W" || arg == "-dont_use") && argidx+1 < args.size()) { if (arg == "-lut" || arg == "-luts") lut_mode = true; From 915912cc761cb5b059bcb823df1646424cf3b42a Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Wed, 11 Feb 2026 11:39:09 +0100 Subject: [PATCH 30/58] abc9: remove -dont_use --- passes/techmap/abc9.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/passes/techmap/abc9.cc b/passes/techmap/abc9.cc index 7ed94617e..16df82bb6 100644 --- a/passes/techmap/abc9.cc +++ b/passes/techmap/abc9.cc @@ -219,8 +219,7 @@ struct Abc9Pass : public ScriptPass for (argidx = 1; argidx < args.size(); argidx++) { std::string arg = args[argidx]; if ((arg == "-exe" || arg == "-script" || arg == "-D" || - arg == "-lut" || arg == "-luts" || - arg == "-W" || arg == "-dont_use") && + arg == "-lut" || arg == "-luts" || arg == "-W") && argidx+1 < args.size()) { if (arg == "-lut" || arg == "-luts") lut_mode = true; From 3f1fbfdaee9049c0c274e73032e09266d6a36525 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Wed, 11 Feb 2026 12:16:02 +0100 Subject: [PATCH 31/58] blifparse: add bounds check --- frontends/blif/blifparse.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/frontends/blif/blifparse.cc b/frontends/blif/blifparse.cc index 30512d324..350d7cafe 100644 --- a/frontends/blif/blifparse.cc +++ b/frontends/blif/blifparse.cc @@ -629,6 +629,7 @@ void parse_blif(RTLIL::Design *design, std::istream &f, IdString dff_name, bool goto try_next_value; } } + log_assert(i < lutptr->size()); lutptr->set(i, !strcmp(output, "0") ? RTLIL::State::S0 : RTLIL::State::S1); try_next_value:; } From 12ace45b89035e128ba41b10938ed2665ae30c2a Mon Sep 17 00:00:00 2001 From: Gus Smith Date: Wed, 22 Jun 2022 10:57:46 -0700 Subject: [PATCH 32/58] Support param. default values in JSON FE and SV BE --- abc | 2 +- backends/verilog/verilog_backend.cc | 11 +++++++++++ frontends/json/jsonparse.cc | 3 +++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/abc b/abc index 734f64d5b..799ba6322 160000 --- a/abc +++ b/abc @@ -1 +1 @@ -Subproject commit 734f64d5b907158dc4337ee82b3b74566d74ba08 +Subproject commit 799ba632239b2a4db2bacda81de4e6efdc486b0c diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index 3d451117c..b3029b051 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -421,6 +421,14 @@ void dump_attributes(std::ostream &f, std::string indent, dictattributes, "\n", /*modattr=*/false, /*regattr=*/reg_wires.count(wire->name)); @@ -2438,6 +2446,9 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module) f << indent + " " << "reg " << id(initial_id) << " = 0;\n"; } + for (auto p : module->parameter_default_values) + dump_parameter(f, indent + " ", p.first, p.second); + // first dump input / output according to their order in module->ports for (auto port : module->ports) dump_wire(f, indent + " ", module->wire(port)); diff --git a/frontends/json/jsonparse.cc b/frontends/json/jsonparse.cc index 743ac5d9e..803931f32 100644 --- a/frontends/json/jsonparse.cc +++ b/frontends/json/jsonparse.cc @@ -302,6 +302,9 @@ void json_import(Design *design, string &modname, JsonNode *node) if (node->data_dict.count("attributes")) json_parse_attr_param(module->attributes, node->data_dict.at("attributes")); + if (node->data_dict.count("parameter_default_values")) + json_parse_attr_param(module->parameter_default_values, node->data_dict.at("parameter_default_values")); + dict signal_bits; if (node->data_dict.count("ports")) From 9ad7aed4a53e3467a89808544a2ac8701c6a5c9f Mon Sep 17 00:00:00 2001 From: Gus Smith Date: Tue, 6 Jan 2026 09:37:13 -0800 Subject: [PATCH 33/58] Update backends/verilog/verilog_backend.cc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Marcelina Kościelnicka <236399+mwkmwkmwk@users.noreply.github.com> --- backends/verilog/verilog_backend.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index b3029b051..6284cdf33 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -426,7 +426,7 @@ void dump_parameter(std::ostream &f, std::string indent, RTLIL::IdString id_stri f << stringf("%sparameter %s", indent.c_str(), id(id_string).c_str()); f << stringf(" = "); dump_const(f, parameter); - f << stringf(";\n"); + f << ";\n"; } void dump_wire(std::ostream &f, std::string indent, RTLIL::Wire *wire) From 1ede98797f7eee220cba4fad695e41cdec05684e Mon Sep 17 00:00:00 2001 From: Gus Smith Date: Tue, 6 Jan 2026 09:37:21 -0800 Subject: [PATCH 34/58] Update backends/verilog/verilog_backend.cc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Marcelina Kościelnicka <236399+mwkmwkmwk@users.noreply.github.com> --- backends/verilog/verilog_backend.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index 6284cdf33..13f6acec4 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -423,8 +423,7 @@ void dump_attributes(std::ostream &f, std::string indent, dict Date: Tue, 6 Jan 2026 10:38:03 -0800 Subject: [PATCH 35/58] Add tests --- tests/various/json_param_defaults.v | 10 ++++++++++ tests/various/json_param_defaults.ys | 8 ++++++++ 2 files changed, 18 insertions(+) create mode 100644 tests/various/json_param_defaults.v create mode 100644 tests/various/json_param_defaults.ys diff --git a/tests/various/json_param_defaults.v b/tests/various/json_param_defaults.v new file mode 100644 index 000000000..7d3b94a68 --- /dev/null +++ b/tests/various/json_param_defaults.v @@ -0,0 +1,10 @@ +module json_param_defaults #( + parameter WIDTH = 8, + parameter SIGNED = 1 +) ( + input [WIDTH-1:0] a, + output [WIDTH-1:0] y +); + wire [WIDTH-1:0] y_int = a << SIGNED; + assign y = y_int; +endmodule diff --git a/tests/various/json_param_defaults.ys b/tests/various/json_param_defaults.ys new file mode 100644 index 000000000..2624ab884 --- /dev/null +++ b/tests/various/json_param_defaults.ys @@ -0,0 +1,8 @@ +! mkdir -p temp +read_verilog -sv json_param_defaults.v +write_json temp/json_param_defaults.json +design -reset +read_json temp/json_param_defaults.json +write_verilog -noattr temp/json_param_defaults.v +! grep -qF "parameter WIDTH = 32'd8" temp/json_param_defaults.v +! grep -qF "parameter SIGNED = 32'd1" temp/json_param_defaults.v From be9c857e7252751b77bc1548fdbde0f11906a1e8 Mon Sep 17 00:00:00 2001 From: Gus Smith Date: Wed, 11 Feb 2026 08:12:38 -0800 Subject: [PATCH 36/58] Fix ABC after merge --- abc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/abc b/abc index 799ba6322..734f64d5b 160000 --- a/abc +++ b/abc @@ -1 +1 @@ -Subproject commit 799ba632239b2a4db2bacda81de4e6efdc486b0c +Subproject commit 734f64d5b907158dc4337ee82b3b74566d74ba08 From a13b5c421108fd1dfe6cd1aff0070777a31c2ec5 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 11 Feb 2026 17:30:08 +0100 Subject: [PATCH 37/58] Update ABC as per 2026-02-11 --- abc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/abc b/abc index 734f64d5b..c18b835ef 160000 --- a/abc +++ b/abc @@ -1 +1 @@ -Subproject commit 734f64d5b907158dc4337ee82b3b74566d74ba08 +Subproject commit c18b835ef140217c84a26ba510f98f69d54dd48e From 7a0774c3bb200d8b5d3278c7c69f9e5d893af43c Mon Sep 17 00:00:00 2001 From: Gus Smith Date: Wed, 11 Feb 2026 08:33:39 -0800 Subject: [PATCH 38/58] Don't dump params by default --- backends/verilog/verilog_backend.cc | 17 ++++++++++++++--- tests/various/json_param_defaults.ys | 2 +- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index 13f6acec4..73ffcbf3e 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -95,7 +95,8 @@ bool VERILOG_BACKEND::id_is_verilog_escaped(const std::string &str) { PRIVATE_NAMESPACE_BEGIN -bool verbose, norename, noattr, attr2comment, noexpr, nodec, nohex, nostr, extmem, defparam, decimal, siminit, systemverilog, simple_lhs, noparallelcase; +bool verbose, norename, noattr, attr2comment, noexpr, nodec, nohex, nostr, extmem, defparam, decimal, siminit, systemverilog, simple_lhs, + noparallelcase, default_params; int auto_name_counter, auto_name_offset, auto_name_digits, extmem_counter; dict auto_name_map; std::set reg_wires; @@ -2445,8 +2446,9 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module) f << indent + " " << "reg " << id(initial_id) << " = 0;\n"; } - for (auto p : module->parameter_default_values) - dump_parameter(f, indent + " ", p.first, p.second); + if (default_params) + for (auto p : module->parameter_default_values) + dump_parameter(f, indent + " ", p.first, p.second); // first dump input / output according to their order in module->ports for (auto port : module->ports) @@ -2555,6 +2557,10 @@ struct VerilogBackend : public Backend { log(" use 'defparam' statements instead of the Verilog-2001 syntax for\n"); log(" cell parameters.\n"); log("\n"); + log(" -default_params\n"); + log(" emit module parameter declarations from\n"); + log(" parameter_default_values.\n"); + log("\n"); log(" -blackboxes\n"); log(" usually modules with the 'blackbox' attribute are ignored. with\n"); log(" this option set only the modules with the 'blackbox' attribute\n"); @@ -2592,6 +2598,7 @@ struct VerilogBackend : public Backend { siminit = false; simple_lhs = false; noparallelcase = false; + default_params = false; auto_prefix = ""; bool blackboxes = false; @@ -2652,6 +2659,10 @@ struct VerilogBackend : public Backend { defparam = true; continue; } + if (arg == "-defaultparams") { + default_params = true; + continue; + } if (arg == "-decimal") { decimal = true; continue; diff --git a/tests/various/json_param_defaults.ys b/tests/various/json_param_defaults.ys index 2624ab884..45e312de2 100644 --- a/tests/various/json_param_defaults.ys +++ b/tests/various/json_param_defaults.ys @@ -3,6 +3,6 @@ read_verilog -sv json_param_defaults.v write_json temp/json_param_defaults.json design -reset read_json temp/json_param_defaults.json -write_verilog -noattr temp/json_param_defaults.v +write_verilog -noattr -defaultparams temp/json_param_defaults.v ! grep -qF "parameter WIDTH = 32'd8" temp/json_param_defaults.v ! grep -qF "parameter SIGNED = 32'd1" temp/json_param_defaults.v From 1319112913c48983b8bbfb000f43b2715e148b7d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 12 Feb 2026 00:32:36 +0000 Subject: [PATCH 39/58] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 5bf66c1a9..02fe61004 100644 --- a/Makefile +++ b/Makefile @@ -161,7 +161,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.62+14 +YOSYS_VER := 0.62+39 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 5ea073d45e3988d6115616f56a82547b5befea7d Mon Sep 17 00:00:00 2001 From: Maxim Kudinov Date: Tue, 3 Feb 2026 19:04:31 +0300 Subject: [PATCH 40/58] gowin: format MULT instances --- techlibs/gowin/dsp_map.v | 76 ++++++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/techlibs/gowin/dsp_map.v b/techlibs/gowin/dsp_map.v index dfde0b6a1..f03bcdff0 100644 --- a/techlibs/gowin/dsp_map.v +++ b/techlibs/gowin/dsp_map.v @@ -6,20 +6,20 @@ module \$__MUL9X9 (input [8:0] A, input [8:0] B, output [17:0] Y); parameter A_SIGNED = 0; parameter B_SIGNED = 0; - MULT9X9 __TECHMAP_REPLACE__ ( - .CLK(1'b0), - .CE(1'b0), - .RESET(1'b0), - .A(A), - .SIA({A_WIDTH{1'b0}}), - .ASEL(1'b0), - .ASIGN(A_SIGNED ? 1'b1 : 1'b0), - .B(B), - .SIB({B_WIDTH{1'b0}}), - .BSEL(1'b0), - .BSIGN(B_SIGNED ? 1'b1 : 1'b0), - .DOUT(Y) - ); + MULT9X9 __TECHMAP_REPLACE__ ( + .CLK(1'b0), + .CE(1'b0), + .RESET(1'b0), + .A(A), + .SIA({A_WIDTH{1'b0}}), + .ASEL(1'b0), + .ASIGN(A_SIGNED ? 1'b1 : 1'b0), + .B(B), + .SIB({B_WIDTH{1'b0}}), + .BSEL(1'b0), + .BSIGN(B_SIGNED ? 1'b1 : 1'b0), + .DOUT(Y) + ); endmodule @@ -31,20 +31,20 @@ module \$__MUL18X18 (input [17:0] A, input [17:0] B, output [35:0] Y); parameter A_SIGNED = 0; parameter B_SIGNED = 0; - MULT18X18 __TECHMAP_REPLACE__ ( - .CLK(1'b0), - .CE(1'b0), - .RESET(1'b0), - .A(A), - .SIA({A_WIDTH{1'b0}}), - .ASEL(1'b0), - .ASIGN(A_SIGNED ? 1'b1 : 1'b0), - .B(B), - .SIB({B_WIDTH{1'b0}}), - .BSEL(1'b0), - .BSIGN(B_SIGNED ? 1'b1 : 1'b0), - .DOUT(Y) - ); + MULT18X18 __TECHMAP_REPLACE__ ( + .CLK(1'b0), + .CE(1'b0), + .RESET(1'b0), + .A(A), + .SIA({A_WIDTH{1'b0}}), + .ASEL(1'b0), + .ASIGN(A_SIGNED ? 1'b1 : 1'b0), + .B(B), + .SIB({B_WIDTH{1'b0}}), + .BSEL(1'b0), + .BSIGN(B_SIGNED ? 1'b1 : 1'b0), + .DOUT(Y) + ); endmodule @@ -56,15 +56,15 @@ module \$__MUL36X36 (input [35:0] A, input [35:0] B, output [71:0] Y); parameter A_SIGNED = 0; parameter B_SIGNED = 0; - MULT36X36 __TECHMAP_REPLACE__ ( - .CLK(1'b0), - .RESET(1'b0), - .CE(1'b0), - .A(A), - .ASIGN(A_SIGNED ? 1'b1 : 1'b0), - .B(B), - .BSIGN(B_SIGNED ? 1'b1 : 1'b0), - .DOUT(Y) - ); + MULT36X36 __TECHMAP_REPLACE__ ( + .CLK(1'b0), + .RESET(1'b0), + .CE(1'b0), + .A(A), + .ASIGN(A_SIGNED ? 1'b1 : 1'b0), + .B(B), + .BSIGN(B_SIGNED ? 1'b1 : 1'b0), + .DOUT(Y) + ); endmodule From 542b29fa6a1fe52631d15b7c29632d7532f0acd9 Mon Sep 17 00:00:00 2001 From: Maxim Kudinov Date: Tue, 3 Feb 2026 19:55:47 +0300 Subject: [PATCH 41/58] gowin: synth_gowin: Merge flatten label with coarse --- techlibs/gowin/synth_gowin.cc | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/techlibs/gowin/synth_gowin.cc b/techlibs/gowin/synth_gowin.cc index 9cc213945..2bf21cbc9 100644 --- a/techlibs/gowin/synth_gowin.cc +++ b/techlibs/gowin/synth_gowin.cc @@ -254,17 +254,13 @@ struct SynthGowinPass : public ScriptPass run(stringf("hierarchy -check %s", help_mode ? "-top " : top_opt)); } - if (flatten && check_label("flatten", "(unless -noflatten)")) - { - run("proc"); - run("flatten"); - run("tribuf -logic"); - run("deminout"); - } - if (check_label("coarse")) { run("proc"); + if (flatten || help_mode) + run("flatten", "(unless -noflatten)"); + run("tribuf -logic"); + run("deminout"); run("opt_expr"); run("opt_clean"); run("check"); From 5b94a97fb37787aa34a4808abd3df9de0842583b Mon Sep 17 00:00:00 2001 From: Maxim Kudinov Date: Thu, 12 Feb 2026 13:57:34 +0300 Subject: [PATCH 42/58] gowin: synth_gowin: Add -nodsp option --- techlibs/gowin/synth_gowin.cc | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/techlibs/gowin/synth_gowin.cc b/techlibs/gowin/synth_gowin.cc index 2bf21cbc9..cdc7d20f0 100644 --- a/techlibs/gowin/synth_gowin.cc +++ b/techlibs/gowin/synth_gowin.cc @@ -112,13 +112,16 @@ struct SynthGowinPass : public ScriptPass log(" -setundef\n"); log(" set undriven wires and parameters to zero\n"); log("\n"); + log(" -nodsp\n"); + log(" do not infer DSP multipliers\n"); + log("\n"); log("The following commands are executed by this synthesis command:\n"); help_script(); log("\n"); } string top_opt, vout_file, json_file, family; - bool retime, nobram, nolutram, flatten, nodffe, strict_gw5a_dffs, nowidelut, abc9, noiopads, noalu, no_rw_check, setundef; + bool retime, nobram, nolutram, flatten, nodffe, strict_gw5a_dffs, nowidelut, abc9, noiopads, noalu, no_rw_check, setundef, nodsp; void clear_flags() override { @@ -138,6 +141,7 @@ struct SynthGowinPass : public ScriptPass noalu = false; no_rw_check = false; setundef = false; + nodsp = false; } void execute(std::vector args, RTLIL::Design *design) override @@ -224,6 +228,10 @@ struct SynthGowinPass : public ScriptPass setundef = true; continue; } + if (args[argidx] == "-nodsp") { + nodsp = true; + continue; + } break; } extra_args(args, argidx, design); @@ -273,9 +281,9 @@ struct SynthGowinPass : public ScriptPass run("share"); if (help_mode) { - run("techmap -map +/mul2dsp.v [...]", "(if -family gw1n or gw2a)"); - run("techmap -map +/gowin/dsp_map.v", "(if -family gw1n or gw2a)"); - } else if (family == "gw1n" || family == "gw2a") { + run("techmap -map +/mul2dsp.v [...]", "(unless -nodsp and if -family gw1n or gw2a)"); + run("techmap -map +/gowin/dsp_map.v", "(unless -nodsp and if -family gw1n or gw2a)"); + } else if (!nodsp && (family == "gw1n" || family == "gw2a")) { for (const auto &rule : dsp_rules) { run(stringf("techmap -map +/mul2dsp.v -D DSP_A_MAXWIDTH=%d -D DSP_B_MAXWIDTH=%d -D DSP_A_MINWIDTH=%d -D DSP_B_MINWIDTH=%d -D DSP_NAME=%s", rule.a_maxwidth, rule.b_maxwidth, rule.a_minwidth, rule.b_minwidth, rule.prim)); From b055ea05fd314a6a928f0c2e3f777d6e8bf5f7d8 Mon Sep 17 00:00:00 2001 From: Maxim Kudinov Date: Thu, 12 Feb 2026 14:12:32 +0300 Subject: [PATCH 43/58] gowin: dsp: Add mult inference tests --- tests/arch/gowin/mul_gw1n.ys | 53 ++++++++++++++++++++++++++++++++++++ tests/arch/gowin/mul_gw2a.ys | 53 ++++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 tests/arch/gowin/mul_gw1n.ys create mode 100644 tests/arch/gowin/mul_gw2a.ys diff --git a/tests/arch/gowin/mul_gw1n.ys b/tests/arch/gowin/mul_gw1n.ys new file mode 100644 index 000000000..9b1748255 --- /dev/null +++ b/tests/arch/gowin/mul_gw1n.ys @@ -0,0 +1,53 @@ +read_verilog ../common/mul.v +chparam -set X_WIDTH 8 -set Y_WIDTH 8 -set A_WIDTH 16 +hierarchy -top top +proc +# equivalence checking is somewhat slow (and missing simulation models) +synth_gowin -family gw1n +cd top # Constrain all select calls below inside the top module +select -assert-count 1 t:MULT9X9 + + +# Make sure that DSPs are not inferred with -nodsp option +design -reset +read_verilog ../common/mul.v +chparam -set X_WIDTH 8 -set Y_WIDTH 8 -set A_WIDTH 16 +hierarchy -top top +proc +synth_gowin -family gw1n -nodsp +cd top # Constrain all select calls below inside the top module +select -assert-none t:MULT9X9 + + +design -reset +read_verilog ../common/mul.v +chparam -set X_WIDTH 16 -set Y_WIDTH 16 -set A_WIDTH 32 +hierarchy -top top +proc +synth_gowin -family gw1n +cd top # Constrain all select calls below inside the top module +select -assert-count 1 t:MULT18X18 + + +design -reset +read_verilog ../common/mul.v +chparam -set X_WIDTH 32 -set Y_WIDTH 32 -set A_WIDTH 64 +hierarchy -top top +proc +# equivalence checking is too slow here +synth_gowin +cd top # Constrain all select calls below inside the top module +select -assert-count 1 t:MULT36X36 + + +# We end up with two 18x18 multipliers +# 36x36 min width is 22 +design -reset +read_verilog ../common/mul.v +chparam -set X_WIDTH 32 -set Y_WIDTH 16 -set A_WIDTH 48 +hierarchy -top top +proc +# equivalence checking is too slow here +synth_gowin +cd top # Constrain all select calls below inside the top module +select -assert-count 2 t:MULT18X18 diff --git a/tests/arch/gowin/mul_gw2a.ys b/tests/arch/gowin/mul_gw2a.ys new file mode 100644 index 000000000..895c580b7 --- /dev/null +++ b/tests/arch/gowin/mul_gw2a.ys @@ -0,0 +1,53 @@ +read_verilog ../common/mul.v +chparam -set X_WIDTH 8 -set Y_WIDTH 8 -set A_WIDTH 16 +hierarchy -top top +proc +# equivalence checking is somewhat slow (and missing simulation models) +synth_gowin -family gw2a +cd top # Constrain all select calls below inside the top module +select -assert-count 1 t:MULT9X9 + + +# Make sure that DSPs are not inferred with -nodsp option +design -reset +read_verilog ../common/mul.v +chparam -set X_WIDTH 8 -set Y_WIDTH 8 -set A_WIDTH 16 +hierarchy -top top +proc +synth_gowin -family gw2a -nodsp +cd top # Constrain all select calls below inside the top module +select -assert-none t:MULT9X9 + + +design -reset +read_verilog ../common/mul.v +chparam -set X_WIDTH 16 -set Y_WIDTH 16 -set A_WIDTH 32 +hierarchy -top top +proc +synth_gowin -family gw2a +cd top # Constrain all select calls below inside the top module +select -assert-count 1 t:MULT18X18 + + +design -reset +read_verilog ../common/mul.v +chparam -set X_WIDTH 32 -set Y_WIDTH 32 -set A_WIDTH 64 +hierarchy -top top +proc +# equivalence checking is too slow here +synth_gowin -family gw2a +cd top # Constrain all select calls below inside the top module +select -assert-count 1 t:MULT36X36 + + +# We end up with two 18x18 multipliers +# 36x36 min width is 22 +design -reset +read_verilog ../common/mul.v +chparam -set X_WIDTH 32 -set Y_WIDTH 16 -set A_WIDTH 48 +hierarchy -top top +proc +# equivalence checking is too slow here +synth_gowin -family gw2a +cd top # Constrain all select calls below inside the top module +select -assert-count 2 t:MULT18X18 From cc79c6a76173622aa75d1d8c1f2c206b601e24c2 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Thu, 12 Feb 2026 12:17:07 +0100 Subject: [PATCH 44/58] Support building out of tree, but keep always in tests/unit --- Makefile | 4 ++-- tests/unit/Makefile | 9 +++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 7ce3153df..f20e63078 100644 --- a/Makefile +++ b/Makefile @@ -1013,11 +1013,11 @@ ystests: $(TARGETS) $(EXTRA_TARGETS) # Unit test unit-test: libyosys.so - @$(MAKE) -C $(UNITESTPATH) CXX="$(CXX)" CC="$(CC)" CPPFLAGS="$(CPPFLAGS)" \ + @$(MAKE) -f $(UNITESTPATH)/Makefile CXX="$(CXX)" CC="$(CC)" CPPFLAGS="$(CPPFLAGS)" \ CXXFLAGS="$(CXXFLAGS)" LINKFLAGS="$(LINKFLAGS)" LIBS="$(LIBS)" ROOTPATH="$(CURDIR)" clean-unit-test: - @$(MAKE) -C $(UNITESTPATH) clean + @$(MAKE) -f $(UNITESTPATH)/Makefile clean install-dev: $(PROGRAM_PREFIX)yosys-config share $(INSTALL_SUDO) mkdir -p $(DESTDIR)$(BINDIR) diff --git a/tests/unit/Makefile b/tests/unit/Makefile index b275d7f41..e8f76cba9 100644 --- a/tests/unit/Makefile +++ b/tests/unit/Makefile @@ -18,10 +18,11 @@ endif EXTRAFLAGS := -lyosys -pthread -OBJTEST := objtest -BINTEST := bintest +MAKEFILE_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) +OBJTEST := $(MAKEFILE_DIR)objtest +BINTEST := $(MAKEFILE_DIR)bintest -ALLTESTFILE := $(shell find . -name '*Test.cc' | sed 's|^\./||' | tr '\n' ' ') +ALLTESTFILE := $(shell cd $(MAKEFILE_DIR) && find . -name '*Test.cc' | sed 's|^\./||' | tr '\n' ' ') TESTDIRS := $(sort $(dir $(ALLTESTFILE))) TESTS := $(addprefix $(BINTEST)/, $(basename $(ALLTESTFILE:%Test.cc=%Test.o))) @@ -34,7 +35,7 @@ $(BINTEST)/%: $(OBJTEST)/%.o | prepare $(CXX) -L$(ROOTPATH) $(RPATH) $(LINKFLAGS) -o $@ $^ $(LIBS) \ $(GTEST_LDFLAGS) $(EXTRAFLAGS) -$(OBJTEST)/%.o: $(basename $(subst $(OBJTEST),.,%)).cc | prepare +$(OBJTEST)/%.o: $(MAKEFILE_DIR)/%.cc | prepare $(CXX) -o $@ -c -I$(ROOTPATH) $(CPPFLAGS) $(CXXFLAGS) $(GTEST_CXXFLAGS) $^ .PHONY: prepare run-tests clean From c6e48f4bea903c08a99b4f5f6b91f30652155786 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Thu, 12 Feb 2026 14:06:08 +0100 Subject: [PATCH 45/58] These are tests from other Makefile --- .github/workflows/test-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml index 06eb8187c..2a870cd29 100644 --- a/.github/workflows/test-build.yml +++ b/.github/workflows/test-build.yml @@ -220,7 +220,7 @@ jobs: - name: Run tests shell: bash run: | - make -C docs vanilla-test -j$procs + make -C docs test -j$procs test-docs-build: name: Try build docs From e5b3e9fc1f43c3c3e09ae0d4b143528a213cb1c9 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Thu, 12 Feb 2026 14:08:49 +0100 Subject: [PATCH 46/58] This one should run only vanilla-tests --- .github/workflows/test-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml index 2a870cd29..4f14e149c 100644 --- a/.github/workflows/test-build.yml +++ b/.github/workflows/test-build.yml @@ -132,7 +132,7 @@ jobs: - name: Run tests shell: bash run: | - make -j$procs test OBJS= TARGETS= EXTRA_TARGETS= CONFIG=$CC + make -j$procs vanilla-test OBJS= TARGETS= EXTRA_TARGETS= CONFIG=$CC - name: Report errors if: ${{ failure() }} From bb7aa7d208921fd8c1f438335822d661fe8e01ad Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Thu, 12 Feb 2026 14:56:45 +0100 Subject: [PATCH 47/58] Cleanup of yml files --- .github/actions/setup-build-env/action.yml | 9 --------- .github/workflows/test-build.yml | 2 +- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/.github/actions/setup-build-env/action.yml b/.github/actions/setup-build-env/action.yml index 3c5465a9b..c9dc5fc22 100644 --- a/.github/actions/setup-build-env/action.yml +++ b/.github/actions/setup-build-env/action.yml @@ -52,15 +52,6 @@ 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 - # with: - # packages: - # version: ${{ inputs.runs-on }}-testys - - name: Install macOS Dependencies if: runner.os == 'macOS' shell: bash diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml index 4f14e149c..ebdeb15d8 100644 --- a/.github/workflows/test-build.yml +++ b/.github/workflows/test-build.yml @@ -132,7 +132,7 @@ jobs: - name: Run tests shell: bash run: | - make -j$procs vanilla-test OBJS= TARGETS= EXTRA_TARGETS= CONFIG=$CC + make -j$procs vanilla-test TARGETS= EXTRA_TARGETS= CONFIG=$CC - name: Report errors if: ${{ failure() }} From e2f0c4d9a04dcc2b2e5667471635073db6102517 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 13 Feb 2026 00:35:27 +0000 Subject: [PATCH 48/58] Bump version --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 02fe61004..0f76cdbef 100644 --- a/Makefile +++ b/Makefile @@ -161,7 +161,7 @@ ifeq ($(OS), Haiku) CXXFLAGS += -D_DEFAULT_SOURCE endif -YOSYS_VER := 0.62+39 +YOSYS_VER := 0.62+55 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 e81b5b810d35c156280d0c649291ce5617e10fb3 Mon Sep 17 00:00:00 2001 From: Akash Levy Date: Fri, 13 Feb 2026 01:04:59 -0800 Subject: [PATCH 49/58] Lack of node retention should only be a warning --- passes/techmap/abc.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index 66f6e76db..46bdcfc92 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -1485,7 +1485,7 @@ void AbcModuleState::extract(AbcSigMap &assign_map, dict & } wire->add_strpool_attribute(ID::src, src_pool); } else if (run_abc.config.abc_node_retention) { - log_error("No node retention sources found for wire %s\n", w->name.c_str()); + log_warning("No node retention sources found for wire %s\n", w->name.c_str()); } if (markgroups) wire->attributes[ID::abcgroup] = map_autoidx; From b8d83c1d5bd2048a1dd65ec204ed506e28d23711 Mon Sep 17 00:00:00 2001 From: Akash Levy Date: Fri, 13 Feb 2026 01:05:51 -0800 Subject: [PATCH 50/58] Fix cell naming issues --- kernel/ffmerge.cc | 4 ++-- kernel/ffmerge.h | 2 +- kernel/rtlil.cc | 4 ++-- passes/memory/memory_dff.cc | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/kernel/ffmerge.cc b/kernel/ffmerge.cc index 709549e4d..1547e9c37 100644 --- a/kernel/ffmerge.cc +++ b/kernel/ffmerge.cc @@ -156,8 +156,8 @@ bool FfMergeHelper::find_output_ff(RTLIL::SigSpec sig, FfData &ff, pool> &bits) { - ff = FfData(module, initvals, NEW_ID); +bool FfMergeHelper::find_input_ff(RTLIL::SigSpec sig, FfData &ff, pool> &bits, RTLIL::IdString name) { + ff = FfData(module, initvals, name); sigmap->apply(sig); bool found = false; diff --git a/kernel/ffmerge.h b/kernel/ffmerge.h index 028987503..5c904c5ff 100644 --- a/kernel/ffmerge.h +++ b/kernel/ffmerge.h @@ -110,7 +110,7 @@ struct FfMergeHelper // a constant-input FF bit (with matching initial value and reset value). // However, this will not work if the input is all-constant — if the caller // cares about this case, it needs to check for it explicitely. - bool find_input_ff(RTLIL::SigSpec sig, FfData &ff, pool> &bits); + bool find_input_ff(RTLIL::SigSpec sig, FfData &ff, pool> &bits, RTLIL::IdString name); // To be called on find_output_ff result that will be merged. This // marks the given FF bits as used up (and not to be considered for diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index d27eabc25..79908bb54 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -3489,7 +3489,7 @@ DEF_METHOD(Shiftx, sig_a.size(), ID($shiftx)) } \ RTLIL::SigSpec RTLIL::Module::_func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const std::string &src) { \ Module *module = this; \ - RTLIL::SigSpec sig_y = addWire(!_pmux ? NEW_ID : NEW_ID4_SUFFIX("y"), sig_a.size()); \ + RTLIL::SigSpec sig_y = addWire(NEW_ID4_SUFFIX("y"), sig_a.size()); \ add ## _func(name, sig_a, sig_b, sig_s, sig_y, src); \ return sig_y; \ } // SILIMATE: Improve the naming (NOT IMPROVED FOR MUX!) @@ -3579,7 +3579,7 @@ DEF_METHOD(Bweqx, ID($bweqx)) } \ RTLIL::SigBit RTLIL::Module::_func(RTLIL::IdString name, const RTLIL::SigBit &sig1, const RTLIL::SigBit &sig2, const RTLIL::SigBit &sig3, const std::string &src) { \ Module *module = this; \ - RTLIL::SigBit sig4 = addWire(_mux ? NEW_ID : NEW_ID4_SUFFIX(#_P4)); \ + RTLIL::SigBit sig4 = addWire(NEW_ID4_SUFFIX(#_P4)); \ add ## _func(name, sig1, sig2, sig3, sig4, src); \ return sig4; \ } // SILIMATE: Improve the naming (NOT IMPROVED AT ALL!) diff --git a/passes/memory/memory_dff.cc b/passes/memory/memory_dff.cc index 5b8f6a1db..9cd0f7bbf 100644 --- a/passes/memory/memory_dff.cc +++ b/passes/memory/memory_dff.cc @@ -558,7 +558,7 @@ struct MemoryDffWorker FfData ff; pool> bits; - if (!merger.find_input_ff(port.addr, ff, bits)) { + if (!merger.find_input_ff(port.addr, ff, bits, mem.memid)) { log("no address FF found.\n"); return; } From 04855766323d64c92a2ac3d2f9e1f3712b1398ef Mon Sep 17 00:00:00 2001 From: Akash Levy Date: Fri, 13 Feb 2026 04:14:14 -0800 Subject: [PATCH 51/58] Revert rtlil changes --- kernel/rtlil.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 79908bb54..d27eabc25 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -3489,7 +3489,7 @@ DEF_METHOD(Shiftx, sig_a.size(), ID($shiftx)) } \ RTLIL::SigSpec RTLIL::Module::_func(RTLIL::IdString name, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_b, const RTLIL::SigSpec &sig_s, const std::string &src) { \ Module *module = this; \ - RTLIL::SigSpec sig_y = addWire(NEW_ID4_SUFFIX("y"), sig_a.size()); \ + RTLIL::SigSpec sig_y = addWire(!_pmux ? NEW_ID : NEW_ID4_SUFFIX("y"), sig_a.size()); \ add ## _func(name, sig_a, sig_b, sig_s, sig_y, src); \ return sig_y; \ } // SILIMATE: Improve the naming (NOT IMPROVED FOR MUX!) @@ -3579,7 +3579,7 @@ DEF_METHOD(Bweqx, ID($bweqx)) } \ RTLIL::SigBit RTLIL::Module::_func(RTLIL::IdString name, const RTLIL::SigBit &sig1, const RTLIL::SigBit &sig2, const RTLIL::SigBit &sig3, const std::string &src) { \ Module *module = this; \ - RTLIL::SigBit sig4 = addWire(NEW_ID4_SUFFIX(#_P4)); \ + RTLIL::SigBit sig4 = addWire(_mux ? NEW_ID : NEW_ID4_SUFFIX(#_P4)); \ add ## _func(name, sig1, sig2, sig3, sig4, src); \ return sig4; \ } // SILIMATE: Improve the naming (NOT IMPROVED AT ALL!) From 5debd619e5634a3e29eb53de21948fd7dcaee485 Mon Sep 17 00:00:00 2001 From: Akash Levy Date: Fri, 13 Feb 2026 06:51:42 -0800 Subject: [PATCH 52/58] Add workaround for Liberty duplication --- kernel/rtlil.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index d27eabc25..baf938660 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -1346,8 +1346,10 @@ void RTLIL::Design::add(RTLIL::Binding *binding) RTLIL::Module *RTLIL::Design::addModule(RTLIL::IdString name) { - if (modules_.count(name) != 0) - log_error("Attempted to add new module named '%s', but a module by that name already exists\n", name); + if (modules_.count(name) != 0) { + log_warning("Attempted to add new module named '%s', but a module by that name already exists\n", name); + return modules_.at(name); + } log_assert(refcount_modules_ == 0); RTLIL::Module *module = new RTLIL::Module; From c04975b78c288ba50b125cc48a6e5d8e99ce3ead Mon Sep 17 00:00:00 2001 From: Akash Levy Date: Tue, 17 Feb 2026 20:41:29 -0800 Subject: [PATCH 53/58] Remove custom mux opt_exprs --- passes/opt/opt_expr.cc | 40 ---------------------------------------- 1 file changed, 40 deletions(-) diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc index 00837fa48..41927ecf0 100644 --- a/passes/opt/opt_expr.cc +++ b/passes/opt/opt_expr.cc @@ -1484,26 +1484,6 @@ skip_identity: goto next_cell; } - if (consume_x && mux_bool && (cell->type == ID($_MUX_) || (cell->type == ID($mux) && cell->parameters[ID::WIDTH] == 1)) && cell->getPort(ID::A) == State::S1) { - log_debug("Replacing %s cell `%s' in module `%s' with or-gate and not-gate.\n", log_id(cell->type), log_id(cell), log_id(module)); - cell->setPort(ID::A, module->Not(NEW_ID2_SUFFIX("not"), cell->getPort(ID::S), false, cell->get_src_attribute())); - cell->unsetPort(ID::S); - if (cell->type == ID($mux)) { - Const width = cell->parameters[ID::WIDTH]; - cell->parameters[ID::A_WIDTH] = width; - cell->parameters[ID::B_WIDTH] = width; - cell->parameters[ID::Y_WIDTH] = width; - cell->parameters[ID::A_SIGNED] = 0; - cell->parameters[ID::B_SIGNED] = 0; - cell->parameters.erase(ID::WIDTH); - cell->type = ID($or); - } else - cell->type = ID($_OR_); - module->rename(cell, NEW_ID2_SUFFIX("ornot")); - did_something = true; - goto next_cell; - } - if (consume_x && mux_bool && cell->type.in(ID($mux), ID($_MUX_)) && cell->getPort(ID::B) == State::S1) { log_debug("Replacing %s cell `%s' in module `%s' with or-gate.\n", log_id(cell->type), log_id(cell), log_id(module)); cell->setPort(ID::B, cell->getPort(ID::S)); @@ -1523,26 +1503,6 @@ skip_identity: goto next_cell; } - if (consume_x && mux_bool && cell->type.in(ID($mux), ID($_MUX_)) && cell->getPort(ID::B) == State::S0) { - log_debug("Replacing %s cell `%s' in module `%s' with and-gate and not-gate.\n", log_id(cell->type), log_id(cell), log_id(module)); - cell->setPort(ID::B, module->Not(NEW_ID2_SUFFIX("not"), cell->getPort(ID::S), false, cell->get_src_attribute())); - cell->unsetPort(ID::S); - if (cell->type == ID($mux)) { - Const width = cell->parameters[ID::WIDTH]; - cell->parameters[ID::A_WIDTH] = width; - cell->parameters[ID::B_WIDTH] = width; - cell->parameters[ID::Y_WIDTH] = width; - cell->parameters[ID::A_SIGNED] = 0; - cell->parameters[ID::B_SIGNED] = 0; - cell->parameters.erase(ID::WIDTH); - cell->type = ID($and); - } else - cell->type = ID($_AND_); - module->rename(cell, NEW_ID2_SUFFIX("andnot")); - did_something = true; - goto next_cell; - } - if (mux_undef && cell->type.in(ID($mux), ID($pmux))) { RTLIL::SigSpec new_a, new_b, new_s; int width = GetSize(cell->getPort(ID::A)); From 650c636d3955a00b783541a6f030e1cc9155f379 Mon Sep 17 00:00:00 2001 From: Akash Levy Date: Wed, 18 Feb 2026 01:12:35 -0800 Subject: [PATCH 54/58] Fixups --- tests/memlib/generate.py | 8 +- tests/silimate/mux_andnot.ys | 222 ----------------------------------- tests/silimate/mux_ornot.ys | 222 ----------------------------------- tests/unit/Makefile | 3 +- 4 files changed, 6 insertions(+), 449 deletions(-) delete mode 100644 tests/silimate/mux_andnot.ys delete mode 100644 tests/silimate/mux_ornot.ys diff --git a/tests/memlib/generate.py b/tests/memlib/generate.py index c52114aeb..46eff6b43 100644 --- a/tests/memlib/generate.py +++ b/tests/memlib/generate.py @@ -1428,7 +1428,7 @@ endmodule for (testname, reset_gate, rdwr, clk_en, add_logic) in [ ("no_reset", "", "old", False, 0), ("gclken", "rst", "old", False, 0), - ("ungated", "ungated", "old", False, 2), # muxes wren with rst + ("ungated", "ungated", "old", False, 1), # muxes wren with rst ("gclken_ce", "rst", "old", True, 3), # AND to simulate CLK_EN ("grden", "rden && rst", "old", False, 1), # selects _clken, simulates _rden ("grden_ce", "rden && rst", "old", True, 4), # both of the above @@ -1473,9 +1473,9 @@ end""" for (testname, reset_gate, defs, rdwr, add_logic) in [ ("wr_byte", "", ["USE_SRST_BLOCKING"], "old", 0), ("trans_byte", "", ["USE_SRST_BLOCKING"], "new", 0), - ("wr_rst_byte", "rst", ["USE_SRST"], "old", 3), # expected mux to emulate blocking - ("rst_wr_byte", "rst", ["USE_SRST_BLOCKING"], "old", 3), # should use hardware blocking, doesn't - ("rdenrst_wr_byte", "rden && rst", ["USE_SRST"], "old", 4), + ("wr_rst_byte", "rst", ["USE_SRST"], "old", 2), # expected mux to emulate blocking + ("rst_wr_byte", "rst", ["USE_SRST_BLOCKING"], "old", 2), # should use hardware blocking, doesn't + ("rdenrst_wr_byte", "rden && rst", ["USE_SRST"], "old", 3), ]: wordsloop = "for (i=0; i /dev/null 2>&1; then echo "python3-config --embed"; else echo "python3-config"; fi) +EXTRAFLAGS := -lyosys -pthread $(shell $(PYTHON_CONFIG) --ldflags --libs) MAKEFILE_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) OBJTEST := $(MAKEFILE_DIR)objtest From 5769cdbea80f7a13da89f16fedd9bab750b6449b Mon Sep 17 00:00:00 2001 From: AdvaySingh1 Date: Wed, 18 Feb 2026 16:03:34 -0800 Subject: [PATCH 55/58] Added node retention --- passes/techmap/clockgate.cc | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/passes/techmap/clockgate.cc b/passes/techmap/clockgate.cc index 58b7520ac..01ab2e771 100644 --- a/passes/techmap/clockgate.cc +++ b/passes/techmap/clockgate.cc @@ -222,6 +222,8 @@ struct ClockgatePass : public Pass { log(" Intended for DFT scan-enable pins.\n"); log(" -min_net_size \n"); log(" Only transform sets of at least eligible FFs.\n"); + log(" -max_src \n"); + log(" Maximum number of src attributes to copy to ICG cells (default: unlimited).\n"); log(" \n"); } @@ -252,6 +254,12 @@ struct ClockgatePass : public Pass { int net_size; // After ICG generation, we have new gated CLK signals Wire* new_net; + // The ICG cell created for this clock net + Cell* icg_cell = nullptr; + // The CE inverter cell (if pol_ce is negative) + Cell* ce_not_cell = nullptr; + // Count of src attributes added + int src_count = 0; }; ClkNetInfo clk_info_from_ff(FfData& ff) { @@ -270,6 +278,7 @@ struct ClockgatePass : public Pass { std::vector liberty_files; std::vector dont_use_cells; int min_net_size = 0; + int max_src = -1; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { @@ -301,6 +310,10 @@ struct ClockgatePass : public Pass { min_net_size = atoi(args[++argidx].c_str()); continue; } + if (args[argidx] == "-max_src" && argidx+1 < args.size()) { + max_src = atoi(args[++argidx].c_str()); + continue; + } break; } @@ -374,14 +387,19 @@ struct ClockgatePass : public Pass { icg->setPort(matching_icg_desc->ce_pin, clk.ce_bit); icg->setPort(matching_icg_desc->clk_in_pin, clk.clk_bit); gclk.new_net = module->addWire(NEW_ID2_SUFFIX("gclk")); + gclk.icg_cell = icg; icg->setPort(matching_icg_desc->clk_out_pin, gclk.new_net); // Tie low DFT ports like scan chain enable for (auto port : matching_icg_desc->tie_lo_pins) icg->setPort(port, Const(0, 1)); // Fix CE polarity if needed if (!clk.pol_ce) { - SigBit ce_fixed_pol = module->NotGate(NEW_ID2_SUFFIX("ce_not"), clk.ce_bit); - icg->setPort(matching_icg_desc->ce_pin, ce_fixed_pol); + Wire *ce_not_wire = module->addWire(NEW_ID2_SUFFIX("ce_not_w")); + Cell *ce_not = module->addCell(NEW_ID2_SUFFIX("ce_not"), ID($_NOT_)); + ce_not->setPort(ID::A, clk.ce_bit); + ce_not->setPort(ID::Y, ce_not_wire); + gclk.ce_not_cell = ce_not; + icg->setPort(matching_icg_desc->ce_pin, ce_not_wire); } } @@ -393,6 +411,14 @@ struct ClockgatePass : public Pass { if (!it->second.new_net) continue; + + // Accumulate src attributes from all FFs sharing this ICG + if (max_src < 0 || it->second.src_count < max_src) { + it->second.icg_cell->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + if (it->second.ce_not_cell) + it->second.ce_not_cell->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + it->second.src_count++; + } log_debug("Fix up FF %s\n", cell->name); // Now we start messing with the design @@ -416,3 +442,4 @@ struct ClockgatePass : public Pass { PRIVATE_NAMESPACE_END + From 3e9a5c68b136fb073d0cdd186ffe8002becfd465 Mon Sep 17 00:00:00 2001 From: Akash Levy Date: Wed, 18 Feb 2026 21:57:14 -0800 Subject: [PATCH 56/58] Switch back to main Verific without VHDL support --- Makefile | 2 +- tests/verific/README.md | 2 ++ tests/verific/import_warning_operator.ys | 5 ----- tests/verific/{mixed_flist.ys => mixed_flist.ys.DISABLED} | 0 verific | 2 +- 5 files changed, 4 insertions(+), 7 deletions(-) delete mode 100644 tests/verific/import_warning_operator.ys rename tests/verific/{mixed_flist.ys => mixed_flist.ys.DISABLED} (100%) diff --git a/Makefile b/Makefile index 88b9c6c1c..81e39cd43 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ ENABLE_GHDL := 0 ENABLE_SLANG := 0 ENABLE_VERIFIC := 1 ENABLE_VERIFIC_SYSTEMVERILOG := 1 -ENABLE_VERIFIC_VHDL := 1 +ENABLE_VERIFIC_VHDL := 0 ENABLE_VERIFIC_HIER_TREE := 1 ENABLE_VERIFIC_SILIMATE_EXTENSIONS := 1 ENABLE_VERIFIC_YOSYSHQ_EXTENSIONS := 0 diff --git a/tests/verific/README.md b/tests/verific/README.md index aa4ce6ca1..a8d28f270 100644 --- a/tests/verific/README.md +++ b/tests/verific/README.md @@ -2,6 +2,8 @@ ## Disabled +- `import_warning_operator`: no VHDL +- `mixed_flist`: no VHDL - `memory_semantics`: relies on initial values being retained, which we do not want - `rom_case`: we need different behavior for multi-port memories - `blackbox*`: we need different behavior for parametrized blackboxes diff --git a/tests/verific/import_warning_operator.ys b/tests/verific/import_warning_operator.ys deleted file mode 100644 index 1ecd6d296..000000000 --- a/tests/verific/import_warning_operator.ys +++ /dev/null @@ -1,5 +0,0 @@ -logger -expect warning "import_warning_operator.vhd:[0-9]+.[0-9]+-[0-9]+.[0-9]+: Unsupported Verific operator: nor_4 \(fallback to gate level implementation provided by verific\)" 1 -verific -vhdl import_warning_operator.vhd -verific -import top -logger -check-expected -design -reset diff --git a/tests/verific/mixed_flist.ys b/tests/verific/mixed_flist.ys.DISABLED similarity index 100% rename from tests/verific/mixed_flist.ys rename to tests/verific/mixed_flist.ys.DISABLED diff --git a/verific b/verific index 01ad443c3..4feaf1f92 160000 --- a/verific +++ b/verific @@ -1 +1 @@ -Subproject commit 01ad443c3fff2a92c9473b69291ac32ef788683a +Subproject commit 4feaf1f923157af0ed064eab8e302647bd5fa1b7 From bf4ce9d6f729ef5d42e07c6e13eef9b06053418b Mon Sep 17 00:00:00 2001 From: Akash Levy Date: Thu, 19 Feb 2026 00:24:32 -0800 Subject: [PATCH 57/58] Import uniquify fix --- frontends/verific/verific.cc | 10 ++++++++-- frontends/verific/verific.h | 2 ++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 9a5ffc767..05b24fe7c 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -257,12 +257,16 @@ bool is_blackbox(Netlist *nl) RTLIL::IdString VerificImporter::new_verific_id(Verific::DesignObj *obj) { - return module->uniquify(RTLIL::escape_id(obj->Name())); + RTLIL::IdString base = RTLIL::escape_id(obj->Name()); + int &idx = uniquify_cache[base]; + return module->uniquify(base, idx); } RTLIL::IdString VerificImporter::new_verific_id_suffix(RTLIL::IdString id, const char *suffix) { - return module->uniquify(stringf("%s_%s", id, suffix)); + RTLIL::IdString base = stringf("%s_%s", id, suffix); + int &idx = uniquify_cache[base]; + return module->uniquify(base, idx); } static const RTLIL::Const extract_vhdl_boolean(std::string &val) @@ -1549,6 +1553,8 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma module->name = module_name; design->add(module); + uniquify_cache.clear(); + if (is_blackbox(nl)) { log("Importing blackbox module %s.\n", RTLIL::id2cstr(module->name)); log_flush(); diff --git a/frontends/verific/verific.h b/frontends/verific/verific.h index 3d7e9c241..2c00e2414 100644 --- a/frontends/verific/verific.h +++ b/frontends/verific/verific.h @@ -80,6 +80,8 @@ struct VerificImporter bool mode_gates, mode_keep, mode_nosva, mode_sva_continue, mode_names, mode_verific; bool mode_autocover, mode_fullinit; + dict uniquify_cache; + int num_sva_continue = 0; VerificImporter(bool mode_gates, bool mode_keep, bool mode_nosva, bool mode_sva_continue, bool mode_names, bool mode_verific, bool mode_autocover, bool mode_fullinit); From 723ddd74cf752598db5d4eb41bdb3fe808a45c07 Mon Sep 17 00:00:00 2001 From: Akash Levy Date: Thu, 19 Feb 2026 01:03:26 -0800 Subject: [PATCH 58/58] Improve wreduce runtime --- passes/opt/wreduce.cc | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc index 2e42873e6..b0f9202f5 100644 --- a/passes/opt/wreduce.cc +++ b/passes/opt/wreduce.cc @@ -462,7 +462,7 @@ struct WreduceWorker return count; } - void run_wire(Wire *w, pool complete_wires) + void run_wire(Wire *w, const pool &complete_wires) { int unused_top_bits = 0; @@ -482,7 +482,7 @@ struct WreduceWorker if (unused_top_bits == 0 || unused_top_bits == GetSize(w)) return; - if (complete_wires[mi.sigmap(w).extract(0, GetSize(w) - unused_top_bits)]) + if (complete_wires.count(mi.sigmap(w).extract(0, GetSize(w) - unused_top_bits))) return; log_debug("Removed top %d bits (of %d) from wire %s.%s.\n", unused_top_bits, GetSize(w), log_id(module), log_id(w)); @@ -512,21 +512,25 @@ struct WreduceWorker keep_bits.insert(bit); } - while (!work_queue_cells.empty() && !work_queue_wires.empty()) + while (!work_queue_cells.empty() || !work_queue_wires.empty()) { - // Initialize complete wires - pool complete_wires; - for (auto w : module->wires()) - complete_wires.insert(mi.sigmap(w)); - // Run cells work_queue_bits.clear(); for (auto c : work_queue_cells) run_cell(c); // Run wires - for (auto w : work_queue_wires) - run_wire(w, complete_wires); + if (!work_queue_wires.empty()) { + pool complete_wires; + for (auto w : module->wires()) + complete_wires.insert(mi.sigmap(w)); + for (auto w : work_queue_wires) + run_wire(w, complete_wires); + } + + // Skip reload if nothing changed + if (work_queue_bits.empty()) + break; // Get next batch of cells to process work_queue_cells.clear(); @@ -541,8 +545,9 @@ struct WreduceWorker if (bit.wire != NULL && module->selected(bit.wire)) work_queue_wires.insert(bit.wire); - // Reload module - mi.reload_module(); + // Reload module only if there is more work to do + if (!work_queue_cells.empty() || !work_queue_wires.empty()) + mi.reload_module(); } } };