Python Passes can now be added with the -m option or with the plugin command. There...
authorBenedikt Tutzer <e1225461@student.tuwien.ac.at>
Thu, 16 Aug 2018 14:00:11 +0000 (16:00 +0200)
committerBenedikt Tutzer <e1225461@student.tuwien.ac.at>
Thu, 16 Aug 2018 14:00:11 +0000 (16:00 +0200)
Makefile
kernel/python_wrappers.cc
kernel/yosys.cc
kernel/yosys.h
passes/cmds/plugin.cc

index 691f43798815ff50e23f6bb4c28ab872b5507ad6..6466bddf2c1d31b9f92e9a2bfce400125aff596a 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -23,7 +23,7 @@ PYTHON_VERSION := 3.5
 
 # other configuration flags
 ENABLE_GPROF := 0
-ENABLE_DEBUG := 0
+ENABLE_DEBUG := 1
 ENABLE_NDEBUG := 0
 LINK_CURSES := 0
 LINK_TERMCAP := 0
index 18b0010aeb24a1afee12a32c21ef7ff48339cb16..197be08537998b6ef2abd7ad44bfcd3f1b765cf6 100644 (file)
@@ -34,6 +34,11 @@ namespace YOSYS_PYTHON {
                Yosys::run_pass(command);
        }
 
+       void log(std::string text)
+       {
+               Yosys::log(text.c_str());
+       }
+
        struct IdString
        {
                Yosys::RTLIL::IdString* ref_obj;
@@ -1388,7 +1393,7 @@ namespace YOSYS_PYTHON {
         virtual void py_notify_connect_tuple(Module *module, boost::python::tuple sigsig){};
         virtual void py_notify_connect_list(Module* module, boost::python::list sigsig_list){};
         virtual void py_notify_blackout(Module*){};
-        };
+    };
 
     struct MonitorWrap : Monitor, boost::python::wrapper<Monitor>
     {
@@ -1471,6 +1476,59 @@ namespace YOSYS_PYTHON {
         }
     };
 
+    struct PyPass : public Yosys::Pass
+    {
+               PyPass(std::string name, std::string short_help) : Yosys::Pass(name, short_help) { }
+       
+               virtual void execute(vector<string> args, Yosys::RTLIL::Design* d)  YS_OVERRIDE
+               {
+                       boost::python::list py_args;
+            for(auto arg : args)
+                py_args.append(arg);
+                       py_execute(py_args, new Design(d));
+               }
+
+               virtual void help() YS_OVERRIDE
+               {
+                       py_help();
+               }
+
+               virtual void py_execute(boost::python::list args, Design* d){}
+               virtual void py_help(){}
+    };
+
+    struct PassWrap : PyPass, boost::python::wrapper<PyPass>
+    {
+
+               PassWrap(std::string name, std::string short_help) : PyPass(name, short_help) { }
+       
+               void py_execute(boost::python::list args, Design* d)
+               {
+            if(boost::python::override py_execute = this->get_override("py_execute"))
+                py_execute(args, d);
+            else
+                PyPass::py_execute(args, d);
+               }
+
+               void default_py_execute(boost::python::list args, Design* d)
+               {
+                       this->PyPass::py_execute(args, d);
+               }
+
+               void py_help()
+               {
+            if(boost::python::override py_help = this->get_override("py_help"))
+                py_help();
+            else
+                PyPass::py_help();
+               }
+
+               void default_py_help()
+               {
+                       this->PyPass::py_help();
+               }
+    };
+
        void Module::register_monitor(Monitor* const m)
        {
                Yosys::RTLIL::Module* cpp_module = this->get_cpp_obj();
@@ -2778,6 +2836,11 @@ namespace YOSYS_PYTHON {
                    .def("py_notify_blackout", &Monitor::py_notify_blackout, &MonitorWrap::default_py_notify_blackout)
                    ;
 
+               class_<PassWrap, boost::noncopyable>("Pass", init<std::string, std::string>())
+                   .def("py_execute", &PyPass::py_execute, &PassWrap::default_py_execute)
+                   .def("py_help", &PyPass::py_help, &PassWrap::default_py_help)
+                   ;
+
                class_<Initializer>("Initializer");
                scope().attr("_hidden") = new Initializer();
 
@@ -3099,6 +3162,7 @@ namespace YOSYS_PYTHON {
                def("const_neg", const_neg);
 
                def("run",run);
+               def("log",log);
 
        }
 
index 750a154e633654cacc1ed9e6749c1842de56ddb3..8e16ba01df6c9275559a60e2e511d6e3723068de 100644 (file)
@@ -469,21 +469,40 @@ int GetSize(RTLIL::Wire *wire)
        return wire->width;
 }
 
+bool already_setup = false;
+
 void yosys_setup()
 {
+       if(already_setup)
+               return;
+       already_setup = true;
        // if there are already IdString objects then we have a global initialization order bug
        IdString empty_id;
        log_assert(empty_id.index_ == 0);
        IdString::get_reference(empty_id.index_);
 
+       #ifdef WITH_PYTHON
+               Py_Initialize();
+               PyRun_SimpleString("import sys");
+               PyRun_SimpleString("sys.path.append(\"./\")");
+               //PyRun_SimpleString("import libyosys");
+               //PyRun_SimpleString("sys.path.append(\"./plugins\")");
+               //PyRun_SimpleString(("sys.path.append(\""+proc_share_dirname()+"plugins\")").c_str());
+       #endif
+
        Pass::init_register();
        yosys_design = new RTLIL::Design;
        yosys_celltypes.setup();
        log_push();
 }
 
+bool already_shutdown = false;
+
 void yosys_shutdown()
 {
+       if(already_shutdown)
+               return;
+       already_shutdown = true;
        log_pop();
 
        delete yosys_design;
@@ -511,9 +530,16 @@ void yosys_shutdown()
                dlclose(it.second);
 
        loaded_plugins.clear();
+#ifdef WITH_PYTHON
+       loaded_python_plugins.clear();
+#endif
        loaded_plugin_aliases.clear();
 #endif
 
+#ifdef WITH_PYTHON
+       Py_Finalize();
+#endif
+
        IdString empty_id;
        IdString::put_reference(empty_id.index_);
 }
index 14cbcd610111a5d42e5e88ab4e019edfa6ff94b7..4380a5b6962822c9ec6a0f8bcbb3b9540d7ae158 100644 (file)
@@ -66,6 +66,8 @@
 #include <stdio.h>
 #include <limits.h>
 
+#include <Python.h>
+
 #ifndef _YOSYS_
 #  error It looks like you are trying to build Yosys without the config defines set. \
          When building Yosys with a custom make system, make sure you set all the \
@@ -317,6 +319,9 @@ extern std::vector<RTLIL::Design*> pushed_designs;
 
 // from passes/cmds/pluginc.cc
 extern std::map<std::string, void*> loaded_plugins;
+#ifdef WITH_PYTHON
+extern std::map<std::string, void*> loaded_python_plugins;
+#endif
 extern std::map<std::string, std::string> loaded_plugin_aliases;
 void load_plugin(std::string filename, std::vector<std::string> aliases);
 
index 828c671de69dca27a7ca71153fea7ec6f96925fe..b5d22a84ae44f78c7e5b12edd72d6fd6111bfb9f 100644 (file)
 #  include <dlfcn.h>
 #endif
 
+#ifdef WITH_PYTHON
+#  include <boost/algorithm/string/predicate.hpp>
+#  include <Python.h>
+#endif
+
 YOSYS_NAMESPACE_BEGIN
 
 std::map<std::string, void*> loaded_plugins;
+#ifdef WITH_PYTHON
+std::map<std::string, void*> loaded_python_plugins;
+#endif
 std::map<std::string, std::string> loaded_plugin_aliases;
 
 #ifdef YOSYS_ENABLE_PLUGINS
@@ -37,6 +45,48 @@ void load_plugin(std::string filename, std::vector<std::string> aliases)
                filename = "./" + filename;
 
        if (!loaded_plugins.count(filename)) {
+
+               #ifdef WITH_PYTHON
+               if(boost::algorithm::ends_with(filename, ".py"))
+               {
+                       int last_slash = filename.find('/');
+                       filename = filename.substr(last_slash+1, filename.size());
+                       filename = filename.substr(0,filename.size()-3);
+                       PyObject *filename_p = PyUnicode_FromString(filename.c_str());//filename.c_str());
+                       if(filename_p == NULL)
+                       {
+                               log_cmd_error("Issues converting `%s' to Python\n", filename.c_str());
+                               return;
+                       }
+                       PyObject *module_p = PyImport_Import(filename_p);
+                       if(module_p == NULL)
+                       {
+                               log_cmd_error("Can't load python module `%s'\n", filename.c_str());
+                               return;
+                       }/*
+                       PyObject *dict_p = PyModule_GetDict(module_p);
+                       if(dict_p == NULL)
+                       {
+                               log_cmd_error("Can't load dictionary from module `%s'\n", filename.c_str());
+                               return;
+                       }
+                       PyObject *func_p = PyDict_GetItemString(dict_p, "test");
+                       if(module_p == NULL)
+                       {
+                               log_cmd_error("Module `%s' does not contain test function\n", filename.c_str());
+                               return;
+                       }
+                       PyObject *args_p = PyTuple_New(0);
+                       PyObject *result_p = PyObject_CallObject(func_p, args_p);
+                       if(result_p == NULL)
+                                       printf("Calling test failed\n");
+                       printf("Loaded Python module\n");
+                       */
+                       loaded_python_plugins[orig_filename] = module_p;
+                       Pass::init_register();
+               } else {
+               #endif
+
                void *hdl = dlopen(filename.c_str(), RTLD_LAZY|RTLD_LOCAL);
                if (hdl == NULL && orig_filename.find('/') == std::string::npos)
                        hdl = dlopen((proc_share_dirname() + "plugins/" + orig_filename + ".so").c_str(), RTLD_LAZY|RTLD_LOCAL);
@@ -44,6 +94,10 @@ void load_plugin(std::string filename, std::vector<std::string> aliases)
                        log_cmd_error("Can't load module `%s': %s\n", filename.c_str(), dlerror());
                loaded_plugins[orig_filename] = hdl;
                Pass::init_register();
+
+               #ifdef WITH_PYTHON
+               }
+               #endif
        }
 
        for (auto &alias : aliases)
@@ -107,7 +161,11 @@ struct PluginPass : public Pass {
                if (list_mode)
                {
                        log("\n");
+#ifdef WITH_PYTHON
+                       if (loaded_plugins.empty() and loaded_python_plugins.empty())
+#else
                        if (loaded_plugins.empty())
+#endif
                                log("No plugins loaded.\n");
                        else
                                log("Loaded plugins:\n");
@@ -115,6 +173,11 @@ struct PluginPass : public Pass {
                        for (auto &it : loaded_plugins)
                                log("  %s\n", it.first.c_str());
 
+#ifdef WITH_PYTHON
+                       for (auto &it : loaded_python_plugins)
+                               log("  %s\n", it.first.c_str());
+#endif
+
                        if (!loaded_plugin_aliases.empty()) {
                                log("\n");
                                int max_alias_len = 1;