mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-11-04 13:29:12 +00:00 
			
		
		
		
	write_cxxrtl: enable separate compilation.
This commit makes it possible to use several cxxrtl-generated files in one application, as well as compiling cxxrtl-generated code as a separate compilation unit.
This commit is contained in:
		
							parent
							
								
									f44b287f8e
								
							
						
					
					
						commit
						102fb5424f
					
				
					 1 changed files with 81 additions and 9 deletions
				
			
		| 
						 | 
					@ -357,13 +357,19 @@ struct FlowGraph {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct CxxrtlWorker {
 | 
					struct CxxrtlWorker {
 | 
				
			||||||
 | 
						bool split_intf = false;
 | 
				
			||||||
 | 
						std::string intf_filename;
 | 
				
			||||||
 | 
						std::string design_ns = "cxxrtl_design";
 | 
				
			||||||
 | 
						std::ostream *impl_f = nullptr;
 | 
				
			||||||
 | 
						std::ostream *intf_f = nullptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool elide_internal = false;
 | 
						bool elide_internal = false;
 | 
				
			||||||
	bool elide_public = false;
 | 
						bool elide_public = false;
 | 
				
			||||||
	bool localize_internal = false;
 | 
						bool localize_internal = false;
 | 
				
			||||||
	bool localize_public = false;
 | 
						bool localize_public = false;
 | 
				
			||||||
	bool run_splitnets = false;
 | 
						bool run_splitnets = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	std::ostream &f;
 | 
						std::ostringstream f;
 | 
				
			||||||
	std::string indent;
 | 
						std::string indent;
 | 
				
			||||||
	int temporary = 0;
 | 
						int temporary = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -377,8 +383,6 @@ struct CxxrtlWorker {
 | 
				
			||||||
	dict<const RTLIL::Module*, std::vector<FlowGraph::Node>> schedule;
 | 
						dict<const RTLIL::Module*, std::vector<FlowGraph::Node>> schedule;
 | 
				
			||||||
	pool<const RTLIL::Wire*> localized_wires;
 | 
						pool<const RTLIL::Wire*> localized_wires;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	CxxrtlWorker(std::ostream &f) : f(f) {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void inc_indent() {
 | 
						void inc_indent() {
 | 
				
			||||||
		indent += "\t";
 | 
							indent += "\t";
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -1191,7 +1195,7 @@ struct CxxrtlWorker {
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void dump_module(RTLIL::Module *module)
 | 
						void dump_module_intf(RTLIL::Module *module)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		dump_attrs(module);
 | 
							dump_attrs(module);
 | 
				
			||||||
		f << "struct " << mangle(module) << " : public module {\n";
 | 
							f << "struct " << mangle(module) << " : public module {\n";
 | 
				
			||||||
| 
						 | 
					@ -1220,7 +1224,10 @@ struct CxxrtlWorker {
 | 
				
			||||||
		dec_indent();
 | 
							dec_indent();
 | 
				
			||||||
		f << "}; // struct " << mangle(module) << "\n";
 | 
							f << "}; // struct " << mangle(module) << "\n";
 | 
				
			||||||
		f << "\n";
 | 
							f << "\n";
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void dump_module_impl(RTLIL::Module *module)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
		f << "void " << mangle(module) << "::eval() {\n";
 | 
							f << "void " << mangle(module) << "::eval() {\n";
 | 
				
			||||||
		inc_indent();
 | 
							inc_indent();
 | 
				
			||||||
			for (auto wire : module->wires())
 | 
								for (auto wire : module->wires())
 | 
				
			||||||
| 
						 | 
					@ -1323,18 +1330,49 @@ struct CxxrtlWorker {
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		log_assert(topo_design.sort());
 | 
							log_assert(topo_design.sort());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		f << "#include <cxxrtl.h>\n";
 | 
							if (split_intf) {
 | 
				
			||||||
 | 
								// The only thing more depraved than include guards, is mangling filenames to turn them into include guards.
 | 
				
			||||||
 | 
								std::string include_guard = design_ns + "_header";
 | 
				
			||||||
 | 
								std::transform(include_guard.begin(), include_guard.end(), include_guard.begin(), ::toupper);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								f << "#ifndef " << include_guard << "\n";
 | 
				
			||||||
 | 
								f << "#define " << include_guard << "\n";
 | 
				
			||||||
			f << "\n";
 | 
								f << "\n";
 | 
				
			||||||
		f << "using namespace cxxrtl_yosys;\n";
 | 
								f << "#include <backends/cxxrtl/cxxrtl.h>\n";
 | 
				
			||||||
			f << "\n";
 | 
								f << "\n";
 | 
				
			||||||
		f << "namespace cxxrtl_design {\n";
 | 
								f << "using namespace cxxrtl;\n";
 | 
				
			||||||
 | 
								f << "\n";
 | 
				
			||||||
 | 
								f << "namespace " << design_ns << " {\n";
 | 
				
			||||||
			f << "\n";
 | 
								f << "\n";
 | 
				
			||||||
			for (auto module : topo_design.sorted) {
 | 
								for (auto module : topo_design.sorted) {
 | 
				
			||||||
				if (!design->selected_module(module))
 | 
									if (!design->selected_module(module))
 | 
				
			||||||
					continue;
 | 
										continue;
 | 
				
			||||||
			dump_module(module);
 | 
									dump_module_intf(module);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		f << "} // namespace cxxrtl_design\n";
 | 
								f << "} // namespace " << design_ns << "\n";
 | 
				
			||||||
 | 
								f << "\n";
 | 
				
			||||||
 | 
								f << "#endif\n";
 | 
				
			||||||
 | 
								*intf_f << f.str(); f.str("");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (split_intf)
 | 
				
			||||||
 | 
								f << "#include \"" << intf_filename << "\"\n";
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								f << "#include <backends/cxxrtl/cxxrtl.h>\n";
 | 
				
			||||||
 | 
							f << "\n";
 | 
				
			||||||
 | 
							f << "using namespace cxxrtl_yosys;\n";
 | 
				
			||||||
 | 
							f << "\n";
 | 
				
			||||||
 | 
							f << "namespace " << design_ns << " {\n";
 | 
				
			||||||
 | 
							f << "\n";
 | 
				
			||||||
 | 
							for (auto module : topo_design.sorted) {
 | 
				
			||||||
 | 
								if (!design->selected_module(module))
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								if (!split_intf)
 | 
				
			||||||
 | 
									dump_module_intf(module);
 | 
				
			||||||
 | 
								dump_module_impl(module);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							f << "} // namespace " << design_ns << "\n";
 | 
				
			||||||
 | 
							*impl_f << f.str(); f.str("");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Edge-type sync rules require us to emit edge detectors, which require coordination between
 | 
						// Edge-type sync rules require us to emit edge detectors, which require coordination between
 | 
				
			||||||
| 
						 | 
					@ -1618,6 +1656,16 @@ struct CxxrtlBackend : public Backend {
 | 
				
			||||||
		log("\n");
 | 
							log("\n");
 | 
				
			||||||
		log("The following options are supported by this backend:\n");
 | 
							log("The following options are supported by this backend:\n");
 | 
				
			||||||
		log("\n");
 | 
							log("\n");
 | 
				
			||||||
 | 
							log("    -header\n");
 | 
				
			||||||
 | 
							log("        generate separate interface (.h) and implementation (.cc) files.\n");
 | 
				
			||||||
 | 
							log("        if specified, the backend must be called with a filename, and filename\n");
 | 
				
			||||||
 | 
							log("        of the interface is derived from filename of the implementation.\n");
 | 
				
			||||||
 | 
							log("        otherwise, interface and implementation are generated together.\n");
 | 
				
			||||||
 | 
							log("\n");
 | 
				
			||||||
 | 
							log("    -namespace <ns-name>\n");
 | 
				
			||||||
 | 
							log("        place the generated code into namespace <ns-name>. if not specified,\n");
 | 
				
			||||||
 | 
							log("        \"cxxrtl_design\" is used.\n");
 | 
				
			||||||
 | 
							log("\n");
 | 
				
			||||||
		log("    -O <level>\n");
 | 
							log("    -O <level>\n");
 | 
				
			||||||
		log("        set the optimization level. the default is -O%d. higher optimization\n", DEFAULT_OPT_LEVEL);
 | 
							log("        set the optimization level. the default is -O%d. higher optimization\n", DEFAULT_OPT_LEVEL);
 | 
				
			||||||
		log("        levels dramatically decrease compile and run time, and highest level\n");
 | 
							log("        levels dramatically decrease compile and run time, and highest level\n");
 | 
				
			||||||
| 
						 | 
					@ -1645,6 +1693,7 @@ struct CxxrtlBackend : public Backend {
 | 
				
			||||||
	void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
 | 
						void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		int opt_level = DEFAULT_OPT_LEVEL;
 | 
							int opt_level = DEFAULT_OPT_LEVEL;
 | 
				
			||||||
 | 
							CxxrtlWorker worker;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		log_header(design, "Executing CXXRTL backend.\n");
 | 
							log_header(design, "Executing CXXRTL backend.\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1659,11 +1708,18 @@ struct CxxrtlBackend : public Backend {
 | 
				
			||||||
				opt_level = std::stoi(args[argidx].substr(2));
 | 
									opt_level = std::stoi(args[argidx].substr(2));
 | 
				
			||||||
				continue;
 | 
									continue;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
								if (args[argidx] == "-header") {
 | 
				
			||||||
 | 
									worker.split_intf = true;
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (args[argidx] == "-namespace" && argidx+1 < args.size()) {
 | 
				
			||||||
 | 
									worker.design_ns = args[++argidx];
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		extra_args(f, filename, args, argidx);
 | 
							extra_args(f, filename, args, argidx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		CxxrtlWorker worker(*f);
 | 
					 | 
				
			||||||
		switch (opt_level) {
 | 
							switch (opt_level) {
 | 
				
			||||||
			case 5:
 | 
								case 5:
 | 
				
			||||||
				worker.run_splitnets = true;
 | 
									worker.run_splitnets = true;
 | 
				
			||||||
| 
						 | 
					@ -1680,6 +1736,22 @@ struct CxxrtlBackend : public Backend {
 | 
				
			||||||
			default:
 | 
								default:
 | 
				
			||||||
				log_cmd_error("Invalid optimization level %d.\n", opt_level);
 | 
									log_cmd_error("Invalid optimization level %d.\n", opt_level);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							std::ofstream intf_f;
 | 
				
			||||||
 | 
							if (worker.split_intf) {
 | 
				
			||||||
 | 
								if (filename == "<stdout>")
 | 
				
			||||||
 | 
									log_cmd_error("Option -header must be used with a filename.\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								worker.intf_filename = filename.substr(0, filename.rfind('.')) + ".h";
 | 
				
			||||||
 | 
								intf_f.open(worker.intf_filename, std::ofstream::trunc);
 | 
				
			||||||
 | 
								if (intf_f.fail())
 | 
				
			||||||
 | 
									log_cmd_error("Can't open file `%s' for writing: %s\n",
 | 
				
			||||||
 | 
									              worker.intf_filename.c_str(), strerror(errno));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								worker.intf_f = &intf_f;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							worker.impl_f = f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		worker.prepare_design(design);
 | 
							worker.prepare_design(design);
 | 
				
			||||||
		worker.dump_design(design);
 | 
							worker.dump_design(design);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue