mirror of
https://github.com/YosysHQ/yosys
synced 2025-07-28 06:57:57 +00:00
Revert "Add groups to command reference"
This commit is contained in:
parent
2223d7848b
commit
81f87ce6ed
124 changed files with 474 additions and 2035 deletions
|
@ -90,10 +90,10 @@ public:
|
|||
template<typename T>
|
||||
void array(const T &&values)
|
||||
{
|
||||
begin_array();
|
||||
begin_object();
|
||||
for (auto &item : values)
|
||||
value(item);
|
||||
end_array();
|
||||
end_object();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -1,151 +0,0 @@
|
|||
/*
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2025 Krystine Dawn <krystinedawn@yosyshq.com>
|
||||
*
|
||||
* 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
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "kernel/log_help.h"
|
||||
|
||||
USING_YOSYS_NAMESPACE
|
||||
|
||||
Json ContentListing::to_json() {
|
||||
Json::object object;
|
||||
object["type"] = type;
|
||||
if (body.length()) object["body"] = body;
|
||||
if (strcmp(source_file, "unknown") != 0) object["source_file"] = source_file;
|
||||
if (source_line != 0) object["source_line"] = source_line;
|
||||
object["options"] = Json(options);
|
||||
Json::array content_array;
|
||||
for (auto child : _content) content_array.push_back(child->to_json());
|
||||
object["content"] = content_array;
|
||||
return object;
|
||||
}
|
||||
|
||||
void ContentListing::usage(const string &text,
|
||||
const source_location location)
|
||||
{
|
||||
log_assert(type.compare("root") == 0);
|
||||
add_content("usage", text, location);
|
||||
}
|
||||
|
||||
void ContentListing::option(const string &text, const string &description,
|
||||
const source_location location)
|
||||
{
|
||||
auto option = open_option(text);
|
||||
if (description.length())
|
||||
option->add_content("text", description, location);
|
||||
}
|
||||
|
||||
void ContentListing::codeblock(const string &code, const string &language,
|
||||
const source_location location)
|
||||
{
|
||||
add_content("code", code, location);
|
||||
back()->set_option("language", language);
|
||||
}
|
||||
|
||||
void ContentListing::paragraph(const string &text,
|
||||
const source_location location)
|
||||
{
|
||||
add_content("text", text, location);
|
||||
}
|
||||
|
||||
ContentListing* ContentListing::open_usage(const string &text,
|
||||
const source_location location)
|
||||
{
|
||||
usage(text, location);
|
||||
return back();
|
||||
}
|
||||
|
||||
ContentListing* ContentListing::open_option(const string &text,
|
||||
const source_location location)
|
||||
{
|
||||
log_assert(type.compare("root") == 0 || type.compare("usage") == 0);
|
||||
auto option = new ContentListing("option", text, location);
|
||||
add_content(option);
|
||||
return option;
|
||||
}
|
||||
|
||||
#define MAX_LINE_LEN 80
|
||||
void log_pass_str(const std::string &pass_str, std::string indent_str, bool leading_newline=false) {
|
||||
if (pass_str.empty())
|
||||
return;
|
||||
std::istringstream iss(pass_str);
|
||||
if (leading_newline)
|
||||
log("\n");
|
||||
for (std::string line; std::getline(iss, line);) {
|
||||
log("%s", indent_str.c_str());
|
||||
auto curr_len = indent_str.length();
|
||||
std::istringstream lss(line);
|
||||
for (std::string word; std::getline(lss, word, ' ');) {
|
||||
while (word[0] == '`' && word.back() == '`')
|
||||
word = word.substr(1, word.length()-2);
|
||||
if (curr_len + word.length() >= MAX_LINE_LEN-1) {
|
||||
curr_len = 0;
|
||||
log("\n%s", indent_str.c_str());
|
||||
}
|
||||
if (word.length()) {
|
||||
log("%s ", word.c_str());
|
||||
curr_len += word.length() + 1;
|
||||
}
|
||||
}
|
||||
log("\n");
|
||||
}
|
||||
}
|
||||
void log_pass_str(const std::string &pass_str, int indent=0, bool leading_newline=false) {
|
||||
std::string indent_str(indent*4, ' ');
|
||||
log_pass_str(pass_str, indent_str, leading_newline);
|
||||
}
|
||||
|
||||
PrettyHelp *current_help = nullptr;
|
||||
|
||||
PrettyHelp::PrettyHelp()
|
||||
{
|
||||
_prior = current_help;
|
||||
_root_listing = ContentListing("root", "");
|
||||
|
||||
current_help = this;
|
||||
}
|
||||
|
||||
PrettyHelp::~PrettyHelp()
|
||||
{
|
||||
current_help = _prior;
|
||||
}
|
||||
|
||||
PrettyHelp *PrettyHelp::get_current()
|
||||
{
|
||||
if (current_help == nullptr)
|
||||
new PrettyHelp();
|
||||
return current_help;
|
||||
}
|
||||
|
||||
void PrettyHelp::log_help()
|
||||
{
|
||||
for (auto content : _root_listing.get_content()) {
|
||||
if (content->type.compare("usage") == 0) {
|
||||
log_pass_str(content->body, 1, true);
|
||||
log("\n");
|
||||
} else if (content->type.compare("option") == 0) {
|
||||
log_pass_str(content->body, 1);
|
||||
for (auto text : content->get_content()) {
|
||||
log_pass_str(text->body, 2);
|
||||
log("\n");
|
||||
}
|
||||
} else {
|
||||
log_pass_str(content->body, 0);
|
||||
log("\n");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,132 +0,0 @@
|
|||
/*
|
||||
* yosys -- Yosys Open SYnthesis Suite
|
||||
*
|
||||
* Copyright (C) 2025 Krystine Dawn <krystinedawn@yosyshq.com>
|
||||
*
|
||||
* 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
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LOG_HELP_H
|
||||
#define LOG_HELP_H
|
||||
|
||||
#include "kernel/yosys_common.h"
|
||||
#include "kernel/json.h"
|
||||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
class ContentListing {
|
||||
vector<ContentListing *> _content;
|
||||
public:
|
||||
string type;
|
||||
string body;
|
||||
const char* source_file;
|
||||
int source_line;
|
||||
std::map<string, string> options;
|
||||
|
||||
ContentListing(
|
||||
string type = "root", string body = "",
|
||||
const char* source_file = "unknown", int source_line = 0
|
||||
) : type(type), body(body), source_file(source_file), source_line(source_line) {
|
||||
_content = {};
|
||||
options = {};
|
||||
}
|
||||
|
||||
ContentListing(string type, string body, source_location location) :
|
||||
ContentListing(type, body, location.file_name(), location.line()) { }
|
||||
|
||||
void add_content(ContentListing *new_content) {
|
||||
_content.push_back(new_content);
|
||||
}
|
||||
|
||||
void add_content(string type, string body, source_location location) {
|
||||
auto new_content = new ContentListing(type, body, location);
|
||||
add_content(new_content);
|
||||
}
|
||||
|
||||
bool has_content() { return _content.size() != 0; }
|
||||
const vector<ContentListing *> get_content() {
|
||||
const vector<ContentListing *> content = _content;
|
||||
return content;
|
||||
}
|
||||
ContentListing* back() {
|
||||
return _content.back();
|
||||
}
|
||||
|
||||
void set_option(string key, string val = "") {
|
||||
options[key] = val;
|
||||
}
|
||||
|
||||
void usage(
|
||||
const string &text,
|
||||
const source_location location = source_location::current()
|
||||
);
|
||||
void option(
|
||||
const string &text,
|
||||
const string &description = "",
|
||||
const source_location location = source_location::current()
|
||||
);
|
||||
void codeblock(
|
||||
const string &code,
|
||||
const string &language = "none",
|
||||
const source_location location = source_location::current()
|
||||
);
|
||||
void paragraph(
|
||||
const string &text,
|
||||
const source_location location = source_location::current()
|
||||
);
|
||||
|
||||
ContentListing* open_usage(
|
||||
const string &text,
|
||||
const source_location location = source_location::current()
|
||||
);
|
||||
ContentListing* open_option(
|
||||
const string &text,
|
||||
const source_location location = source_location::current()
|
||||
);
|
||||
|
||||
Json to_json();
|
||||
};
|
||||
|
||||
class PrettyHelp
|
||||
{
|
||||
public:
|
||||
string group = "unknown";
|
||||
|
||||
private:
|
||||
PrettyHelp *_prior;
|
||||
ContentListing _root_listing;
|
||||
|
||||
public:
|
||||
PrettyHelp();
|
||||
~PrettyHelp();
|
||||
|
||||
static PrettyHelp *get_current();
|
||||
|
||||
bool has_content() { return _root_listing.has_content(); }
|
||||
const vector<ContentListing *> get_content() {
|
||||
return _root_listing.get_content();
|
||||
}
|
||||
ContentListing* get_root() {
|
||||
return &_root_listing;
|
||||
}
|
||||
|
||||
void set_group(const string g) { group = g; }
|
||||
bool has_group() { return group.compare("unknown") != 0; }
|
||||
|
||||
void log_help();
|
||||
};
|
||||
|
||||
YOSYS_NAMESPACE_END
|
||||
|
||||
#endif
|
|
@ -21,7 +21,6 @@
|
|||
#include "kernel/satgen.h"
|
||||
#include "kernel/json.h"
|
||||
#include "kernel/gzip.h"
|
||||
#include "kernel/log_help.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -42,8 +41,7 @@ std::map<std::string, Backend*> backend_register;
|
|||
|
||||
std::vector<std::string> Frontend::next_args;
|
||||
|
||||
Pass::Pass(std::string name, std::string short_help, source_location location) :
|
||||
pass_name(name), short_help(short_help), location(location)
|
||||
Pass::Pass(std::string name, std::string short_help) : pass_name(name), short_help(short_help)
|
||||
{
|
||||
next_queued_pass = first_queued_pass;
|
||||
first_queued_pass = this;
|
||||
|
@ -118,19 +116,9 @@ void Pass::post_execute(Pass::pre_post_exec_state_t state)
|
|||
|
||||
void Pass::help()
|
||||
{
|
||||
auto prettyHelp = PrettyHelp();
|
||||
if (formatted_help()) {
|
||||
prettyHelp.log_help();
|
||||
} else {
|
||||
log("\n");
|
||||
log("No help message for command `%s'.\n", pass_name.c_str());
|
||||
log("\n");
|
||||
}
|
||||
}
|
||||
|
||||
bool Pass::formatted_help()
|
||||
{
|
||||
return false;
|
||||
log("\n");
|
||||
log("No help message for command `%s'.\n", pass_name.c_str());
|
||||
log("\n");
|
||||
}
|
||||
|
||||
void Pass::clear_flags()
|
||||
|
@ -393,8 +381,8 @@ void ScriptPass::help_script()
|
|||
script();
|
||||
}
|
||||
|
||||
Frontend::Frontend(std::string name, std::string short_help, source_location location) :
|
||||
Pass(name.rfind("=", 0) == 0 ? name.substr(1) : "read_" + name, short_help, location),
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
@ -539,8 +527,8 @@ void Frontend::frontend_call(RTLIL::Design *design, std::istream *f, std::string
|
|||
}
|
||||
}
|
||||
|
||||
Backend::Backend(std::string name, std::string short_help, source_location location) :
|
||||
Pass(name.rfind("=", 0) == 0 ? name.substr(1) : "write_" + name, short_help, location),
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
@ -693,23 +681,6 @@ static string get_cell_name(string name) {
|
|||
return is_code_getter(name) ? name.substr(0, name.length()-1) : name;
|
||||
}
|
||||
|
||||
static void log_warning_flags(Pass *pass) {
|
||||
bool has_warnings = false;
|
||||
const string name = pass->pass_name;
|
||||
if (pass->experimental_flag) {
|
||||
if (!has_warnings) log("\n");
|
||||
has_warnings = true;
|
||||
log("WARNING: THE '%s' COMMAND IS EXPERIMENTAL.\n", name.c_str());
|
||||
}
|
||||
if (pass->internal_flag) {
|
||||
if (!has_warnings) log("\n");
|
||||
has_warnings = true;
|
||||
log("WARNING: THE '%s' COMMAND IS INTENDED FOR INTERNAL DEVELOPER USE ONLY.\n", name.c_str());
|
||||
}
|
||||
if (has_warnings)
|
||||
log("\n");
|
||||
}
|
||||
|
||||
static struct CellHelpMessages {
|
||||
dict<string, SimHelper> cell_help;
|
||||
CellHelpMessages() {
|
||||
|
@ -735,211 +706,155 @@ struct HelpPass : public Pass {
|
|||
log(" help <celltype>+ .... print verilog code for given cell type\n");
|
||||
log("\n");
|
||||
}
|
||||
bool dump_cmds_json(PrettyJson &json) {
|
||||
// init json
|
||||
json.begin_object();
|
||||
json.entry("version", "Yosys command reference");
|
||||
json.entry("generator", yosys_version_str);
|
||||
void write_cmd_rst(std::string cmd, std::string title, std::string text)
|
||||
{
|
||||
FILE *f = fopen(stringf("docs/source/cmd/%s.rst", cmd.c_str()).c_str(), "wt");
|
||||
// make header
|
||||
size_t char_len = cmd.length() + 3 + title.length();
|
||||
std::string title_line = "\n";
|
||||
title_line.insert(0, char_len, '=');
|
||||
fprintf(f, "%s", title_line.c_str());
|
||||
fprintf(f, "%s - %s\n", cmd.c_str(), title.c_str());
|
||||
fprintf(f, "%s\n", title_line.c_str());
|
||||
|
||||
bool raise_error = false;
|
||||
std::map<string, vector<string>> groups;
|
||||
|
||||
json.name("cmds"); json.begin_object();
|
||||
// iterate over commands
|
||||
for (auto &it : pass_register) {
|
||||
auto name = it.first;
|
||||
auto pass = it.second;
|
||||
auto title = pass->short_help;
|
||||
|
||||
auto cmd_help = PrettyHelp();
|
||||
auto has_pretty_help = pass->formatted_help();
|
||||
|
||||
if (!has_pretty_help) {
|
||||
enum PassUsageState {
|
||||
PUState_none,
|
||||
PUState_signature,
|
||||
PUState_options,
|
||||
PUState_optionbody,
|
||||
};
|
||||
|
||||
source_location null_source;
|
||||
string current_buffer = "";
|
||||
auto root_listing = cmd_help.get_root();
|
||||
auto current_listing = root_listing;
|
||||
|
||||
// dump command help
|
||||
std::ostringstream buf;
|
||||
log_streams.push_back(&buf);
|
||||
pass->help();
|
||||
log_streams.pop_back();
|
||||
std::stringstream ss;
|
||||
ss << buf.str();
|
||||
|
||||
// parse command help
|
||||
size_t def_strip_count = 0;
|
||||
auto current_state = PUState_none;
|
||||
auto catch_verific = false;
|
||||
auto blank_lines = 2;
|
||||
for (string line; std::getline(ss, line, '\n');) {
|
||||
// find position of first non space character
|
||||
std::size_t first_pos = line.find_first_not_of(" \t");
|
||||
std::size_t last_pos = line.find_last_not_of(" \t");
|
||||
if (first_pos == std::string::npos) {
|
||||
switch (current_state)
|
||||
{
|
||||
case PUState_signature:
|
||||
root_listing->usage(current_buffer, null_source);
|
||||
current_listing = root_listing;
|
||||
current_state = PUState_none;
|
||||
current_buffer = "";
|
||||
break;
|
||||
case PUState_none:
|
||||
case PUState_optionbody:
|
||||
blank_lines += 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// skip empty lines
|
||||
continue;
|
||||
}
|
||||
|
||||
// strip leading and trailing whitespace
|
||||
std::string stripped_line = line.substr(first_pos, last_pos - first_pos +1);
|
||||
bool IsDefinition = stripped_line[0] == '-';
|
||||
IsDefinition &= stripped_line[1] != ' ' && stripped_line[1] != '>';
|
||||
bool IsDedent = def_strip_count && first_pos < def_strip_count;
|
||||
bool IsIndent = def_strip_count < first_pos;
|
||||
|
||||
// line looks like a signature
|
||||
bool IsSignature = stripped_line.find(name) == 0 && (stripped_line.length() == name.length() || stripped_line.at(name.size()) == ' ');
|
||||
|
||||
if (IsSignature && first_pos <= 4 && (blank_lines >= 2 || current_state == PUState_signature)) {
|
||||
if (current_state == PUState_options || current_state == PUState_optionbody) {
|
||||
current_listing->codeblock(current_buffer, "none", null_source);
|
||||
current_buffer = "";
|
||||
} else if (current_state == PUState_signature) {
|
||||
root_listing->usage(current_buffer, null_source);
|
||||
current_buffer = "";
|
||||
} else if (current_state == PUState_none && !current_buffer.empty()) {
|
||||
current_listing->codeblock(current_buffer, "none", null_source);
|
||||
current_buffer = "";
|
||||
}
|
||||
current_listing = root_listing;
|
||||
current_state = PUState_signature;
|
||||
def_strip_count = first_pos;
|
||||
catch_verific = false;
|
||||
} else if (IsDedent) {
|
||||
def_strip_count = first_pos;
|
||||
if (current_state == PUState_optionbody) {
|
||||
if (!current_buffer.empty()) {
|
||||
current_listing->codeblock(current_buffer, "none", null_source);
|
||||
current_buffer = "";
|
||||
}
|
||||
if (IsIndent) {
|
||||
current_state = PUState_options;
|
||||
current_listing = root_listing->back();
|
||||
} else {
|
||||
current_state = PUState_none;
|
||||
current_listing = root_listing;
|
||||
}
|
||||
} else {
|
||||
current_state = PUState_none;
|
||||
}
|
||||
}
|
||||
|
||||
if (IsDefinition && !catch_verific && current_state != PUState_signature) {
|
||||
if (!current_buffer.empty()) {
|
||||
current_listing->codeblock(current_buffer, "none", null_source);
|
||||
current_buffer = "";
|
||||
}
|
||||
current_state = PUState_options;
|
||||
current_listing = root_listing->open_option(stripped_line, null_source);
|
||||
def_strip_count = first_pos;
|
||||
} else {
|
||||
if (current_state == PUState_options) {
|
||||
current_state = PUState_optionbody;
|
||||
}
|
||||
if (current_buffer.empty())
|
||||
current_buffer = stripped_line;
|
||||
else if (current_state == PUState_signature && IsIndent)
|
||||
current_buffer += stripped_line;
|
||||
else if (current_state == PUState_none) {
|
||||
current_buffer += (blank_lines > 0 ? "\n\n" : "\n") + line;
|
||||
} else
|
||||
current_buffer += (blank_lines > 0 ? "\n\n" : "\n") + stripped_line;
|
||||
if (stripped_line.compare("Command file parser supports following commands in file:") == 0)
|
||||
catch_verific = true;
|
||||
}
|
||||
blank_lines = 0;
|
||||
}
|
||||
|
||||
if (!current_buffer.empty()) {
|
||||
if (current_buffer.size() > 64 && current_buffer.substr(0, 64).compare("The following commands are executed by this synthesis command:\n\n") == 0) {
|
||||
current_listing->paragraph(current_buffer.substr(0, 62), null_source);
|
||||
current_listing->codeblock(current_buffer.substr(64), "yoscrypt", null_source);
|
||||
} else
|
||||
current_listing->codeblock(current_buffer, "none", null_source);
|
||||
current_buffer = "";
|
||||
}
|
||||
// render html
|
||||
fprintf(f, ".. cmd:def:: %s\n", cmd.c_str());
|
||||
fprintf(f, " :title: %s\n\n", title.c_str());
|
||||
fprintf(f, " .. only:: html\n\n");
|
||||
std::stringstream ss;
|
||||
std::string textcp = text;
|
||||
ss << text;
|
||||
bool IsUsage = true;
|
||||
int blank_count = 0;
|
||||
size_t def_strip_count = 0;
|
||||
bool WasDefinition = false;
|
||||
for (std::string line; std::getline(ss, line, '\n');) {
|
||||
// find position of first non space character
|
||||
std::size_t first_pos = line.find_first_not_of(" \t");
|
||||
std::size_t last_pos = line.find_last_not_of(" \t");
|
||||
if (first_pos == std::string::npos) {
|
||||
// skip formatting empty lines
|
||||
if (!WasDefinition)
|
||||
fputc('\n', f);
|
||||
blank_count += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
// attempt auto group
|
||||
if (!cmd_help.has_group()) {
|
||||
string source_file = pass->location.file_name();
|
||||
bool has_source = source_file.compare("unknown") != 0;
|
||||
if (pass->internal_flag)
|
||||
cmd_help.group = "internal";
|
||||
else if (source_file.find("backends/") == 0 || (!has_source && name.find("read_") == 0))
|
||||
cmd_help.group = "backends";
|
||||
else if (source_file.find("frontends/") == 0 || (!has_source && name.find("write_") == 0))
|
||||
cmd_help.group = "frontends";
|
||||
else if (has_source) {
|
||||
auto last_slash = source_file.find_last_of('/');
|
||||
if (last_slash != string::npos) {
|
||||
auto parent_path = source_file.substr(0, last_slash);
|
||||
cmd_help.group = parent_path;
|
||||
}
|
||||
// strip leading and trailing whitespace
|
||||
std::string stripped_line = line.substr(first_pos, last_pos - first_pos +1);
|
||||
bool IsDefinition = stripped_line[0] == '-';
|
||||
IsDefinition &= stripped_line[1] != ' ' && stripped_line[1] != '>';
|
||||
bool IsDedent = def_strip_count && first_pos <= def_strip_count;
|
||||
bool IsIndent = first_pos == 2 || first_pos == 4;
|
||||
if (cmd.compare(0, 7, "verific") == 0)
|
||||
// verific.cc has strange and different formatting from the rest
|
||||
IsIndent = false;
|
||||
|
||||
// another usage block
|
||||
bool NewUsage = stripped_line.find(cmd) == 0;
|
||||
|
||||
if (IsUsage) {
|
||||
if (stripped_line.compare(0, 4, "See ") == 0) {
|
||||
// description refers to another function
|
||||
fprintf(f, "\n %s\n", stripped_line.c_str());
|
||||
} else {
|
||||
// usage should be the first line of help output
|
||||
fprintf(f, "\n .. code:: yoscrypt\n\n %s\n\n ", stripped_line.c_str());
|
||||
WasDefinition = true;
|
||||
}
|
||||
// implicit !has_source
|
||||
else if (name.find("equiv") == 0)
|
||||
cmd_help.group = "passes/equiv";
|
||||
else if (name.find("fsm") == 0)
|
||||
cmd_help.group = "passes/fsm";
|
||||
else if (name.find("memory") == 0)
|
||||
cmd_help.group = "passes/memory";
|
||||
else if (name.find("opt") == 0)
|
||||
cmd_help.group = "passes/opt";
|
||||
else if (name.find("proc") == 0)
|
||||
cmd_help.group = "passes/proc";
|
||||
IsUsage = false;
|
||||
} else if (IsIndent && NewUsage && (blank_count >= 2 || WasDefinition)) {
|
||||
// another usage block
|
||||
fprintf(f, "\n .. code:: yoscrypt\n\n %s\n\n ", stripped_line.c_str());
|
||||
WasDefinition = true;
|
||||
def_strip_count = 0;
|
||||
} else if (IsIndent && IsDefinition && (blank_count || WasDefinition)) {
|
||||
// format definition term
|
||||
fprintf(f, "\n\n .. code:: yoscrypt\n\n %s\n\n ", stripped_line.c_str());
|
||||
WasDefinition = true;
|
||||
def_strip_count = first_pos;
|
||||
} else {
|
||||
if (IsDedent) {
|
||||
fprintf(f, "\n\n ::\n");
|
||||
def_strip_count = first_pos;
|
||||
} else if (WasDefinition) {
|
||||
fprintf(f, "::\n");
|
||||
WasDefinition = false;
|
||||
}
|
||||
fprintf(f, "\n %s", line.substr(def_strip_count, std::string::npos).c_str());
|
||||
}
|
||||
|
||||
if (groups.count(cmd_help.group) == 0) {
|
||||
groups[cmd_help.group] = vector<string>();
|
||||
}
|
||||
groups[cmd_help.group].push_back(name);
|
||||
|
||||
// write to json
|
||||
json.name(name.c_str()); json.begin_object();
|
||||
json.entry("title", title);
|
||||
json.name("content"); json.begin_array();
|
||||
for (auto content : cmd_help.get_content())
|
||||
json.value(content->to_json());
|
||||
json.end_array();
|
||||
json.entry("group", cmd_help.group);
|
||||
json.entry("source_file", pass->location.file_name());
|
||||
json.entry("source_line", pass->location.line());
|
||||
json.entry("source_func", pass->location.function_name());
|
||||
json.entry("experimental_flag", pass->experimental_flag);
|
||||
json.entry("internal_flag", pass->internal_flag);
|
||||
json.end_object();
|
||||
blank_count = 0;
|
||||
}
|
||||
json.end_object();
|
||||
fputc('\n', f);
|
||||
|
||||
json.entry("groups", groups);
|
||||
// render latex
|
||||
fprintf(f, ".. only:: latex\n\n");
|
||||
fprintf(f, " ::\n\n");
|
||||
std::stringstream ss2;
|
||||
ss2 << textcp;
|
||||
for (std::string line; std::getline(ss2, line, '\n');) {
|
||||
fprintf(f, " %s\n", line.c_str());
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
void write_cell_rst(Yosys::SimHelper cell, Yosys::CellType ct)
|
||||
{
|
||||
// open
|
||||
FILE *f = fopen(stringf("docs/source/cell/%s.rst", cell.filesafe_name().c_str()).c_str(), "wt");
|
||||
|
||||
json.end_object();
|
||||
return raise_error;
|
||||
// make header
|
||||
string title_line;
|
||||
if (cell.title.length())
|
||||
title_line = stringf("%s - %s", cell.name.c_str(), cell.title.c_str());
|
||||
else title_line = cell.name;
|
||||
string underline = "\n";
|
||||
underline.insert(0, title_line.length(), '=');
|
||||
fprintf(f, "%s\n", title_line.c_str());
|
||||
fprintf(f, "%s\n", underline.c_str());
|
||||
|
||||
// help text, with cell def for links
|
||||
fprintf(f, ".. cell:def:: %s\n", cell.name.c_str());
|
||||
if (cell.title.length())
|
||||
fprintf(f, " :title: %s\n\n", cell.title.c_str());
|
||||
else
|
||||
fprintf(f, " :title: %s\n\n", cell.name.c_str());
|
||||
std::stringstream ss;
|
||||
ss << cell.desc;
|
||||
for (std::string line; std::getline(ss, line, '\n');) {
|
||||
fprintf(f, " %s\n", line.c_str());
|
||||
}
|
||||
|
||||
// properties
|
||||
fprintf(f, "\nProperties");
|
||||
fprintf(f, "\n----------\n\n");
|
||||
dict<string, bool> prop_dict = {
|
||||
{"is_evaluable", ct.is_evaluable},
|
||||
{"is_combinatorial", ct.is_combinatorial},
|
||||
{"is_synthesizable", ct.is_synthesizable},
|
||||
};
|
||||
for (auto &it : prop_dict) {
|
||||
fprintf(f, "- %s: %s\n", it.first.c_str(), it.second ? "true" : "false");
|
||||
}
|
||||
|
||||
// source code
|
||||
fprintf(f, "\nSimulation model (Verilog)");
|
||||
fprintf(f, "\n--------------------------\n\n");
|
||||
fprintf(f, ".. code-block:: verilog\n");
|
||||
fprintf(f, " :caption: %s\n\n", cell.source.c_str());
|
||||
std::stringstream ss2;
|
||||
ss2 << cell.code;
|
||||
for (std::string line; std::getline(ss2, line, '\n');) {
|
||||
fprintf(f, " %s\n", line.c_str());
|
||||
}
|
||||
|
||||
// footer
|
||||
fprintf(f, "\n.. note::\n\n");
|
||||
fprintf(f, " This page was auto-generated from the output of\n");
|
||||
fprintf(f, " ``help %s``.\n", cell.name.c_str());
|
||||
|
||||
// close
|
||||
fclose(f);
|
||||
}
|
||||
bool dump_cells_json(PrettyJson &json) {
|
||||
// init json
|
||||
|
@ -1045,7 +960,11 @@ struct HelpPass : public Pass {
|
|||
log("=");
|
||||
log("\n");
|
||||
it.second->help();
|
||||
log_warning_flags(it.second);
|
||||
if (it.second->experimental_flag) {
|
||||
log("\n");
|
||||
log("WARNING: THE '%s' COMMAND IS EXPERIMENTAL.\n", it.first.c_str());
|
||||
log("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (args[1] == "-cells") {
|
||||
|
@ -1059,9 +978,44 @@ struct HelpPass : public Pass {
|
|||
log("\n");
|
||||
return;
|
||||
}
|
||||
// this option is undocumented as it is for internal use only
|
||||
else if (args[1] == "-write-rst-command-reference-manual") {
|
||||
for (auto &it : pass_register) {
|
||||
std::ostringstream buf;
|
||||
log_streams.push_back(&buf);
|
||||
it.second->help();
|
||||
if (it.second->experimental_flag) {
|
||||
log("\n");
|
||||
log("WARNING: THE '%s' COMMAND IS EXPERIMENTAL.\n", it.first.c_str());
|
||||
log("\n");
|
||||
}
|
||||
log_streams.pop_back();
|
||||
write_cmd_rst(it.first, it.second->short_help, buf.str());
|
||||
}
|
||||
}
|
||||
// this option is also undocumented as it is for internal use only
|
||||
else if (args[1] == "-write-rst-cells-manual") {
|
||||
bool raise_error = false;
|
||||
for (auto &it : yosys_celltypes.cell_types) {
|
||||
auto name = it.first.str();
|
||||
if (cell_help_messages.contains(name)) {
|
||||
write_cell_rst(cell_help_messages.get(name), it.second);
|
||||
} else {
|
||||
log("ERROR: Missing cell help for cell '%s'.\n", name.c_str());
|
||||
raise_error |= true;
|
||||
}
|
||||
}
|
||||
if (raise_error) {
|
||||
log_error("One or more cells defined in celltypes.h are missing help documentation.\n");
|
||||
}
|
||||
}
|
||||
else if (pass_register.count(args[1])) {
|
||||
pass_register.at(args[1])->help();
|
||||
log_warning_flags(pass_register.at(args[1]));
|
||||
if (pass_register.at(args[1])->experimental_flag) {
|
||||
log("\n");
|
||||
log("WARNING: THE '%s' COMMAND IS EXPERIMENTAL.\n", args[1].c_str());
|
||||
log("\n");
|
||||
}
|
||||
}
|
||||
else if (cell_help_messages.contains(args[1])) {
|
||||
auto help_cell = cell_help_messages.get(args[1]);
|
||||
|
@ -1090,17 +1044,7 @@ struct HelpPass : public Pass {
|
|||
log("No such command or cell type: %s\n", args[1].c_str());
|
||||
return;
|
||||
} else if (args.size() == 3) {
|
||||
// this option is undocumented as it is for internal use only
|
||||
if (args[1] == "-dump-cmds-json") {
|
||||
PrettyJson json;
|
||||
if (!json.write_to_file(args[2]))
|
||||
log_error("Can't open file `%s' for writing: %s\n", args[2].c_str(), strerror(errno));
|
||||
if (dump_cmds_json(json)) {
|
||||
log_abort();
|
||||
}
|
||||
}
|
||||
// this option is undocumented as it is for internal use only
|
||||
else if (args[1] == "-dump-cells-json") {
|
||||
if (args[1] == "-dump-cells-json") {
|
||||
PrettyJson json;
|
||||
if (!json.write_to_file(args[2]))
|
||||
log_error("Can't open file `%s' for writing: %s\n", args[2].c_str(), strerror(errno));
|
||||
|
@ -1108,8 +1052,6 @@ struct HelpPass : public Pass {
|
|||
log_error("One or more cells defined in celltypes.h are missing help documentation.\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
log("Unknown help command: `%s %s'\n", args[1].c_str(), args[2].c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,62 +23,27 @@
|
|||
#include "kernel/yosys_common.h"
|
||||
#include "kernel/yosys.h"
|
||||
|
||||
#include <version>
|
||||
#if __cpp_lib_source_location == 201907L
|
||||
#include <source_location>
|
||||
using std::source_location;
|
||||
#elif defined(__has_include)
|
||||
# if __has_include(<experimental/source_location>)
|
||||
#include <experimental/source_location>
|
||||
using std::experimental::source_location;
|
||||
# else
|
||||
#define SOURCE_FALLBACK
|
||||
# endif
|
||||
#else
|
||||
#define SOURCE_FALLBACK
|
||||
#endif
|
||||
|
||||
#ifdef SOURCE_FALLBACK
|
||||
struct source_location { // dummy placeholder
|
||||
int line() const { return 0; }
|
||||
int column() const { return 0; }
|
||||
const char* file_name() const { return "unknown"; }
|
||||
const char* function_name() const { return "unknown"; }
|
||||
static const source_location current(...) { return source_location(); }
|
||||
};
|
||||
#endif
|
||||
|
||||
YOSYS_NAMESPACE_BEGIN
|
||||
|
||||
struct Pass
|
||||
{
|
||||
std::string pass_name, short_help;
|
||||
source_location location;
|
||||
Pass(std::string name, std::string short_help = "** document me **",
|
||||
source_location location = source_location::current());
|
||||
Pass(std::string name, std::string short_help = "** document me **");
|
||||
// Prefer overriding 'Pass::on_shutdown()' if possible
|
||||
virtual ~Pass();
|
||||
|
||||
// Makes calls to log() to generate help message
|
||||
virtual void help();
|
||||
// Uses PrettyHelp::get_current() to produce a more portable formatted help message
|
||||
virtual bool formatted_help();
|
||||
virtual void clear_flags();
|
||||
virtual void execute(std::vector<std::string> args, RTLIL::Design *design) = 0;
|
||||
|
||||
int call_counter;
|
||||
int64_t runtime_ns;
|
||||
bool experimental_flag = false;
|
||||
bool internal_flag = false;
|
||||
|
||||
void experimental() {
|
||||
experimental_flag = true;
|
||||
}
|
||||
|
||||
void internal() {
|
||||
internal_flag = true;
|
||||
}
|
||||
|
||||
struct pre_post_exec_state_t {
|
||||
Pass *parent_pass;
|
||||
int64_t begin_ns;
|
||||
|
@ -116,8 +81,7 @@ struct ScriptPass : Pass
|
|||
RTLIL::Design *active_design;
|
||||
std::string active_run_from, active_run_to;
|
||||
|
||||
ScriptPass(std::string name, std::string short_help = "** document me **", source_location location = source_location::current()) :
|
||||
Pass(name, short_help, location) { }
|
||||
ScriptPass(std::string name, std::string short_help = "** document me **") : Pass(name, short_help) { }
|
||||
|
||||
virtual void script() = 0;
|
||||
|
||||
|
@ -135,8 +99,7 @@ struct Frontend : Pass
|
|||
static std::string last_here_document;
|
||||
|
||||
std::string frontend_name;
|
||||
Frontend(std::string name, std::string short_help = "** document me **",
|
||||
source_location location = source_location::current());
|
||||
Frontend(std::string name, std::string short_help = "** document me **");
|
||||
void run_register() override;
|
||||
~Frontend() override;
|
||||
void execute(std::vector<std::string> args, RTLIL::Design *design) override final;
|
||||
|
@ -152,8 +115,7 @@ struct Frontend : Pass
|
|||
struct Backend : Pass
|
||||
{
|
||||
std::string backend_name;
|
||||
Backend(std::string name, std::string short_help = "** document me **",
|
||||
source_location location = source_location::current());
|
||||
Backend(std::string name, std::string short_help = "** document me **");
|
||||
void run_register() override;
|
||||
~Backend() override;
|
||||
void execute(std::vector<std::string> args, RTLIL::Design *design) override final;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue