Add a few more filename rewrites
[yosys.git] / kernel / register.cc
index da35698310e4c20b988dd6bf6d6ad464f2ffddd6..26da96b95b6d9e62a217f3577050a25d510c4d38 100644 (file)
@@ -2,11 +2,11 @@
  *  yosys -- Yosys Open SYnthesis Suite
  *
  *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
- *  
+ *
  *  Permission to use, copy, modify, and/or distribute this software for any
  *  purpose with or without fee is hereby granted, provided that the above
  *  copyright notice and this permission notice appear in all copies.
- *  
+ *
  *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  *
  */
 
-#include "kernel/compatibility.h"
-#include "kernel/register.h"
-#include "kernel/log.h"
+#include "kernel/yosys.h"
+#include "kernel/satgen.h"
+
 #include <string.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <errno.h>
 
-using namespace REGISTER_INTERN;
+YOSYS_NAMESPACE_BEGIN
+
 #define MAX_REG_COUNT 1000
 
-namespace REGISTER_INTERN
-{
-       bool echo_mode = false;
-       Pass *first_queued_pass;
+bool echo_mode = false;
+Pass *first_queued_pass;
+Pass *current_pass;
 
-       std::map<std::string, Frontend*> frontend_register;
-       std::map<std::string, Pass*> pass_register;
-       std::map<std::string, Backend*> backend_register;
-}
+std::map<std::string, Frontend*> frontend_register;
+std::map<std::string, Pass*> pass_register;
+std::map<std::string, Backend*> backend_register;
 
 std::vector<std::string> Frontend::next_args;
 
@@ -45,6 +44,7 @@ Pass::Pass(std::string name, std::string short_help) : pass_name(name), short_he
        next_queued_pass = first_queued_pass;
        first_queued_pass = this;
        call_counter = 0;
+       runtime_ns = 0;
 }
 
 void Pass::run_register()
@@ -73,6 +73,29 @@ Pass::~Pass()
 {
 }
 
+Pass::pre_post_exec_state_t Pass::pre_execute()
+{
+       pre_post_exec_state_t state;
+       call_counter++;
+       state.begin_ns = PerformanceTimer::query();
+       state.parent_pass = current_pass;
+       current_pass = this;
+       clear_flags();
+       return state;
+}
+
+void Pass::post_execute(Pass::pre_post_exec_state_t state)
+{
+       IdString::checkpoint();
+       log_suppressed();
+
+       int64_t time_ns = PerformanceTimer::query() - state.begin_ns;
+       runtime_ns += time_ns;
+       current_pass = state.parent_pass;
+       if (current_pass)
+               current_pass->runtime_ns -= time_ns;
+}
+
 void Pass::help()
 {
        log("\n");
@@ -80,6 +103,10 @@ void Pass::help()
        log("\n");
 }
 
+void Pass::clear_flags()
+{
+}
+
 void Pass::cmd_log_args(const std::vector<std::string> &args)
 {
        if (args.size() <= 1)
@@ -115,7 +142,7 @@ void Pass::extra_args(std::vector<std::string> args, size_t argidx, RTLIL::Desig
                std::string arg = args[argidx];
 
                if (arg.substr(0, 1) == "-")
-                       cmd_error(args, argidx, "Unkown option or option in arguments.");
+                       cmd_error(args, argidx, "Unknown option or option in arguments.");
 
                if (!select)
                        cmd_error(args, argidx, "Extra argument.");
@@ -129,35 +156,39 @@ void Pass::extra_args(std::vector<std::string> args, size_t argidx, RTLIL::Desig
 void Pass::call(RTLIL::Design *design, std::string command)
 {
        std::vector<std::string> args;
-       char *s = strdup(command.c_str()), *sstart = s, *saveptr;
-       s += strspn(s, " \t\r\n");
-       if (*s == 0 || *s == '#') {
-               free(sstart);
+
+       std::string cmd_buf = command;
+       std::string tok = next_token(cmd_buf, " \t\r\n", true);
+
+       if (tok.empty())
                return;
-       }
-       if (*s == '!') {
-               for (s++; *s == ' ' || *s == '\t'; s++) { }
-               char *p = s + strlen(s) - 1;
-               while (p >= s && (*p == '\r' || *p == '\n'))
-                       *(p--) = 0;
-               log_header("Shell command: %s\n", s);
-               int retCode = system(s);
+
+       if (tok[0] == '!') {
+               cmd_buf = command.substr(command.find('!') + 1);
+               while (!cmd_buf.empty() && (cmd_buf.back() == ' ' || cmd_buf.back() == '\t' ||
+                               cmd_buf.back() == '\r' || cmd_buf.back() == '\n'))
+                       cmd_buf.resize(cmd_buf.size()-1);
+               log_header(design, "Shell command: %s\n", cmd_buf.c_str());
+               int retCode = run_command(cmd_buf);
                if (retCode != 0)
                        log_cmd_error("Shell command returned error code %d.\n", retCode);
-               free(sstart);
                return;
        }
-       for (char *p = strtok_r(s, " \t\r\n", &saveptr); p; p = strtok_r(NULL, " \t\r\n", &saveptr)) {
-               std::string str = p;
-               int strsz = str.size();
-               if (str == "#")
-                       break;
-               if (strsz > 0 && str[strsz-1] == ';') {
+
+       while (!tok.empty()) {
+               if (tok[0] == '#') {
+                       int stop;
+                       for (stop = 0; stop < GetSize(cmd_buf); stop++)
+                               if (cmd_buf[stop] == '\r' || cmd_buf[stop] == '\n')
+                                       break;
+                       cmd_buf = cmd_buf.substr(stop);
+               } else
+               if (tok.back() == ';') {
                        int num_semikolon = 0;
-                       while (strsz > 0 && str[strsz-1] == ';')
-                               strsz--, num_semikolon++;
-                       if (strsz > 0)
-                               args.push_back(str.substr(0, strsz));
+                       while (!tok.empty() && tok.back() == ';')
+                               tok.resize(tok.size()-1), num_semikolon++;
+                       if (!tok.empty())
+                               args.push_back(tok);
                        call(design, args);
                        args.clear();
                        if (num_semikolon == 2)
@@ -165,15 +196,28 @@ void Pass::call(RTLIL::Design *design, std::string command)
                        if (num_semikolon == 3)
                                call(design, "clean -purge");
                } else
-                       args.push_back(str);
+                       args.push_back(tok);
+               bool found_nl = false;
+               for (auto c : cmd_buf) {
+                       if (c == ' ' || c == '\t')
+                               continue;
+                       if (c == '\r' || c == '\n')
+                               found_nl = true;
+                       break;
+               }
+               if (found_nl) {
+                       call(design, args);
+                       args.clear();
+               }
+               tok = next_token(cmd_buf, " \t\r\n", true);
        }
-       free(sstart);
+
        call(design, args);
 }
 
 void Pass::call(RTLIL::Design *design, std::vector<std::string> args)
 {
-       if (args.size() == 0 || args[0][0] == '#')
+       if (args.size() == 0 || args[0][0] == '#' || args[0][0] == ':')
                return;
 
        if (echo_mode) {
@@ -187,8 +231,9 @@ void Pass::call(RTLIL::Design *design, std::vector<std::string> args)
                log_cmd_error("No such command: %s (type 'help' for a command overview)\n", args[0].c_str());
 
        size_t orig_sel_stack_pos = design->selection_stack.size();
-       pass_register[args[0]]->call_counter++;
+       auto state = pass_register[args[0]]->pre_execute();
        pass_register[args[0]]->execute(args, design);
+       pass_register[args[0]]->post_execute(state);
        while (design->selection_stack.size() > orig_sel_stack_pos)
                design->selection_stack.pop_back();
 
@@ -222,7 +267,7 @@ void Pass::call_on_selection(RTLIL::Design *design, const RTLIL::Selection &sele
 void Pass::call_on_module(RTLIL::Design *design, RTLIL::Module *module, std::string command)
 {
        std::string backup_selected_active_module = design->selected_active_module;
-       design->selected_active_module = module->name;
+       design->selected_active_module = module->name.str();
        design->selection_stack.push_back(RTLIL::Selection(false));
        design->selection_stack.back().select(module);
 
@@ -235,7 +280,7 @@ void Pass::call_on_module(RTLIL::Design *design, RTLIL::Module *module, std::str
 void Pass::call_on_module(RTLIL::Design *design, RTLIL::Module *module, std::vector<std::string> args)
 {
        std::string backup_selected_active_module = design->selected_active_module;
-       design->selected_active_module = module->name;
+       design->selected_active_module = module->name.str();
        design->selection_stack.push_back(RTLIL::Selection(false));
        design->selection_stack.back().select(module);
 
@@ -245,7 +290,63 @@ void Pass::call_on_module(RTLIL::Design *design, RTLIL::Module *module, std::vec
        design->selected_active_module = backup_selected_active_module;
 }
 
-Frontend::Frontend(std::string name, std::string short_help) : Pass("read_"+name, short_help), frontend_name(name)
+bool ScriptPass::check_label(std::string label, std::string info)
+{
+       if (active_design == nullptr) {
+               log("\n");
+               if (info.empty())
+                       log("    %s:\n", label.c_str());
+               else
+                       log("    %s:    %s\n", label.c_str(), info.c_str());
+               return true;
+       } else {
+               if (!active_run_from.empty() && active_run_from == active_run_to) {
+                       block_active = (label == active_run_from);
+               } else {
+                       if (label == active_run_from)
+                               block_active = true;
+                       if (label == active_run_to)
+                               block_active = false;
+               }
+               return block_active;
+       }
+}
+
+void ScriptPass::run(std::string command, std::string info)
+{
+       if (active_design == nullptr) {
+               if (info.empty())
+                       log("        %s\n", command.c_str());
+               else
+                       log("        %s    %s\n", command.c_str(), info.c_str());
+       } else
+               Pass::call(active_design, command);
+}
+
+void ScriptPass::run_script(RTLIL::Design *design, std::string run_from, std::string run_to)
+{
+       help_mode = false;
+       active_design = design;
+       block_active = run_from.empty();
+       active_run_from = run_from;
+       active_run_to = run_to;
+       script();
+}
+
+void ScriptPass::help_script()
+{
+       clear_flags();
+       help_mode = true;
+       active_design = nullptr;
+       block_active = true;
+       active_run_from.clear();
+       active_run_to.clear();
+       script();
+}
+
+Frontend::Frontend(std::string name, std::string short_help) :
+               Pass(name.rfind("=", 0) == 0 ? name.substr(1) : "read_" + name, short_help),
+               frontend_name(name.rfind("=", 0) == 0 ? name.substr(1) : name)
 {
 }
 
@@ -266,29 +367,31 @@ void Frontend::execute(std::vector<std::string> args, RTLIL::Design *design)
 {
        log_assert(next_args.empty());
        do {
-               FILE *f = NULL;
+               std::istream *f = NULL;
                next_args.clear();
-               call_counter++;
+               auto state = pre_execute();
                execute(f, std::string(), args, design);
+               post_execute(state);
                args = next_args;
-               fclose(f);
+               delete f;
        } while (!args.empty());
 }
 
 FILE *Frontend::current_script_file = NULL;
 std::string Frontend::last_here_document;
 
-void Frontend::extra_args(FILE *&f, std::string &filename, std::vector<std::string> args, size_t argidx)
+void Frontend::extra_args(std::istream *&f, std::string &filename, std::vector<std::string> args, size_t argidx)
 {
        bool called_with_fp = f != NULL;
 
        next_args.clear();
-       for (; argidx < args.size(); argidx++)
+
+       if (argidx < args.size())
        {
                std::string arg = args[argidx];
 
                if (arg.substr(0, 1) == "-")
-                       cmd_error(args, argidx, "Unkown option or option in arguments.");
+                       cmd_error(args, argidx, "Unknown option or option in arguments.");
                if (f != NULL)
                        cmd_error(args, argidx, "Extra filename argument in direct file mode.");
 
@@ -312,14 +415,28 @@ void Frontend::extra_args(FILE *&f, std::string &filename, std::vector<std::stri
                                        if (buffer.size() > 0 && (buffer[buffer.size() - 1] == '\n' || buffer[buffer.size() - 1] == '\r'))
                                                break;
                                }
-                               int indent = buffer.find_first_not_of(" \t\r\n");
-                               if (buffer.substr(indent, eot_marker.size()) == eot_marker)
+                               size_t indent = buffer.find_first_not_of(" \t\r\n");
+                               if (indent != std::string::npos && buffer.substr(indent, eot_marker.size()) == eot_marker)
                                        break;
                                last_here_document += buffer;
                        }
-                       f = fmemopen((void*)last_here_document.c_str(), last_here_document.size(), "r");
-               } else
-                       f = fopen(filename.c_str(), "r");
+                       f = new std::istringstream(last_here_document);
+               } else {
+                       rewrite_filename(filename);
+                       vector<string> filenames = glob_filename(filename);
+                       filename = filenames.front();
+                       if (GetSize(filenames) > 1) {
+                               next_args.insert(next_args.end(), args.begin(), args.begin()+argidx);
+                               next_args.insert(next_args.end(), filenames.begin()+1, filenames.end());
+                       }
+                       std::ifstream *ff = new std::ifstream;
+                       ff->open(filename.c_str());
+                       yosys_input_files.insert(filename);
+                       if (ff->fail())
+                               delete ff;
+                       else
+                               f = ff;
+               }
                if (f == NULL)
                        log_cmd_error("Can't open input file `%s' for reading: %s\n", filename.c_str(), strerror(errno));
 
@@ -328,12 +445,13 @@ void Frontend::extra_args(FILE *&f, std::string &filename, std::vector<std::stri
                                cmd_error(args, i, "Found option, expected arguments.");
 
                if (argidx+1 < args.size()) {
-                       next_args.insert(next_args.begin(), args.begin(), args.begin()+argidx);
-                       next_args.insert(next_args.begin()+argidx, args.begin()+argidx+1, args.end());
+                       if (next_args.empty())
+                               next_args.insert(next_args.end(), args.begin(), args.begin()+argidx);
+                       next_args.insert(next_args.end(), args.begin()+argidx+1, args.end());
                        args.erase(args.begin()+argidx+1, args.end());
                }
-               break;
        }
+
        if (f == NULL)
                cmd_error(args, argidx, "No filename given.");
 
@@ -343,7 +461,7 @@ void Frontend::extra_args(FILE *&f, std::string &filename, std::vector<std::stri
        // cmd_log_args(args);
 }
 
-void Frontend::frontend_call(RTLIL::Design *design, FILE *f, std::string filename, std::string command)
+void Frontend::frontend_call(RTLIL::Design *design, std::istream *f, std::string filename, std::string command)
 {
        std::vector<std::string> args;
        char *s = strdup(command.c_str());
@@ -353,7 +471,7 @@ void Frontend::frontend_call(RTLIL::Design *design, FILE *f, std::string filenam
        frontend_call(design, f, filename, args);
 }
 
-void Frontend::frontend_call(RTLIL::Design *design, FILE *f, std::string filename, std::vector<std::string> args)
+void Frontend::frontend_call(RTLIL::Design *design, std::istream *f, std::string filename, std::vector<std::string> args)
 {
        if (args.size() == 0)
                return;
@@ -361,12 +479,14 @@ void Frontend::frontend_call(RTLIL::Design *design, FILE *f, std::string filenam
                log_cmd_error("No such frontend: %s\n", args[0].c_str());
 
        if (f != NULL) {
-               frontend_register[args[0]]->call_counter++;
+               auto state = frontend_register[args[0]]->pre_execute();
                frontend_register[args[0]]->execute(f, filename, args, design);
+               frontend_register[args[0]]->post_execute(state);
        } else if (filename == "-") {
-               FILE *f_stdin = stdin; // workaround for OpenBSD 'stdin' implementation
-               frontend_register[args[0]]->call_counter++;
-               frontend_register[args[0]]->execute(f_stdin, "<stdin>", args, design);
+               std::istream *f_cin = &std::cin;
+               auto state = frontend_register[args[0]]->pre_execute();
+               frontend_register[args[0]]->execute(f_cin, "<stdin>", args, design);
+               frontend_register[args[0]]->post_execute(state);
        } else {
                if (!filename.empty())
                        args.push_back(filename);
@@ -376,7 +496,9 @@ void Frontend::frontend_call(RTLIL::Design *design, FILE *f, std::string filenam
        design->check();
 }
 
-Backend::Backend(std::string name, std::string short_help) : Pass("write_"+name, short_help), backend_name(name)
+Backend::Backend(std::string name, std::string short_help) :
+               Pass(name.rfind("=", 0) == 0 ? name.substr(1) : "write_" + name, short_help),
+               backend_name(name.rfind("=", 0) == 0 ? name.substr(1) : name)
 {
 }
 
@@ -395,14 +517,15 @@ Backend::~Backend()
 
 void Backend::execute(std::vector<std::string> args, RTLIL::Design *design)
 {
-       FILE *f = NULL;
-       call_counter++;
+       std::ostream *f = NULL;
+       auto state = pre_execute();
        execute(f, std::string(), args, design);
-       if (f != stdout)
-               fclose(f);
+       post_execute(state);
+       if (f != &std::cout)
+               delete f;
 }
 
-void Backend::extra_args(FILE *&f, std::string &filename, std::vector<std::string> args, size_t argidx)
+void Backend::extra_args(std::ostream *&f, std::string &filename, std::vector<std::string> args, size_t argidx)
 {
        bool called_with_fp = f != NULL;
 
@@ -411,20 +534,26 @@ void Backend::extra_args(FILE *&f, std::string &filename, std::vector<std::strin
                std::string arg = args[argidx];
 
                if (arg.substr(0, 1) == "-" && arg != "-")
-                       cmd_error(args, argidx, "Unkown option or option in arguments.");
+                       cmd_error(args, argidx, "Unknown option or option in arguments.");
                if (f != NULL)
                        cmd_error(args, argidx, "Extra filename argument in direct file mode.");
 
                if (arg == "-") {
                        filename = "<stdout>";
-                       f = stdout;
+                       f = &std::cout;
                        continue;
                }
 
                filename = arg;
-               f = fopen(filename.c_str(), "w");
-               if (f == NULL)
+               rewrite_filename(filename);
+               std::ofstream *ff = new std::ofstream;
+               ff->open(filename.c_str(), std::ofstream::trunc);
+               yosys_output_files.insert(filename);
+               if (ff->fail()) {
+                       delete ff;
                        log_cmd_error("Can't open output file `%s' for writing: %s\n", filename.c_str(), strerror(errno));
+               }
+               f = ff;
        }
 
        if (called_with_fp)
@@ -434,11 +563,11 @@ void Backend::extra_args(FILE *&f, std::string &filename, std::vector<std::strin
 
        if (f == NULL) {
                filename = "<stdout>";
-               f = stdout;
+               f = &std::cout;
        }
 }
 
-void Backend::backend_call(RTLIL::Design *design, FILE *f, std::string filename, std::string command)
+void Backend::backend_call(RTLIL::Design *design, std::ostream *f, std::string filename, std::string command)
 {
        std::vector<std::string> args;
        char *s = strdup(command.c_str());
@@ -448,7 +577,7 @@ void Backend::backend_call(RTLIL::Design *design, FILE *f, std::string filename,
        backend_call(design, f, filename, args);
 }
 
-void Backend::backend_call(RTLIL::Design *design, FILE *f, std::string filename, std::vector<std::string> args)
+void Backend::backend_call(RTLIL::Design *design, std::ostream *f, std::string filename, std::vector<std::string> args)
 {
        if (args.size() == 0)
                return;
@@ -458,12 +587,14 @@ void Backend::backend_call(RTLIL::Design *design, FILE *f, std::string filename,
        size_t orig_sel_stack_pos = design->selection_stack.size();
 
        if (f != NULL) {
-               backend_register[args[0]]->call_counter++;
+               auto state = backend_register[args[0]]->pre_execute();
                backend_register[args[0]]->execute(f, filename, args, design);
+               backend_register[args[0]]->post_execute(state);
        } else if (filename == "-") {
-               FILE *f_stdout = stdout; // workaround for OpenBSD 'stdout' implementation
-               backend_register[args[0]]->call_counter++;
-               backend_register[args[0]]->execute(f_stdout, "<stdout>", args, design);
+               std::ostream *f_cout = &std::cout;
+               auto state = backend_register[args[0]]->pre_execute();
+               backend_register[args[0]]->execute(f_cout, "<stdout>", args, design);
+               backend_register[args[0]]->post_execute(state);
        } else {
                if (!filename.empty())
                        args.push_back(filename);
@@ -476,23 +607,36 @@ void Backend::backend_call(RTLIL::Design *design, FILE *f, std::string filename,
        design->check();
 }
 
+static struct CellHelpMessages {
+       dict<string, string> cell_help, cell_code;
+       CellHelpMessages() {
+#include "techlibs/common/simlib_help.inc"
+#include "techlibs/common/simcells_help.inc"
+               cell_help.sort();
+               cell_code.sort();
+       }
+} cell_help_messages;
+
 struct HelpPass : public Pass {
        HelpPass() : Pass("help", "display help messages") { }
-       virtual void help()
+       void help() YS_OVERRIDE
        {
                log("\n");
-               log("    help  .............  list all commands\n");
-               log("    help <command>  ...  print help message for given command\n");
-               log("    help -all  ........  print complete command reference\n");
+               log("    help  ................  list all commands\n");
+               log("    help <command>  ......  print help message for given command\n");
+               log("    help -all  ...........  print complete command reference\n");
+               log("\n");
+               log("    help -cells ..........  list all cell types\n");
+               log("    help <celltype>  .....  print help message for given cell type\n");
+               log("    help <celltype>+  ....  print verilog code for given cell type\n");
                log("\n");
        }
        void escape_tex(std::string &tex)
        {
-               size_t pos = 0;
-               while ((pos = tex.find('_', pos)) != std::string::npos) {
+               for (size_t pos = 0; (pos = tex.find('_', pos)) != std::string::npos; pos += 2)
                        tex.replace(pos, 1, "\\_");
-                       pos += 2;
-               }
+               for (size_t pos = 0; (pos = tex.find('$', pos)) != std::string::npos; pos += 2)
+                       tex.replace(pos, 1, "\\$");
        }
        void write_tex(FILE *f, std::string cmd, std::string title, std::string text)
        {
@@ -544,21 +688,22 @@ struct HelpPass : public Pass {
 
                fclose(f);
        }
-       virtual void execute(std::vector<std::string> args, RTLIL::Design*)
+       void execute(std::vector<std::string> args, RTLIL::Design*) YS_OVERRIDE
        {
                if (args.size() == 1) {
                        log("\n");
-                       for (auto &it : REGISTER_INTERN::pass_register)
+                       for (auto &it : pass_register)
                                log("    %-20s %s\n", it.first.c_str(), it.second->short_help.c_str());
                        log("\n");
                        log("Type 'help <command>' for more information on a command.\n");
+                       log("Type 'help -cells' for a list of all cell types.\n");
                        log("\n");
                        return;
                }
 
                if (args.size() == 2) {
                        if (args[1] == "-all") {
-                               for (auto &it : REGISTER_INTERN::pass_register) {
+                               for (auto &it : pass_register) {
                                        log("\n\n");
                                        log("%s  --  %s\n", it.first.c_str(), it.second->short_help.c_str());
                                        for (size_t i = 0; i < it.first.size() + it.second->short_help.size() + 6; i++)
@@ -567,53 +712,67 @@ struct HelpPass : public Pass {
                                        it.second->help();
                                }
                        }
+                       else if (args[1] == "-cells") {
+                               log("\n");
+                               for (auto &it : cell_help_messages.cell_help) {
+                                       string line = split_tokens(it.second, "\n").at(0);
+                                       string cell_name = next_token(line);
+                                       log("    %-15s %s\n", cell_name.c_str(), line.c_str());
+                               }
+                               log("\n");
+                               log("Type 'help <cell_type>' for more information on a cell type.\n");
+                               log("\n");
+                               return;
+                       }
                        // this option is undocumented as it is for internal use only
                        else if (args[1] == "-write-tex-command-reference-manual") {
                                FILE *f = fopen("command-reference-manual.tex", "wt");
                                fprintf(f, "%% Generated using the yosys 'help -write-tex-command-reference-manual' command.\n\n");
-                               for (auto &it : REGISTER_INTERN::pass_register) {
-                                       size_t memsize;
-                                       char *memptr;
-                                       FILE *memf = open_memstream(&memptr, &memsize);
-                                       log_files.push_back(memf);
+                               for (auto &it : pass_register) {
+                                       std::ostringstream buf;
+                                       log_streams.push_back(&buf);
                                        it.second->help();
-                                       log_files.pop_back();
-                                       fclose(memf);
-                                       write_tex(f, it.first, it.second->short_help, memptr);
-                                       free(memptr);
+                                       log_streams.pop_back();
+                                       write_tex(f, it.first, it.second->short_help, buf.str());
                                }
                                fclose(f);
                        }
                        // this option is undocumented as it is for internal use only
                        else if (args[1] == "-write-web-command-reference-manual") {
                                FILE *f = fopen("templates/cmd_index.in", "wt");
-                               for (auto &it : REGISTER_INTERN::pass_register) {
-                                       size_t memsize;
-                                       char *memptr;
-                                       FILE *memf = open_memstream(&memptr, &memsize);
-                                       log_files.push_back(memf);
+                               for (auto &it : pass_register) {
+                                       std::ostringstream buf;
+                                       log_streams.push_back(&buf);
                                        it.second->help();
-                                       log_files.pop_back();
-                                       fclose(memf);
-                                       write_html(f, it.first, it.second->short_help, memptr);
-                                       free(memptr);
+                                       log_streams.pop_back();
+                                       write_html(f, it.first, it.second->short_help, buf.str());
                                }
                                fclose(f);
                        }
-                       else if (REGISTER_INTERN::pass_register.count(args[1]) == 0)
-                               log("No such command: %s\n", args[1].c_str());
+                       else if (pass_register.count(args[1])) {
+                               pass_register.at(args[1])->help();
+                       }
+                       else if (cell_help_messages.cell_help.count(args[1])) {
+                               log("%s", cell_help_messages.cell_help.at(args[1]).c_str());
+                               log("Run 'help %s+' to display the Verilog model for this cell type.\n", args[1].c_str());
+                               log("\n");
+                       }
+                       else if (cell_help_messages.cell_code.count(args[1])) {
+                               log("\n");
+                               log("%s", cell_help_messages.cell_code.at(args[1]).c_str());
+                       }
                        else
-                               REGISTER_INTERN::pass_register.at(args[1])->help();
+                               log("No such command or cell type: %s\n", args[1].c_str());
                        return;
                }
 
                help();
        }
 } HelpPass;
+
 struct EchoPass : public Pass {
        EchoPass() : Pass("echo", "turning echoing back of commands on and off") { }
-       virtual void help()
+       void help() YS_OVERRIDE
        {
                log("\n");
                log("    echo on\n");
@@ -626,7 +785,7 @@ struct EchoPass : public Pass {
                log("Do not print all commands to log before executing them. (default)\n");
                log("\n");
        }
-       virtual void execute(std::vector<std::string> args, RTLIL::Design*)
+       void execute(std::vector<std::string> args, RTLIL::Design*) YS_OVERRIDE
        {
                if (args.size() > 2)
                        cmd_error(args, 2, "Unexpected argument.");
@@ -643,4 +802,17 @@ struct EchoPass : public Pass {
                log("echo %s\n", echo_mode ? "on" : "off");
        }
 } EchoPass;
+
+SatSolver *yosys_satsolver_list;
+SatSolver *yosys_satsolver;
+
+struct MinisatSatSolver : public SatSolver {
+       MinisatSatSolver() : SatSolver("minisat") {
+               yosys_satsolver = this;
+       }
+       ezSAT *create() YS_OVERRIDE {
+               return new ezMiniSAT();
+       }
+} MinisatSatSolver;
+
+YOSYS_NAMESPACE_END