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
 | ||||
| ENABLE_GPROF := 0 | ||||
| ENABLE_DEBUG := 0 | ||||
| ENABLE_DEBUG := 1 | ||||
| ENABLE_NDEBUG := 0 | ||||
| LINK_CURSES := 0 | ||||
| LINK_TERMCAP := 0 | ||||
|  |  | |||
|  | @ -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); | ||||
| 
 | ||||
| 	} | ||||
| 
 | ||||
|  |  | |||
|  | @ -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_); | ||||
| } | ||||
|  |  | |||
|  | @ -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); | ||||
| 
 | ||||
|  |  | |||
|  | @ -23,9 +23,17 @@ | |||
| #  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; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue