mirror of https://github.com/YosysHQ/yosys.git
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
|
@ -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 << "#include <backends/cxxrtl/cxxrtl.h>\n";
|
||||||
|
f << "\n";
|
||||||
|
f << "using namespace cxxrtl;\n";
|
||||||
|
f << "\n";
|
||||||
|
f << "namespace " << design_ns << " {\n";
|
||||||
|
f << "\n";
|
||||||
|
for (auto module : topo_design.sorted) {
|
||||||
|
if (!design->selected_module(module))
|
||||||
|
continue;
|
||||||
|
dump_module_intf(module);
|
||||||
|
}
|
||||||
|
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 << "\n";
|
||||||
f << "using namespace cxxrtl_yosys;\n";
|
f << "using namespace cxxrtl_yosys;\n";
|
||||||
f << "\n";
|
f << "\n";
|
||||||
f << "namespace cxxrtl_design {\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);
|
if (!split_intf)
|
||||||
|
dump_module_intf(module);
|
||||||
|
dump_module_impl(module);
|
||||||
}
|
}
|
||||||
f << "} // namespace cxxrtl_design\n";
|
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…
Reference in New Issue