From 65083e9520e3f39bef3e89a56ecc08f60c1286e6 Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 2 Nov 2020 19:18:56 +0000 Subject: [PATCH] cxxrtl: run `hierarchy -auto-top` if no top module is present. In most cases, a CXXRTL simulation would use a top module, either because this module serves as an entry point to the CXXRTL C API, or because the outputs of a top module are unbuffered, improving performance. Taking this into account, the CXXRTL backend now runs `hierarchy -auto-top` if there is no top module. For the few cases where this behavior is unwanted, it now accepts a `-nohierarchy` option. Fixes #2373. --- backends/cxxrtl/cxxrtl_backend.cc | 33 ++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/backends/cxxrtl/cxxrtl_backend.cc b/backends/cxxrtl/cxxrtl_backend.cc index ac4c78267..a48ea5b23 100644 --- a/backends/cxxrtl/cxxrtl_backend.cc +++ b/backends/cxxrtl/cxxrtl_backend.cc @@ -527,6 +527,7 @@ struct CxxrtlWorker { std::ostream *impl_f = nullptr; std::ostream *intf_f = nullptr; + bool run_hierarchy = false; bool run_flatten = false; bool run_proc = false; @@ -2329,9 +2330,9 @@ struct CxxrtlWorker { } } - void check_design(RTLIL::Design *design, bool &has_sync_init, bool &has_packed_mem) + void check_design(RTLIL::Design *design, bool &has_top, bool &has_sync_init, bool &has_packed_mem) { - has_sync_init = has_packed_mem = false; + has_sync_init = has_packed_mem = has_top = false; for (auto module : design->modules()) { if (module->get_blackbox_attribute() && !module->has_attribute(ID(cxxrtl_blackbox))) @@ -2343,6 +2344,9 @@ struct CxxrtlWorker { if (!design->selected_module(module)) continue; + if (module->get_bool_attribute(ID::top)) + has_top = true; + for (auto proc : module->processes) for (auto sync : proc.second->syncs) if (sync->type == RTLIL::STi) @@ -2358,9 +2362,13 @@ struct CxxrtlWorker { void prepare_design(RTLIL::Design *design) { bool did_anything = false; - bool has_sync_init, has_packed_mem; + bool has_top, has_sync_init, has_packed_mem; log_push(); - check_design(design, has_sync_init, has_packed_mem); + check_design(design, has_top, has_sync_init, has_packed_mem); + if (run_hierarchy && !has_top) { + Pass::call(design, "hierarchy -auto-top"); + did_anything = true; + } if (run_flatten) { Pass::call(design, "flatten"); did_anything = true; @@ -2381,9 +2389,9 @@ struct CxxrtlWorker { did_anything = true; } // Recheck the design if it was modified. - if (has_sync_init || has_packed_mem) - check_design(design, has_sync_init, has_packed_mem); - log_assert(!(has_sync_init || has_packed_mem)); + if (did_anything) + check_design(design, has_top, has_sync_init, has_packed_mem); + log_assert(has_top && !has_sync_init && !has_packed_mem); log_pop(); if (did_anything) log_spacer(); @@ -2565,6 +2573,11 @@ struct CxxrtlBackend : public Backend { log(" place the generated code into namespace . if not specified,\n"); log(" \"cxxrtl_design\" is used.\n"); log("\n"); + log(" -nohierarchy\n"); + log(" use design hierarchy as-is. in most designs, a top module should be\n"); + log(" present as it is exposed through the C API and has unbuffered outputs\n"); + log(" for improved performance; it will be determined automatically if absent.\n"); + log("\n"); log(" -noflatten\n"); log(" don't flatten the design. fully flattened designs can evaluate within\n"); log(" one delta cycle if they have no combinatorial feedback.\n"); @@ -2621,6 +2634,7 @@ struct CxxrtlBackend : public Backend { void execute(std::ostream *&f, std::string filename, std::vector args, RTLIL::Design *design) override { + bool nohierarchy = false; bool noflatten = false; bool noproc = false; int opt_level = DEFAULT_OPT_LEVEL; @@ -2632,6 +2646,10 @@ struct CxxrtlBackend : public Backend { size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { + if (args[argidx] == "-nohierarchy") { + nohierarchy = true; + continue; + } if (args[argidx] == "-noflatten") { noflatten = true; continue; @@ -2677,6 +2695,7 @@ struct CxxrtlBackend : public Backend { } extra_args(f, filename, args, argidx); + worker.run_hierarchy = !nohierarchy; worker.run_flatten = !noflatten; worker.run_proc = !noproc; switch (opt_level) {