From fb864e91ee7ba47cc52a38024c353acec156b78a Mon Sep 17 00:00:00 2001 From: Natalia Date: Wed, 14 Jan 2026 17:35:45 -0800 Subject: [PATCH] Add Design::run_pass() API for programmatic pass execution This commit adds a new run_pass() method to the RTLIL::Design class, providing a convenient API for executing Yosys passes programmatically. This is particularly useful for PyYosys users who want to run passes on a design object without needing to manually construct Pass::call() invocations. The method wraps Pass::call() with appropriate logging to maintain consistency with command-line pass execution. Example usage (from Python): design = ys.Design() # ... build or load design ... design.run_pass("hierarchy") design.run_pass("proc") design.run_pass("opt") Changes: - kernel/rtlil.h: Add run_pass() method declaration - kernel/rtlil.cc: Implement run_pass() method - tests/unit/kernel/test_design_run_pass.cc: Add unit tests --- kernel/rtlil.cc | 7 +++ kernel/rtlil.h | 3 ++ tests/unit/kernel/test_design_run_pass.cc | 59 +++++++++++++++++++++++ 3 files changed, 69 insertions(+) create mode 100644 tests/unit/kernel/test_design_run_pass.cc diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 0103cabfb..357ac2c5a 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -1610,6 +1610,13 @@ std::vector RTLIL::Design::selected_modules(RTLIL::SelectPartial return result; } +void RTLIL::Design::run_pass(std::string command) +{ + log("\n-- Running command `%s' --\n", command.c_str()); + Pass::call(this, command); + log_flush(); +} + RTLIL::Module::Module() { static unsigned int hashidx_count = 123456789; diff --git a/kernel/rtlil.h b/kernel/rtlil.h index fe280c965..532aa20b4 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -2031,6 +2031,9 @@ struct RTLIL::Design // returns all selected unboxed whole modules, warning the user if any // partially selected or boxed modules have been ignored std::vector selected_unboxed_whole_modules_warn() const { return selected_modules(SELECT_WHOLE_WARN, SB_UNBOXED_WARN); } + + void run_pass(std::string command); + static std::map *get_all_designs(void); std::string to_rtlil_str(bool only_selected = true) const; diff --git a/tests/unit/kernel/test_design_run_pass.cc b/tests/unit/kernel/test_design_run_pass.cc new file mode 100644 index 000000000..0553f4eb2 --- /dev/null +++ b/tests/unit/kernel/test_design_run_pass.cc @@ -0,0 +1,59 @@ +#include +#include "kernel/rtlil.h" +#include "kernel/register.h" + +YOSYS_NAMESPACE_BEGIN + +class DesignRunPassTest : public testing::Test { +protected: + DesignRunPassTest() { + if (log_files.empty()) log_files.emplace_back(stdout); + } + virtual void SetUp() override { + IdString::ensure_prepopulated(); + } +}; + +TEST_F(DesignRunPassTest, RunPassExecutesSuccessfully) +{ + // Create a design with a simple module + RTLIL::Design *design = new RTLIL::Design; + RTLIL::Module *module = new RTLIL::Module; + module->name = RTLIL::IdString("\\test_module"); + design->add(module); + + // Add a simple wire to the module + RTLIL::Wire *wire = module->addWire(RTLIL::IdString("\\test_wire"), 1); + wire->port_input = true; + wire->port_id = 1; + module->fixup_ports(); + + // Call run_pass with a simple pass + // We use "check" which is a simple pass that just validates the design + ASSERT_NO_THROW(design->run_pass("check")); + + // Verify the design still exists and has the module + EXPECT_EQ(design->modules().size(), 1); + EXPECT_NE(design->module(RTLIL::IdString("\\test_module")), nullptr); + + delete design; +} + +TEST_F(DesignRunPassTest, RunPassWithHierarchy) +{ + // Create a design with a simple module + RTLIL::Design *design = new RTLIL::Design; + RTLIL::Module *module = new RTLIL::Module; + module->name = RTLIL::IdString("\\top"); + design->add(module); + + // Call run_pass with hierarchy pass + ASSERT_NO_THROW(design->run_pass("hierarchy")); + + // Verify the design still has the module + EXPECT_EQ(design->modules().size(), 1); + + delete design; +} + +YOSYS_NAMESPACE_END