X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=kernel%2Fregister.cc;h=26da96b95b6d9e62a217f3577050a25d510c4d38;hb=8767ec3fbdc0986854107de9cf178953ef09f1db;hp=4569481fadb4bef9ebe63d24ae4fb5f3e4e9f63f;hpb=e6df25bf740b259027541db3543a769ecfc92d4f;p=yosys.git diff --git a/kernel/register.cc b/kernel/register.cc index 4569481fa..26da96b95 100644 --- a/kernel/register.cc +++ b/kernel/register.cc @@ -2,11 +2,11 @@ * yosys -- Yosys Open SYnthesis Suite * * Copyright (C) 2012 Clifford Wolf - * + * * 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 @@ -17,26 +17,25 @@ * */ -#include "kernel/compatibility.h" -#include "kernel/register.h" -#include "kernel/log.h" +#include "kernel/yosys.h" +#include "kernel/satgen.h" + #include #include #include #include -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 frontend_register; - std::map pass_register; - std::map backend_register; -} +std::map frontend_register; +std::map pass_register; +std::map backend_register; std::vector 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 &args) { if (args.size() <= 1) @@ -115,7 +142,7 @@ void Pass::extra_args(std::vector 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 args, size_t argidx, RTLIL::Desig void Pass::call(RTLIL::Design *design, std::string command) { std::vector 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 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 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 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 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 args, size_t argidx) +void Frontend::extra_args(std::istream *&f, std::string &filename, std::vector 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 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 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 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 args) +void Frontend::frontend_call(RTLIL::Design *design, std::istream *f, std::string filename, std::vector 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, "", args, design); + std::istream *f_cin = &std::cin; + auto state = frontend_register[args[0]]->pre_execute(); + frontend_register[args[0]]->execute(f_cin, "", args, design); + frontend_register[args[0]]->post_execute(state); } else { if (!filename.empty()) args.push_back(filename); @@ -377,8 +497,8 @@ void Frontend::frontend_call(RTLIL::Design *design, FILE *f, std::string filenam } Backend::Backend(std::string name, std::string short_help) : - Pass(name.substr(0, 1) == "=" ? name.substr(1) : "write_"+name, short_help), - backend_name(name.substr(0, 1) == "=" ? name.substr(1) : name) + Pass(name.rfind("=", 0) == 0 ? name.substr(1) : "write_" + name, short_help), + backend_name(name.rfind("=", 0) == 0 ? name.substr(1) : name) { } @@ -397,14 +517,15 @@ Backend::~Backend() void Backend::execute(std::vector 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 args, size_t argidx) +void Backend::extra_args(std::ostream *&f, std::string &filename, std::vector args, size_t argidx) { bool called_with_fp = f != NULL; @@ -413,20 +534,26 @@ void Backend::extra_args(FILE *&f, std::string &filename, std::vectoropen(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) @@ -436,11 +563,11 @@ void Backend::extra_args(FILE *&f, std::string &filename, std::vector args; char *s = strdup(command.c_str()); @@ -450,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 args) +void Backend::backend_call(RTLIL::Design *design, std::ostream *f, std::string filename, std::vector args) { if (args.size() == 0) return; @@ -460,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, "", args, design); + std::ostream *f_cout = &std::cout; + auto state = backend_register[args[0]]->pre_execute(); + backend_register[args[0]]->execute(f_cout, "", args, design); + backend_register[args[0]]->post_execute(state); } else { if (!filename.empty()) args.push_back(filename); @@ -478,23 +607,36 @@ void Backend::backend_call(RTLIL::Design *design, FILE *f, std::string filename, design->check(); } +static struct CellHelpMessages { + dict 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 ... print help message for given command\n"); - log(" help -all ........ print complete command reference\n"); + log(" help ................ list all commands\n"); + log(" help ...... 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 ..... print help message for given cell type\n"); + log(" help + .... 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) { @@ -546,21 +688,22 @@ struct HelpPass : public Pass { fclose(f); } - virtual void execute(std::vector args, RTLIL::Design*) + void execute(std::vector 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 ' 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++) @@ -569,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 ' 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"); @@ -628,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 args, RTLIL::Design*) + void execute(std::vector args, RTLIL::Design*) YS_OVERRIDE { if (args.size() > 2) cmd_error(args, 2, "Unexpected argument."); @@ -645,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