mirror of
https://github.com/YosysHQ/yosys
synced 2025-07-29 15:37:59 +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
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue