mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-31 19:52:31 +00:00 
			
		
		
		
	Python Passes can now be added with the -m option or with the plugin command. There are still issues when run in shell mode, but they can be used just fine in a python script
This commit is contained in:
		
							parent
							
								
									bf7b73acfc
								
							
						
					
					
						commit
						d79a2808cf
					
				
					 5 changed files with 160 additions and 2 deletions
				
			
		
							
								
								
									
										2
									
								
								Makefile
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								Makefile
									
										
									
									
									
								
							|  | @ -23,7 +23,7 @@ PYTHON_VERSION := 3.5 | ||||||
| 
 | 
 | ||||||
| # other configuration flags
 | # other configuration flags
 | ||||||
| ENABLE_GPROF := 0 | ENABLE_GPROF := 0 | ||||||
| ENABLE_DEBUG := 0 | ENABLE_DEBUG := 1 | ||||||
| ENABLE_NDEBUG := 0 | ENABLE_NDEBUG := 0 | ||||||
| LINK_CURSES := 0 | LINK_CURSES := 0 | ||||||
| LINK_TERMCAP := 0 | LINK_TERMCAP := 0 | ||||||
|  |  | ||||||
|  | @ -34,6 +34,11 @@ namespace YOSYS_PYTHON { | ||||||
| 		Yosys::run_pass(command); | 		Yosys::run_pass(command); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	void log(std::string text) | ||||||
|  | 	{ | ||||||
|  | 		Yosys::log(text.c_str()); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	struct IdString | 	struct IdString | ||||||
| 	{ | 	{ | ||||||
| 		Yosys::RTLIL::IdString* ref_obj; | 		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_tuple(Module *module, boost::python::tuple sigsig){}; | ||||||
|         virtual void py_notify_connect_list(Module* module, boost::python::list sigsig_list){}; |         virtual void py_notify_connect_list(Module* module, boost::python::list sigsig_list){}; | ||||||
|         virtual void py_notify_blackout(Module*){}; |         virtual void py_notify_blackout(Module*){}; | ||||||
|         }; |     }; | ||||||
| 
 | 
 | ||||||
|     struct MonitorWrap : Monitor, boost::python::wrapper<Monitor> |     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) | 	void Module::register_monitor(Monitor* const m) | ||||||
| 	{ | 	{ | ||||||
| 		Yosys::RTLIL::Module* cpp_module = this->get_cpp_obj(); | 		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) | 		    .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"); | 		class_<Initializer>("Initializer"); | ||||||
| 		scope().attr("_hidden") = new Initializer(); | 		scope().attr("_hidden") = new Initializer(); | ||||||
| 
 | 
 | ||||||
|  | @ -3099,6 +3162,7 @@ namespace YOSYS_PYTHON { | ||||||
| 		def("const_neg", const_neg); | 		def("const_neg", const_neg); | ||||||
| 
 | 
 | ||||||
| 		def("run",run); | 		def("run",run); | ||||||
|  | 		def("log",log); | ||||||
| 
 | 
 | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -469,21 +469,40 @@ int GetSize(RTLIL::Wire *wire) | ||||||
| 	return wire->width; | 	return wire->width; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | bool already_setup = false; | ||||||
|  | 
 | ||||||
| void yosys_setup() | void yosys_setup() | ||||||
| { | { | ||||||
|  | 	if(already_setup) | ||||||
|  | 		return; | ||||||
|  | 	already_setup = true; | ||||||
| 	// if there are already IdString objects then we have a global initialization order bug
 | 	// if there are already IdString objects then we have a global initialization order bug
 | ||||||
| 	IdString empty_id; | 	IdString empty_id; | ||||||
| 	log_assert(empty_id.index_ == 0); | 	log_assert(empty_id.index_ == 0); | ||||||
| 	IdString::get_reference(empty_id.index_); | 	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(); | 	Pass::init_register(); | ||||||
| 	yosys_design = new RTLIL::Design; | 	yosys_design = new RTLIL::Design; | ||||||
| 	yosys_celltypes.setup(); | 	yosys_celltypes.setup(); | ||||||
| 	log_push(); | 	log_push(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | bool already_shutdown = false; | ||||||
|  | 
 | ||||||
| void yosys_shutdown() | void yosys_shutdown() | ||||||
| { | { | ||||||
|  | 	if(already_shutdown) | ||||||
|  | 		return; | ||||||
|  | 	already_shutdown = true; | ||||||
| 	log_pop(); | 	log_pop(); | ||||||
| 
 | 
 | ||||||
| 	delete yosys_design; | 	delete yosys_design; | ||||||
|  | @ -511,9 +530,16 @@ void yosys_shutdown() | ||||||
| 		dlclose(it.second); | 		dlclose(it.second); | ||||||
| 
 | 
 | ||||||
| 	loaded_plugins.clear(); | 	loaded_plugins.clear(); | ||||||
|  | #ifdef WITH_PYTHON | ||||||
|  | 	loaded_python_plugins.clear(); | ||||||
|  | #endif | ||||||
| 	loaded_plugin_aliases.clear(); | 	loaded_plugin_aliases.clear(); | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | #ifdef WITH_PYTHON | ||||||
|  | 	Py_Finalize(); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| 	IdString empty_id; | 	IdString empty_id; | ||||||
| 	IdString::put_reference(empty_id.index_); | 	IdString::put_reference(empty_id.index_); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -66,6 +66,8 @@ | ||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| #include <limits.h> | #include <limits.h> | ||||||
| 
 | 
 | ||||||
|  | #include <Python.h> | ||||||
|  | 
 | ||||||
| #ifndef _YOSYS_ | #ifndef _YOSYS_ | ||||||
| #  error It looks like you are trying to build Yosys without the config defines set. \ | #  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 \ |          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
 | // from passes/cmds/pluginc.cc
 | ||||||
| extern std::map<std::string, void*> loaded_plugins; | 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; | extern std::map<std::string, std::string> loaded_plugin_aliases; | ||||||
| void load_plugin(std::string filename, std::vector<std::string> aliases); | void load_plugin(std::string filename, std::vector<std::string> aliases); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -23,9 +23,17 @@ | ||||||
| #  include <dlfcn.h> | #  include <dlfcn.h> | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | #ifdef WITH_PYTHON | ||||||
|  | #  include <boost/algorithm/string/predicate.hpp> | ||||||
|  | #  include <Python.h> | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| YOSYS_NAMESPACE_BEGIN | YOSYS_NAMESPACE_BEGIN | ||||||
| 
 | 
 | ||||||
| std::map<std::string, void*> loaded_plugins; | 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; | std::map<std::string, std::string> loaded_plugin_aliases; | ||||||
| 
 | 
 | ||||||
| #ifdef YOSYS_ENABLE_PLUGINS | #ifdef YOSYS_ENABLE_PLUGINS | ||||||
|  | @ -37,6 +45,48 @@ void load_plugin(std::string filename, std::vector<std::string> aliases) | ||||||
| 		filename = "./" + filename; | 		filename = "./" + filename; | ||||||
| 
 | 
 | ||||||
| 	if (!loaded_plugins.count(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); | 		void *hdl = dlopen(filename.c_str(), RTLD_LAZY|RTLD_LOCAL); | ||||||
| 		if (hdl == NULL && orig_filename.find('/') == std::string::npos) | 		if (hdl == NULL && orig_filename.find('/') == std::string::npos) | ||||||
| 			hdl = dlopen((proc_share_dirname() + "plugins/" + orig_filename + ".so").c_str(), RTLD_LAZY|RTLD_LOCAL); | 			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()); | 			log_cmd_error("Can't load module `%s': %s\n", filename.c_str(), dlerror()); | ||||||
| 		loaded_plugins[orig_filename] = hdl; | 		loaded_plugins[orig_filename] = hdl; | ||||||
| 		Pass::init_register(); | 		Pass::init_register(); | ||||||
|  | 
 | ||||||
|  | 		#ifdef WITH_PYTHON | ||||||
|  | 		} | ||||||
|  | 		#endif | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	for (auto &alias : aliases) | 	for (auto &alias : aliases) | ||||||
|  | @ -107,7 +161,11 @@ struct PluginPass : public Pass { | ||||||
| 		if (list_mode) | 		if (list_mode) | ||||||
| 		{ | 		{ | ||||||
| 			log("\n"); | 			log("\n"); | ||||||
|  | #ifdef WITH_PYTHON | ||||||
|  | 			if (loaded_plugins.empty() and loaded_python_plugins.empty()) | ||||||
|  | #else | ||||||
| 			if (loaded_plugins.empty()) | 			if (loaded_plugins.empty()) | ||||||
|  | #endif | ||||||
| 				log("No plugins loaded.\n"); | 				log("No plugins loaded.\n"); | ||||||
| 			else | 			else | ||||||
| 				log("Loaded plugins:\n"); | 				log("Loaded plugins:\n"); | ||||||
|  | @ -115,6 +173,11 @@ struct PluginPass : public Pass { | ||||||
| 			for (auto &it : loaded_plugins) | 			for (auto &it : loaded_plugins) | ||||||
| 				log("  %s\n", it.first.c_str()); | 				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()) { | 			if (!loaded_plugin_aliases.empty()) { | ||||||
| 				log("\n"); | 				log("\n"); | ||||||
| 				int max_alias_len = 1; | 				int max_alias_len = 1; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue